Coverage Report

Created: 2025-10-10 06:38

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
0
{
48
0
  const u_char *p = sshbuf_ptr(buf);
49
0
  int r;
50
51
0
  if ((r = sshbuf_consume(buf, 8)) < 0)
52
0
    return r;
53
0
  if (valp != NULL)
54
0
    *valp = PEEK_U64(p);
55
0
  return 0;
56
0
}
57
58
int
59
sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
60
0
{
61
0
  const u_char *p = sshbuf_ptr(buf);
62
0
  int r;
63
64
0
  if ((r = sshbuf_consume(buf, 4)) < 0)
65
0
    return r;
66
0
  if (valp != NULL)
67
0
    *valp = PEEK_U32(p);
68
0
  return 0;
69
0
}
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
0
{
87
0
  const u_char *p = sshbuf_ptr(buf);
88
0
  int r;
89
90
0
  if ((r = sshbuf_consume(buf, 1)) < 0)
91
0
    return r;
92
0
  if (valp != NULL)
93
0
    *valp = (u_int8_t)*p;
94
0
  return 0;
95
0
}
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
0
{
187
0
  const u_char *val;
188
0
  size_t len;
189
0
  int r;
190
191
0
  if (valp != NULL)
192
0
    *valp = NULL;
193
0
  if (lenp != NULL)
194
0
    *lenp = 0;
195
0
  if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
196
0
    return r;
197
0
  if (valp != NULL) {
198
0
    if ((*valp = malloc(len + 1)) == NULL) {
199
0
      SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
200
0
      return SSH_ERR_ALLOC_FAIL;
201
0
    }
202
0
    if (len != 0)
203
0
      memcpy(*valp, val, len);
204
0
    (*valp)[len] = '\0';
205
0
  }
206
0
  if (lenp != NULL)
207
0
    *lenp = len;
208
0
  return 0;
209
0
}
210
211
int
212
sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
213
0
{
214
0
  size_t len;
215
0
  const u_char *p;
216
0
  int r;
217
218
0
  if (valp != NULL)
219
0
    *valp = NULL;
220
0
  if (lenp != NULL)
221
0
    *lenp = 0;
222
0
  if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
223
0
    return r;
224
0
  if (valp != NULL)
225
0
    *valp = p;
226
0
  if (lenp != NULL)
227
0
    *lenp = len;
228
0
  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
0
  return 0;
235
0
}
236
237
int
238
sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
239
    size_t *lenp)
240
0
{
241
0
  u_int32_t len;
242
0
  const u_char *p = sshbuf_ptr(buf);
243
244
0
  if (valp != NULL)
245
0
    *valp = NULL;
246
0
  if (lenp != NULL)
247
0
    *lenp = 0;
248
0
  if (sshbuf_len(buf) < 4) {
249
0
    SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
250
0
    return SSH_ERR_MESSAGE_INCOMPLETE;
251
0
  }
252
0
  len = PEEK_U32(p);
253
0
  if (len > SSHBUF_SIZE_MAX - 4) {
254
0
    SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
255
0
    return SSH_ERR_STRING_TOO_LARGE;
256
0
  }
257
0
  if (sshbuf_len(buf) - 4 < len) {
258
0
    SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
259
0
    return SSH_ERR_MESSAGE_INCOMPLETE;
260
0
  }
261
0
  if (valp != NULL)
262
0
    *valp = p + 4;
263
0
  if (lenp != NULL)
264
0
    *lenp = len;
265
0
  return 0;
266
0
}
267
268
int
269
sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
270
0
{
271
0
  size_t len;
272
0
  const u_char *p, *z;
273
0
  int r;
274
275
0
  if (valp != NULL)
276
0
    *valp = NULL;
277
0
  if (lenp != NULL)
278
0
    *lenp = 0;
279
0
  if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
280
0
    return r;
281
  /* Allow a \0 only at the end of the string */
282
0
  if (len > 0 &&
283
0
      (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
284
0
    SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
285
0
    return SSH_ERR_INVALID_FORMAT;
286
0
  }
287
0
  if ((r = sshbuf_skip_string(buf)) != 0)
288
0
    return -1;
289
0
  if (valp != NULL) {
290
0
    if ((*valp = malloc(len + 1)) == NULL) {
291
0
      SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
292
0
      return SSH_ERR_ALLOC_FAIL;
293
0
    }
294
0
    if (len != 0)
295
0
      memcpy(*valp, p, len);
296
0
    (*valp)[len] = '\0';
297
0
  }
298
0
  if (lenp != NULL)
299
0
    *lenp = (size_t)len;
300
0
  return 0;
301
0
}
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
0
{
326
0
  u_char *p;
327
0
  int r;
328
329
0
  if ((r = sshbuf_reserve(buf, len, &p)) < 0)
330
0
    return r;
331
0
  if (len != 0)
332
0
    memcpy(p, v, len);
333
0
  return 0;
334
0
}
335
336
int
337
sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
338
0
{
339
0
  if (v == NULL)
340
0
    return 0;
341
0
  return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
342
0
}
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
0
{
404
0
  u_char *p;
405
0
  int r;
406
407
0
  if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
408
0
    return r;
409
0
  POKE_U32(p, val);
410
0
  return 0;
411
0
}
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
0
{
428
0
  u_char *p;
429
0
  int r;
430
431
0
  if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
432
0
    return r;
433
0
  p[0] = val;
434
0
  return 0;
435
0
}
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
0
{
547
0
  const u_char *p;
548
0
  size_t len;
549
0
  struct sshbuf *ret;
550
0
  int r;
551
552
0
  if (buf == NULL || bufp == NULL)
553
0
    return SSH_ERR_INVALID_ARGUMENT;
554
0
  *bufp = NULL;
555
0
  if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
556
0
    return r;
557
0
  if ((ret = sshbuf_from(p, len)) == NULL)
558
0
    return SSH_ERR_ALLOC_FAIL;
559
0
  if ((r = sshbuf_consume(buf, len + 4)) != 0 ||  /* Shouldn't happen */
560
0
      (r = sshbuf_set_parent(ret, buf)) != 0) {
561
0
    sshbuf_free(ret);
562
0
    return r;
563
0
  }
564
0
  *bufp = ret;
565
0
  return 0;
566
0
}
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
0
{
601
0
  const u_char *d;
602
0
  size_t len, olen;
603
0
  int r;
604
605
0
  if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
606
0
    return r;
607
0
  len = olen;
608
  /* Refuse negative (MSB set) bignums */
609
0
  if ((len != 0 && (*d & 0x80) != 0))
610
0
    return SSH_ERR_BIGNUM_IS_NEGATIVE;
611
  /* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
612
0
  if (len > SSHBUF_MAX_BIGNUM + 1 ||
613
0
      (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
614
0
    return SSH_ERR_BIGNUM_TOO_LARGE;
615
  /* Trim leading zeros */
616
0
  while (len > 0 && *d == 0x00) {
617
0
    d++;
618
0
    len--;
619
0
  }
620
0
  if (valp != NULL)
621
0
    *valp = d;
622
0
  if (lenp != NULL)
623
0
    *lenp = len;
624
0
  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
0
  return 0;
631
0
}