]>
Commit | Line | Data |
---|---|---|
0f113f3e MC |
1 | /* |
2 | * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project | |
3 | * 1999. | |
9aeaf1b4 DSH |
4 | */ |
5 | /* ==================================================================== | |
6 | * Copyright (c) 1999 The OpenSSL Project. All rights reserved. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * 1. Redistributions of source code must retain the above copyright | |
0f113f3e | 13 | * notice, this list of conditions and the following disclaimer. |
9aeaf1b4 DSH |
14 | * |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in | |
17 | * the documentation and/or other materials provided with the | |
18 | * distribution. | |
19 | * | |
20 | * 3. All advertising materials mentioning features or use of this | |
21 | * software must display the following acknowledgment: | |
22 | * "This product includes software developed by the OpenSSL Project | |
23 | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" | |
24 | * | |
25 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | |
26 | * endorse or promote products derived from this software without | |
27 | * prior written permission. For written permission, please contact | |
28 | * licensing@OpenSSL.org. | |
29 | * | |
30 | * 5. Products derived from this software may not be called "OpenSSL" | |
31 | * nor may "OpenSSL" appear in their names without prior written | |
32 | * permission of the OpenSSL Project. | |
33 | * | |
34 | * 6. Redistributions of any form whatsoever must retain the following | |
35 | * acknowledgment: | |
36 | * "This product includes software developed by the OpenSSL Project | |
37 | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" | |
38 | * | |
39 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | |
40 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
42 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | |
43 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
44 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
45 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
46 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
48 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
49 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
50 | * OF THE POSSIBILITY OF SUCH DAMAGE. | |
51 | * ==================================================================== | |
52 | * | |
53 | * This product includes cryptographic software written by Eric Young | |
54 | * (eay@cryptsoft.com). This product includes software written by Tim | |
55 | * Hudson (tjh@cryptsoft.com). | |
56 | * | |
57 | */ | |
58 | /* X509 v3 extension utilities */ | |
59 | ||
e527ba09 | 60 | #include <stdio.h> |
b39fc560 | 61 | #include "internal/cryptlib.h" |
ec577822 BM |
62 | #include <openssl/conf.h> |
63 | #include <openssl/x509v3.h> | |
9aeaf1b4 | 64 | |
08cba610 DSH |
65 | #include "ext_dat.h" |
66 | ||
0d3b0afe | 67 | static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL; |
9aeaf1b4 | 68 | |
0f113f3e MC |
69 | static int ext_cmp(const X509V3_EXT_METHOD *const *a, |
70 | const X509V3_EXT_METHOD *const *b); | |
9aeaf1b4 DSH |
71 | static void ext_list_free(X509V3_EXT_METHOD *ext); |
72 | ||
6b691a5c | 73 | int X509V3_EXT_add(X509V3_EXT_METHOD *ext) |
9aeaf1b4 | 74 | { |
75ebbd9a RS |
75 | if (ext_list == NULL |
76 | && (ext_list = sk_X509V3_EXT_METHOD_new(ext_cmp)) == NULL) { | |
0f113f3e MC |
77 | X509V3err(X509V3_F_X509V3_EXT_ADD, ERR_R_MALLOC_FAILURE); |
78 | return 0; | |
79 | } | |
80 | if (!sk_X509V3_EXT_METHOD_push(ext_list, ext)) { | |
81 | X509V3err(X509V3_F_X509V3_EXT_ADD, ERR_R_MALLOC_FAILURE); | |
82 | return 0; | |
83 | } | |
84 | return 1; | |
9aeaf1b4 DSH |
85 | } |
86 | ||
0f113f3e MC |
87 | static int ext_cmp(const X509V3_EXT_METHOD *const *a, |
88 | const X509V3_EXT_METHOD *const *b) | |
9aeaf1b4 | 89 | { |
0f113f3e | 90 | return ((*a)->ext_nid - (*b)->ext_nid); |
9aeaf1b4 DSH |
91 | } |
92 | ||
0f113f3e MC |
93 | DECLARE_OBJ_BSEARCH_CMP_FN(const X509V3_EXT_METHOD *, |
94 | const X509V3_EXT_METHOD *, ext); | |
babb3798 | 95 | IMPLEMENT_OBJ_BSEARCH_CMP_FN(const X509V3_EXT_METHOD *, |
0f113f3e | 96 | const X509V3_EXT_METHOD *, ext); |
babb3798 | 97 | |
8cf27823 DSH |
98 | /* |
99 | * This table will be searched using OBJ_bsearch so it *must* kept in order | |
100 | * of the ext_nid values. | |
101 | */ | |
102 | ||
103 | static const X509V3_EXT_METHOD *standard_exts[] = { | |
104 | &v3_nscert, | |
105 | &v3_ns_ia5_list[0], | |
106 | &v3_ns_ia5_list[1], | |
107 | &v3_ns_ia5_list[2], | |
108 | &v3_ns_ia5_list[3], | |
109 | &v3_ns_ia5_list[4], | |
110 | &v3_ns_ia5_list[5], | |
111 | &v3_ns_ia5_list[6], | |
112 | &v3_skey_id, | |
113 | &v3_key_usage, | |
114 | &v3_pkey_usage_period, | |
115 | &v3_alt[0], | |
116 | &v3_alt[1], | |
117 | &v3_bcons, | |
118 | &v3_crl_num, | |
119 | &v3_cpols, | |
120 | &v3_akey_id, | |
121 | &v3_crld, | |
122 | &v3_ext_ku, | |
123 | &v3_delta_crl, | |
124 | &v3_crl_reason, | |
125 | #ifndef OPENSSL_NO_OCSP | |
126 | &v3_crl_invdate, | |
127 | #endif | |
128 | &v3_sxnet, | |
129 | &v3_info, | |
130 | #ifndef OPENSSL_NO_RFC3779 | |
131 | &v3_addr, | |
132 | &v3_asid, | |
133 | #endif | |
134 | #ifndef OPENSSL_NO_OCSP | |
135 | &v3_ocsp_nonce, | |
136 | &v3_ocsp_crlid, | |
137 | &v3_ocsp_accresp, | |
138 | &v3_ocsp_nocheck, | |
139 | &v3_ocsp_acutoff, | |
140 | &v3_ocsp_serviceloc, | |
141 | #endif | |
142 | &v3_sinfo, | |
143 | &v3_policy_constraints, | |
144 | #ifndef OPENSSL_NO_OCSP | |
145 | &v3_crl_hold, | |
146 | #endif | |
147 | &v3_pci, | |
148 | &v3_name_constraints, | |
149 | &v3_policy_mappings, | |
150 | &v3_inhibit_anyp, | |
151 | &v3_idp, | |
152 | &v3_alt[2], | |
153 | &v3_freshest_crl, | |
3149baf8 | 154 | #ifndef OPENSSL_NO_CT |
8cf27823 DSH |
155 | &v3_ct_scts[0], |
156 | &v3_ct_scts[1], | |
157 | #endif | |
ba67253d | 158 | &v3_tls_feature, |
8cf27823 DSH |
159 | }; |
160 | ||
161 | /* Number of standard extensions */ | |
162 | ||
163 | #define STANDARD_EXTENSION_COUNT OSSL_NELEM(standard_exts) | |
164 | ||
babb3798 | 165 | const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid) |
9aeaf1b4 | 166 | { |
0f113f3e MC |
167 | X509V3_EXT_METHOD tmp; |
168 | const X509V3_EXT_METHOD *t = &tmp, *const *ret; | |
169 | int idx; | |
170 | if (nid < 0) | |
171 | return NULL; | |
172 | tmp.ext_nid = nid; | |
173 | ret = OBJ_bsearch_ext(&t, standard_exts, STANDARD_EXTENSION_COUNT); | |
174 | if (ret) | |
175 | return *ret; | |
176 | if (!ext_list) | |
177 | return NULL; | |
178 | idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp); | |
179 | if (idx == -1) | |
180 | return NULL; | |
181 | return sk_X509V3_EXT_METHOD_value(ext_list, idx); | |
9aeaf1b4 DSH |
182 | } |
183 | ||
babb3798 | 184 | const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext) |
9aeaf1b4 | 185 | { |
0f113f3e | 186 | int nid; |
4903abd5 | 187 | if ((nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext))) == NID_undef) |
0f113f3e MC |
188 | return NULL; |
189 | return X509V3_EXT_get_nid(nid); | |
9aeaf1b4 DSH |
190 | } |
191 | ||
6b691a5c | 192 | int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist) |
9aeaf1b4 | 193 | { |
0f113f3e MC |
194 | for (; extlist->ext_nid != -1; extlist++) |
195 | if (!X509V3_EXT_add(extlist)) | |
196 | return 0; | |
197 | return 1; | |
9aeaf1b4 DSH |
198 | } |
199 | ||
6b691a5c | 200 | int X509V3_EXT_add_alias(int nid_to, int nid_from) |
9aeaf1b4 | 201 | { |
0f113f3e MC |
202 | const X509V3_EXT_METHOD *ext; |
203 | X509V3_EXT_METHOD *tmpext; | |
204 | ||
75ebbd9a RS |
205 | if ((ext = X509V3_EXT_get_nid(nid_from)) == NULL) { |
206 | X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS, X509V3_R_EXTENSION_NOT_FOUND); | |
0f113f3e MC |
207 | return 0; |
208 | } | |
75ebbd9a | 209 | if ((tmpext = OPENSSL_malloc(sizeof(*tmpext))) == NULL) { |
0f113f3e MC |
210 | X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS, ERR_R_MALLOC_FAILURE); |
211 | return 0; | |
212 | } | |
213 | *tmpext = *ext; | |
214 | tmpext->ext_nid = nid_to; | |
215 | tmpext->ext_flags |= X509V3_EXT_DYNAMIC; | |
216 | return X509V3_EXT_add(tmpext); | |
9aeaf1b4 DSH |
217 | } |
218 | ||
6b691a5c | 219 | void X509V3_EXT_cleanup(void) |
9aeaf1b4 | 220 | { |
0f113f3e MC |
221 | sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free); |
222 | ext_list = NULL; | |
9aeaf1b4 DSH |
223 | } |
224 | ||
6b691a5c | 225 | static void ext_list_free(X509V3_EXT_METHOD *ext) |
9aeaf1b4 | 226 | { |
0f113f3e MC |
227 | if (ext->ext_flags & X509V3_EXT_DYNAMIC) |
228 | OPENSSL_free(ext); | |
9aeaf1b4 DSH |
229 | } |
230 | ||
0f113f3e MC |
231 | /* |
232 | * Legacy function: we don't need to add standard extensions any more because | |
233 | * they are now kept in ext_dat.h. | |
08cba610 | 234 | */ |
0ca5f8b1 | 235 | |
6b691a5c | 236 | int X509V3_add_standard_extensions(void) |
9aeaf1b4 | 237 | { |
0f113f3e | 238 | return 1; |
9aeaf1b4 | 239 | } |
0be9747b DSH |
240 | |
241 | /* Return an extension internal structure */ | |
242 | ||
f5fedc04 | 243 | void *X509V3_EXT_d2i(X509_EXTENSION *ext) |
0be9747b | 244 | { |
0f113f3e MC |
245 | const X509V3_EXT_METHOD *method; |
246 | const unsigned char *p; | |
4903abd5 DSH |
247 | ASN1_STRING *extvalue; |
248 | int extlen; | |
0f113f3e | 249 | |
75ebbd9a | 250 | if ((method = X509V3_EXT_get(ext)) == NULL) |
0f113f3e | 251 | return NULL; |
4903abd5 DSH |
252 | extvalue = X509_EXTENSION_get_data(ext); |
253 | p = ASN1_STRING_data(extvalue); | |
254 | extlen = ASN1_STRING_length(extvalue); | |
0f113f3e | 255 | if (method->it) |
4903abd5 DSH |
256 | return ASN1_item_d2i(NULL, &p, extlen, ASN1_ITEM_ptr(method->it)); |
257 | return method->d2i(NULL, &p, extlen); | |
0be9747b DSH |
258 | } |
259 | ||
3a83462d MC |
260 | /*- |
261 | * Get critical flag and decoded version of extension from a NID. | |
4654ef98 DSH |
262 | * The "idx" variable returns the last found extension and can |
263 | * be used to retrieve multiple extensions of the same NID. | |
264 | * However multiple extensions with the same NID is usually | |
265 | * due to a badly encoded certificate so if idx is NULL we | |
266 | * choke if multiple extensions exist. | |
267 | * The "crit" variable is set to the critical value. | |
268 | * The return value is the decoded extension or NULL on | |
269 | * error. The actual error can have several different causes, | |
270 | * the value of *crit reflects the cause: | |
271 | * >= 0, extension found but not decoded (reflects critical value). | |
272 | * -1 extension not found. | |
273 | * -2 extension occurs more than once. | |
274 | */ | |
275 | ||
0f113f3e MC |
276 | void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, |
277 | int *idx) | |
4654ef98 | 278 | { |
0f113f3e MC |
279 | int lastpos, i; |
280 | X509_EXTENSION *ex, *found_ex = NULL; | |
281 | if (!x) { | |
282 | if (idx) | |
283 | *idx = -1; | |
284 | if (crit) | |
285 | *crit = -1; | |
286 | return NULL; | |
287 | } | |
288 | if (idx) | |
289 | lastpos = *idx + 1; | |
290 | else | |
291 | lastpos = 0; | |
292 | if (lastpos < 0) | |
293 | lastpos = 0; | |
294 | for (i = lastpos; i < sk_X509_EXTENSION_num(x); i++) { | |
295 | ex = sk_X509_EXTENSION_value(x, i); | |
4903abd5 | 296 | if (OBJ_obj2nid(X509_EXTENSION_get_object(ex)) == nid) { |
0f113f3e MC |
297 | if (idx) { |
298 | *idx = i; | |
299 | found_ex = ex; | |
300 | break; | |
301 | } else if (found_ex) { | |
302 | /* Found more than one */ | |
303 | if (crit) | |
304 | *crit = -2; | |
305 | return NULL; | |
306 | } | |
307 | found_ex = ex; | |
308 | } | |
309 | } | |
310 | if (found_ex) { | |
311 | /* Found it */ | |
312 | if (crit) | |
313 | *crit = X509_EXTENSION_get_critical(found_ex); | |
314 | return X509V3_EXT_d2i(found_ex); | |
315 | } | |
316 | ||
317 | /* Extension not found */ | |
318 | if (idx) | |
319 | *idx = -1; | |
320 | if (crit) | |
321 | *crit = -1; | |
322 | return NULL; | |
4654ef98 | 323 | } |
0d3b0afe | 324 | |
0f113f3e MC |
325 | /* |
326 | * This function is a general extension append, replace and delete utility. | |
57d2f217 DSH |
327 | * The precise operation is governed by the 'flags' value. The 'crit' and |
328 | * 'value' arguments (if relevant) are the extensions internal structure. | |
329 | */ | |
330 | ||
28ddfc61 | 331 | int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, |
0f113f3e | 332 | int crit, unsigned long flags) |
57d2f217 | 333 | { |
0f113f3e MC |
334 | int extidx = -1; |
335 | int errcode; | |
336 | X509_EXTENSION *ext, *extmp; | |
337 | unsigned long ext_op = flags & X509V3_ADD_OP_MASK; | |
338 | ||
339 | /* | |
340 | * If appending we don't care if it exists, otherwise look for existing | |
341 | * extension. | |
342 | */ | |
343 | if (ext_op != X509V3_ADD_APPEND) | |
344 | extidx = X509v3_get_ext_by_NID(*x, nid, -1); | |
345 | ||
346 | /* See if extension exists */ | |
347 | if (extidx >= 0) { | |
348 | /* If keep existing, nothing to do */ | |
349 | if (ext_op == X509V3_ADD_KEEP_EXISTING) | |
350 | return 1; | |
351 | /* If default then its an error */ | |
352 | if (ext_op == X509V3_ADD_DEFAULT) { | |
353 | errcode = X509V3_R_EXTENSION_EXISTS; | |
354 | goto err; | |
355 | } | |
356 | /* If delete, just delete it */ | |
357 | if (ext_op == X509V3_ADD_DELETE) { | |
358 | if (!sk_X509_EXTENSION_delete(*x, extidx)) | |
359 | return -1; | |
360 | return 1; | |
361 | } | |
362 | } else { | |
363 | /* | |
364 | * If replace existing or delete, error since extension must exist | |
365 | */ | |
366 | if ((ext_op == X509V3_ADD_REPLACE_EXISTING) || | |
367 | (ext_op == X509V3_ADD_DELETE)) { | |
368 | errcode = X509V3_R_EXTENSION_NOT_FOUND; | |
369 | goto err; | |
370 | } | |
371 | } | |
372 | ||
373 | /* | |
374 | * If we get this far then we have to create an extension: could have | |
375 | * some flags for alternative encoding schemes... | |
376 | */ | |
377 | ||
378 | ext = X509V3_EXT_i2d(nid, crit, value); | |
379 | ||
380 | if (!ext) { | |
381 | X509V3err(X509V3_F_X509V3_ADD1_I2D, | |
382 | X509V3_R_ERROR_CREATING_EXTENSION); | |
383 | return 0; | |
384 | } | |
385 | ||
386 | /* If extension exists replace it.. */ | |
387 | if (extidx >= 0) { | |
388 | extmp = sk_X509_EXTENSION_value(*x, extidx); | |
389 | X509_EXTENSION_free(extmp); | |
390 | if (!sk_X509_EXTENSION_set(*x, extidx, ext)) | |
391 | return -1; | |
392 | return 1; | |
393 | } | |
394 | ||
75ebbd9a RS |
395 | if (*x == NULL |
396 | && (*x = sk_X509_EXTENSION_new_null()) == NULL) | |
0f113f3e MC |
397 | return -1; |
398 | if (!sk_X509_EXTENSION_push(*x, ext)) | |
399 | return -1; | |
400 | ||
401 | return 1; | |
402 | ||
403 | err: | |
404 | if (!(flags & X509V3_ADD_SILENT)) | |
405 | X509V3err(X509V3_F_X509V3_ADD1_I2D, errcode); | |
406 | return 0; | |
57d2f217 | 407 | } |