GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/lib/../sshbuf-getput-basic.c Lines: 164 232 70.7 %
Date: 2017-11-07 Branches: 84 164 51.2 %

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
40752
	const u_char *p = sshbuf_ptr(buf);
59
	int r;
60
61
20376
	if ((r = sshbuf_consume(buf, 4)) < 0)
62
		return r;
63
20376
	if (valp != NULL)
64
20375
		*valp = PEEK_U32(p);
65
20376
	return 0;
66
20376
}
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
29840
	const u_char *p = sshbuf_ptr(buf);
85
	int r;
86
87
14920
	if ((r = sshbuf_consume(buf, 1)) < 0)
88
		return r;
89
14920
	if (valp != NULL)
90
14903
		*valp = (u_int8_t)*p;
91
14920
	return 0;
92
14920
}
93
94
int
95
sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
96
{
97
186
	const u_char *val;
98
93
	size_t len;
99
	int r;
100
101
93
	if (valp != NULL)
102
83
		*valp = NULL;
103
93
	if (lenp != NULL)
104
83
		*lenp = 0;
105
93
	if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
106
		return r;
107
93
	if (valp != NULL) {
108
83
		if ((*valp = malloc(len + 1)) == NULL) {
109
			SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
110
			return SSH_ERR_ALLOC_FAIL;
111
		}
112
83
		if (len != 0)
113
83
			memcpy(*valp, val, len);
114
83
		(*valp)[len] = '\0';
115
83
	}
116
93
	if (lenp != NULL)
117
83
		*lenp = len;
118
93
	return 0;
119
93
}
120
121
int
122
sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
123
{
124
19716
	size_t len;
125
9858
	const u_char *p;
126
	int r;
127
128
9858
	if (valp != NULL)
129
9588
		*valp = NULL;
130
9858
	if (lenp != NULL)
131
9588
		*lenp = 0;
132
9858
	if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
133
		return r;
134
9858
	if (valp != NULL)
135
9588
		*valp = p;
136
9858
	if (lenp != NULL)
137
9588
		*lenp = len;
138
9858
	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
9858
	return 0;
145
9858
}
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
20498
	const u_char *p = sshbuf_ptr(buf);
153
154
10249
	if (valp != NULL)
155
10249
		*valp = NULL;
156
10249
	if (lenp != NULL)
157
10249
		*lenp = 0;
158
10249
	if (sshbuf_len(buf) < 4) {
159
		SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
160
		return SSH_ERR_MESSAGE_INCOMPLETE;
161
	}
162
10249
	len = PEEK_U32(p);
163
10249
	if (len > SSHBUF_SIZE_MAX - 4) {
164
		SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
165
		return SSH_ERR_STRING_TOO_LARGE;
166
	}
167
10249
	if (sshbuf_len(buf) - 4 < len) {
168
		SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
169
		return SSH_ERR_MESSAGE_INCOMPLETE;
170
	}
171
10249
	if (valp != NULL)
172
10249
		*valp = p + 4;
173
10249
	if (lenp != NULL)
174
10249
		*lenp = len;
175
10249
	return 0;
176
10249
}
177
178
int
179
sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
180
{
181
480
	size_t len;
182
240
	const u_char *p, *z;
183
	int r;
184
185
240
	if (valp != NULL)
186
240
		*valp = NULL;
187
240
	if (lenp != NULL)
188
1
		*lenp = 0;
189
240
	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

240
	if (len > 0 &&
193
236
	    (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
240
	if ((r = sshbuf_skip_string(buf)) != 0)
198
		return -1;
199
240
	if (valp != NULL) {
200
240
		if ((*valp = malloc(len + 1)) == NULL) {
201
			SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
202
			return SSH_ERR_ALLOC_FAIL;
203
		}
204
240
		if (len != 0)
205
236
			memcpy(*valp, p, len);
206
240
		(*valp)[len] = '\0';
207
240
	}
208
240
	if (lenp != NULL)
209
1
		*lenp = (size_t)len;
210
240
	return 0;
211
240
}
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
219926
	u_char *p;
237
	int r;
238
239
109963
	if ((r = sshbuf_reserve(buf, len, &p)) < 0)
240
		return r;
241
109963
	if (len != 0)
242
109963
		memcpy(p, v, len);
243
109963
	return 0;
244
109963
}
245
246
int
247
sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
248
{
249
2
	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
64
	va_list ap;
256
	int r;
257
258
32
	va_start(ap, fmt);
259
32
	r = sshbuf_putfv(buf, fmt, ap);
260
32
	va_end(ap);
261
32
	return r;
262
32
}
263
264
int
265
sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
266
{
267
64
	va_list ap2;
268
	int r, len;
269
32
	u_char *p;
270
271
32
	va_copy(ap2, ap);
272
32
	if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
273
		r = SSH_ERR_INVALID_ARGUMENT;
274
		goto out;
275
	}
276
32
	if (len == 0) {
277
		r = 0;
278
		goto out; /* Nothing to do */
279
	}
280
32
	va_end(ap2);
281
32
	va_copy(ap2, ap);
282
32
	if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
283
		goto out;
284
32
	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
32
	if ((r = sshbuf_consume_end(buf, 1)) != 0)
290
		goto out;
291
	r = 0;
292
 out:
293
32
	va_end(ap2);
294
32
	return r;
295
32
}
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
85342
	u_char *p;
