/src/boringssl/crypto/x509/x_name.cc
Line | Count | Source |
1 | | // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <ctype.h> |
16 | | #include <limits.h> |
17 | | #include <string.h> |
18 | | |
19 | | #include <utility> |
20 | | |
21 | | #include <openssl/asn1.h> |
22 | | #include <openssl/asn1t.h> |
23 | | #include <openssl/bytestring.h> |
24 | | #include <openssl/buf.h> |
25 | | #include <openssl/err.h> |
26 | | #include <openssl/mem.h> |
27 | | #include <openssl/obj.h> |
28 | | #include <openssl/stack.h> |
29 | | #include <openssl/x509.h> |
30 | | |
31 | | #include "../asn1/internal.h" |
32 | | #include "../bytestring/internal.h" |
33 | | #include "../internal.h" |
34 | | #include "../mem_internal.h" |
35 | | #include "internal.h" |
36 | | |
37 | | |
38 | | using namespace bssl; |
39 | | |
40 | | // X509_NAME_MAX is the length of the maximum encoded `X509_NAME` we accept. |
41 | 359k | #define X509_NAME_MAX (1024 * 1024) |
42 | | |
43 | | static int asn1_marshal_string_canon(CBB *cbb, const ASN1_STRING *in); |
44 | | |
45 | 891k | bssl::X509NameEntry::X509NameEntry() { |
46 | 891k | object.reset(const_cast<ASN1_OBJECT *>(OBJ_get_undef())); |
47 | 891k | } |
48 | | |
49 | 74 | X509_NAME_ENTRY *X509_NAME_ENTRY_new() { return New<X509NameEntry>(); } |
50 | | |
51 | 890k | void X509_NAME_ENTRY_free(X509_NAME_ENTRY *entry) { Delete(FromOpaque(entry)); } |
52 | | |
53 | 891k | static int x509_parse_name_entry(CBS *cbs, X509_NAME_ENTRY *out) { |
54 | 891k | auto *out_impl = FromOpaque(out); |
55 | 891k | CBS seq; |
56 | 891k | if (!CBS_get_asn1(cbs, &seq, CBS_ASN1_SEQUENCE)) { |
57 | 172 | OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); |
58 | 172 | return 0; |
59 | 172 | } |
60 | 891k | out_impl->object.reset(asn1_parse_object(&seq, /*tag=*/0)); |
61 | 891k | if (out_impl->object == nullptr || // |
62 | 891k | !asn1_parse_any_as_string(&seq, out_impl->value.get()) || // |
63 | 890k | CBS_len(&seq) != 0) { |
64 | 1.16k | OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); |
65 | 1.16k | return 0; |
66 | 1.16k | } |
67 | 890k | return 1; |
68 | 891k | } |
69 | | |
70 | | static int x509_marshal_name_entry(CBB *cbb, const X509_NAME_ENTRY *entry, |
71 | 1.77M | int canonicalize) { |
72 | 1.77M | auto *entry_impl = FromOpaque(entry); |
73 | 1.77M | CBB seq; |
74 | 1.77M | if (!CBB_add_asn1(cbb, &seq, CBS_ASN1_SEQUENCE) || |
75 | 1.77M | !asn1_marshal_object(&seq, entry_impl->object.get(), /*tag=*/0)) { |
76 | 0 | return 0; |
77 | 0 | } |
78 | 1.77M | int ok = canonicalize |
79 | 1.77M | ? asn1_marshal_string_canon(&seq, entry_impl->value.get()) |
80 | 1.77M | : asn1_marshal_any_string(&seq, entry_impl->value.get()); |
81 | 1.77M | if (!ok) { |
82 | 0 | return 0; |
83 | 0 | } |
84 | 1.77M | return CBB_flush(cbb); |
85 | 1.77M | } |
86 | | |
87 | | static int x509_marshal_name_entry_no_canon(CBB *cbb, |
88 | 0 | const X509_NAME_ENTRY *entry) { |
89 | 0 | return x509_marshal_name_entry(cbb, entry, /*canonicalize=*/0); |
90 | 0 | } |
91 | | |
92 | | BSSL_NAMESPACE_BEGIN |
93 | | |
94 | | IMPLEMENT_EXTERN_ASN1_PARSE_INTO(X509_NAME_ENTRY, X509_NAME_ENTRY_new, |
95 | | X509_NAME_ENTRY_free, CBS_ASN1_SEQUENCE, |
96 | | x509_parse_name_entry, |
97 | | x509_marshal_name_entry_no_canon) |
98 | | |
99 | | BSSL_NAMESPACE_END |
100 | | |
101 | 0 | X509_NAME_ENTRY *X509_NAME_ENTRY_dup(const X509_NAME_ENTRY *entry) { |
102 | 0 | ScopedCBB cbb; |
103 | 0 | if (!CBB_init(cbb.get(), 16) || |
104 | 0 | !x509_marshal_name_entry(cbb.get(), entry, /*canonicalize=*/0)) { |
105 | 0 | return nullptr; |
106 | 0 | } |
107 | 0 | CBS cbs; |
108 | 0 | CBS_init(&cbs, CBB_data(cbb.get()), CBB_len(cbb.get())); |
109 | 0 | UniquePtr<X509_NAME_ENTRY> copy(X509_NAME_ENTRY_new()); |
110 | 0 | if (copy == nullptr || !x509_parse_name_entry(&cbs, copy.get())) { |
111 | 0 | return nullptr; |
112 | 0 | } |
113 | 0 | return copy.release(); |
114 | 0 | } |
115 | | |
116 | 379k | bssl::X509Name::~X509Name() { Delete(cache.exchange(nullptr)); } |
117 | | |
118 | 5.38k | X509_NAME *X509_NAME_new() { return New<X509Name>(); } |
119 | | |
120 | 9.99k | void X509_NAME_free(X509_NAME *name) { Delete(FromOpaque(name)); } |
121 | | |
122 | 359k | int bssl::x509_parse_name(CBS *cbs, X509_NAME *out) { |
123 | 359k | auto *impl = FromOpaque(out); |
124 | 359k | impl->entries = nullptr; |
125 | 359k | x509_name_invalidate_cache(impl); |
126 | | |
127 | 359k | impl->entries.reset(sk_X509_NAME_ENTRY_new_null()); |
128 | 359k | if (impl->entries == nullptr) { |
129 | 0 | return 0; |
130 | 0 | } |
131 | 359k | CBS seq, rdn; |
132 | 359k | if (!CBS_get_asn1(cbs, &seq, CBS_ASN1_SEQUENCE) || |
133 | | // Bound the size of an X509_NAME we are willing to parse. |
134 | 359k | CBS_len(&seq) > X509_NAME_MAX) { |
135 | 199 | OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); |
136 | 199 | return 0; |
137 | 199 | } |
138 | 359k | static_assert(X509_NAME_MAX <= INT_MAX, "set may overflow"); |
139 | 1.05M | for (int set = 0; CBS_len(&seq) > 0; set++) { |
140 | 699k | if (!CBS_get_asn1(&seq, &rdn, CBS_ASN1_SET) || // |
141 | 698k | CBS_len(&rdn) == 0) { |
142 | 280 | OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); |
143 | 280 | return 0; |
144 | 280 | } |
145 | 1.58M | while (CBS_len(&rdn) != 0) { |
146 | 891k | auto entry = MakeUnique<X509NameEntry>(); |
147 | 891k | if (entry == nullptr || !x509_parse_name_entry(&rdn, entry.get())) { |
148 | 1.29k | return 0; |
149 | 1.29k | } |
150 | 889k | entry->set = set; |
151 | 889k | if (!PushToStack(impl->entries.get(), std::move(entry))) { |
152 | 0 | return 0; |
153 | 0 | } |
154 | 889k | } |
155 | 698k | } |
156 | | |
157 | | // While we are single-threaded, also fill in the cached state. |
158 | 357k | return x509_name_get_cache(impl) != nullptr; |
159 | 359k | } |
160 | | |
161 | | static int x509_marshal_name_entries(CBB *out, const X509_NAME *name, |
162 | 715k | int canonicalize) { |
163 | 715k | auto *impl = FromOpaque(name); |
164 | 715k | if (sk_X509_NAME_ENTRY_num(impl->entries.get()) == 0) { |
165 | 10.5k | return 1; |
166 | 10.5k | } |
167 | | |
168 | | // Bootstrap the first RDN. |
169 | 704k | int set = FromOpaque(sk_X509_NAME_ENTRY_value(impl->entries.get(), 0))->set; |
170 | 704k | CBB rdn; |
171 | 704k | if (!CBB_add_asn1(out, &rdn, CBS_ASN1_SET)) { |
172 | 0 | return 0; |
173 | 0 | } |
174 | | |
175 | 1.77M | for (const X509_NAME_ENTRY *entry : impl->entries.get()) { |
176 | 1.77M | if (FromOpaque(entry)->set != set) { |
177 | | // Flush the previous RDN and start a new one. |
178 | 684k | if (!CBB_flush_asn1_set_of(&rdn) || |
179 | 684k | !CBB_add_asn1(out, &rdn, CBS_ASN1_SET)) { |
180 | 0 | return 0; |
181 | 0 | } |
182 | 684k | set = FromOpaque(entry)->set; |
183 | 684k | } |
184 | 1.77M | if (!x509_marshal_name_entry(&rdn, entry, canonicalize)) { |
185 | 0 | return 0; |
186 | 0 | } |
187 | 1.77M | } |
188 | | |
189 | 704k | return CBB_flush_asn1_set_of(&rdn) && CBB_flush(out); |
190 | 704k | } |
191 | | |
192 | 372k | const X509NameCache *bssl::x509_name_get_cache(const X509_NAME *name) { |
193 | 372k | auto *impl = FromOpaque(name); |
194 | 372k | const X509NameCache *cache = impl->cache.load(); |
195 | 372k | if (cache != nullptr) { |
196 | 15.3k | return cache; |
197 | 15.3k | } |
198 | | |
199 | 357k | UniquePtr<X509NameCache> new_cache = MakeUnique<X509NameCache>(); |
200 | | // Cache the DER encoding, including the outer TLV. |
201 | 357k | ScopedCBB cbb; |
202 | 357k | CBB seq; |
203 | 357k | if (!CBB_init(cbb.get(), 16) || |
204 | 357k | !CBB_add_asn1(cbb.get(), &seq, CBS_ASN1_SEQUENCE) || |
205 | 357k | !x509_marshal_name_entries(&seq, impl, /*canonicalize=*/0) || |
206 | 357k | !CBBFinishArray(cbb.get(), &new_cache->der)) { |
207 | 0 | return nullptr; |
208 | 0 | } |
209 | | // Cache the canonicalized form, without the outer TLV. |
210 | 357k | if (!CBB_init(cbb.get(), 16) || |
211 | 357k | !x509_marshal_name_entries(cbb.get(), impl, /*canonicalize=*/1) || |
212 | 357k | !CBBFinishArray(cbb.get(), &new_cache->canon)) { |
213 | 0 | return nullptr; |
214 | 0 | } |
215 | | |
216 | 357k | X509NameCache *expected = nullptr; |
217 | 357k | if (impl->cache.compare_exchange_strong(expected, new_cache.get())) { |
218 | | // We won the race. `impl` now owns `new_cache`. |
219 | 357k | return new_cache.release(); |
220 | 357k | } |
221 | | |
222 | | // Some other thread installed a (presumably identical) cache. Release the one |
223 | | // we made and return the winning one. |
224 | 357k | assert(expected != nullptr); |
225 | 0 | return expected; |
226 | 0 | } |
227 | | |
228 | 359k | void bssl::x509_name_invalidate_cache(X509_NAME *name) { |
229 | 359k | auto *impl = FromOpaque(name); |
230 | 359k | Delete(impl->cache.exchange(nullptr)); |
231 | 359k | } |
232 | | |
233 | 6.27k | int bssl::x509_marshal_name(CBB *out, const X509_NAME *in) { |
234 | 6.27k | const X509NameCache *cache = x509_name_get_cache(in); |
235 | 6.27k | if (cache == nullptr) { |
236 | 0 | return 0; |
237 | 0 | } |
238 | 6.27k | return CBB_add_bytes(out, cache->der.data(), cache->der.size()); |
239 | 6.27k | } |
240 | | |
241 | 0 | int bssl::x509_name_copy(X509_NAME *dst, const X509_NAME *src) { |
242 | 0 | const X509NameCache *cache = x509_name_get_cache(src); |
243 | 0 | if (cache == nullptr) { |
244 | 0 | return 0; |
245 | 0 | } |
246 | | // Callers sometimes try to set a name back to itself. We check this after |
247 | | // `x509_name_get_cache` because, if `src` was so broken that it could not be |
248 | | // serialized, we used to return an error. (It's not clear if this codepath is |
249 | | // even possible.) |
250 | 0 | if (dst == src) { |
251 | 0 | return 1; |
252 | 0 | } |
253 | 0 | CBS cbs(cache->der); |
254 | 0 | if (!x509_parse_name(&cbs, dst)) { |
255 | 0 | return 0; |
256 | 0 | } |
257 | 0 | assert(CBS_len(&cbs) == 0); |
258 | 0 | return 1; |
259 | 0 | } |
260 | | |
261 | 0 | X509_NAME *X509_NAME_dup(const X509_NAME *name) { |
262 | 0 | UniquePtr<X509_NAME> copy(X509_NAME_new()); |
263 | 0 | if (copy == nullptr || !x509_name_copy(copy.get(), name)) { |
264 | 0 | return nullptr; |
265 | 0 | } |
266 | 0 | return copy.release(); |
267 | 0 | } |
268 | | |
269 | 1.31k | X509_NAME *d2i_X509_NAME(X509_NAME **out, const uint8_t **inp, long len) { |
270 | 1.31k | return D2IFromCBS(out, inp, len, [](CBS *cbs) -> UniquePtr<X509_NAME> { |
271 | 1.31k | UniquePtr<X509_NAME> name(X509_NAME_new()); |
272 | 1.31k | if (name == nullptr || !x509_parse_name(cbs, name.get())) { |
273 | 477 | return nullptr; |
274 | 477 | } |
275 | 839 | return name; |
276 | 1.31k | }); |
277 | 1.31k | } |
278 | | |
279 | 3.40k | int i2d_X509_NAME(const X509_NAME *in, uint8_t **outp) { |
280 | 3.40k | if (in == nullptr) { |
281 | 0 | OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); |
282 | 0 | return -1; |
283 | 0 | } |
284 | 3.40k | const X509NameCache *cache = x509_name_get_cache(in); |
285 | 3.40k | if (cache == nullptr) { |
286 | 0 | return -1; |
287 | 0 | } |
288 | 3.40k | if (cache->der.size() > INT_MAX) { |
289 | 0 | OPENSSL_PUT_ERROR(X509, ERR_R_OVERFLOW); |
290 | 0 | return -1; |
291 | 0 | } |
292 | 3.40k | int len = static_cast<int>(cache->der.size()); |
293 | 3.40k | if (outp == nullptr) { |
294 | 0 | return len; |
295 | 0 | } |
296 | 3.40k | if (*outp == nullptr) { |
297 | 3.40k | *outp = static_cast<uint8_t *>( |
298 | 3.40k | OPENSSL_memdup(cache->der.data(), cache->der.size())); |
299 | 3.40k | return *outp != nullptr ? len : -1; |
300 | 3.40k | } |
301 | 0 | OPENSSL_memcpy(*outp, cache->der.data(), cache->der.size()); |
302 | 0 | *outp += cache->der.size(); |
303 | 0 | return len; |
304 | 3.40k | } |
305 | | |
306 | | IMPLEMENT_EXTERN_ASN1_PARSE_INTO(X509_NAME, X509_NAME_new, X509_NAME_free, |
307 | | CBS_ASN1_SEQUENCE, x509_parse_name, |
308 | | x509_marshal_name) |
309 | | |
310 | 885k | static int asn1_marshal_string_canon(CBB *cbb, const ASN1_STRING *in) { |
311 | 885k | int (*decode_func)(CBS *, uint32_t *); |
312 | 885k | int error; |
313 | 885k | switch (in->type) { |
314 | 256k | case V_ASN1_UTF8STRING: |
315 | 256k | decode_func = CBS_get_utf8; |
316 | 256k | error = ASN1_R_INVALID_UTF8STRING; |
317 | 256k | break; |
318 | 4.92k | case V_ASN1_BMPSTRING: |
319 | 4.92k | decode_func = CBS_get_ucs2_be; |
320 | 4.92k | error = ASN1_R_INVALID_BMPSTRING; |
321 | 4.92k | break; |
322 | 6.47k | case V_ASN1_UNIVERSALSTRING: |
323 | 6.47k | decode_func = CBS_get_utf32_be; |
324 | 6.47k | error = ASN1_R_INVALID_UNIVERSALSTRING; |
325 | 6.47k | break; |
326 | 305k | case V_ASN1_PRINTABLESTRING: |
327 | 324k | case V_ASN1_T61STRING: |
328 | 354k | case V_ASN1_IA5STRING: |
329 | 357k | case V_ASN1_VISIBLESTRING: |
330 | 357k | decode_func = CBS_get_latin1; |
331 | 357k | error = ERR_R_INTERNAL_ERROR; // Latin-1 inputs are never invalid. |
332 | 357k | break; |
333 | 259k | default: |
334 | | // Other string types are not canonicalized. |
335 | 259k | return asn1_marshal_any_string(cbb, in); |
336 | 885k | } |
337 | | |
338 | 625k | CBB child; |
339 | 625k | if (!CBB_add_asn1(cbb, &child, CBS_ASN1_UTF8STRING)) { |
340 | 0 | return 0; |
341 | 0 | } |
342 | | |
343 | 625k | bool empty = true; |
344 | 625k | bool in_whitespace = false; |
345 | 625k | CBS cbs; |
346 | 625k | CBS_init(&cbs, in->data, in->length); |
347 | 25.8M | while (CBS_len(&cbs) != 0) { |
348 | 25.2M | uint32_t c; |
349 | 25.2M | if (!decode_func(&cbs, &c)) { |
350 | 0 | OPENSSL_PUT_ERROR(ASN1, error); |
351 | 0 | return 0; |
352 | 0 | } |
353 | 25.2M | if (OPENSSL_isspace(c)) { |
354 | 683k | if (empty) { |
355 | 15.0k | continue; // Trim leading whitespace. |
356 | 15.0k | } |
357 | 668k | in_whitespace = true; |
358 | 24.5M | } else { |
359 | 24.5M | if (in_whitespace) { |
360 | | // Collapse the previous run of whitespace into one space. |
361 | 516k | if (!CBB_add_u8(&child, ' ')) { |
362 | 0 | return 0; |
363 | 0 | } |
364 | 516k | } |
365 | 24.5M | in_whitespace = false; |
366 | | // Lowecase ASCII codepoints. |
367 | 24.5M | if (c <= 0x7f) { |
368 | 7.30M | c = OPENSSL_tolower(c); |
369 | 7.30M | } |
370 | 24.5M | if (!CBB_add_utf8(&child, c)) { |
371 | 0 | return 0; |
372 | 0 | } |
373 | 24.5M | empty = false; |
374 | 24.5M | } |
375 | 25.2M | } |
376 | | |
377 | 625k | return CBB_flush(cbb); |
378 | 625k | } |
379 | | |
380 | 0 | int X509_NAME_set(X509_NAME **xn, const X509_NAME *name) { |
381 | 0 | UniquePtr<X509_NAME> copy(X509_NAME_dup(name)); |
382 | 0 | if (copy == nullptr) { |
383 | 0 | return 0; |
384 | 0 | } |
385 | 0 | X509_NAME_free(*xn); |
386 | 0 | *xn = copy.release(); |
387 | 0 | return 1; |
388 | 0 | } |
389 | | |
390 | 870 | int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne) { |
391 | 870 | return FromOpaque(ne)->set; |
392 | 870 | } |
393 | | |
394 | | int X509_NAME_get0_der(const X509_NAME *nm, const unsigned char **out_der, |
395 | 0 | size_t *out_der_len) { |
396 | 0 | const X509NameCache *cache = x509_name_get_cache(nm); |
397 | 0 | if (cache == nullptr) { |
398 | 0 | return 0; |
399 | 0 | } |
400 | 0 | if (out_der != nullptr) { |
401 | 0 | *out_der = cache->der.data(); |
402 | 0 | } |
403 | 0 | if (out_der_len != nullptr) { |
404 | 0 | *out_der_len = cache->der.size(); |
405 | 0 | } |
406 | 0 | return 1; |
407 | 0 | } |