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