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