313
	int r;
314
315
42671
	if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
316
		return r;
317
42671
	POKE_U32(p, val);
318
42671
	return 0;
319
42671
}
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
17670
	u_char *p;
337
	int r;
338
339
8835
	if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
340
		return r;
341
8835
	p[0] = val;
342
8835
	return 0;
343
8835
}
344
345
int
346
sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
347
{
348
86592
	u_char *d;
349
	int r;
350
351
43296
	if (len > SSHBUF_SIZE_MAX - 4) {
352
		SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
353
		return SSH_ERR_NO_BUFFER_SPACE;
354
	}
355
43296
	if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
356
		return r;
357
43296
	POKE_U32(d, len);
358
43296
	if (len != 0)
359
43286
		memcpy(d + 4, v, len);
360
43296
	return 0;
361
43296
}
362
363
int
364
sshbuf_put_cstring(struct sshbuf *buf, const char *v)
365
{
366
1092
	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
24
	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
44
	const u_char *p;
379
22
	size_t len;
380
	struct sshbuf *ret;
381
	int r;
382
383
22
	if (buf == NULL || bufp == NULL)
384
		return SSH_ERR_INVALID_ARGUMENT;
385
22
	*bufp = NULL;
386
22
	if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
387
		return r;
388
22
	if ((ret = sshbuf_from(p, len)) == NULL)
389
		return SSH_ERR_ALLOC_FAIL;
390

44
	if ((r = sshbuf_consume(buf, len + 4)) != 0 ||  /* Shouldn't happen */
391
22
	    (r = sshbuf_set_parent(ret, buf)) != 0) {
392
		sshbuf_free(ret);
393
		return r;
394
	}
395
22
	*bufp = ret;
396
22
	return 0;
397
22
}
398
399
int
400
sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
401
{
402
2
	u_char *d;
403
	const u_char *s = (const u_char *)v;
404
	int r, prepend;
405
406
1
	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

2
	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
3
	prepend = len > 0 && (s[0] & 0x80) != 0;
418
1
	if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
419
		return r;
420
1
	POKE_U32(d, len + prepend);
421
1
	if (prepend)
422
1
		d[4] = 0;
423
1
	if (len != 0)
424
1
		memcpy(d + 4 + prepend, s, len);
425
1
	return 0;
426
1
}
427
428
int
429
sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
430
    const u_char **valp, size_t *lenp)
431
{
432
240
	const u_char *d;
433
120
	size_t len, olen;
434
	int r;
435
436
120
	if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
437
		return r;
438
120
	len = olen;
439
	/* Refuse negative (MSB set) bignums */
440

240
	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

120
	if (len > SSHBUF_MAX_BIGNUM + 1 ||
444
120
	    (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
445
		return SSH_ERR_BIGNUM_TOO_LARGE;
446
	/* Trim leading zeros */
447

432
	while (len > 0 && *d == 0x00) {
448
64
		d++;
449
64
		len--;
450
	}
451
120
	if (valp != NULL)
452
120
		*valp = d;
453
120
	if (lenp != NULL)
454
120
		*lenp = len;
455
120
	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
120
	return 0;
462
120
}