Annotation of src/usr.bin/ssh/sshbuf-getput-basic.c, Revision 1.9
1.9 ! djm 1: /* $OpenBSD: sshbuf-getput-basic.c,v 1.8 2019/07/14 23:32:27 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) {
197: SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
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 */
228: SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
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) {
247: SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
248: return SSH_ERR_MESSAGE_INCOMPLETE;
249: }
250: len = PEEK_U32(p);
251: if (len > SSHBUF_SIZE_MAX - 4) {
252: SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
253: return SSH_ERR_STRING_TOO_LARGE;
254: }
255: if (sshbuf_len(buf) - 4 < len) {
256: SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
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) {
282: SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
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) {
289: SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
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: {
337: return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
338: }
339:
340: int
341: sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
342: {
343: va_list ap;
344: int r;
345:
346: va_start(ap, fmt);
347: r = sshbuf_putfv(buf, fmt, ap);
348: va_end(ap);
349: return r;
350: }
351:
352: int
353: sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
354: {
355: va_list ap2;
356: int r, len;
357: u_char *p;
358:
359: va_copy(ap2, ap);
360: if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
361: r = SSH_ERR_INVALID_ARGUMENT;
362: goto out;
363: }
364: if (len == 0) {
365: r = 0;
366: goto out; /* Nothing to do */
367: }
368: va_end(ap2);
369: va_copy(ap2, ap);
370: if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
371: goto out;
372: if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
373: r = SSH_ERR_INTERNAL_ERROR;
374: goto out; /* Shouldn't happen */
375: }
376: /* Consume terminating \0 */
377: if ((r = sshbuf_consume_end(buf, 1)) != 0)
378: goto out;
379: r = 0;
380: out:
381: va_end(ap2);
382: return r;
383: }
384:
385: int
386: sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
387: {
388: u_char *p;
389: int r;
390:
391: if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
392: return r;
393: POKE_U64(p, val);
394: return 0;
395: }
396:
397: int
398: sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
399: {
400: u_char *p;
401: int r;
402:
403: if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
404: return r;
405: POKE_U32(p, val);
406: return 0;
407: }
408:
409: int
410: sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
411: {
412: u_char *p;
413: int r;
414:
415: if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
416: return r;
417: POKE_U16(p, val);
418: return 0;
419: }
420:
421: int
422: sshbuf_put_u8(struct sshbuf *buf, u_char val)
423: {
424: u_char *p;
425: int r;
426:
427: if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
428: return r;
429: p[0] = val;
1.8 djm 430: return 0;
431: }
432:
433: static int
434: check_woffset(struct sshbuf *buf, size_t offset, size_t len, u_char **p)
435: {
436: int r;
437:
438: *p = NULL;
439: if ((r = check_offset(buf, 1, offset, len)) != 0)
440: return r;
441: if (sshbuf_mutable_ptr(buf) == NULL)
442: return SSH_ERR_BUFFER_READ_ONLY;
443: *p = sshbuf_mutable_ptr(buf) + offset;
444: return 0;
445: }
446:
447: int
448: sshbuf_poke_u64(struct sshbuf *buf, size_t offset, u_int64_t val)
449: {
450: u_char *p = NULL;
451: int r;
452:
453: if ((r = check_woffset(buf, offset, 8, &p)) != 0)
454: return r;
455: POKE_U64(p, val);
456: return 0;
457: }
458:
459: int
460: sshbuf_poke_u32(struct sshbuf *buf, size_t offset, u_int32_t val)
461: {
462: u_char *p = NULL;
463: int r;
464:
465: if ((r = check_woffset(buf, offset, 4, &p)) != 0)
466: return r;
467: POKE_U32(p, val);
468: return 0;
469: }
470:
471: int
472: sshbuf_poke_u16(struct sshbuf *buf, size_t offset, u_int16_t val)
473: {
474: u_char *p = NULL;
475: int r;
476:
477: if ((r = check_woffset(buf, offset, 2, &p)) != 0)
478: return r;
479: POKE_U16(p, val);
480: return 0;
481: }
482:
483: int
484: sshbuf_poke_u8(struct sshbuf *buf, size_t offset, u_char val)
485: {
486: u_char *p = NULL;
487: int r;
488:
489: if ((r = check_woffset(buf, offset, 1, &p)) != 0)
490: return r;
491: *p = val;
492: return 0;
493: }
494:
495: int
496: sshbuf_poke(struct sshbuf *buf, size_t offset, void *v, size_t len)
497: {
498: u_char *p = NULL;
499: int r;
500:
501: if ((r = check_woffset(buf, offset, len, &p)) != 0)
502: return r;
503: memcpy(p, v, len);
1.1 djm 504: return 0;
505: }
506:
507: int
508: sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
509: {
510: u_char *d;
511: int r;
512:
513: if (len > SSHBUF_SIZE_MAX - 4) {
514: SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
515: return SSH_ERR_NO_BUFFER_SPACE;
516: }
517: if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
518: return r;
519: POKE_U32(d, len);
1.3 djm 520: if (len != 0)
521: memcpy(d + 4, v, len);
1.1 djm 522: return 0;
523: }
524:
525: int
526: sshbuf_put_cstring(struct sshbuf *buf, const char *v)
527: {
1.7 djm 528: return sshbuf_put_string(buf, v, v == NULL ? 0 : strlen(v));
1.1 djm 529: }
530:
531: int
532: sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
533: {
534: return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
535: }
536:
537: int
538: sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
539: {
540: const u_char *p;
541: size_t len;
542: struct sshbuf *ret;
543: int r;
544:
545: if (buf == NULL || bufp == NULL)
546: return SSH_ERR_INVALID_ARGUMENT;
547: *bufp = NULL;
548: if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
549: return r;
550: if ((ret = sshbuf_from(p, len)) == NULL)
551: return SSH_ERR_ALLOC_FAIL;
552: if ((r = sshbuf_consume(buf, len + 4)) != 0 || /* Shouldn't happen */
553: (r = sshbuf_set_parent(ret, buf)) != 0) {
554: sshbuf_free(ret);
555: return r;
556: }
557: *bufp = ret;
558: return 0;
559: }
560:
561: int
562: sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
563: {
564: u_char *d;
565: const u_char *s = (const u_char *)v;
566: int r, prepend;
567:
568: if (len > SSHBUF_SIZE_MAX - 5) {
569: SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
570: return SSH_ERR_NO_BUFFER_SPACE;
571: }
572: /* Skip leading zero bytes */
573: for (; len > 0 && *s == 0; len--, s++)
574: ;
575: /*
576: * If most significant bit is set then prepend a zero byte to
577: * avoid interpretation as a negative number.
578: */
579: prepend = len > 0 && (s[0] & 0x80) != 0;
580: if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
581: return r;
582: POKE_U32(d, len + prepend);
583: if (prepend)
584: d[4] = 0;
1.3 djm 585: if (len != 0)
586: memcpy(d + 4 + prepend, s, len);
1.4 djm 587: return 0;
588: }
589:
590: int
591: sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
592: const u_char **valp, size_t *lenp)
593: {
594: const u_char *d;
595: size_t len, olen;
596: int r;
597:
598: if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
599: return r;
600: len = olen;
601: /* Refuse negative (MSB set) bignums */
602: if ((len != 0 && (*d & 0x80) != 0))
603: return SSH_ERR_BIGNUM_IS_NEGATIVE;
604: /* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
605: if (len > SSHBUF_MAX_BIGNUM + 1 ||
606: (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
607: return SSH_ERR_BIGNUM_TOO_LARGE;
608: /* Trim leading zeros */
609: while (len > 0 && *d == 0x00) {
610: d++;
611: len--;
612: }
1.5 mmcc 613: if (valp != NULL)
1.4 djm 614: *valp = d;
615: if (lenp != NULL)
616: *lenp = len;
617: if (sshbuf_consume(buf, olen + 4) != 0) {
618: /* Shouldn't happen */
619: SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
620: SSHBUF_ABORT();
621: return SSH_ERR_INTERNAL_ERROR;
622: }
1.1 djm 623: return 0;
624: }