summaryrefslogtreecommitdiff
path: root/src/lib/libssl/bs_cbs.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib/libssl/bs_cbs.c390
1 files changed, 390 insertions, 0 deletions
diff --git a/src/lib/libssl/bs_cbs.c b/src/lib/libssl/bs_cbs.c
new file mode 100644
index 0000000000..7edfe65288
--- /dev/null
+++ b/src/lib/libssl/bs_cbs.c
@@ -0,0 +1,390 @@
1/* $OpenBSD: bs_cbs.c,v 1.1 2015/02/06 09:36:16 doug 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#include <assert.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include <openssl/opensslconf.h>
22#include <openssl/buffer.h>
23#include <openssl/crypto.h>
24
25#include "bytestring.h"
26
27void CBS_init(CBS *cbs, const uint8_t *data, size_t len) {
28 cbs->data = data;
29 cbs->len = len;
30}
31
32static int cbs_get(CBS *cbs, const uint8_t **p, size_t n) {
33 if (cbs->len < n) {
34 return 0;
35 }
36
37 *p = cbs->data;
38 cbs->data += n;
39 cbs->len -= n;
40 return 1;
41}
42
43int CBS_skip(CBS *cbs, size_t len) {
44 const uint8_t *dummy;
45 return cbs_get(cbs, &dummy, len);
46}
47
48const uint8_t *CBS_data(const CBS *cbs) {
49 return cbs->data;
50}
51
52size_t CBS_len(const CBS *cbs) {
53 return cbs->len;
54}
55
56int CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len) {
57 if (*out_ptr != NULL) {
58 free(*out_ptr);
59 *out_ptr = NULL;
60 }
61 *out_len = 0;
62
63 if (cbs->len == 0) {
64 return 1;
65 }
66 *out_ptr = BUF_memdup(cbs->data, cbs->len);
67 if (*out_ptr == NULL) {
68 return 0;
69 }
70 *out_len = cbs->len;
71 return 1;
72}
73
74int CBS_strdup(const CBS *cbs, char **out_ptr) {
75 if (*out_ptr != NULL) {
76 free(*out_ptr);
77 }
78 *out_ptr = strndup((const char*)cbs->data, cbs->len);
79 return (*out_ptr != NULL);
80}
81
82int CBS_contains_zero_byte(const CBS *cbs) {
83 return memchr(cbs->data, 0, cbs->len) != NULL;
84}
85
86int CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len) {
87 if (len != cbs->len)
88 return 0;
89 return CRYPTO_memcmp(cbs->data, data, len) == 0;
90}
91
92static int cbs_get_u(CBS *cbs, uint32_t *out, size_t len) {
93 uint32_t result = 0;
94 size_t i;
95 const uint8_t *data;
96
97 if (!cbs_get(cbs, &data, len)) {
98 return 0;
99 }
100 for (i = 0; i < len; i++) {
101 result <<= 8;
102 result |= data[i];
103 }
104 *out = result;
105 return 1;
106}
107
108int CBS_get_u8(CBS *cbs, uint8_t *out) {
109 const uint8_t *v;
110 if (!cbs_get(cbs, &v, 1)) {
111 return 0;
112 }
113 *out = *v;
114 return 1;
115}
116
117int CBS_get_u16(CBS *cbs, uint16_t *out) {
118 uint32_t v;
119 if (!cbs_get_u(cbs, &v, 2)) {
120 return 0;
121 }
122 *out = v;
123 return 1;
124}
125
126int CBS_get_u24(CBS *cbs, uint32_t *out) {
127 return cbs_get_u(cbs, out, 3);
128}
129
130int CBS_get_u32(CBS *cbs, uint32_t *out) {
131 return cbs_get_u(cbs, out, 4);
132}
133
134int CBS_get_bytes(CBS *cbs, CBS *out, size_t len) {
135 const uint8_t *v;
136 if (!cbs_get(cbs, &v, len)) {
137 return 0;
138 }
139 CBS_init(out, v, len);
140 return 1;
141}
142
143static int cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len) {
144 uint32_t len;
145 if (!cbs_get_u(cbs, &len, len_len)) {
146 return 0;
147 }
148 return CBS_get_bytes(cbs, out, len);
149}
150
151int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out) {
152 return cbs_get_length_prefixed(cbs, out, 1);
153}
154
155int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out) {
156 return cbs_get_length_prefixed(cbs, out, 2);
157}
158
159int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) {
160 return cbs_get_length_prefixed(cbs, out, 3);
161}
162
163int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
164 size_t *out_header_len) {
165 uint8_t tag, length_byte;
166 CBS header = *cbs;
167 CBS throwaway;
168
169 if (out == NULL) {
170 out = &throwaway;
171 }
172
173 if (!CBS_get_u8(&header, &tag) ||
174 !CBS_get_u8(&header, &length_byte)) {
175 return 0;
176 }
177
178 if ((tag & 0x1f) == 0x1f) {
179 /* Long form tags are not supported. */
180 return 0;
181 }
182
183 if (out_tag != NULL) {
184 *out_tag = tag;
185 }
186
187 size_t len;
188 if ((length_byte & 0x80) == 0) {
189 /* Short form length. */
190 len = ((size_t) length_byte) + 2;
191 if (out_header_len != NULL) {
192 *out_header_len = 2;
193 }
194 } else {
195 /* Long form length. */
196 const size_t num_bytes = length_byte & 0x7f;
197 uint32_t len32;
198
199 if ((tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) {
200 /* indefinite length */
201 *out_header_len = 2;
202 return CBS_get_bytes(cbs, out, 2);
203 }
204
205 if (num_bytes == 0 || num_bytes > 4) {
206 return 0;
207 }
208 if (!cbs_get_u(&header, &len32, num_bytes)) {
209 return 0;
210 }
211 if (len32 < 128) {
212 /* Length should have used short-form encoding. */
213 return 0;
214 }
215 if ((len32 >> ((num_bytes-1)*8)) == 0) {
216 /* Length should have been at least one byte shorter. */
217 return 0;
218 }
219 len = len32;
220 if (len + 2 + num_bytes < len) {
221 /* Overflow. */
222 return 0;
223 }
224 len += 2 + num_bytes;
225 if (out_header_len != NULL) {
226 *out_header_len = 2 + num_bytes;
227 }
228 }
229
230 return CBS_get_bytes(cbs, out, len);
231}
232
233static int cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value,
234 int skip_header) {
235 size_t header_len;
236 unsigned tag;
237 CBS throwaway;
238
239 if (out == NULL) {
240 out = &throwaway;
241 }
242
243 if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) ||
244 tag != tag_value ||
245 (header_len > 0 &&
246 /* This ensures that the tag is either zero length or
247 * indefinite-length. */
248 CBS_len(out) == header_len &&
249 CBS_data(out)[header_len - 1] == 0x80)) {
250 return 0;
251 }
252
253 if (skip_header && !CBS_skip(out, header_len)) {
254 assert(0);
255 return 0;
256 }
257
258 return 1;
259}
260
261int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value) {
262 return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */);
263}
264
265int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value) {
266 return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */);
267}
268
269int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) {
270 if (CBS_len(cbs) < 1) {
271 return 0;
272 }
273 return CBS_data(cbs)[0] == tag_value;
274}
275
276int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
277 CBS bytes;
278 const uint8_t *data;
279 size_t i, len;
280
281 if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER)) {
282 return 0;
283 }
284
285 *out = 0;
286 data = CBS_data(&bytes);
287 len = CBS_len(&bytes);
288
289 if (len == 0) {
290 /* An INTEGER is encoded with at least one octet. */
291 return 0;
292 }
293
294 if ((data[0] & 0x80) != 0) {
295 /* negative number */
296 return 0;
297 }
298
299 for (i = 0; i < len; i++) {
300 if ((*out >> 56) != 0) {
301 /* Too large to represent as a uint64_t. */
302 return 0;
303 }
304 *out <<= 8;
305 *out |= data[i];
306 }
307
308 return 1;
309}
310
311int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) {
312 if (CBS_peek_asn1_tag(cbs, tag)) {
313 if (!CBS_get_asn1(cbs, out, tag)) {
314 return 0;
315 }
316 *out_present = 1;
317 } else {
318 *out_present = 0;
319 }
320 return 1;
321}
322
323int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present,
324 unsigned tag) {
325 CBS child;
326 int present;
327 if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
328 return 0;
329 }
330 if (present) {
331 if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) ||
332 CBS_len(&child) != 0) {
333 return 0;
334 }
335 } else {
336 CBS_init(out, NULL, 0);
337 }
338 if (out_present) {
339 *out_present = present;
340 }
341 return 1;
342}
343
344int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag,
345 uint64_t default_value) {
346 CBS child;
347 int present;
348 if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
349 return 0;
350 }
351 if (present) {
352 if (!CBS_get_asn1_uint64(&child, out) ||
353 CBS_len(&child) != 0) {
354 return 0;
355 }
356 } else {
357 *out = default_value;
358 }
359 return 1;
360}
361
362int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
363 int default_value) {
364 CBS child, child2;
365 int present;
366 if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
367 return 0;
368 }
369 if (present) {
370 uint8_t boolean;
371
372 if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
373 CBS_len(&child2) != 1 ||
374 CBS_len(&child) != 0) {
375 return 0;
376 }
377
378 boolean = CBS_data(&child2)[0];
379 if (boolean == 0) {
380 *out = 0;
381 } else if (boolean == 0xff) {
382 *out = 1;
383 } else {
384 return 0;
385 }
386 } else {
387 *out = default_value;
388 }
389 return 1;
390}