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