Annotation of src/usr.bin/ssh/sshbuf-getput-basic.c, Revision 1.8
1.8 ! djm 1: /* $OpenBSD: sshbuf-getput-basic.c,v 1.7 2017/06/01 04:51:58 djm Exp $ */
1.1 djm 2: /*
3: * Copyright (c) 2011 Damien Miller
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: #include <sys/types.h>
1.6 dtucker 19:
20: #include <stdarg.h>
1.1 djm 21: #include <stdlib.h>
22: #include <stdio.h>
23: #include <string.h>
24:
25: #include "ssherr.h"
26: #define SSHBUF_INTERNAL
27: #include "sshbuf.h"
28:
29: int
30: sshbuf_get(struct sshbuf *buf, void *v, size_t len)
31: {
32: const u_char *p = sshbuf_ptr(buf);
33: int r;
34:
35: if ((r = sshbuf_consume(buf, len)) < 0)
36: return r;
1.3 djm 37: if (v != NULL && len != 0)
1.1 djm 38: memcpy(v, p, len);
39: return 0;
40: }
41:
42: int
43: sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
44: {
45: const u_char *p = sshbuf_ptr(buf);
46: int r;
47:
48: if ((r = sshbuf_consume(buf, 8)) < 0)
49: return r;
50: if (valp != NULL)
51: *valp = PEEK_U64(p);
52: return 0;
53: }
54:
55: int
56: sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
57: {
58: const u_char *p = sshbuf_ptr(buf);
59: int r;
60:
61: if ((r = sshbuf_consume(buf, 4)) < 0)
62: return r;
63: if (valp != NULL)
64: *valp = PEEK_U32(p);
65: return 0;
66: }
67:
68: int
69: sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp)
70: {
71: const u_char *p = sshbuf_ptr(buf);
72: int r;
73:
74: if ((r = sshbuf_consume(buf, 2)) < 0)
75: return r;
76: if (valp != NULL)
77: *valp = PEEK_U16(p);
78: return 0;
79: }
80:
81: int
82: sshbuf_get_u8(struct sshbuf *buf, u_char *valp)
83: {
84: const u_char *p = sshbuf_ptr(buf);
85: int r;
86:
87: if ((r = sshbuf_consume(buf, 1)) < 0)
88: return r;
89: if (valp != NULL)
90: *valp = (u_int8_t)*p;
91: return 0;
92: }
93:
1.8 ! djm 94: static int
! 95: check_offset(const struct sshbuf *buf, int wr, size_t offset, size_t len)
! 96: {
! 97: if (sshbuf_ptr(buf) == NULL) /* calls sshbuf_check_sanity() */
! 98: return SSH_ERR_INTERNAL_ERROR;
! 99: if (offset >= SIZE_MAX - len)
! 100: return SSH_ERR_INVALID_ARGUMENT;
! 101: if (offset + len > sshbuf_len(buf)) {
! 102: return wr ?
! 103: SSH_ERR_NO_BUFFER_SPACE : SSH_ERR_MESSAGE_INCOMPLETE;
! 104: }
! 105: return 0;
! 106: }
! 107:
! 108: static int
! 109: check_roffset(const struct sshbuf *buf, size_t offset, size_t len,
! 110: const u_char **p)
! 111: {
! 112: int r;
! 113:
! 114: *p = NULL;
! 115: if ((r = check_offset(buf, 0, offset, len)) != 0)
! 116: return r;
! 117: *p = sshbuf_ptr(buf) + offset;
! 118: return 0;
! 119: }
! 120:
! 121: int
! 122: sshbuf_peek_u64(const struct sshbuf *buf, size_t offset, u_int64_t *valp)
! 123: {
! 124: const u_char *p = NULL;
! 125: int r;
! 126:
! 127: if (valp != NULL)
! 128: *valp = 0;
! 129: if ((r = check_roffset(buf, offset, 8, &p)) != 0)
! 130: return r;
! 131: if (valp != NULL)
! 132: *valp = PEEK_U64(p);
! 133: return 0;
! 134: }
! 135:
! 136: int
! 137: sshbuf_peek_u32(const struct sshbuf *buf, size_t offset, u_int32_t *valp)
! 138: {
! 139: const u_char *p = NULL;
! 140: int r;
! 141:
! 142: if (valp != NULL)
! 143: *valp = 0;
! 144: if ((r = check_roffset(buf, offset, 4, &p)) != 0)
! 145: return r;
! 146: if (valp != NULL)
! 147: *valp = PEEK_U32(p);
! 148: return 0;
! 149: }
! 150:
! 151: int
! 152: sshbuf_peek_u16(const struct sshbuf *buf, size_t offset, u_int16_t *valp)
! 153: {
! 154: const u_char *p = NULL;
! 155: int r;
! 156:
! 157: if (valp != NULL)
! 158: *valp = 0;
! 159: if ((r = check_roffset(buf, offset, 2, &p)) != 0)
! 160: return r;
! 161: if (valp != NULL)
! 162: *valp = PEEK_U16(p);
! 163: return 0;
! 164: }
! 165:
! 166: int
! 167: sshbuf_peek_u8(const struct sshbuf *buf, size_t offset, u_char *valp)
! 168: {
! 169: const u_char *p = NULL;
! 170: int r;
! 171:
! 172: if (valp != NULL)
! 173: *valp = 0;
! 174: if ((r = check_roffset(buf, offset, 1, &p)) != 0)
! 175: return r;
! 176: if (valp != NULL)
! 177: *valp = *p;
! 178: return 0;
! 179: }
! 180:
1.1 djm 181: int
182: sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
183: {
184: const u_char *val;
185: size_t len;
186: int r;
187:
188: if (valp != NULL)
189: *valp = NULL;
190: if (lenp != NULL)
191: *lenp = 0;
192: if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
193: return r;
194: if (valp != NULL) {
195: if ((*valp = malloc(len + 1)) == NULL) {
196: SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
197: return SSH_ERR_ALLOC_FAIL;
198: }
1.3 djm 199: if (len != 0)
200: memcpy(*valp, val, len);
1.1 djm 201: (*valp)[len] = '\0';
202: }
203: if (lenp != NULL)
204: *lenp = len;
205: return 0;
206: }
207:
208: int
209: sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
210: {
211: size_t len;
212: const u_char *p;
213: int r;
214:
215: if (valp != NULL)
216: *valp = NULL;
217: if (lenp != NULL)
218: *lenp = 0;
219: if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
220: return r;
1.5 mmcc 221: if (valp != NULL)
1.1 djm 222: *valp = p;
223: if (lenp != NULL)
224: *lenp = len;
225: if (sshbuf_consume(buf, len + 4) != 0) {
226: /* Shouldn't happen */
227: SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
228: SSHBUF_ABORT();
229: return SSH_ERR_INTERNAL_ERROR;
230: }
231: return 0;
232: }
233:
234: int
235: sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
236: size_t *lenp)
237: {
238: u_int32_t len;
239: const u_char *p = sshbuf_ptr(buf);
240:
241: if (valp != NULL)
242: *valp = NULL;
243: if (lenp != NULL)
244: *lenp = 0;
245: if (sshbuf_len(buf) < 4) {
246: SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
247: return SSH_ERR_MESSAGE_INCOMPLETE;
248: }
249: len = PEEK_U32(p);
250: if (len > SSHBUF_SIZE_MAX - 4) {
251: SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
252: return SSH_ERR_STRING_TOO_LARGE;
253: }
254: if (sshbuf_len(buf) - 4 < len) {
255: SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
256: return SSH_ERR_MESSAGE_INCOMPLETE;
257: }
1.5 mmcc 258: if (valp != NULL)
1.1 djm 259: *valp = p + 4;
260: if (lenp != NULL)
261: *lenp = len;
262: return 0;
263: }
264:
265: int
266: sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
267: {
268: size_t len;
269: const u_char *p, *z;
270: int r;
271:
272: if (valp != NULL)
273: *valp = NULL;
274: if (lenp != NULL)
275: *lenp = 0;
276: if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
277: return r;
278: /* Allow a \0 only at the end of the string */
279: if (len > 0 &&
280: (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
281: SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
282: return SSH_ERR_INVALID_FORMAT;
283: }
284: if ((r = sshbuf_skip_string(buf)) != 0)
285: return -1;
286: if (valp != NULL) {
287: if ((*valp = malloc(len + 1)) == NULL) {
288: SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
289: return SSH_ERR_ALLOC_FAIL;
290: }
1.3 djm 291: if (len != 0)
292: memcpy(*valp, p, len);
1.1 djm 293: (*valp)[len] = '\0';
294: }
295: if (lenp != NULL)
296: *lenp = (size_t)len;
297: return 0;
298: }
299:
300: int
301: sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
302: {
303: u_int32_t len;
304: u_char *p;
305: int r;
306:
307: /*
308: * Use sshbuf_peek_string_direct() to figure out if there is
309: * a complete string in 'buf' and copy the string directly
310: * into 'v'.
311: */
312: if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
313: (r = sshbuf_get_u32(buf, &len)) != 0 ||
314: (r = sshbuf_reserve(v, len, &p)) != 0 ||
315: (r = sshbuf_get(buf, p, len)) != 0)
316: return r;
317: return 0;
318: }
319:
320: int
321: sshbuf_put(struct sshbuf *buf, const void *v, size_t len)
322: {
323: u_char *p;
324: int r;
325:
326: if ((r = sshbuf_reserve(buf, len, &p)) < 0)
327: return r;
1.3 djm 328: if (len != 0)
329: memcpy(p, v, len);
1.1 djm 330: return 0;
331: }
332:
333: int
334: sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
335: {
336: return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
337: }
338:
339: int
340: sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
341: {
342: va_list ap;
343: int r;
344:
345: va_start(ap, fmt);
346: r = sshbuf_putfv(buf, fmt, ap);
347: va_end(ap);
348: return r;
349: }
350:
351: int
352: sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
353: {
354: va_list ap2;
355: int r, len;
356: u_char *p;
357:
358: va_copy(ap2, ap);
359: if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
360: r = SSH_ERR_INVALID_ARGUMENT;
361: goto out;
362: }
363: if (len == 0) {
364: r = 0;
365: goto out; /* Nothing to do */
366: }
367: va_end(ap2);
368: va_copy(ap2, ap);
369: if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
370: goto out;
371: if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
372: r = SSH_ERR_INTERNAL_ERROR;
373: goto out; /* Shouldn't happen */
374: }
375: /* Consume terminating \0 */
376: if ((r = sshbuf_consume_end(buf, 1)) != 0)
377: goto out;
378: r = 0;
379: out:
380: va_end(ap2);
381: return r;
382: }
383:
384: int
385: sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
386: {
387: u_char *p;
388: int r;
389:
390: if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
391: return r;
392: POKE_U64(p, val);
393: return 0;
394: }
395:
396: int
397: sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
398: {
399: u_char *p;
400: int r;
401:
402: if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
403: return r;
404: POKE_U32(p, val);
405: return 0;
406: }
407:
408: int
409: sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
410: {
411: u_char *p;
412: int r;
413:
414: if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
415: return r;
416: POKE_U16(p, val);
417: return 0;
418: }
419:
420: int
421: sshbuf_put_u8(struct sshbuf *buf, u_char val)
422: {
423: u_char *p;
424: int r;
425:
426: if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
427: return r;
428: p[0] = val;
1.8 ! djm 429: return 0;
! 430: }
! 431:
! 432: static int
! 433: check_woffset(struct sshbuf *buf, size_t offset, size_t len, u_char **p)
! 434: {
! 435: int r;
! 436:
! 437: *p = NULL;
! 438: if ((r = check_offset(buf, 1, offset, len)) != 0)
! 439: return r;
! 440: if (sshbuf_mutable_ptr(buf) == NULL)
! 441: return SSH_ERR_BUFFER_READ_ONLY;
! 442: *p = sshbuf_mutable_ptr(buf) + offset;
! 443: return 0;
! 444: }
! 445:
! 446: int
! 447: sshbuf_poke_u64(struct sshbuf *buf, size_t offset, u_int64_t val)
! 448: {
! 449: u_char *p = NULL;
! 450: int r;
! 451:
! 452: if ((r = check_woffset(buf, offset, 8, &p)) != 0)
! 453: return r;
! 454: POKE_U64(p, val);
! 455: return 0;
! 456: }
! 457:
! 458: int
! 459: sshbuf_poke_u32(struct sshbuf *buf, size_t offset, u_int32_t val)
! 460: {
! 461: u_char *p = NULL;
! 462: int r;
! 463:
! 464: if ((r = check_woffset(buf, offset, 4, &p)) != 0)
! 465: return r;
! 466: POKE_U32(p, val);
! 467: return 0;
! 468: }
! 469:
! 470: int
! 471: sshbuf_poke_u16(struct sshbuf *buf, size_t offset, u_int16_t val)
! 472: {
! 473: u_char *p = NULL;
! 474: int r;
! 475:
! 476: if ((r = check_woffset(buf, offset, 2, &p)) != 0)
! 477: return r;
! 478: POKE_U16(p, val);
! 479: return 0;
! 480: }
! 481:
! 482: int
! 483: sshbuf_poke_u8(struct sshbuf *buf, size_t offset, u_char val)
! 484: {
! 485: u_char *p = NULL;
! 486: int r;
! 487:
! 488: if ((r = check_woffset(buf, offset, 1, &p)) != 0)
! 489: return r;
! 490: *p = val;
! 491: return 0;
! 492: }
! 493:
! 494: int
! 495: sshbuf_poke(struct sshbuf *buf, size_t offset, void *v, size_t len)
! 496: {
! 497: u_char *p = NULL;
! 498: int r;
! 499:
! 500: if ((r = check_woffset(buf, offset, len, &p)) != 0)
! 501: return r;
! 502: memcpy(p, v, len);
1.1 djm 503: return 0;
504: }
505:
506: int
507: sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
508: {
509: u_char *d;
510: int r;
511:
512: if (len > SSHBUF_SIZE_MAX - 4) {
513: SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
514: return SSH_ERR_NO_BUFFER_SPACE;
515: }
516: if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
517: return r;
518: POKE_U32(d, len);
1.3 djm 519: if (len != 0)
520: memcpy(d + 4, v, len);
1.1 djm 521: return 0;
522: }
523:
524: int
525: sshbuf_put_cstring(struct sshbuf *buf, const char *v)
526: {
1.7 djm 527: return sshbuf_put_string(buf, v, v == NULL ? 0 : strlen(v));
1.1 djm 528: }
529:
530: int
531: sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
532: {
533: return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
534: }
535:
536: int
537: sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
538: {
539: const u_char *p;
540: size_t len;
541: struct sshbuf *ret;
542: int r;
543:
544: if (buf == NULL || bufp == NULL)
545: return SSH_ERR_INVALID_ARGUMENT;
546: *bufp = NULL;
547: if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
548: return r;
549: if ((ret = sshbuf_from(p, len)) == NULL)
550: return SSH_ERR_ALLOC_FAIL;
551: if ((r = sshbuf_consume(buf, len + 4)) != 0 || /* Shouldn't happen */
552: (r = sshbuf_set_parent(ret, buf)) != 0) {
553: sshbuf_free(ret);
554: return r;
555: }
556: *bufp = ret;
557: return 0;
558: }
559:
560: int
561: sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
562: {
563: u_char *d;
564: const u_char *s = (const u_char *)v;
565: int r, prepend;
566:
567: if (len > SSHBUF_SIZE_MAX - 5) {
568: SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
569: return SSH_ERR_NO_BUFFER_SPACE;
570: }
571: /* Skip leading zero bytes */
572: for (; len > 0 && *s == 0; len--, s++)
573: ;
574: /*
575: * If most significant bit is set then prepend a zero byte to
576: * avoid interpretation as a negative number.
577: */
578: prepend = len > 0 && (s[0] & 0x80) != 0;
579: if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
580: return r;
581: POKE_U32(d, len + prepend);
582: if (prepend)
583: d[4] = 0;
1.3 djm 584: if (len != 0)
585: memcpy(d + 4 + prepend, s, len);
1.4 djm 586: return 0;
587: }
588:
589: int
590: sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
591: const u_char **valp, size_t *lenp)
592: {
593: const u_char *d;
594: size_t len, olen;
595: int r;
596:
597: if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
598: return r;
599: len = olen;
600: /* Refuse negative (MSB set) bignums */
601: if ((len != 0 && (*d & 0x80) != 0))
602: return SSH_ERR_BIGNUM_IS_NEGATIVE;
603: /* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
604: if (len > SSHBUF_MAX_BIGNUM + 1 ||
605: (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
606: return SSH_ERR_BIGNUM_TOO_LARGE;
607: /* Trim leading zeros */
608: while (len > 0 && *d == 0x00) {
609: d++;
610: len--;
611: }
1.5 mmcc 612: if (valp != NULL)
1.4 djm 613: *valp = d;
614: if (lenp != NULL)
615: *lenp = len;
616: if (sshbuf_consume(buf, olen + 4) != 0) {
617: /* Shouldn't happen */
618: SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
619: SSHBUF_ABORT();
620: return SSH_ERR_INTERNAL_ERROR;
621: }
1.1 djm 622: return 0;
623: }