Coverage Report

Created: 2025-11-01 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssh/sshbuf-getput-basic.c
Line
Count
Source
1
/*  $OpenBSD: sshbuf-getput-basic.c,v 1.13 2022/05/25 06:03:44 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
#define SSHBUF_INTERNAL
19
#include "includes.h"
20
21
#include <sys/types.h>
22
23
#include <stdarg.h>
24
#include <stdlib.h>
25
#include <stdio.h>
26
#include <string.h>
27
#include <stdint.h>
28
29
#include "ssherr.h"
30
#include "sshbuf.h"
31
32
int
33
sshbuf_get(struct sshbuf *buf, void *v, size_t len)
34
0
{
35
0
  const u_char *p = sshbuf_ptr(buf);
36
0
  int r;
37
38
0
  if ((r = sshbuf_consume(buf, len)) < 0)
39
0
    return r;
40
0
  if (v != NULL && len != 0)
41
0
    memcpy(v, p, len);
42
0
  return 0;
43
0
}
44
45
int
46
sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
47
5.00k
{
48
5.00k
  const u_char *p = sshbuf_ptr(buf);
49
5.00k
  int r;
50
51
5.00k
  if ((r = sshbuf_consume(buf, 8)) < 0)
52
46
    return r;
53
4.95k
  if (valp != NULL)
54
4.95k
    *valp = PEEK_U64(p);
55
4.95k
  return 0;
56
5.00k
}
57
58
int
59
sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
60
2.05k
{
61
2.05k
  const u_char *p = sshbuf_ptr(buf);
62
2.05k
  int r;
63
64
2.05k
  if ((r = sshbuf_consume(buf, 4)) < 0)
65
4
    return r;
66
2.05k
  if (valp != NULL)
67
2.05k
    *valp = PEEK_U32(p);
68
2.05k
  return 0;
69
2.05k
}
70
71
int
72
sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp)
73
0
{
74
0
  const u_char *p = sshbuf_ptr(buf);
75
0
  int r;
76
77
0
  if ((r = sshbuf_consume(buf, 2)) < 0)
78
0
    return r;
79
0
  if (valp != NULL)
80
0
    *valp = PEEK_U16(p);
81
0
  return 0;
82
0
}
83
84
int
85
sshbuf_get_u8(struct sshbuf *buf, u_char *valp)
86
335
{
87
335
  const u_char *p = sshbuf_ptr(buf);
88
335
  int r;
89
90
335
  if ((r = sshbuf_consume(buf, 1)) < 0)
91
2
    return r;
92
333
  if (valp != NULL)
93
333
    *valp = (u_int8_t)*p;
94
333
  return 0;
95
335
}
96
97
static int
98
check_offset(const struct sshbuf *buf, int wr, size_t offset, size_t len)
99
0
{
100
0
  if (sshbuf_ptr(buf) == NULL) /* calls sshbuf_check_sanity() */
101
0
    return SSH_ERR_INTERNAL_ERROR;
102
0
  if (offset >= SIZE_MAX - len)
103
0
    return SSH_ERR_INVALID_ARGUMENT;
104
0
  if (offset + len > sshbuf_len(buf)) {
105
0
    return wr ?
106
0
        SSH_ERR_NO_BUFFER_SPACE : SSH_ERR_MESSAGE_INCOMPLETE;
107
0
  }
108
0
  return 0;
109
0
}
110
111
static int
112
check_roffset(const struct sshbuf *buf, size_t offset, size_t len,
113
    const u_char **p)
