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