/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 | 374k | #define X509_NAME_MAX (1024 * 1024) |
42 | | |
43 | | namespace { |
44 | | |
45 | 932k | int asn1_marshal_string_canon(CBB *cbb, const ASN1_STRING *in) { |
46 | 932k | int (*decode_func)(CBS *, uint32_t *); |
47 | 932k | int error; |
48 | 932k | switch (in->type) { |
49 | 281k | case V_ASN1_UTF8STRING: |
50 | 281k | decode_func = CBS_get_utf8; |
51 | 281k | error = ASN1_R_INVALID_UTF8STRING; |
52 | 281k | break; |
53 | 5.69k | case V_ASN1_BMPSTRING: |
54 | 5.69k | decode_func = CBS_get_ucs2_be; |
55 | 5.69k | error = ASN1_R_INVALID_BMPSTRING; |
56 | 5.69k | break; |
57 | 5.52k | case V_ASN1_UNIVERSALSTRING: |
58 | 5.52k | decode_func = CBS_get_utf32_be; |
59 | 5.52k | error = ASN1_R_INVALID_UNIVERSALSTRING; |
60 | 5.52k | break; |
61 | 325k | case V_ASN1_PRINTABLESTRING: |
62 | 346k | case V_ASN1_T61STRING: |
63 | 375k | case V_ASN1_IA5STRING: |
64 | 378k | case V_ASN1_VISIBLESTRING: |
65 | 378k | decode_func = CBS_get_latin1; |
66 | 378k | error = ERR_R_INTERNAL_ERROR; // Latin-1 inputs are never invalid. |
67 | 378k | break; |
68 | 261k | default: |
69 | | // Other string types are not canonicalized. |
70 | 261k | return asn1_marshal_any_string(cbb, in); |
71 | 932k | } |
72 | | |
73 | 671k | CBB child; |
74 | 671k | if (!CBB_add_asn1(cbb, &child, CBS_ASN1_UTF8STRING)) { |
75 | 0 | return 0; |
76 | 0 | } |
77 | | |
78 | 671k | bool empty = true; |
79 | 671k | bool in_whitespace = false; |
80 | 671k | CBS cbs; |
81 | 671k | CBS_init(&cbs, in->data, in->length); |
82 | 26.6M | while (CBS_len(&cbs) != 0) { |
83 | 25.9M | uint32_t c; |
84 | 25.9M | if (!decode_func(&cbs, &c)) { |
85 | 0 | OPENSSL_PUT_ERROR(ASN1, error); |
86 | 0 | return 0; |
87 | 0 | } |
88 | 25.9M | if (OPENSSL_isspace(c)) { |
89 | 739k | if (empty) { |
90 | 15.3k | continue; // Trim leading whitespace. |
91 | 15.3k | } |
92 | 723k | in_whitespace = true; |
93 | 25.2M | } else { |
94 | 25.2M | if (in_whitespace) { |
95 | | // Collapse the previous run of whitespace into one space. |
96 | 548k | if (!CBB_add_u8(&child, ' ')) { |
97 | 0 | return 0; |
98 | 0 | } |
99 | 548k | } |
100 | 25.2M | in_whitespace = false; |
101 | | // Lowecase ASCII codepoints. |
102 | 25.2M | if (c <= 0x7f) { |
103 | 6.95M | c = OPENSSL_tolower(c); |
104 | 6.95M | } |
105 | 25.2M | if (!CBB_add_utf8(&child, c)) { |
106 | 0 | return 0; |
107 | 0 | } |
108 | 25.2M | empty = false; |
109 | 25.2M | } |
110 | 25.9M | } |
111 | | |
112 | 671k | return CBB_flush(cbb); |
113 | 671k | } |
114 | | |
115 | 949k | int x509_parse_name_entry(CBS *cbs, X509_NAME_ENTRY *out) { |
116 | 949k | auto *out_impl = FromOpaque(out); |
117 | 949k | CBS seq; |
118 | 949k | if (!CBS_get_asn1(cbs, &seq, CBS_ASN1_SEQUENCE)) { |
119 | 211 | OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); |
120 | 211 | return 0; |
121 | 211 | } |
122 | 949k | out_impl->object.reset(asn1_parse_object(&seq, /*tag=*/0)); |
123 | 949k | if (out_impl->object == nullptr || // |
124 | 949k | !asn1_parse_any_as_string(&seq, out_impl->value.get()) || // |
125 | 948k | CBS_len(&seq) != 0) { |
126 | 1.08k | OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); |
127 | 1.08k | return 0; |
128 | 1.08k | } |
129 | 948k | return 1; |
130 | 949k | } |
131 | | |
132 | | int x509_marshal_name_entry(CBB *cbb, const X509_NAME_ENTRY *entry, |
133 | 1.88M | int canonicalize) { |
134 | 1.88M | auto *entry_impl = FromOpaque(entry); |
135 | 1.88M | CBB seq; |
136 | 1.88M | if (!CBB_add_asn1(cbb, &seq, CBS_ASN1_SEQUENCE) || |
137 | 1.88M | !asn1_marshal_object(&seq, entry_impl->object.get(), /*tag=*/0)) { |
138 | 3 | return 0; |
139 | 3 | } |
140 | 1.88M | int ok = canonicalize |
141 | 1.88M | ? asn1_marshal_string_canon(&seq, entry_impl->value.get()) |
142 | 1.88M | : asn1_marshal_any_string(&seq, entry_impl->value.get()); |
143 | 1.88M | if (!ok) { |
144 | 0 | return 0; |
145 | 0 | } |
146 | 1.88M | return CBB_flush(cbb); |
147 | 1.88M | } |
148 | | |
149 | 8.59k | int x509_marshal_name_entry_no_canon(CBB *cbb, const X509_NAME_ENTRY *entry) { |
150 | 8.59k | return x509_marshal_name_entry(cbb, entry, /*canonicalize=*/0); |
151 | 8.59k | } |
152 | | |
153 | | int x509_marshal_name_entries(CBB *out, const X509_NAME *name, |
154 | 752k | int canonicalize) { |
155 | 752k | auto *impl = FromOpaque(name); |
156 | 752k | if (sk_X509_NAME_ENTRY_num(impl->entries.get()) == 0) { |
157 | 12.4k | return 1; |
158 | 12.4k | } |
159 | | |
160 | | // Bootstrap the first RDN. |
161 | 739k | int set = FromOpaque(sk_X509_NAME_ENTRY_value(impl->entries.get(), 0))->set; |
162 | 739k | CBB rdn; |
163 | 739k | if (!CBB_add_asn1(out, &rdn, CBS_ASN1_SET)) { |
164 | 0 | return 0; |
165 | 0 | } |
166 | | |
167 | 1.86M | for (const X509_NAME_ENTRY *entry : impl->entries.get()) { |
168 | 1.86M | if (FromOpaque(entry)->set != set) { |
169 | | // Flush the previous RDN and start a new one. |
170 | 749k | if (!CBB_flush_asn1_set_of(&rdn) || |
171 | 749k | !CBB_add_asn1(out, &rdn, CBS_ASN1_SET)) { |
172 | 0 | return 0; |
173 | 0 | } |
174 | 749k | set = FromOpaque(entry)->set; |
175 | 749k | } |
176 | 1.86M | if (!x509_marshal_name_entry(&rdn, entry, canonicalize)) { |
177 | 0 | return 0; |
178 | 0 | } |
179 | 1.86M | } |
180 | | |
181 | 739k | return CBB_flush_asn1_set_of(&rdn) && CBB_flush(out); |
182 | 739k | } |
183 | | |
184 | | } // namespace |
185 | | |
186 | 965k | bssl::X509NameEntry::X509NameEntry() { |
187 | 965k | object.reset(const_cast<ASN1_OBJECT *>(OBJ_get_undef())); |
188 | 965k | } |
189 | | |
190 | 31.4k | X509_NAME_ENTRY *X509_NAME_ENTRY_new() { return New<X509NameEntry>(); } |
191 | | |
192 | 964k | void X509_NAME_ENTRY_free(X509_NAME_ENTRY *entry) { Delete(FromOpaque(entry)); } |
193 | | |
194 | | BSSL_NAMESPACE_BEGIN |
195 | | |
196 | | IMPLEMENT_EXTERN_ASN1_PARSE_INTO(X509_NAME_ENTRY, X509_NAME_ENTRY_new, |
197 | | X509_NAME_ENTRY_free, CBS_ASN1_SEQUENCE, |
198 | | x509_parse_name_entry, |
199 | | x509_marshal_name_entry_no_canon) |
200 | | |
201 | | BSSL_NAMESPACE_END |
202 | | |
203 | 15.6k | X509_NAME_ENTRY *X509_NAME_ENTRY_dup(const X509_NAME_ENTRY *entry) { |
204 | 15.6k | ScopedCBB cbb; |
205 | 15.6k | if (!CBB_init(cbb.get(), 16) || |
206 | 15.6k | !x509_marshal_name_entry(cbb.get(), entry, /*canonicalize=*/0)) { |
207 | 3 | return nullptr; |
208 | 3 | } |
209 | 15.6k | CBS cbs; |
210 | 15.6k | CBS_init(&cbs, CBB_data(cbb.get()), CBB_len(cbb.get())); |
211 | 15.6k | UniquePtr<X509_NAME_ENTRY> copy(X509_NAME_ENTRY_new()); |
212 | 15.6k | if (copy == nullptr || !x509_parse_name_entry(&cbs, copy.get())) { |
213 | 0 | return nullptr; |
214 | 0 | } |
215 | 15.6k | return copy.release(); |
216 | 15.6k | } |
217 | | |
218 | 452k | bssl::X509Name::~X509Name() { Delete(cache.exchange(nullptr)); } |
219 | | |
220 | 12.7k | X509_NAME *X509_NAME_new() { return New<X509Name>(); } |
221 | | |
222 | 16.1k | void X509_NAME_free(X509_NAME *name) { Delete(FromOpaque(name)); } |
223 | | |
224 | 374k | int bssl::x509_parse_name(CBS *cbs, X509_NAME *out) { |
225 | 374k | auto *impl = FromOpaque(out); |
226 | 374k | impl->entries = nullptr; |
227 | 374k | x509_name_invalidate_cache(impl); |
228 | | |
229 | 374k | impl->entries.reset(sk_X509_NAME_ENTRY_new_null()); |
230 | 374k | if (impl->entries == nullptr) { |
231 | 0 | return 0; |
232 | 0 | } |
233 | 374k | CBS seq, rdn; |
234 | 374k | if (!CBS_get_asn1(cbs, &seq, CBS_ASN1_SEQUENCE) || |
235 | | // Bound the size of an X509_NAME we are willing to parse. |
236 | 374k | CBS_len(&seq) > X509_NAME_MAX) { |
237 | 192 | OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); |
238 | 192 | return 0; |
239 | 192 | } |
240 | 374k | static_assert(X509_NAME_MAX <= INT_MAX, "set may overflow"); |
241 | 1.11M | for (int set = 0; CBS_len(&seq) > 0; set++) { |
242 | 744k | if (!CBS_get_asn1(&seq, &rdn, CBS_ASN1_SET) || // |
243 | 744k | CBS_len(&rdn) == 0) { |
244 | 281 | OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); |
245 | 281 | return 0; |
246 | 281 | } |
247 | 1.67M | while (CBS_len(&rdn) != 0) { |
248 | 934k | auto entry = MakeUnique<X509NameEntry>(); |
249 | 934k | if (entry == nullptr || !x509_parse_name_entry(&rdn, entry.get())) { |
250 | 1.25k | return 0; |
251 | 1.25k | } |
252 | 932k | entry->set = set; |
253 | 932k | if (!PushToStack(impl->entries.get(), std::move(entry))) { |
254 | 0 | return 0; |
255 | 0 | } |
256 | 932k | } |
257 | 744k | } |
258 | | |
259 | | // While we are single-threaded, also fill in the cached state. |
260 | 373k | return x509_name_get_cache(impl) != nullptr; |
261 | 374k | } |
262 | | |
263 | 391k | const X509NameCache *bssl::x509_name_get_cache(const X509_NAME *name) { |
264 | 391k | auto *impl = FromOpaque(name); |
265 | 391k | const X509NameCache *cache = impl->cache.load(); |
266 | 391k | if (cache != nullptr) { |
267 | 14.8k | return cache; |
268 | 14.8k | } |
269 | | |
270 | 376k | UniquePtr<X509NameCache> new_cache = MakeUnique<X509NameCache>(); |
271 | | // Cache the DER encoding, including the outer TLV. |
272 | 376k | ScopedCBB cbb; |
273 | 376k | CBB seq; |
274 | 376k | if (!CBB_init(cbb.get(), 16) || |
275 | 376k | !CBB_add_asn1(cbb.get(), &seq, CBS_ASN1_SEQUENCE) || |
276 | 376k | !x509_marshal_name_entries(&seq, impl, /*canonicalize=*/0) || |
277 | 376k | !CBBFinishArray(cbb.get(), &new_cache->der)) { |
278 | 0 | return nullptr; |
279 | 0 | } |
280 | | // Cache the canonicalized form, without the outer TLV. |
281 | 376k | if (!CBB_init(cbb.get(), 16) || |
282 | 376k | !x509_marshal_name_entries(cbb.get(), impl, /*canonicalize=*/1) || |
283 | 376k | !CBBFinishArray(cbb.get(), &new_cache->canon)) { |
284 | 0 | return nullptr; |
285 | 0 | } |
286 | | |
287 | 376k | X509NameCache *expected = nullptr; |
288 | 376k | if (impl->cache.compare_exchange_strong(expected, new_cache.get())) { |
289 | | // We won the race. `impl` now owns `new_cache`. |
290 | 376k | return new_cache.release(); |
291 | 376k | } |
292 | | |
293 | | // Some other thread installed a (presumably identical) cache. Release the one |
294 | | // we made and return the winning one. |
295 | 376k | assert(expected != nullptr); |
296 | 0 | return expected; |
297 | 0 | } |
298 | | |
299 | 390k | void bssl::x509_name_invalidate_cache(X509_NAME *name) { |
300 | 390k | auto *impl = FromOpaque(name); |
301 | 390k | Delete(impl->cache.exchange(nullptr)); |
302 | 390k | } |
303 | | |
304 | 9.17k | int bssl::x509_marshal_name(CBB *out, const X509_NAME *in) { |
305 | 9.17k | const X509NameCache *cache = x509_name_get_cache(in); |
306 | 9.17k | if (cache == nullptr) { |
307 | 0 | return 0; |
308 | 0 | } |
309 | 9.17k | return CBB_add_bytes(out, cache->der.data(), cache->der.size()); |
310 | 9.17k | } |
311 | | |
312 | 60 | int bssl::x509_name_copy(X509_NAME *dst, const X509_NAME *src) { |
313 | 60 | const X509NameCache *cache = x509_name_get_cache(src); |
314 | 60 | if (cache == nullptr) { |
315 | 0 | return 0; |
316 | 0 | } |
317 | | // Callers sometimes try to set a name back to itself. We check this after |
318 | | // `x509_name_get_cache` because, if `src` was so broken that it could not be |
319 | | // serialized, we used to return an error. (It's not clear if this codepath is |
320 | | // even possible.) |
321 | 60 | if (dst == src) { |
322 | 0 | return 1; |
323 | 0 | } |
324 | 60 | CBS cbs(cache->der); |
325 | 60 | if (!x509_parse_name(&cbs, dst)) { |
326 | 0 | return 0; |
327 | 0 | } |
328 | 60 | assert(CBS_len(&cbs) == 0); |
329 | 60 | return 1; |
330 | 60 | } |
331 | | |
332 | 60 | X509_NAME *X509_NAME_dup(const X509_NAME *name) { |
333 | 60 | UniquePtr<X509_NAME> copy(X509_NAME_new()); |
334 | 60 | if (copy == nullptr || !x509_name_copy(copy.get(), name)) { |
335 | 0 | return nullptr; |
336 | 0 | } |
337 | 60 | return copy.release(); |
338 | 60 | } |
339 | | |
340 | 1.18k | X509_NAME *d2i_X509_NAME(X509_NAME **out, const uint8_t **inp, long len) { |
341 | 1.18k | return D2IFromCBS(out, inp, len, [](CBS *cbs) -> UniquePtr<X509_NAME> { |
342 | 1.18k | UniquePtr<X509_NAME> name(X509_NAME_new()); |
343 | 1.18k | if (name == nullptr || !x509_parse_name(cbs, name.get())) { |
344 | 349 | return nullptr; |
345 | 349 | } |
346 | 836 | return name; |
347 | 1.18k | }); |
348 | 1.18k | } |
349 | | |
350 | 3.27k | int i2d_X509_NAME(const X509_NAME *in, uint8_t **outp) { |
351 | 3.27k | if (in == nullptr) { |
352 | 0 | OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); |
353 | 0 | return -1; |
354 | 0 | } |
355 | 3.27k | const X509NameCache *cache = x509_name_get_cache(in); |
356 | 3.27k | if (cache == nullptr) { |
357 | 0 | return -1; |
358 | 0 | } |
359 | 3.27k | if (cache->der.size() > INT_MAX) { |
360 | 0 | OPENSSL_PUT_ERROR(X509, ERR_R_OVERFLOW); |
361 | 0 | return -1; |
362 | 0 | } |
363 | 3.27k | int len = static_cast<int>(cache->der.size()); |
364 | 3.27k | if (outp == nullptr) { |
365 | 0 | return len; |
366 | 0 | } |
367 | 3.27k | if (*outp == nullptr) { |
368 | 3.27k | *outp = static_cast<uint8_t *>( |
369 | 3.27k | OPENSSL_memdup(cache->der.data(), cache->der.size())); |
370 | 3.27k | return *outp != nullptr ? len : -1; |
371 | 3.27k | } |
372 | 0 | OPENSSL_memcpy(*outp, cache->der.data(), cache->der.size()); |
373 | 0 | *outp += cache->der.size(); |
374 | 0 | return len; |
375 | 3.27k | } |
376 | | |
377 | | IMPLEMENT_EXTERN_ASN1_PARSE_INTO(X509_NAME, X509_NAME_new, X509_NAME_free, |
378 | | CBS_ASN1_SEQUENCE, x509_parse_name, |
379 | | x509_marshal_name) |
380 | | |
381 | 0 | int X509_NAME_set(X509_NAME **xn, const X509_NAME *name) { |
382 | 0 | UniquePtr<X509_NAME> copy(X509_NAME_dup(name)); |
383 | 0 | if (copy == nullptr) { |
384 | 0 | return 0; |
385 | 0 | } |
386 | 0 | X509_NAME_free(*xn); |
387 | 0 | *xn = copy.release(); |
388 | 0 | return 1; |
389 | 0 | } |
390 | | |
391 | 2.83k | int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne) { |
392 | 2.83k | return FromOpaque(ne)->set; |
393 | 2.83k | } |
394 | | |
395 | | int X509_NAME_get0_der(const X509_NAME *nm, const unsigned char **out_der, |
396 | 0 | size_t *out_der_len) { |
397 | 0 | const X509NameCache *cache = x509_name_get_cache(nm); |
398 | 0 | if (cache == nullptr) { |
399 | 0 | return 0; |
400 | 0 | } |
401 | 0 | if (out_der != nullptr) { |
402 | 0 | *out_der = cache->der.data(); |
403 | 0 | } |
404 | 0 | if (out_der_len != nullptr) { |
405 | 0 | *out_der_len = cache->der.size(); |
406 | 0 | } |
407 | 0 | return 1; |
408 | 0 | } |