114
0
{
115
0
  int r;
116
117
0
  *p = NULL;
118
0
  if ((r = check_offset(buf, 0, offset, len)) != 0)
119
0
    return r;
120
0
  *p = sshbuf_ptr(buf) + offset;
121
0
  return 0;
122
0
}
123
124
int
125
sshbuf_peek_u64(const struct sshbuf *buf, size_t offset, u_int64_t *valp)
126
0
{
127
0
  const u_char *p = NULL;
128
0
  int r;
129
130
0
  if (valp != NULL)
131
0
    *valp = 0;
132
0
  if ((r = check_roffset(buf, offset, 8, &p)) != 0)
133
0
    return r;
134
0
  if (valp != NULL)
135
0
    *valp = PEEK_U64(p);
136
0
  return 0;
137
0
}
138
139
int
140
sshbuf_peek_u32(const struct sshbuf *buf, size_t offset, u_int32_t *valp)
141
0
{
142
0
  const u_char *p = NULL;
143
0
  int r;
144
145
0
  if (valp != NULL)
146
0
    *valp = 0;
147
0
  if ((r = check_roffset(buf, offset, 4, &p)) != 0)
148
0
    return r;
149
0
  if (valp != NULL)
150
0
    *valp = PEEK_U32(p);
151
0
  return 0;
152
0
}
153
154
int
155
sshbuf_peek_u16(const struct sshbuf *buf, size_t offset, u_int16_t *valp)
156
0
{
157
0
  const u_char *p = NULL;
158
0
  int r;
159
160
0
  if (valp != NULL)
161
0
    *valp = 0;
162
0
  if ((r = check_roffset(buf, offset, 2, &p)) != 0)
163
0
    return r;
164
0
  if (valp != NULL)
165
0
    *valp = PEEK_U16(p);
166
0
  return 0;
167
0
}
168
169
int
170
sshbuf_peek_u8(const struct sshbuf *buf, size_t offset, u_char *valp)
171
0
{
172
0
  const u_char *p = NULL;
173
0
  int r;
174
175
0
  if (valp != NULL)
176
0
    *valp = 0;
177
0
  if ((r = check_roffset(buf, offset, 1, &p)) != 0)
178
0
    return r;
179
0
  if (valp != NULL)
180
0
    *valp = *p;
181
0
  return 0;
182
0
}
183
184
int
185
sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
186
3.73k
{
187
3.73k
  const u_char *val;
188
3.73k
  size_t len;
189
3.73k
  int r;
190
191
3.73k
  if (valp != NULL)
192
3.73k
    *valp = NULL;
193
3.73k
  if (lenp != NULL)
194
3.73k
    *lenp = 0;
195
3.73k
  if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
196
72
    return r;
197
3.66k
  if (valp != NULL) {
198
3.66k
    if ((*valp = malloc(len + 1)) == NULL) {
199
0
      SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
200
0
      return SSH_ERR_ALLOC_FAIL;
201
0
    }
202
3.66k
    if (len != 0)
203
3.36k
      memcpy(*valp, val, len);
204
3.66k
    (*valp)[len] = '\0';
205
3.66k
  }
206
3.66k
  if (lenp != NULL)
207
3.66k
    *lenp = len;
208
3.66k
  return 0;
209
3.66k
}
210
211
int
212
sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
213
24.1k
{
214
24.1k
  size_t len;
215
24.1k
  const u_char *p;
216
24.1k
  int r;
217
218
24.1k
  if (valp != NULL)
219
4.06k
    *valp = NULL;
220
24.1k
  if (lenp != NULL)
221
4.06k
    *lenp = 0;
222
24.1k
  if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
223
234
    return r;
224
23.8k
  if (valp != NULL)
225
3.98k
    *valp = p;
226
23.8k
  if (lenp != NULL)
227
3.98k
    *lenp = len;
228
23.8k
  if (sshbuf_consume(buf, len + 4) != 0) {
229
    /* Shouldn't happen */
230
0
    SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
231
0
    SSHBUF_ABORT();
232
0
    return SSH_ERR_INTERNAL_ERROR;
233
0
  }
234
23.8k
  return 0;
235
23.8k
}
236
237
int
238
sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
239
    size_t *lenp)
