|
1 /* v3_lib.c */ |
|
2 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL |
|
3 * project 1999. |
|
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 |
|
13 * notice, this list of conditions and the following disclaimer. |
|
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 /* |
|
59 © Portions copyright (c) 2006 Nokia Corporation. All rights reserved. |
|
60 */ |
|
61 |
|
62 /* X509 v3 extension utilities */ |
|
63 |
|
64 #include <stdio.h> |
|
65 #include "cryptlib.h" |
|
66 #include <openssl/conf.h> |
|
67 #include <openssl/x509v3.h> |
|
68 #if (defined(SYMBIAN) && (defined(__WINSCW__) || defined(__WINS__))) |
|
69 #include "libcrypto_wsd_macros.h" |
|
70 #include "libcrypto_wsd.h" |
|
71 #endif |
|
72 |
|
73 #include "ext_dat.h" |
|
74 |
|
75 #ifndef EMULATOR |
|
76 static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL; |
|
77 #else |
|
78 GET_STATIC_VAR_FROM_TLS(ext_list,v3_lib,STACK_OF(X509V3_EXT_METHOD) *) |
|
79 #define ext_list (*GET_WSD_VAR_NAME(ext_list,v3_lib, s)()) |
|
80 #endif |
|
81 |
|
82 static int ext_cmp(const X509V3_EXT_METHOD * const *a, |
|
83 const X509V3_EXT_METHOD * const *b); |
|
84 static void ext_list_free(X509V3_EXT_METHOD *ext); |
|
85 |
|
86 EXPORT_C int X509V3_EXT_add(X509V3_EXT_METHOD *ext) |
|
87 { |
|
88 if(!ext_list && !(ext_list = sk_X509V3_EXT_METHOD_new(ext_cmp))) { |
|
89 X509V3err(X509V3_F_X509V3_EXT_ADD,ERR_R_MALLOC_FAILURE); |
|
90 return 0; |
|
91 } |
|
92 if(!sk_X509V3_EXT_METHOD_push(ext_list, ext)) { |
|
93 X509V3err(X509V3_F_X509V3_EXT_ADD,ERR_R_MALLOC_FAILURE); |
|
94 return 0; |
|
95 } |
|
96 return 1; |
|
97 } |
|
98 |
|
99 static int ext_cmp(const X509V3_EXT_METHOD * const *a, |
|
100 const X509V3_EXT_METHOD * const *b) |
|
101 { |
|
102 return ((*a)->ext_nid - (*b)->ext_nid); |
|
103 } |
|
104 |
|
105 EXPORT_C X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid) |
|
106 { |
|
107 X509V3_EXT_METHOD tmp, *t = &tmp, **ret; |
|
108 int idx; |
|
109 if(nid < 0) return NULL; |
|
110 tmp.ext_nid = nid; |
|
111 ret = (X509V3_EXT_METHOD **) OBJ_bsearch((char *)&t, |
|
112 (char *)standard_exts, STANDARD_EXTENSION_COUNT, |
|
113 sizeof(X509V3_EXT_METHOD *), (int (*)(const void *, const void *))ext_cmp); |
|
114 if(ret) return *ret; |
|
115 if(!ext_list) return NULL; |
|
116 idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp); |
|
117 if(idx == -1) return NULL; |
|
118 return sk_X509V3_EXT_METHOD_value(ext_list, idx); |
|
119 } |
|
120 |
|
121 EXPORT_C X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext) |
|
122 { |
|
123 int nid; |
|
124 if((nid = OBJ_obj2nid(ext->object)) == NID_undef) return NULL; |
|
125 return X509V3_EXT_get_nid(nid); |
|
126 } |
|
127 |
|
128 |
|
129 EXPORT_C int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist) |
|
130 { |
|
131 for(;extlist->ext_nid!=-1;extlist++) |
|
132 if(!X509V3_EXT_add(extlist)) return 0; |
|
133 return 1; |
|
134 } |
|
135 |
|
136 EXPORT_C int X509V3_EXT_add_alias(int nid_to, int nid_from) |
|
137 { |
|
138 X509V3_EXT_METHOD *ext, *tmpext; |
|
139 if(!(ext = X509V3_EXT_get_nid(nid_from))) { |
|
140 X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS,X509V3_R_EXTENSION_NOT_FOUND); |
|
141 return 0; |
|
142 } |
|
143 if(!(tmpext = (X509V3_EXT_METHOD *)OPENSSL_malloc(sizeof(X509V3_EXT_METHOD)))) { |
|
144 X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS,ERR_R_MALLOC_FAILURE); |
|
145 return 0; |
|
146 } |
|
147 *tmpext = *ext; |
|
148 tmpext->ext_nid = nid_to; |
|
149 tmpext->ext_flags |= X509V3_EXT_DYNAMIC; |
|
150 return X509V3_EXT_add(tmpext); |
|
151 } |
|
152 |
|
153 EXPORT_C void X509V3_EXT_cleanup(void) |
|
154 { |
|
155 sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free); |
|
156 ext_list = NULL; |
|
157 } |
|
158 |
|
159 static void ext_list_free(X509V3_EXT_METHOD *ext) |
|
160 { |
|
161 if(ext->ext_flags & X509V3_EXT_DYNAMIC) OPENSSL_free(ext); |
|
162 } |
|
163 |
|
164 /* Legacy function: we don't need to add standard extensions |
|
165 * any more because they are now kept in ext_dat.h. |
|
166 */ |
|
167 |
|
168 EXPORT_C int X509V3_add_standard_extensions(void) |
|
169 { |
|
170 return 1; |
|
171 } |
|
172 |
|
173 /* Return an extension internal structure */ |
|
174 |
|
175 EXPORT_C void *X509V3_EXT_d2i(X509_EXTENSION *ext) |
|
176 { |
|
177 X509V3_EXT_METHOD *method; |
|
178 const unsigned char *p; |
|
179 |
|
180 if(!(method = X509V3_EXT_get(ext))) return NULL; |
|
181 p = ext->value->data; |
|
182 if(method->it) return ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it)); |
|
183 return method->d2i(NULL, &p, ext->value->length); |
|
184 } |
|
185 |
|
186 /* Get critical flag and decoded version of extension from a NID. |
|
187 * The "idx" variable returns the last found extension and can |
|
188 * be used to retrieve multiple extensions of the same NID. |
|
189 * However multiple extensions with the same NID is usually |
|
190 * due to a badly encoded certificate so if idx is NULL we |
|
191 * choke if multiple extensions exist. |
|
192 * The "crit" variable is set to the critical value. |
|
193 * The return value is the decoded extension or NULL on |
|
194 * error. The actual error can have several different causes, |
|
195 * the value of *crit reflects the cause: |
|
196 * >= 0, extension found but not decoded (reflects critical value). |
|
197 * -1 extension not found. |
|
198 * -2 extension occurs more than once. |
|
199 */ |
|
200 |
|
201 EXPORT_C void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx) |
|
202 { |
|
203 int lastpos, i; |
|
204 X509_EXTENSION *ex, *found_ex = NULL; |
|
205 if(!x) { |
|
206 if(idx) *idx = -1; |
|
207 if(crit) *crit = -1; |
|
208 return NULL; |
|
209 } |
|
210 if(idx) lastpos = *idx + 1; |
|
211 else lastpos = 0; |
|
212 if(lastpos < 0) lastpos = 0; |
|
213 for(i = lastpos; i < sk_X509_EXTENSION_num(x); i++) |
|
214 { |
|
215 ex = sk_X509_EXTENSION_value(x, i); |
|
216 if(OBJ_obj2nid(ex->object) == nid) { |
|
217 if(idx) { |
|
218 *idx = i; |
|
219 found_ex = ex; |
|
220 break; |
|
221 } else if(found_ex) { |
|
222 /* Found more than one */ |
|
223 if(crit) *crit = -2; |
|
224 return NULL; |
|
225 } |
|
226 found_ex = ex; |
|
227 } |
|
228 } |
|
229 if(found_ex) { |
|
230 /* Found it */ |
|
231 if(crit) *crit = X509_EXTENSION_get_critical(found_ex); |
|
232 return X509V3_EXT_d2i(found_ex); |
|
233 } |
|
234 |
|
235 /* Extension not found */ |
|
236 if(idx) *idx = -1; |
|
237 if(crit) *crit = -1; |
|
238 return NULL; |
|
239 } |
|
240 |
|
241 /* This function is a general extension append, replace and delete utility. |
|
242 * The precise operation is governed by the 'flags' value. The 'crit' and |
|
243 * 'value' arguments (if relevant) are the extensions internal structure. |
|
244 */ |
|
245 |
|
246 EXPORT_C int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, |
|
247 int crit, unsigned long flags) |
|
248 { |
|
249 int extidx = -1; |
|
250 int errcode; |
|
251 X509_EXTENSION *ext, *extmp; |
|
252 unsigned long ext_op = flags & X509V3_ADD_OP_MASK; |
|
253 |
|
254 /* If appending we don't care if it exists, otherwise |
|
255 * look for existing extension. |
|
256 */ |
|
257 if(ext_op != X509V3_ADD_APPEND) |
|
258 extidx = X509v3_get_ext_by_NID(*x, nid, -1); |
|
259 |
|
260 /* See if extension exists */ |
|
261 if(extidx >= 0) { |
|
262 /* If keep existing, nothing to do */ |
|
263 if(ext_op == X509V3_ADD_KEEP_EXISTING) |
|
264 return 1; |
|
265 /* If default then its an error */ |
|
266 if(ext_op == X509V3_ADD_DEFAULT) { |
|
267 errcode = X509V3_R_EXTENSION_EXISTS; |
|
268 goto err; |
|
269 } |
|
270 /* If delete, just delete it */ |
|
271 if(ext_op == X509V3_ADD_DELETE) { |
|
272 if(!sk_X509_EXTENSION_delete(*x, extidx)) return -1; |
|
273 return 1; |
|
274 } |
|
275 } else { |
|
276 /* If replace existing or delete, error since |
|
277 * extension must exist |
|
278 */ |
|
279 if((ext_op == X509V3_ADD_REPLACE_EXISTING) || |
|
280 (ext_op == X509V3_ADD_DELETE)) { |
|
281 errcode = X509V3_R_EXTENSION_NOT_FOUND; |
|
282 goto err; |
|
283 } |
|
284 } |
|
285 |
|
286 /* If we get this far then we have to create an extension: |
|
287 * could have some flags for alternative encoding schemes... |
|
288 */ |
|
289 |
|
290 ext = X509V3_EXT_i2d(nid, crit, value); |
|
291 |
|
292 if(!ext) { |
|
293 X509V3err(X509V3_F_X509V3_ADD1_I2D, X509V3_R_ERROR_CREATING_EXTENSION); |
|
294 return 0; |
|
295 } |
|
296 |
|
297 /* If extension exists replace it.. */ |
|
298 if(extidx >= 0) { |
|
299 extmp = sk_X509_EXTENSION_value(*x, extidx); |
|
300 X509_EXTENSION_free(extmp); |
|
301 if(!sk_X509_EXTENSION_set(*x, extidx, ext)) return -1; |
|
302 return 1; |
|
303 } |
|
304 |
|
305 if(!*x && !(*x = sk_X509_EXTENSION_new_null())) return -1; |
|
306 if(!sk_X509_EXTENSION_push(*x, ext)) return -1; |
|
307 |
|
308 return 1; |
|
309 |
|
310 err: |
|
311 if(!(flags & X509V3_ADD_SILENT)) |
|
312 X509V3err(X509V3_F_X509V3_ADD1_I2D, errcode); |
|
313 return 0; |
|
314 } |
|
315 |
|
316 IMPLEMENT_STACK_OF(X509V3_EXT_METHOD) |