]>
Commit | Line | Data |
---|---|---|
d3819813 | 1 | /* |
7bf7a6d0 | 2 | * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. |
3e575651 | 3 | * |
7bf7a6d0 MTL |
4 | * Licensed under the OpenSSL license (the "License"). You may not use |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
3e575651 | 8 | */ |
7bf7a6d0 | 9 | |
3e575651 SL |
10 | /* X509 v3 extension utilities */ |
11 | ||
12 | #include <stdio.h> | |
7bf7a6d0 | 13 | #include "internal/cryptlib.h" |
3e575651 SL |
14 | #include <openssl/conf.h> |
15 | #include <openssl/x509v3.h> | |
16 | ||
17 | #include "ext_dat.h" | |
18 | ||
19 | static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL; | |
20 | ||
d3819813 MTL |
21 | static int ext_cmp(const X509V3_EXT_METHOD *const *a, |
22 | const X509V3_EXT_METHOD *const *b); | |
3e575651 SL |
23 | static void ext_list_free(X509V3_EXT_METHOD *ext); |
24 | ||
25 | int X509V3_EXT_add(X509V3_EXT_METHOD *ext) | |
26 | { | |
7bf7a6d0 MTL |
27 | if (ext_list == NULL |
28 | && (ext_list = sk_X509V3_EXT_METHOD_new(ext_cmp)) == NULL) { | |
d3819813 MTL |
29 | X509V3err(X509V3_F_X509V3_EXT_ADD, ERR_R_MALLOC_FAILURE); |
30 | return 0; | |
31 | } | |
32 | if (!sk_X509V3_EXT_METHOD_push(ext_list, ext)) { | |
33 | X509V3err(X509V3_F_X509V3_EXT_ADD, ERR_R_MALLOC_FAILURE); | |
34 | return 0; | |
35 | } | |
36 | return 1; | |
3e575651 SL |
37 | } |
38 | ||
d3819813 MTL |
39 | static int ext_cmp(const X509V3_EXT_METHOD *const *a, |
40 | const X509V3_EXT_METHOD *const *b) | |
3e575651 | 41 | { |
d3819813 | 42 | return ((*a)->ext_nid - (*b)->ext_nid); |
3e575651 SL |
43 | } |
44 | ||
d3819813 MTL |
45 | DECLARE_OBJ_BSEARCH_CMP_FN(const X509V3_EXT_METHOD *, |
46 | const X509V3_EXT_METHOD *, ext); | |
47 | IMPLEMENT_OBJ_BSEARCH_CMP_FN(const X509V3_EXT_METHOD *, | |
48 | const X509V3_EXT_METHOD *, ext); | |
49 | ||
7bf7a6d0 MTL |
50 | /* |
51 | * This table will be searched using OBJ_bsearch so it *must* kept in order | |
52 | * of the ext_nid values. | |
53 | */ | |
54 | ||
55 | static const X509V3_EXT_METHOD *standard_exts[] = { | |
56 | &v3_nscert, | |
57 | &v3_ns_ia5_list[0], | |
58 | &v3_ns_ia5_list[1], | |
59 | &v3_ns_ia5_list[2], | |
60 | &v3_ns_ia5_list[3], | |
61 | &v3_ns_ia5_list[4], | |
62 | &v3_ns_ia5_list[5], | |
63 | &v3_ns_ia5_list[6], | |
64 | &v3_skey_id, | |
65 | &v3_key_usage, | |
66 | &v3_pkey_usage_period, | |
67 | &v3_alt[0], | |
68 | &v3_alt[1], | |
69 | &v3_bcons, | |
70 | &v3_crl_num, | |
71 | &v3_cpols, | |
72 | &v3_akey_id, | |
73 | &v3_crld, | |
74 | &v3_ext_ku, | |
75 | &v3_delta_crl, | |
76 | &v3_crl_reason, | |
77 | #ifndef OPENSSL_NO_OCSP | |
78 | &v3_crl_invdate, | |
79 | #endif | |
80 | &v3_sxnet, | |
81 | &v3_info, | |
82 | #ifndef OPENSSL_NO_RFC3779 | |
83 | &v3_addr, | |
84 | &v3_asid, | |
85 | #endif | |
86 | #ifndef OPENSSL_NO_OCSP | |
87 | &v3_ocsp_nonce, | |
88 | &v3_ocsp_crlid, | |
89 | &v3_ocsp_accresp, | |
90 | &v3_ocsp_nocheck, | |
91 | &v3_ocsp_acutoff, | |
92 | &v3_ocsp_serviceloc, | |
93 | #endif | |
94 | &v3_sinfo, | |
95 | &v3_policy_constraints, | |
96 | #ifndef OPENSSL_NO_OCSP | |
97 | &v3_crl_hold, | |
98 | #endif | |
99 | &v3_pci, | |
100 | &v3_name_constraints, | |
101 | &v3_policy_mappings, | |
102 | &v3_inhibit_anyp, | |
103 | &v3_idp, | |
104 | &v3_alt[2], | |
105 | &v3_freshest_crl, | |
106 | #ifndef OPENSSL_NO_CT | |
107 | &v3_ct_scts[0], | |
108 | &v3_ct_scts[1], | |
109 | &v3_ct_scts[2], | |
110 | #endif | |
111 | &v3_tls_feature, | |
112 | }; | |
113 | ||
114 | /* Number of standard extensions */ | |
115 | ||
116 | #define STANDARD_EXTENSION_COUNT OSSL_NELEM(standard_exts) | |
117 | ||
d3819813 | 118 | const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid) |
3e575651 | 119 | { |
d3819813 MTL |
120 | X509V3_EXT_METHOD tmp; |
121 | const X509V3_EXT_METHOD *t = &tmp, *const *ret; | |
122 | int idx; | |
123 | if (nid < 0) | |
124 | return NULL; | |
125 | tmp.ext_nid = nid; | |
126 | ret = OBJ_bsearch_ext(&t, standard_exts, STANDARD_EXTENSION_COUNT); | |
127 | if (ret) | |
128 | return *ret; | |
129 | if (!ext_list) | |
130 | return NULL; | |
131 | idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp); | |
132 | if (idx == -1) | |
133 | return NULL; | |
134 | return sk_X509V3_EXT_METHOD_value(ext_list, idx); | |
3e575651 SL |
135 | } |
136 | ||
d3819813 | 137 | const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext) |
3e575651 | 138 | { |
d3819813 | 139 | int nid; |
7bf7a6d0 | 140 | if ((nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext))) == NID_undef) |
d3819813 MTL |
141 | return NULL; |
142 | return X509V3_EXT_get_nid(nid); | |
3e575651 SL |
143 | } |
144 | ||
3e575651 SL |
145 | int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist) |
146 | { | |
d3819813 MTL |
147 | for (; extlist->ext_nid != -1; extlist++) |
148 | if (!X509V3_EXT_add(extlist)) | |
149 | return 0; | |
150 | return 1; | |
3e575651 SL |
151 | } |
152 | ||
153 | int X509V3_EXT_add_alias(int nid_to, int nid_from) | |
154 | { | |
d3819813 MTL |
155 | const X509V3_EXT_METHOD *ext; |
156 | X509V3_EXT_METHOD *tmpext; | |
157 | ||
7bf7a6d0 MTL |
158 | if ((ext = X509V3_EXT_get_nid(nid_from)) == NULL) { |
159 | X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS, X509V3_R_EXTENSION_NOT_FOUND); | |
d3819813 MTL |
160 | return 0; |
161 | } | |
7bf7a6d0 | 162 | if ((tmpext = OPENSSL_malloc(sizeof(*tmpext))) == NULL) { |
d3819813 MTL |
163 | X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS, ERR_R_MALLOC_FAILURE); |
164 | return 0; | |
165 | } | |
166 | *tmpext = *ext; | |
167 | tmpext->ext_nid = nid_to; | |
168 | tmpext->ext_flags |= X509V3_EXT_DYNAMIC; | |
169 | return X509V3_EXT_add(tmpext); | |
3e575651 SL |
170 | } |
171 | ||
172 | void X509V3_EXT_cleanup(void) | |
173 | { | |
d3819813 MTL |
174 | sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free); |
175 | ext_list = NULL; | |
3e575651 SL |
176 | } |
177 | ||
178 | static void ext_list_free(X509V3_EXT_METHOD *ext) | |
179 | { | |
d3819813 MTL |
180 | if (ext->ext_flags & X509V3_EXT_DYNAMIC) |
181 | OPENSSL_free(ext); | |
3e575651 SL |
182 | } |
183 | ||
d3819813 MTL |
184 | /* |
185 | * Legacy function: we don't need to add standard extensions any more because | |
186 | * they are now kept in ext_dat.h. | |
3e575651 SL |
187 | */ |
188 | ||
189 | int X509V3_add_standard_extensions(void) | |
190 | { | |
d3819813 | 191 | return 1; |
3e575651 SL |
192 | } |
193 | ||
194 | /* Return an extension internal structure */ | |
195 | ||
196 | void *X509V3_EXT_d2i(X509_EXTENSION *ext) | |
197 | { | |
d3819813 MTL |
198 | const X509V3_EXT_METHOD *method; |
199 | const unsigned char *p; | |
7bf7a6d0 MTL |
200 | ASN1_STRING *extvalue; |
201 | int extlen; | |
d3819813 | 202 | |
7bf7a6d0 | 203 | if ((method = X509V3_EXT_get(ext)) == NULL) |
d3819813 | 204 | return NULL; |
7bf7a6d0 MTL |
205 | extvalue = X509_EXTENSION_get_data(ext); |
206 | p = ASN1_STRING_get0_data(extvalue); | |
207 | extlen = ASN1_STRING_length(extvalue); | |
d3819813 | 208 | if (method->it) |
7bf7a6d0 MTL |
209 | return ASN1_item_d2i(NULL, &p, extlen, ASN1_ITEM_ptr(method->it)); |
210 | return method->d2i(NULL, &p, extlen); | |
3e575651 SL |
211 | } |
212 | ||
d3819813 MTL |
213 | /*- |
214 | * Get critical flag and decoded version of extension from a NID. | |
3e575651 SL |
215 | * The "idx" variable returns the last found extension and can |
216 | * be used to retrieve multiple extensions of the same NID. | |
217 | * However multiple extensions with the same NID is usually | |
218 | * due to a badly encoded certificate so if idx is NULL we | |
219 | * choke if multiple extensions exist. | |
220 | * The "crit" variable is set to the critical value. | |
221 | * The return value is the decoded extension or NULL on | |
222 | * error. The actual error can have several different causes, | |
223 | * the value of *crit reflects the cause: | |
224 | * >= 0, extension found but not decoded (reflects critical value). | |
225 | * -1 extension not found. | |
226 | * -2 extension occurs more than once. | |
227 | */ | |
228 | ||
7bf7a6d0 | 229 | void *X509V3_get_d2i(const STACK_OF(X509_EXTENSION) *x, int nid, int *crit, |
d3819813 | 230 | int *idx) |
3e575651 | 231 | { |
d3819813 MTL |
232 | int lastpos, i; |
233 | X509_EXTENSION *ex, *found_ex = NULL; | |
234 | if (!x) { | |
235 | if (idx) | |
236 | *idx = -1; | |
237 | if (crit) | |
238 | *crit = -1; | |
239 | return NULL; | |
240 | } | |
241 | if (idx) | |
242 | lastpos = *idx + 1; | |
243 | else | |
244 | lastpos = 0; | |
245 | if (lastpos < 0) | |
246 | lastpos = 0; | |
247 | for (i = lastpos; i < sk_X509_EXTENSION_num(x); i++) { | |
248 | ex = sk_X509_EXTENSION_value(x, i); | |
7bf7a6d0 | 249 | if (OBJ_obj2nid(X509_EXTENSION_get_object(ex)) == nid) { |
d3819813 MTL |
250 | if (idx) { |
251 | *idx = i; | |
252 | found_ex = ex; | |
253 | break; | |
254 | } else if (found_ex) { | |
255 | /* Found more than one */ | |
256 | if (crit) | |
257 | *crit = -2; | |
258 | return NULL; | |
259 | } | |
260 | found_ex = ex; | |
261 | } | |
262 | } | |
263 | if (found_ex) { | |
264 | /* Found it */ | |
265 | if (crit) | |
266 | *crit = X509_EXTENSION_get_critical(found_ex); | |
267 | return X509V3_EXT_d2i(found_ex); | |
268 | } | |
269 | ||
270 | /* Extension not found */ | |
271 | if (idx) | |
272 | *idx = -1; | |
273 | if (crit) | |
274 | *crit = -1; | |
275 | return NULL; | |
3e575651 SL |
276 | } |
277 | ||
d3819813 MTL |
278 | /* |
279 | * This function is a general extension append, replace and delete utility. | |
3e575651 SL |
280 | * The precise operation is governed by the 'flags' value. The 'crit' and |
281 | * 'value' arguments (if relevant) are the extensions internal structure. | |
282 | */ | |
283 | ||
284 | int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, | |
d3819813 | 285 | int crit, unsigned long flags) |
3e575651 | 286 | { |
d3819813 MTL |
287 | int extidx = -1; |
288 | int errcode; | |
289 | X509_EXTENSION *ext, *extmp; | |
290 | unsigned long ext_op = flags & X509V3_ADD_OP_MASK; | |
291 | ||
292 | /* | |
293 | * If appending we don't care if it exists, otherwise look for existing | |
294 | * extension. | |
295 | */ | |
296 | if (ext_op != X509V3_ADD_APPEND) | |
297 | extidx = X509v3_get_ext_by_NID(*x, nid, -1); | |
298 | ||
299 | /* See if extension exists */ | |
300 | if (extidx >= 0) { | |
301 | /* If keep existing, nothing to do */ | |
302 | if (ext_op == X509V3_ADD_KEEP_EXISTING) | |
303 | return 1; | |
304 | /* If default then its an error */ | |
305 | if (ext_op == X509V3_ADD_DEFAULT) { | |
306 | errcode = X509V3_R_EXTENSION_EXISTS; | |
307 | goto err; | |
308 | } | |
309 | /* If delete, just delete it */ | |
310 | if (ext_op == X509V3_ADD_DELETE) { | |
311 | if (!sk_X509_EXTENSION_delete(*x, extidx)) | |
312 | return -1; | |
313 | return 1; | |
314 | } | |
315 | } else { | |
316 | /* | |
317 | * If replace existing or delete, error since extension must exist | |
318 | */ | |
319 | if ((ext_op == X509V3_ADD_REPLACE_EXISTING) || | |
320 | (ext_op == X509V3_ADD_DELETE)) { | |
321 | errcode = X509V3_R_EXTENSION_NOT_FOUND; | |
322 | goto err; | |
323 | } | |
324 | } | |
325 | ||
326 | /* | |
327 | * If we get this far then we have to create an extension: could have | |
328 | * some flags for alternative encoding schemes... | |
329 | */ | |
330 | ||
331 | ext = X509V3_EXT_i2d(nid, crit, value); | |
332 | ||
333 | if (!ext) { | |
334 | X509V3err(X509V3_F_X509V3_ADD1_I2D, | |
335 | X509V3_R_ERROR_CREATING_EXTENSION); | |
336 | return 0; | |
337 | } | |
338 | ||
339 | /* If extension exists replace it.. */ | |
340 | if (extidx >= 0) { | |
341 | extmp = sk_X509_EXTENSION_value(*x, extidx); | |
342 | X509_EXTENSION_free(extmp); | |
343 | if (!sk_X509_EXTENSION_set(*x, extidx, ext)) | |
344 | return -1; | |
345 | return 1; | |
346 | } | |
347 | ||
7bf7a6d0 MTL |
348 | if (*x == NULL |
349 | && (*x = sk_X509_EXTENSION_new_null()) == NULL) | |
d3819813 MTL |
350 | return -1; |
351 | if (!sk_X509_EXTENSION_push(*x, ext)) | |
352 | return -1; | |
353 | ||
354 | return 1; | |
355 | ||
356 | err: | |
357 | if (!(flags & X509V3_ADD_SILENT)) | |
358 | X509V3err(X509V3_F_X509V3_ADD1_I2D, errcode); | |
359 | return 0; | |
3e575651 | 360 | } |