240
45.8k
{
241
45.8k
  u_int32_t len;
242
45.8k
  const u_char *p = sshbuf_ptr(buf);
243
244
45.8k
  if (valp != NULL)
245
45.8k
    *valp = NULL;
246
45.8k
  if (lenp != NULL)
247
45.8k
    *lenp = 0;
248
45.8k
  if (sshbuf_len(buf) < 4) {
249
268
    SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
250
268
    return SSH_ERR_MESSAGE_INCOMPLETE;
251
268
  }
252
45.5k
  len = PEEK_U32(p);
253
45.5k
  if (len > SSHBUF_SIZE_MAX - 4) {
254
254
    SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
255
254
    return SSH_ERR_STRING_TOO_LARGE;
256
254
  }
257
45.3k
  if (sshbuf_len(buf) - 4 < len) {
258
320
    SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
259
320
    return SSH_ERR_MESSAGE_INCOMPLETE;
260
320
  }
261
45.0k
  if (valp != NULL)
262
45.0k
    *valp = p + 4;
263
45.0k
  if (lenp != NULL)
264
45.0k
    *lenp = len;
265
45.0k
  return 0;
266
45.3k
}
267
268
int
269
sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
270
12.3k
{
271
12.3k
  size_t len;
272
12.3k
  const u_char *p, *z;
273
12.3k
  int r;
274
275
12.3k
  if (valp != NULL)
276
12.3k
    *valp = NULL;
277
12.3k
  if (lenp != NULL)
278
1.72k
    *lenp = 0;
279
12.3k
  if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
280
307
    return r;
281
  /* Allow a \0 only at the end of the string */
282
12.0k
  if (len > 0 &&
283
6.26k
      (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
284
25
    SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
285
25
    return SSH_ERR_INVALID_FORMAT;
286
25
  }
287
12.0k
  if ((r = sshbuf_skip_string(buf)) != 0)
288
0
    return -1;
289
12.0k
  if (valp != NULL) {
290
12.0k
    if ((*valp = malloc(len + 1)) == NULL) {
291
0
      SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
292
0
      return SSH_ERR_ALLOC_FAIL;
293
0
    }
294
12.0k
    if (len != 0)
295
6.24k
      memcpy(*valp, p, len);
296
12.0k
    (*valp)[len] = '\0';
297
12.0k
  }
298
12.0k
  if (lenp != NULL)
299
1.70k
    *lenp = (size_t)len;
300
12.0k
  return 0;
301
12.0k
}
302
303
int
304
sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
305
0
{
306
0
  u_int32_t len;
307
0
  u_char *p;
308
0
  int r;
309
310
  /*
311
   * Use sshbuf_peek_string_direct() to figure out if there is
312
   * a complete string in 'buf' and copy the string directly
313
   * into 'v'.
314
   */
315
0
  if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
316
0
      (r = sshbuf_get_u32(buf, &len)) != 0 ||
317
0
      (r = sshbuf_reserve(v, len, &p)) != 0 ||
318
0
      (r = sshbuf_get(buf, p, len)) != 0)
319
0
    return r;
320
0
  return 0;
321
0
}
322
323
int
324
sshbuf_put(struct sshbuf *buf, const void *v, size_t len)
325
5.43k
{
326
5.43k
  u_char *p;
327
5.43k
  int r;
328
329
5.43k
  if ((r = sshbuf_reserve(buf, len, &p)) < 0)
330
0
    return r;
331
5.43k
  if (len != 0)
332
2.54k
    memcpy(p, v, len);
333
5.43k
  return 0;
334
5.43k
}
335
336
int
337
sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
338
4.79k
{
339
4.79k
  if (v == NULL)
340
7
    return 0;
341
4.78k
  return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
342
4.79k
}
343
344
int
345
sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
346
0
{
347
0
  va_list ap;
348
0
  int r;
349
350
0
  va_start(ap, fmt);
351
0
  r = sshbuf_putfv(buf, fmt, ap);
352
0
  va_end(ap);
353
0
  return r;
354
0
}
355
356
int
357
sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
358
0
{
359
0
  va_list ap2;
360
0
  int r, len;
361
0
  u_char *p;
362
363
0
  VA_COPY(ap2, ap);
364
0
  if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
365
0
    r = SSH_ERR_INVALID_ARGUMENT;
366
0
    goto out;
367
0
  }
368
0
  if (len == 0) {
369
0
    r = 0;
370
0
    goto out; /* Nothing to do */
371
0
  }
372
0
  va_end(ap2);
373
0
  VA_COPY(ap2, ap);
374
0
  if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
