summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/bytestring/bs_cbs.c
diff options
context:
space:
mode:
authorjsing <>2021-11-20 18:10:52 +0000
committerjsing <>2021-11-20 18:10:52 +0000
commit31bb83716fbab03eb14d42ef39e80187115a7a4d (patch)
tree4dd79bfd9558b2dede4f3c209ef98fe0c4fe96cb /src/lib/libcrypto/bytestring/bs_cbs.c
parentddffb653bb836ef8741e0b2e002c1ea1c0a17dc8 (diff)
downloadopenbsd-31bb83716fbab03eb14d42ef39e80187115a7a4d.tar.gz
openbsd-31bb83716fbab03eb14d42ef39e80187115a7a4d.tar.bz2
openbsd-31bb83716fbab03eb14d42ef39e80187115a7a4d.zip
Provide the bytestring APIs for libcrypto internal use.
Bring a copy of the bytestring APIs (CBB/CBS) from libssl, for use in libcrypto - these are not exposed publicly. Discussed with beck@ and tb@
Diffstat (limited to 'src/lib/libcrypto/bytestring/bs_cbs.c')
-rw-r--r--src/lib/libcrypto/bytestring/bs_cbs.c510
1 files changed, 510 insertions, 0 deletions
diff --git a/src/lib/libcrypto/bytestring/bs_cbs.c b/src/lib/libcrypto/bytestring/bs_cbs.c
new file mode 100644
index 0000000000..06283abd94
--- /dev/null
+++ b/src/lib/libcrypto/bytestring/bs_cbs.c
@@ -0,0 +1,510 @@
1/* $OpenBSD: bs_cbs.c,v 1.1 2021/11/20 18:10:52 jsing Exp $ */
2/*
3 * Copyright (c) 2014, Google Inc.
4 *
5 * Permission to use, copy, modify, and/or 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 ANY
12 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
14 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <stdlib.h>
19#include <string.h>
20
21#include "bytestring.h"
22
23void
24CBS_init(CBS *cbs, const uint8_t *data, size_t len)
25{
26 cbs->data = data;
27 cbs->initial_len = len;
28 cbs->len = len;
29}
30
31void
32CBS_dup(const CBS *cbs, CBS *out)
33{
34 CBS_init(out, CBS_data(cbs), CBS_len(cbs));
35 out->initial_len = cbs->initial_len;
36}
37
38static int
39cbs_get(CBS *cbs, const uint8_t **p, size_t n)
40{
41 if (cbs->len < n)
42 return 0;
43
44 *p = cbs->data;
45 cbs->data += n;
46 cbs->len -= n;
47 return 1;
48}
49
50size_t
51CBS_offset(const CBS *cbs)
52{
53 return cbs->initial_len - cbs->len;
54}
55
56int
57CBS_skip(CBS *cbs, size_t len)
58{
59 const uint8_t *dummy;
60 return cbs_get(cbs, &dummy, len);
61}
62
63const uint8_t *
64CBS_data(const CBS *cbs)
65{
66 return cbs->data;
67}
68
69size_t
70CBS_len(const CBS *cbs)
71{
72 return cbs->len;
73}
74
75int
76CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len)
77{
78 free(*out_ptr);
79 *out_ptr = NULL;
80 *out_len = 0;
81
82 if (cbs->len == 0)
83 return 1;
84
85 if ((*out_ptr = malloc(cbs->len)) == NULL)
86 return 0;
87
88 memcpy(*out_ptr, cbs->data, cbs->len);
89
90 *out_len = cbs->len;
91 return 1;
92}
93
94int
95CBS_strdup(const CBS *cbs, char **out_ptr)
96{
97 free(*out_ptr);
98 *out_ptr = NULL;
99
100 if (CBS_contains_zero_byte(cbs))
101 return 0;
102
103 *out_ptr = strndup((const char *)cbs->data, cbs->len);
104 return (*out_ptr != NULL);
105}
106
107int
108CBS_write_bytes(const CBS *cbs, uint8_t *dst, size_t dst_len, size_t *copied)
109{
110 if (dst_len < cbs->len)
111 return 0;
112
113 memmove(dst, cbs->data, cbs->len);
114
115 if (copied != NULL)
116 *copied = cbs->len;
117
118 return 1;
119}
120
121int
122CBS_contains_zero_byte(const CBS *cbs)
123{
124 return memchr(cbs->data, 0, cbs->len) != NULL;
125}
126
127int
128CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len)
129{
130 if (len != cbs->len)
131 return 0;
132
133 return timingsafe_memcmp(cbs->data, data, len) == 0;
134}
135
136static int
137cbs_get_u(CBS *cbs, uint32_t *out, size_t len)
138{
139 uint32_t result = 0;
140 size_t i;
141 const uint8_t *data;
142
143 if (len < 1 || len > 4)
144 return 0;
145
146 if (!cbs_get(cbs, &data, len))
147 return 0;
148
149 for (i = 0; i < len; i++) {
150 result <<= 8;
151 result |= data[i];
152 }
153 *out = result;
154 return 1;
155}
156
157int
158CBS_get_u8(CBS *cbs, uint8_t *out)
159{
160 const uint8_t *v;
161
162 if (!cbs_get(cbs, &v, 1))
163 return 0;
164
165 *out = *v;
166 return 1;
167}
168
169int
170CBS_get_u16(CBS *cbs, uint16_t *out)
171{
172 uint32_t v;
173
174 if (!cbs_get_u(cbs, &v, 2))
175 return 0;
176
177 *out = v;
178 return 1;
179}
180
181int
182CBS_get_u24(CBS *cbs, uint32_t *out)
183{
184 return cbs_get_u(cbs, out, 3);
185}
186
187int
188CBS_get_u32(CBS *cbs, uint32_t *out)
189{
190 return cbs_get_u(cbs, out, 4);
191}
192
193int
194CBS_get_bytes(CBS *cbs, CBS *out, size_t len)
195{
196 const uint8_t *v;
197
198 if (!cbs_get(cbs, &v, len))
199 return 0;
200
201 CBS_init(out, v, len);
202 return 1;
203}
204
205static int
206cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len)
207{
208 uint32_t len;
209
210 if (!cbs_get_u(cbs, &len, len_len))
211 return 0;
212
213 return CBS_get_bytes(cbs, out, len);
214}
215
216int
217CBS_get_u8_length_prefixed(CBS *cbs, CBS *out)
218{
219 return cbs_get_length_prefixed(cbs, out, 1);
220}
221
222int
223CBS_get_u16_length_prefixed(CBS *cbs, CBS *out)
224{
225 return cbs_get_length_prefixed(cbs, out, 2);
226}
227
228int
229CBS_get_u24_length_prefixed(CBS *cbs, CBS *out)
230{
231 return cbs_get_length_prefixed(cbs, out, 3);
232}
233
234int
235CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned int *out_tag,
236 size_t *out_header_len)
237{
238 return cbs_get_any_asn1_element_internal(cbs, out, out_tag,
239 out_header_len, 1);
240}
241
242/*
243 * Review X.690 for details on ASN.1 DER encoding.
244 *
245 * If non-strict mode is enabled, then DER rules are relaxed
246 * for indefinite constructs (violates DER but a little closer to BER).
247 * Non-strict mode should only be used by bs_ber.c
248 *
249 * Sections 8, 10 and 11 for DER encoding
250 */
251int
252cbs_get_any_asn1_element_internal(CBS *cbs, CBS *out, unsigned int *out_tag,
253 size_t *out_header_len, int strict)
254{
255 uint8_t tag, length_byte;
256 CBS header = *cbs;
257 CBS throwaway;
258 size_t len;
259
260 if (out == NULL)
261 out = &throwaway;
262
263 /*
264 * Get identifier octet and length octet. Only 1 octet for each
265 * is a CBS limitation.
266 */
267 if (!CBS_get_u8(&header, &tag) || !CBS_get_u8(&header, &length_byte))
268 return 0;
269
270 /* CBS limitation: long form tags are not supported. */
271 if ((tag & 0x1f) == 0x1f)
272 return 0;
273
274 if (out_tag != NULL)
275 *out_tag = tag;
276
277 if ((length_byte & 0x80) == 0) {
278 /* Short form length. */
279 len = ((size_t) length_byte) + 2;
280 if (out_header_len != NULL)
281 *out_header_len = 2;
282
283 } else {
284 /* Long form length. */
285 const size_t num_bytes = length_byte & 0x7f;
286 uint32_t len32;
287
288 /* ASN.1 reserved value for future extensions */
289 if (num_bytes == 0x7f)
290 return 0;
291
292 /* Handle indefinite form length */
293 if (num_bytes == 0) {
294 /* DER encoding doesn't allow for indefinite form. */
295 if (strict)
296 return 0;
297
298 /* Primitive cannot use indefinite in BER or DER. */
299 if ((tag & CBS_ASN1_CONSTRUCTED) == 0)
300 return 0;
301
302 /* Constructed, indefinite length allowed in BER. */
303 if (out_header_len != NULL)
304 *out_header_len = 2;
305 return CBS_get_bytes(cbs, out, 2);
306 }
307
308 /* CBS limitation. */
309 if (num_bytes > 4)
310 return 0;
311
312 if (!cbs_get_u(&header, &len32, num_bytes))
313 return 0;
314
315 /* DER has a minimum length octet requirement. */
316 if (len32 < 128)
317 /* Should have used short form instead */
318 return 0;
319
320 if ((len32 >> ((num_bytes - 1) * 8)) == 0)
321 /* Length should have been at least one byte shorter. */
322 return 0;
323
324 len = len32;
325 if (len + 2 + num_bytes < len)
326 /* Overflow. */
327 return 0;
328
329 len += 2 + num_bytes;
330 if (out_header_len != NULL)
331 *out_header_len = 2 + num_bytes;
332 }
333
334 return CBS_get_bytes(cbs, out, len);
335}
336
337static int
338cbs_get_asn1(CBS *cbs, CBS *out, unsigned int tag_value, int skip_header)
339{
340 size_t header_len;
341 unsigned int tag;
342 CBS throwaway;
343
344 if (out == NULL)
345 out = &throwaway;
346
347 if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) ||
348 tag != tag_value)
349 return 0;
350
351 if (skip_header && !CBS_skip(out, header_len))
352 return 0;
353
354 return 1;
355}
356
357int
358CBS_get_asn1(CBS *cbs, CBS *out, unsigned int tag_value)
359{
360 return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */);
361}
362
363int
364CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned int tag_value)
365{
366 return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */);
367}
368
369int
370CBS_peek_asn1_tag(const CBS *cbs, unsigned int tag_value)
371{
372 if (CBS_len(cbs) < 1)
373 return 0;
374
375 /*
376 * Tag number 31 indicates the start of a long form number.
377 * This is valid in ASN.1, but CBS only supports short form.
378 */
379 if ((tag_value & 0x1f) == 0x1f)
380 return 0;
381
382 return CBS_data(cbs)[0] == tag_value;
383}
384
385/* Encoding details are in ASN.1: X.690 section 8.3 */
386int
387CBS_get_asn1_uint64(CBS *cbs, uint64_t *out)
388{
389 CBS bytes;
390 const uint8_t *data;
391 size_t i, len;
392
393 if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER))
394 return 0;
395
396 *out = 0;
397 data = CBS_data(&bytes);
398 len = CBS_len(&bytes);
399
400 if (len == 0)
401 /* An INTEGER is encoded with at least one content octet. */
402 return 0;
403
404 if ((data[0] & 0x80) != 0)
405 /* Negative number. */
406 return 0;
407
408 if (data[0] == 0 && len > 1 && (data[1] & 0x80) == 0)
409 /* Violates smallest encoding rule: excessive leading zeros. */
410 return 0;
411
412 for (i = 0; i < len; i++) {
413 if ((*out >> 56) != 0)
414 /* Too large to represent as a uint64_t. */
415 return 0;
416
417 *out <<= 8;
418 *out |= data[i];
419 }
420
421 return 1;
422}
423
424int
425CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned int tag)
426{
427 if (CBS_peek_asn1_tag(cbs, tag)) {
428 if (!CBS_get_asn1(cbs, out, tag))
429 return 0;
430
431 *out_present = 1;
432 } else {
433 *out_present = 0;
434 }
435 return 1;
436}
437
438int
439CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present,
440 unsigned int tag)
441{
442 CBS child;
443 int present;
444
445 if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
446 return 0;
447
448 if (present) {
449 if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) ||
450 CBS_len(&child) != 0)
451 return 0;
452 } else {
453 CBS_init(out, NULL, 0);
454 }
455 if (out_present)
456 *out_present = present;
457
458 return 1;
459}
460
461int
462CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned int tag,
463 uint64_t default_value)
464{
465 CBS child;
466 int present;
467
468 if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
469 return 0;
470
471 if (present) {
472 if (!CBS_get_asn1_uint64(&child, out) ||
473 CBS_len(&child) != 0)
474 return 0;
475 } else {
476 *out = default_value;
477 }
478 return 1;
479}
480
481int
482CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned int tag,
483 int default_value)
484{
485 CBS child, child2;
486 int present;
487
488 if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
489 return 0;
490
491 if (present) {
492 uint8_t boolean;
493
494 if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
495 CBS_len(&child2) != 1 || CBS_len(&child) != 0)
496 return 0;
497
498 boolean = CBS_data(&child2)[0];
499 if (boolean == 0)
500 *out = 0;
501 else if (boolean == 0xff)
502 *out = 1;
503 else
504 return 0;
505
506 } else {
507 *out = default_value;
508 }
509 return 1;
510}