Annotation of src/usr.bin/ssh/sshbuf-getput-basic.c, Revision 1.7
1.7 ! djm 1: /* $OpenBSD: sshbuf-getput-basic.c,v 1.6 2016/06/16 11:00:17 dtucker 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:
94: int
95: sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
96: {
97: const u_char *val;
98: size_t len;
99: int r;
100:
101: if (valp != NULL)
102: *valp = NULL;
103: if (lenp != NULL)
104: *lenp = 0;
105: if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
106: return r;
107: if (valp != NULL) {
108: if ((*valp = malloc(len + 1)) == NULL) {
109: SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
110: return SSH_ERR_ALLOC_FAIL;
111: }
1.3 djm 112: if (len != 0)
113: memcpy(*valp, val, len);
1.1 djm 114: (*valp)[len] = '\0';
115: }
116: if (lenp != NULL)
117: *lenp = len;
118: return 0;
119: }
120:
121: int
122: sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
123: {
124: size_t len;
125: const u_char *p;
126: int r;
127:
128: if (valp != NULL)
129: *valp = NULL;
130: if (lenp != NULL)
131: *lenp = 0;
132: if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
133: return r;
1.5 mmcc 134: if (valp != NULL)
1.1 djm 135: *valp = p;
136: if (lenp != NULL)
137: *lenp = len;
138: if (sshbuf_consume(buf, len + 4) != 0) {
139: /* Shouldn't happen */
140: SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
141: SSHBUF_ABORT();
142: return SSH_ERR_INTERNAL_ERROR;
143: }
144: return 0;
145: }
146:
147: int
148: sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
149: size_t *lenp)
150: {
151: u_int32_t len;
152: const u_char *p = sshbuf_ptr(buf);
153:
154: if (valp != NULL)
155: *valp = NULL;
156: if (lenp != NULL)
157: *lenp = 0;
158: if (sshbuf_len(buf) < 4) {
159: SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
160: return SSH_ERR_MESSAGE_INCOMPLETE;
161: }
162: len = PEEK_U32(p);
163: if (len > SSHBUF_SIZE_MAX - 4) {
164: SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
165: return SSH_ERR_STRING_TOO_LARGE;
166: }
167: if (sshbuf_len(buf) - 4 < len) {
168: SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
169: return SSH_ERR_MESSAGE_INCOMPLETE;
170: }
1.5 mmcc 171: if (valp != NULL)
1.1 djm 172: *valp = p + 4;
173: if (lenp != NULL)
174: *lenp = len;
175: return 0;
176: }
177:
178: int
179: sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
180: {
181: size_t len;
182: const u_char *p, *z;
183: int r;
184:
185: if (valp != NULL)
186: *valp = NULL;
187: if (lenp != NULL)
188: *lenp = 0;
189: if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
190: return r;
191: /* Allow a \0 only at the end of the string */
192: if (len > 0 &&
193: (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
194: SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
195: return SSH_ERR_INVALID_FORMAT;
196: }
197: if ((r = sshbuf_skip_string(buf)) != 0)
198: return -1;
199: if (valp != NULL) {
200: if ((*valp = malloc(len + 1)) == NULL) {
201: SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
202: return SSH_ERR_ALLOC_FAIL;
203: }
1.3 djm 204: if (len != 0)
205: memcpy(*valp, p, len);
1.1 djm 206: (*valp)[len] = '\0';
207: }
208: if (lenp != NULL)
209: *lenp = (size_t)len;
210: return 0;
211: }
212:
213: int
214: sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
215: {
216: u_int32_t len;
217: u_char *p;
218: int r;
219:
220: /*
221: * Use sshbuf_peek_string_direct() to figure out if there is
222: * a complete string in 'buf' and copy the string directly
223: * into 'v'.
224: */
225: if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
226: (r = sshbuf_get_u32(buf, &len)) != 0 ||
227: (r = sshbuf_reserve(v, len, &p)) != 0 ||
228: (r = sshbuf_get(buf, p, len)) != 0)
229: return r;
230: return 0;
231: }
232:
233: int
234: sshbuf_put(struct sshbuf *buf, const void *v, size_t len)
235: {
236: u_char *p;
237: int r;
238:
239: if ((r = sshbuf_reserve(buf, len, &p)) < 0)
240: return r;
1.3 djm 241: if (len != 0)
242: memcpy(p, v, len);
1.1 djm 243: return 0;
244: }
245:
246: int
247: sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
248: {
249: return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
250: }
251:
252: int
253: sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
254: {
255: va_list ap;
256: int r;
257:
258: va_start(ap, fmt);
259: r = sshbuf_putfv(buf, fmt, ap);
260: va_end(ap);
261: return r;
262: }
263:
264: int
265: sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
266: {
267: va_list ap2;
268: int r, len;
269: u_char *p;
270:
271: va_copy(ap2, ap);
272: if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
273: r = SSH_ERR_INVALID_ARGUMENT;
274: goto out;
275: }
276: if (len == 0) {
277: r = 0;
278: goto out; /* Nothing to do */
279: }
280: va_end(ap2);
281: va_copy(ap2, ap);
282: if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
283: goto out;
284: if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
285: r = SSH_ERR_INTERNAL_ERROR;
286: goto out; /* Shouldn't happen */
287: }
288: /* Consume terminating \0 */
289: if ((r = sshbuf_consume_end(buf, 1)) != 0)
290: goto out;
291: r = 0;
292: out:
293: va_end(ap2);
294: return r;
295: }
296:
297: int
298: sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
299: {
300: u_char *p;
301: int r;
302:
303: if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
304: return r;
305: POKE_U64(p, val);
306: return 0;
307: }
308:
309: int
310: sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
311: {
312: u_char *p;
313: int r;
314:
315: if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
316: return r;
317: POKE_U32(p, val);
318: return 0;
319: }
320:
321: int
322: sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
323: {
324: u_char *p;
325: int r;
326:
327: if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
328: return r;
329: POKE_U16(p, val);
330: return 0;
331: }
332:
333: int
334: sshbuf_put_u8(struct sshbuf *buf, u_char val)
335: {
336: u_char *p;
337: int r;
338:
339: if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
340: return r;
341: p[0] = val;
342: return 0;
343: }
344:
345: int
346: sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
347: {
348: u_char *d;
349: int r;
350:
351: if (len > SSHBUF_SIZE_MAX - 4) {
352: SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
353: return SSH_ERR_NO_BUFFER_SPACE;
354: }
355: if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
356: return r;
357: POKE_U32(d, len);
1.3 djm 358: if (len != 0)
359: memcpy(d + 4, v, len);
1.1 djm 360: return 0;
361: }
362:
363: int
364: sshbuf_put_cstring(struct sshbuf *buf, const char *v)
365: {
1.7 ! djm 366: return sshbuf_put_string(buf, v, v == NULL ? 0 : strlen(v));
1.1 djm 367: }
368:
369: int
370: sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
371: {
372: return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
373: }
374:
375: int
376: sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
377: {
378: const u_char *p;
379: size_t len;
380: struct sshbuf *ret;
381: int r;
382:
383: if (buf == NULL || bufp == NULL)
384: return SSH_ERR_INVALID_ARGUMENT;
385: *bufp = NULL;
386: if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
387: return r;
388: if ((ret = sshbuf_from(p, len)) == NULL)
389: return SSH_ERR_ALLOC_FAIL;
390: if ((r = sshbuf_consume(buf, len + 4)) != 0 || /* Shouldn't happen */
391: (r = sshbuf_set_parent(ret, buf)) != 0) {
392: sshbuf_free(ret);
393: return r;
394: }
395: *bufp = ret;
396: return 0;
397: }
398:
399: int
400: sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
401: {
402: u_char *d;
403: const u_char *s = (const u_char *)v;
404: int r, prepend;
405:
406: if (len > SSHBUF_SIZE_MAX - 5) {
407: SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
408: return SSH_ERR_NO_BUFFER_SPACE;
409: }
410: /* Skip leading zero bytes */
411: for (; len > 0 && *s == 0; len--, s++)
412: ;
413: /*
414: * If most significant bit is set then prepend a zero byte to
415: * avoid interpretation as a negative number.
416: */
417: prepend = len > 0 && (s[0] & 0x80) != 0;
418: if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
419: return r;
420: POKE_U32(d, len + prepend);
421: if (prepend)
422: d[4] = 0;
1.3 djm 423: if (len != 0)
424: memcpy(d + 4 + prepend, s, len);
1.4 djm 425: return 0;
426: }
427:
428: int
429: sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
430: const u_char **valp, size_t *lenp)
431: {
432: const u_char *d;
433: size_t len, olen;
434: int r;
435:
436: if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
437: return r;
438: len = olen;
439: /* Refuse negative (MSB set) bignums */
440: if ((len != 0 && (*d & 0x80) != 0))
441: return SSH_ERR_BIGNUM_IS_NEGATIVE;
442: /* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
443: if (len > SSHBUF_MAX_BIGNUM + 1 ||
444: (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
445: return SSH_ERR_BIGNUM_TOO_LARGE;
446: /* Trim leading zeros */
447: while (len > 0 && *d == 0x00) {
448: d++;
449: len--;
450: }
1.5 mmcc 451: if (valp != NULL)
1.4 djm 452: *valp = d;
453: if (lenp != NULL)
454: *lenp = len;
455: if (sshbuf_consume(buf, olen + 4) != 0) {
456: /* Shouldn't happen */
457: SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
458: SSHBUF_ABORT();
459: return SSH_ERR_INTERNAL_ERROR;
460: }
1.1 djm 461: return 0;
462: }