375
0
    goto out;
376
0
  if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
377
0
    r = SSH_ERR_INTERNAL_ERROR;
378
0
    goto out; /* Shouldn't happen */
379
0
  }
380
  /* Consume terminating \0 */
381
0
  if ((r = sshbuf_consume_end(buf, 1)) != 0)
382
0
    goto out;
383
0
  r = 0;
384
0
 out:
385
0
  va_end(ap2);
386
0
  return r;
387
0
}
388
389
int
390
sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
391
0
{
392
0
  u_char *p;
393
0
  int r;
394
395
0
  if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
396
0
    return r;
397
0
  POKE_U64(p, val);
398
0
  return 0;
399
0
}
400
401
int
402
sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
403
21
{
404
21
  u_char *p;
405
21
  int r;
406
407
21
  if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
408
0
    return r;
409
21
  POKE_U32(p, val);
410
21
  return 0;
411
21
}
412
413
int
414
sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
415
0
{
416
0
  u_char *p;
417
0
  int r;
418
419
0
  if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
420
0
    return r;
421
0
  POKE_U16(p, val);
422
0
  return 0;
423
0
}
424
425
int
426
sshbuf_put_u8(struct sshbuf *buf, u_char val)
427
21
{
428
21
  u_char *p;
429
21
  int r;
430
431
21
  if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
432
0
    return r;
433
21
  p[0] = val;
434
21
  return 0;
435
21
}
436
437
static int
438
check_woffset(struct sshbuf *buf, size_t offset, size_t len, u_char **p)
439
0
{
440
0
  int r;
441
442
0
  *p = NULL;
443
0
  if ((r = check_offset(buf, 1, offset, len)) != 0)
444
0
    return r;
445
0
  if (sshbuf_mutable_ptr(buf) == NULL)
446
0
    return SSH_ERR_BUFFER_READ_ONLY;
447
0
  *p = sshbuf_mutable_ptr(buf) + offset;
448
0
  return 0;
449
0
}
450
451
int
452
sshbuf_poke_u64(struct sshbuf *buf, size_t offset, u_int64_t val)
453
0
{
454
0
  u_char *p = NULL;
455
0
  int r;
456
457
0
  if ((r = check_woffset(buf, offset, 8, &p)) != 0)
458
0
    return r;
459
0
  POKE_U64(p, val);
460
0
  return 0;
461
0
}
462
463
int
464
sshbuf_poke_u32(struct sshbuf *buf, size_t offset, u_int32_t val)
465
0
{
466
0
  u_char *p = NULL;
467
0
  int r;
468
469
0
  if ((r = check_woffset(buf, offset, 4, &p)) != 0)
470
0
    return r;
471
0
  POKE_U32(p, val);
472
0
  return 0;
473
0
}
474
475
int
476
sshbuf_poke_u16(struct sshbuf *buf, size_t offset, u_int16_t val)
477
0
{
478
0
  u_char *p = NULL;
479
0
  int r;
480
481
0
  if ((r = check_woffset(buf, offset, 2, &p)) != 0)
482
0
    return r;
483
0
  POKE_U16(p, val);
484
0
  return 0;
485
0
}
486
487
int
488
sshbuf_poke_u8(struct sshbuf *buf, size_t offset, u_char val)
489
0
{
490
0
  u_char *p = NULL;
491
0
  int r;
492
493
0
  if ((r = check_woffset(buf, offset, 1, &p)) != 0)
494
0
    return r;
495
0
  *p = val;
496
0
  return 0;
497
0
}
498
499
int
500
sshbuf_poke(struct sshbuf *buf, size_t offset, void *v, size_t len)
501
0
{
502
0
  u_char *p = NULL;
503
0
  int r;
504
505
0
  if ((r = check_woffset(buf, offset, len, &p)) != 0)
506
0
    return r;
507
0
  memcpy(p, v, len);
508
0
  return 0;
509
0
}
510
511
int
512
sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
513
0
{
514
0
  u_char *d;
515
0
  int r;
516
517
0
  if (len > SSHBUF_SIZE_MAX - 4) {
518
0
    SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
519
0
    return SSH_ERR_NO_BUFFER_SPACE;
520
0
  }
521
0
  if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
522
0
    return r;
523
0
  POKE_U32(d, len);
524
0
  if (len != 0)
525
0
    memcpy(d + 4, v, len);
526
0
  return 0;
527
0
}
528
529
int
530
sshbuf_put_cstring(struct sshbuf *buf, const char *v)
531
0
{
532
0
  return sshbuf_put_string(buf, v, v == NULL ? 0 : strlen(v));
533
0
}
534
535
int
536
sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
537
0
{
538
0
  if (v == NULL)
539
0
    return sshbuf_put_string(buf, NULL, 0);
540
541
0
  return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
542
0
}
543
544
int
545
sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
546
7.10k
{
547
7.10k
  const u_char *p;
548
7.10k
  size_t len;
549
7.10k
  struct sshbuf *ret;
550
7.10k
  int r;
551
552
7.10k
  if (buf == NULL || bufp == NULL)
553
0
    return SSH_ERR_INVALID_ARGUMENT;
554
7.10k
  *bufp = NULL;
555
7.10k
  if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
556
90
    return r;
557
7.01k
  if ((ret = sshbuf_from(p, len)) == NULL)
558
0
    return SSH_ERR_ALLOC_FAIL;
559
7.01k
  if ((r = sshbuf_consume(buf, len + 4)) != 0 ||  /* Shouldn't happen */
560
7.01k
      (r = sshbuf_set_parent(ret, buf)) != 0) {
561
0
    sshbuf_free(ret);
562
0
    return r;
563
0
  }
564
7.01k
  *bufp = ret;
565
7.01k
  return 0;
566
7.01k
}
567
568
int
569
sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
570
0
{
571
0
  u_char *d;
572
0
  const u_char *s = (const u_char *)v;
573
0
  int r, prepend;
574
575
0
  if (len > SSHBUF_SIZE_MAX - 5) {
576
0
    SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
577
0
    return SSH_ERR_NO_BUFFER_SPACE;
578
0
  }
579
  /* Skip leading zero bytes */
580
0
  for (; len > 0 && *s == 0; len--, s++)
581
0
    ;
582
  /*
583
   * If most significant bit is set then prepend a zero byte to
584
   * avoid interpretation as a negative number.
585
   */
586
0
  prepend = len > 0 && (s[0] & 0x80) != 0;
587
0
  if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
588
0
    return r;
589
0
  POKE_U32(d, len + prepend);
590
0
  if (prepend)
591
0
    d[4] = 0;
592
0
  if (len != 0)
593
0
    memcpy(d + 4 + prepend, s, len);
594
0
  return 0;
595
0
}
596
597
int
598
sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
599
    const u_char **valp, size_t *lenp)
