GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/lib/../sshbuf-getput-basic.c Lines: 0 215 0.0 %
Date: 2017-11-13 Branches: 0 164 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: sshbuf-getput-basic.c,v 1.7 2017/06/01 04:51:58 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
20
#include <stdarg.h>
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;
37
	if (v != NULL && len != 0)
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
		}
112
		if (len != 0)
113
			memcpy(*valp, val, len);
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;
134
	if (valp != NULL)
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
	}
171
	if (valp != NULL)
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
		}
204
		if (len != 0)
205
			memcpy(*valp, p, len);
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;
241
	if (len != 0)
242
		memcpy(p, v, len);
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);
358
	if (len != 0)
359
		memcpy(d + 4, v, len);
360
	return 0;
361
}
362
363
int
364
sshbuf_put_cstring(struct sshbuf *buf, const char *v)
365
{
366
	return sshbuf_put_string(buf, v, v == NULL ? 0 : strlen(v));
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;
423
	if (len != 0)
424
		memcpy(d + 4 + prepend, s, len);
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
	}
451
	if (valp != NULL)
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
	}
461
	return 0;
462
}