/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 | } |