/src/boringssl/crypto/x509/v3_lib.cc
Line | Count | Source |
1 | | // Copyright 1999-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 | | /* X509 v3 extension utilities */ |
16 | | |
17 | | #include <assert.h> |
18 | | #include <stdio.h> |
19 | | |
20 | | #include <openssl/conf.h> |
21 | | #include <openssl/err.h> |
22 | | #include <openssl/mem.h> |
23 | | #include <openssl/obj.h> |
24 | | #include <openssl/x509.h> |
25 | | |
26 | | #include "../mem_internal.h" |
27 | | #include "internal.h" |
28 | | |
29 | | |
30 | | using namespace bssl; |
31 | | |
32 | | // This is indirected though a pointer to avoid a global destructor. If we ever |
33 | | // add bssl::NoDestructor, we can avoid this, but this API is already |
34 | | // problematic and not thread-safe. |
35 | | static bssl::Vector<const X509V3_EXT_METHOD *> *ext_list = nullptr; |
36 | | |
37 | 0 | int X509V3_EXT_add(X509V3_EXT_METHOD *ext) { |
38 | | // We only support |ASN1_ITEM|-based extensions. |
39 | 0 | assert(ext->it != nullptr); |
40 | | |
41 | | // TODO(crbug.com/42290461): This API is not locked and doesn't check for |
42 | | // duplicates. Remove it altogether as, even if those issues were fixed, it |
43 | | // would not be possible to use safely anyway. |
44 | 0 | if (ext_list == nullptr) { |
45 | 0 | ext_list = bssl::New<bssl::Vector<const X509V3_EXT_METHOD *>>(); |
46 | 0 | } |
47 | 0 | if (ext_list == nullptr || !ext_list->Push(ext)) { |
48 | 0 | return 0; |
49 | 0 | } |
50 | 0 | return 1; |
51 | 0 | } |
52 | | |
53 | 52.6k | const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid) { |
54 | 52.6k | if (nid < 0) { |
55 | 0 | return nullptr; |
56 | 0 | } |
57 | | |
58 | 52.6k | switch (nid) { |
59 | 328 | case NID_netscape_cert_type: |
60 | 328 | return &v3_nscert; |
61 | 447 | case NID_netscape_base_url: |
62 | 447 | return &v3_netscape_base_url; |
63 | 83 | case NID_netscape_revocation_url: |
64 | 83 | return &v3_netscape_revocation_url; |
65 | 80 | case NID_netscape_ca_revocation_url: |
66 | 80 | return &v3_netscape_ca_revocation_url; |
67 | 52 | case NID_netscape_renewal_url: |
68 | 52 | return &v3_netscape_renewal_url; |
69 | 231 | case NID_netscape_ca_policy_url: |
70 | 231 | return &v3_netscape_ca_policy_url; |
71 | 95 | case NID_netscape_ssl_server_name: |
72 | 95 | return &v3_netscape_ssl_server_name; |
73 | 325 | case NID_netscape_comment: |
74 | 325 | return &v3_netscape_comment; |
75 | 1.85k | case NID_subject_key_identifier: |
76 | 1.85k | return &v3_skey_id; |
77 | 5.74k | case NID_key_usage: |
78 | 5.74k | return &v3_key_usage; |
79 | 5.67k | case NID_subject_alt_name: |
80 | 5.67k | return &v3_subject_alt_name; |
81 | 2.07k | case NID_issuer_alt_name: |
82 | 2.07k | return &v3_issuer_alt_name; |
83 | 666 | case NID_certificate_issuer: |
84 | 666 | return &v3_certificate_issuer; |
85 | 1.54k | case NID_basic_constraints: |
86 | 1.54k | return &v3_bcons; |
87 | 274 | case NID_crl_number: |
88 | 274 | return &v3_crl_num; |
89 | 2.13k | case NID_certificate_policies: |
90 | 2.13k | return &v3_cpols; |
91 | 3.06k | case NID_authority_key_identifier: |
92 | 3.06k | return &v3_akey_id; |
93 | 2.17k | case NID_crl_distribution_points: |
94 | 2.17k | return &v3_crld; |
95 | 1.63k | case NID_ext_key_usage: |
96 | 1.63k | return &v3_ext_ku; |
97 | 701 | case NID_delta_crl: |
98 | 701 | return &v3_delta_crl; |
99 | 3.36k | case NID_crl_reason: |
100 | 3.36k | return &v3_crl_reason; |
101 | 2.37k | case NID_invalidity_date: |
102 | 2.37k | return &v3_crl_invdate; |
103 | 182 | case NID_info_access: |
104 | 182 | return &v3_info; |
105 | 86 | case NID_id_pkix_OCSP_noCheck: |
106 | 86 | return &v3_ocsp_nocheck; |
107 | 128 | case NID_sinfo_access: |
108 | 128 | return &v3_sinfo; |
109 | 1.75k | case NID_policy_constraints: |
110 | 1.75k | return &v3_policy_constraints; |
111 | 2.49k | case NID_name_constraints: |
112 | 2.49k | return &v3_name_constraints; |
113 | 562 | case NID_policy_mappings: |
114 | 562 | return &v3_policy_mappings; |
115 | 2.23k | case NID_inhibit_any_policy: |
116 | 2.23k | return &v3_inhibit_anyp; |
117 | 2.92k | case NID_issuing_distribution_point: |
118 | 2.92k | return &v3_idp; |
119 | 4.39k | case NID_freshest_crl: |
120 | 4.39k | return &v3_freshest_crl; |
121 | 52.6k | } |
122 | | |
123 | 2.94k | if (ext_list != nullptr) { |
124 | 0 | for (const X509V3_EXT_METHOD *ext : *ext_list) { |
125 | 0 | if (ext->ext_nid == nid) { |
126 | 0 | return ext; |
127 | 0 | } |
128 | 0 | } |
129 | 0 | } |
130 | 2.94k | return nullptr; |
131 | 2.94k | } |
132 | | |
133 | 57.1k | const X509V3_EXT_METHOD *X509V3_EXT_get(const X509_EXTENSION *ext) { |
134 | 57.1k | int nid; |
135 | 57.1k | if ((nid = OBJ_obj2nid(ext->object)) == NID_undef) { |
136 | 21.6k | return nullptr; |
137 | 21.6k | } |
138 | 35.4k | return X509V3_EXT_get_nid(nid); |
139 | 57.1k | } |
140 | | |
141 | 3.53k | int X509V3_EXT_free(int nid, void *ext_data) { |
142 | 3.53k | const X509V3_EXT_METHOD *ext_method = X509V3_EXT_get_nid(nid); |
143 | 3.53k | if (ext_method == nullptr) { |
144 | 0 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_CANNOT_FIND_FREE_FUNCTION); |
145 | 0 | return 0; |
146 | 0 | } |
147 | | |
148 | 3.53k | ASN1_item_free(reinterpret_cast<ASN1_VALUE *>(ext_data), |
149 | 3.53k | ASN1_ITEM_ptr(ext_method->it)); |
150 | 3.53k | return 1; |
151 | 3.53k | } |
152 | | |
153 | 0 | int X509V3_EXT_add_alias(int nid_to, int nid_from) { |
154 | 0 | OPENSSL_BEGIN_ALLOW_DEPRECATED |
155 | 0 | const X509V3_EXT_METHOD *ext; |
156 | 0 | X509V3_EXT_METHOD *tmpext; |
157 | |
|
158 | 0 | if (!(ext = X509V3_EXT_get_nid(nid_from))) { |
159 | 0 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_NOT_FOUND); |
160 | 0 | return 0; |
161 | 0 | } |
162 | 0 | if (!(tmpext = New<X509V3_EXT_METHOD>())) { |
163 | 0 | return 0; |
164 | 0 | } |
165 | 0 | *tmpext = *ext; |
166 | 0 | tmpext->ext_nid = nid_to; |
167 | 0 | if (!X509V3_EXT_add(tmpext)) { |
168 | 0 | Delete(tmpext); |
169 | 0 | return 0; |
170 | 0 | } |
171 | 0 | return 1; |
172 | 0 | OPENSSL_END_ALLOW_DEPRECATED |
173 | 0 | } |
174 | | |
175 | 0 | int X509V3_add_standard_extensions() { return 1; } |
176 | | |
177 | | // Return an extension internal structure |
178 | | |
179 | 30.9k | void *X509V3_EXT_d2i(const X509_EXTENSION *ext) { |
180 | 30.9k | const X509V3_EXT_METHOD *method; |
181 | 30.9k | const unsigned char *p; |
182 | | |
183 | 30.9k | if (!(method = X509V3_EXT_get(ext))) { |
184 | 12.2k | return nullptr; |
185 | 12.2k | } |
186 | 18.7k | p = ext->value->data; |
187 | 18.7k | void *ret = |
188 | 18.7k | ASN1_item_d2i(nullptr, &p, ext->value->length, ASN1_ITEM_ptr(method->it)); |
189 | 18.7k | if (ret == nullptr) { |
190 | 9.97k | return nullptr; |
191 | 9.97k | } |
192 | | // Check for trailing data. |
193 | 8.72k | if (p != ext->value->data + ext->value->length) { |
194 | 2.34k | ASN1_item_free(reinterpret_cast<ASN1_VALUE *>(ret), |
195 | 2.34k | ASN1_ITEM_ptr(method->it)); |
196 | 2.34k | OPENSSL_PUT_ERROR(X509V3, X509V3_R_TRAILING_DATA_IN_EXTENSION); |
197 | 2.34k | return nullptr; |
198 | 2.34k | } |
199 | 6.38k | return ret; |
200 | 8.72k | } |
201 | | |
202 | | void *X509V3_get_d2i(const STACK_OF(X509_EXTENSION) *extensions, int nid, |
203 | 25.5k | int *out_critical, int *out_idx) { |
204 | 25.5k | int lastpos; |
205 | 25.5k | X509_EXTENSION *ex, *found_ex = nullptr; |
206 | 25.5k | if (!extensions) { |
207 | 2.84k | if (out_idx) { |
208 | 0 | *out_idx = -1; |
209 | 0 | } |
210 | 2.84k | if (out_critical) { |
211 | 2.84k | *out_critical = -1; |
212 | 2.84k | } |
213 | 2.84k | return nullptr; |
214 | 2.84k | } |
215 | 22.7k | if (out_idx) { |
216 | 0 | lastpos = *out_idx + 1; |
217 | 22.7k | } else { |
218 | 22.7k | lastpos = 0; |
219 | 22.7k | } |
220 | 22.7k | if (lastpos < 0) { |
221 | 0 | lastpos = 0; |
222 | 0 | } |
223 | 215k | for (size_t i = lastpos; i < sk_X509_EXTENSION_num(extensions); i++) { |
224 | 193k | ex = sk_X509_EXTENSION_value(extensions, i); |
225 | 193k | if (OBJ_obj2nid(ex->object) == nid) { |
226 | 3.58k | if (out_idx) { |
227 | | // TODO(https://crbug.com/boringssl/379): Consistently reject |
228 | | // duplicate extensions. |
229 | 0 | *out_idx = (int)i; |
230 | 0 | found_ex = ex; |
231 | 0 | break; |
232 | 3.58k | } else if (found_ex) { |
233 | | // Found more than one |
234 | 727 | if (out_critical) { |
235 | 727 | *out_critical = -2; |
236 | 727 | } |
237 | 727 | return nullptr; |
238 | 727 | } |
239 | 2.85k | found_ex = ex; |
240 | 2.85k | } |
241 | 193k | } |
242 | 21.9k | if (found_ex) { |
243 | | // Found it |
244 | 2.12k | if (out_critical) { |
245 | 2.12k | *out_critical = X509_EXTENSION_get_critical(found_ex); |
246 | 2.12k | } |
247 | 2.12k | return X509V3_EXT_d2i(found_ex); |
248 | 2.12k | } |
249 | | |
250 | | // Extension not found |
251 | 19.8k | if (out_idx) { |
252 | 0 | *out_idx = -1; |
253 | 0 | } |
254 | 19.8k | if (out_critical) { |
255 | 19.8k | *out_critical = -1; |
256 | 19.8k | } |
257 | 19.8k | return nullptr; |
258 | 21.9k | } |
259 | | |
260 | | // This function is a general extension append, replace and delete utility. |
261 | | // The precise operation is governed by the 'flags' value. The 'crit' and |
262 | | // 'value' arguments (if relevant) are the extensions internal structure. |
263 | | |
264 | | int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, |
265 | 0 | int crit, unsigned long flags) { |
266 | 0 | int errcode, extidx = -1; |
267 | 0 | X509_EXTENSION *ext = nullptr, *extmp; |
268 | 0 | STACK_OF(X509_EXTENSION) *ret = nullptr; |
269 | 0 | unsigned long ext_op = flags & X509V3_ADD_OP_MASK; |
270 | | |
271 | | // If appending we don't care if it exists, otherwise look for existing |
272 | | // extension. |
273 | 0 | if (ext_op != X509V3_ADD_APPEND) { |
274 | 0 | extidx = X509v3_get_ext_by_NID(*x, nid, -1); |
275 | 0 | } |
276 | | |
277 | | // See if extension exists |
278 | 0 | if (extidx >= 0) { |
279 | | // If keep existing, nothing to do |
280 | 0 | if (ext_op == X509V3_ADD_KEEP_EXISTING) { |
281 | 0 | return 1; |
282 | 0 | } |
283 | | // If default then its an error |
284 | 0 | if (ext_op == X509V3_ADD_DEFAULT) { |
285 | 0 | errcode = X509V3_R_EXTENSION_EXISTS; |
286 | 0 | goto err; |
287 | 0 | } |
288 | | // If delete, just delete it |
289 | 0 | if (ext_op == X509V3_ADD_DELETE) { |
290 | 0 | X509_EXTENSION *prev_ext = sk_X509_EXTENSION_delete(*x, extidx); |
291 | 0 | if (prev_ext == nullptr) { |
292 | 0 | return -1; |
293 | 0 | } |
294 | 0 | X509_EXTENSION_free(prev_ext); |
295 | 0 | return 1; |
296 | 0 | } |
297 | 0 | } else { |
298 | | // If replace existing or delete, error since extension must exist |
299 | 0 | if ((ext_op == X509V3_ADD_REPLACE_EXISTING) || |
300 | 0 | (ext_op == X509V3_ADD_DELETE)) { |
301 | 0 | errcode = X509V3_R_EXTENSION_NOT_FOUND; |
302 | 0 | goto err; |
303 | 0 | } |
304 | 0 | } |
305 | | |
306 | | // If we get this far then we have to create an extension: could have |
307 | | // some flags for alternative encoding schemes... |
308 | | |
309 | 0 | ext = X509V3_EXT_i2d(nid, crit, value); |
310 | |
|
311 | 0 | if (!ext) { |
312 | 0 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_CREATING_EXTENSION); |
313 | 0 | return 0; |
314 | 0 | } |
315 | | |
316 | | // If extension exists replace it.. |
317 | 0 | if (extidx >= 0) { |
318 | 0 | extmp = sk_X509_EXTENSION_value(*x, extidx); |
319 | 0 | X509_EXTENSION_free(extmp); |
320 | 0 | if (!sk_X509_EXTENSION_set(*x, extidx, ext)) { |
321 | 0 | return -1; |
322 | 0 | } |
323 | 0 | return 1; |
324 | 0 | } |
325 | | |
326 | 0 | if ((ret = *x) == nullptr && |
327 | 0 | (ret = sk_X509_EXTENSION_new_null()) == nullptr) { |
328 | 0 | goto m_fail; |
329 | 0 | } |
330 | 0 | if (!sk_X509_EXTENSION_push(ret, ext)) { |
331 | 0 | goto m_fail; |
332 | 0 | } |
333 | | |
334 | 0 | *x = ret; |
335 | 0 | return 1; |
336 | | |
337 | 0 | m_fail: |
338 | 0 | if (ret != *x) { |
339 | 0 | sk_X509_EXTENSION_free(ret); |
340 | 0 | } |
341 | 0 | X509_EXTENSION_free(ext); |
342 | 0 | return -1; |
343 | | |
344 | 0 | err: |
345 | 0 | if (!(flags & X509V3_ADD_SILENT)) { |
346 | 0 | OPENSSL_PUT_ERROR(X509V3, errcode); |
347 | 0 | } |
348 | 0 | return 0; |
349 | 0 | } |