600
1.46k
{
601
1.46k
  const u_char *d;
602
1.46k
  size_t len, olen;
603
1.46k
  int r;
604
605
1.46k
  if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
606
155
    return r;
607
1.30k
  len = olen;
608
  /* Refuse negative (MSB set) bignums */
609
1.30k
  if ((len != 0 && (*d & 0x80) != 0))
610
17
    return SSH_ERR_BIGNUM_IS_NEGATIVE;
611
  /* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
612
1.29k
  if (len > SSHBUF_MAX_BIGNUM + 1 ||
613
1.27k
      (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
614
21
    return SSH_ERR_BIGNUM_TOO_LARGE;
615
  /* Trim leading zeros */
616
2.70k
  while (len > 0 && *d == 0x00) {
617
1.43k
    d++;
618
1.43k
    len--;
619
1.43k
  }
620
1.26k
  if (valp != NULL)
621
1.26k
    *valp = d;
622
1.26k
  if (lenp != NULL)
623
1.26k
    *lenp = len;
624
1.26k
  if (sshbuf_consume(buf, olen + 4) != 0) {
625
    /* Shouldn't happen */
626
0
    SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
627
0
    SSHBUF_ABORT();
628
0
    return SSH_ERR_INTERNAL_ERROR;
629
0
  }
630
1.26k
  return 0;
631
1.26k
}