diff options
author | cvs2svn <admin@example.com> | 2015-08-02 21:54:22 +0000 |
---|---|---|
committer | cvs2svn <admin@example.com> | 2015-08-02 21:54:22 +0000 |
commit | ed3760bf4be4a96a89233fb8f8b84a0d44725862 (patch) | |
tree | 5609c82060f75c53af0a7641d9b33a88574876cd /src/lib/libssl/bs_ber.c | |
parent | f8b563fb5ba1524c821d37308f4e6abfc866bc3f (diff) | |
download | openbsd-OPENBSD_5_8_BASE.tar.gz openbsd-OPENBSD_5_8_BASE.tar.bz2 openbsd-OPENBSD_5_8_BASE.zip |
This commit was manufactured by cvs2git to create tag 'OPENBSD_5_8_BASE'.OPENBSD_5_8_BASE
Diffstat (limited to 'src/lib/libssl/bs_ber.c')
-rw-r--r-- | src/lib/libssl/bs_ber.c | 268 |
1 files changed, 0 insertions, 268 deletions
diff --git a/src/lib/libssl/bs_ber.c b/src/lib/libssl/bs_ber.c deleted file mode 100644 index 6e945a0246..0000000000 --- a/src/lib/libssl/bs_ber.c +++ /dev/null | |||
@@ -1,268 +0,0 @@ | |||
1 | /* $OpenBSD: bs_ber.c,v 1.8 2015/06/21 16:10:45 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 <string.h> | ||
18 | |||
19 | #include <openssl/opensslconf.h> | ||
20 | |||
21 | #include "bytestring.h" | ||
22 | |||
23 | /* | ||
24 | * kMaxDepth is a just a sanity limit. The code should be such that the length | ||
25 | * of the input being processes always decreases. None the less, a very large | ||
26 | * input could otherwise cause the stack to overflow. | ||
27 | */ | ||
28 | static const unsigned int kMaxDepth = 2048; | ||
29 | |||
30 | /* Non-strict version that allows a relaxed DER with indefinite form. */ | ||
31 | static int | ||
32 | cbs_nonstrict_get_any_asn1_element(CBS *cbs, CBS *out, unsigned int *out_tag, | ||
33 | size_t *out_header_len) | ||
34 | { | ||
35 | return cbs_get_any_asn1_element_internal(cbs, out, | ||
36 | out_tag, out_header_len, 0); | ||
37 | } | ||
38 | |||
39 | /* | ||
40 | * cbs_find_indefinite walks an ASN.1 structure in |orig_in| and sets | ||
41 | * |*indefinite_found| depending on whether an indefinite length element was | ||
42 | * found. The value of |orig_in| is not modified. | ||
43 | * | ||
44 | * Returns one on success (i.e. |*indefinite_found| was set) and zero on error. | ||
45 | */ | ||
46 | static int | ||
47 | cbs_find_indefinite(const CBS *orig_in, char *indefinite_found, | ||
48 | unsigned int depth) | ||
49 | { | ||
50 | CBS in; | ||
51 | |||
52 | if (depth > kMaxDepth) | ||
53 | return 0; | ||
54 | |||
55 | CBS_init(&in, CBS_data(orig_in), CBS_len(orig_in)); | ||
56 | |||
57 | while (CBS_len(&in) > 0) { | ||
58 | CBS contents; | ||
59 | unsigned int tag; | ||
60 | size_t header_len; | ||
61 | |||
62 | if (!cbs_nonstrict_get_any_asn1_element(&in, &contents, &tag, | ||
63 | &header_len)) | ||
64 | return 0; | ||
65 | |||
66 | /* Indefinite form not allowed by DER. */ | ||
67 | if (CBS_len(&contents) == header_len && header_len > 0 && | ||
68 | CBS_data(&contents)[header_len - 1] == 0x80) { | ||
69 | *indefinite_found = 1; | ||
70 | return 1; | ||
71 | } | ||
72 | if (tag & CBS_ASN1_CONSTRUCTED) { | ||
73 | if (!CBS_skip(&contents, header_len) || | ||
74 | !cbs_find_indefinite(&contents, indefinite_found, | ||
75 | depth + 1)) | ||
76 | return 0; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | *indefinite_found = 0; | ||
81 | return 1; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * is_primitive_type returns true if |tag| likely a primitive type. Normally | ||
86 | * one can just test the "constructed" bit in the tag but, in BER, even | ||
87 | * primitive tags can have the constructed bit if they have indefinite | ||
88 | * length. | ||
89 | */ | ||
90 | static char | ||
91 | is_primitive_type(unsigned int tag) | ||
92 | { | ||
93 | return (tag & 0xc0) == 0 && | ||
94 | (tag & 0x1f) != (CBS_ASN1_SEQUENCE & 0x1f) && | ||
95 | (tag & 0x1f) != (CBS_ASN1_SET & 0x1f); | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * is_eoc returns true if |header_len| and |contents|, as returned by | ||
100 | * |cbs_nonstrict_get_any_asn1_element|, indicate an "end of contents" (EOC) | ||
101 | * value. | ||
102 | */ | ||
103 | static char | ||
104 | is_eoc(size_t header_len, CBS *contents) | ||
105 | { | ||
106 | return header_len == 2 && CBS_mem_equal(contents, "\x00\x00", 2); | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * cbs_convert_indefinite reads data with DER encoding (but relaxed to allow | ||
111 | * indefinite form) from |in| and writes definite form DER data to |out|. If | ||
112 | * |squash_header| is set then the top-level of elements from |in| will not | ||
113 | * have their headers written. This is used when concatenating the fragments of | ||
114 | * an indefinite length, primitive value. If |looking_for_eoc| is set then any | ||
115 | * EOC elements found will cause the function to return after consuming it. | ||
116 | * It returns one on success and zero on error. | ||
117 | */ | ||
118 | static int | ||
119 | cbs_convert_indefinite(CBS *in, CBB *out, char squash_header, | ||
120 | char looking_for_eoc, unsigned int depth) | ||
121 | { | ||
122 | if (depth > kMaxDepth) | ||
123 | return 0; | ||
124 | |||
125 | while (CBS_len(in) > 0) { | ||
126 | CBS contents; | ||
127 | unsigned int tag; | ||
128 | size_t header_len; | ||
129 | CBB *out_contents, out_contents_storage; | ||
130 | |||
131 | if (!cbs_nonstrict_get_any_asn1_element(in, &contents, &tag, | ||
132 | &header_len)) | ||
133 | return 0; | ||
134 | |||
135 | out_contents = out; | ||
136 | |||
137 | if (CBS_len(&contents) == header_len) { | ||
138 | if (is_eoc(header_len, &contents)) | ||
139 | return looking_for_eoc; | ||
140 | |||
141 | if (header_len > 0 && | ||
142 | CBS_data(&contents)[header_len - 1] == 0x80) { | ||
143 | /* | ||
144 | * This is an indefinite length element. If | ||
145 | * it's a SEQUENCE or SET then we just need to | ||
146 | * write the out the contents as normal, but | ||
147 | * with a concrete length prefix. | ||
148 | * | ||
149 | * If it's a something else then the contents | ||
150 | * will be a series of DER elements of the same | ||
151 | * type which need to be concatenated. | ||
152 | */ | ||
153 | const char context_specific = (tag & 0xc0) | ||
154 | == 0x80; | ||
155 | char squash_child_headers = | ||
156 | is_primitive_type(tag); | ||
157 | |||
158 | /* | ||
159 | * This is a hack, but it sufficies to handle | ||
160 | * NSS's output. If we find an indefinite | ||
161 | * length, context-specific tag with a definite, | ||
162 | * primtive tag inside it, then we assume that | ||
163 | * the context-specific tag is implicit and the | ||
164 | * tags within are fragments of a primitive type | ||
165 | * that need to be concatenated. | ||
166 | */ | ||
167 | if (context_specific && | ||
168 | (tag & CBS_ASN1_CONSTRUCTED)) { | ||
169 | CBS in_copy, inner_contents; | ||
170 | unsigned int inner_tag; | ||
171 | size_t inner_header_len; | ||
172 | |||
173 | CBS_init(&in_copy, CBS_data(in), | ||
174 | CBS_len(in)); | ||
175 | if (!cbs_nonstrict_get_any_asn1_element( | ||
176 | &in_copy, &inner_contents, | ||
177 | &inner_tag, &inner_header_len)) | ||
178 | return 0; | ||
179 | |||
180 | if (CBS_len(&inner_contents) > | ||
181 | inner_header_len && | ||
182 | is_primitive_type(inner_tag)) | ||
183 | squash_child_headers = 1; | ||
184 | } | ||
185 | |||
186 | if (!squash_header) { | ||
187 | unsigned int out_tag = tag; | ||
188 | |||
189 | if (squash_child_headers) | ||
190 | out_tag &= | ||
191 | ~CBS_ASN1_CONSTRUCTED; | ||
192 | |||
193 | if (!CBB_add_asn1(out, | ||
194 | &out_contents_storage, out_tag)) | ||
195 | return 0; | ||
196 | |||
197 | out_contents = &out_contents_storage; | ||
198 | } | ||
199 | |||
200 | if (!cbs_convert_indefinite(in, out_contents, | ||
201 | squash_child_headers, | ||
202 | 1 /* looking for eoc */, depth + 1)) | ||
203 | return 0; | ||
204 | |||
205 | if (out_contents != out && !CBB_flush(out)) | ||
206 | return 0; | ||
207 | |||
208 | continue; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | if (!squash_header) { | ||
213 | if (!CBB_add_asn1(out, &out_contents_storage, tag)) | ||
214 | return 0; | ||
215 | |||
216 | out_contents = &out_contents_storage; | ||
217 | } | ||
218 | |||
219 | if (!CBS_skip(&contents, header_len)) | ||
220 | return 0; | ||
221 | |||
222 | if (tag & CBS_ASN1_CONSTRUCTED) { | ||
223 | if (!cbs_convert_indefinite(&contents, out_contents, | ||
224 | 0 /* don't squash header */, | ||
225 | 0 /* not looking for eoc */, depth + 1)) | ||
226 | return 0; | ||
227 | } else { | ||
228 | if (!CBB_add_bytes(out_contents, CBS_data(&contents), | ||
229 | CBS_len(&contents))) | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | if (out_contents != out && !CBB_flush(out)) | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | return looking_for_eoc == 0; | ||
238 | } | ||
239 | |||
240 | int | ||
241 | CBS_asn1_indefinite_to_definite(CBS *in, uint8_t **out, size_t *out_len) | ||
242 | { | ||
243 | CBB cbb; | ||
244 | |||
245 | /* | ||
246 | * First, do a quick walk to find any indefinite-length elements. Most | ||
247 | * of the time we hope that there aren't any and thus we can quickly | ||
248 | * return. | ||
249 | */ | ||
250 | char conversion_needed; | ||
251 | if (!cbs_find_indefinite(in, &conversion_needed, 0)) | ||
252 | return 0; | ||
253 | |||
254 | if (!conversion_needed) { | ||
255 | *out = NULL; | ||
256 | *out_len = 0; | ||
257 | return 1; | ||
258 | } | ||
259 | |||
260 | if (!CBB_init(&cbb, CBS_len(in))) | ||
261 | return 0; | ||
262 | if (!cbs_convert_indefinite(in, &cbb, 0, 0, 0)) { | ||
263 | CBB_cleanup(&cbb); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | return CBB_finish(&cbb, out, out_len); | ||
268 | } | ||