]>
Commit | Line | Data |
---|---|---|
9aeaf1b4 DSH |
1 | /* v3_conf.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 | */ | |
388ff0b0 | 58 | /* extension creation utilities */ |
9aeaf1b4 | 59 | |
e527ba09 DSH |
60 | |
61 | ||
62 | #include <stdio.h> | |
9aeaf1b4 | 63 | #include <ctype.h> |
e527ba09 DSH |
64 | #include "cryptlib.h" |
65 | #include "conf.h" | |
66 | #include "x509.h" | |
9aeaf1b4 DSH |
67 | #include "x509v3.h" |
68 | ||
388ff0b0 DSH |
69 | #ifndef NOPROTO |
70 | static int v3_check_critical(char **value); | |
71 | static int v3_check_generic(char **value); | |
72 | static X509_EXTENSION *do_ext_conf(LHASH *conf, X509V3_CTX *ctx, int ext_nid, int crit, char *value); | |
e778802f | 73 | static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, int crit, int type); |
f5fedc04 DSH |
74 | static char *conf_lhash_get_string(void *db, char *section, char *value); |
75 | static STACK *conf_lhash_get_section(void *db, char *section); | |
388ff0b0 DSH |
76 | #else |
77 | static int v3_check_critical(); | |
78 | static int v3_check_generic(); | |
79 | static X509_EXTENSION *do_ext_conf(); | |
80 | static X509V3_EXTENSION *v3_generic_extension(); | |
f5fedc04 DSH |
81 | static char *conf_lhash_get_string(); |
82 | static STACK *conf_lhash_get_section(); | |
388ff0b0 DSH |
83 | #endif |
84 | ||
6b691a5c UM |
85 | /* LHASH *conf: Config file */ |
86 | /* char *name: Name */ | |
87 | /* char *value: Value */ | |
88 | X509_EXTENSION *X509V3_EXT_conf(LHASH *conf, X509V3_CTX *ctx, char *name, | |
89 | char *value) | |
9aeaf1b4 | 90 | { |
388ff0b0 DSH |
91 | int crit; |
92 | int ext_type; | |
aa066b9e | 93 | X509_EXTENSION *ret; |
388ff0b0 DSH |
94 | crit = v3_check_critical(&value); |
95 | if((ext_type = v3_check_generic(&value))) | |
96 | return v3_generic_extension(name, value, crit, ext_type); | |
aa066b9e DSH |
97 | ret = do_ext_conf(conf, ctx, OBJ_sn2nid(name), crit, value); |
98 | if(!ret) { | |
99 | X509V3err(X509V3_F_X509V3_EXT_CONF,X509V3_R_ERROR_IN_EXTENSION); | |
100 | ERR_add_error_data(4,"name=", name, ", value=", value); | |
101 | } | |
102 | return ret; | |
9aeaf1b4 DSH |
103 | } |
104 | ||
6b691a5c UM |
105 | /* LHASH *conf: Config file */ |
106 | /* char *value: Value */ | |
107 | X509_EXTENSION *X509V3_EXT_conf_nid(LHASH *conf, X509V3_CTX *ctx, int ext_nid, | |
108 | char *value) | |
388ff0b0 DSH |
109 | { |
110 | int crit; | |
111 | int ext_type; | |
112 | crit = v3_check_critical(&value); | |
113 | if((ext_type = v3_check_generic(&value))) | |
114 | return v3_generic_extension(OBJ_nid2sn(ext_nid), | |
115 | value, crit, ext_type); | |
116 | return do_ext_conf(conf, ctx, ext_nid, crit, value); | |
117 | } | |
118 | ||
6b691a5c UM |
119 | /* LHASH *conf: Config file */ |
120 | /* char *value: Value */ | |
121 | static X509_EXTENSION *do_ext_conf(LHASH *conf, X509V3_CTX *ctx, int ext_nid, | |
122 | int crit, char *value) | |
9aeaf1b4 DSH |
123 | { |
124 | X509_EXTENSION *ext = NULL; | |
125 | X509V3_EXT_METHOD *method; | |
126 | STACK *nval; | |
127 | char *ext_struc; | |
128 | char *ext_der, *p; | |
129 | int ext_len; | |
9aeaf1b4 | 130 | ASN1_OCTET_STRING *ext_oct; |
aa066b9e DSH |
131 | if(ext_nid == NID_undef) { |
132 | X509V3err(X509V3_F_DO_EXT_CONF,X509V3_R_UNKNOWN_EXTENSION_NAME); | |
133 | return NULL; | |
134 | } | |
9aeaf1b4 | 135 | if(!(method = X509V3_EXT_get_nid(ext_nid))) { |
aa066b9e | 136 | X509V3err(X509V3_F_DO_EXT_CONF,X509V3_R_UNKNOWN_EXTENSION); |
9aeaf1b4 DSH |
137 | return NULL; |
138 | } | |
9aeaf1b4 DSH |
139 | /* Now get internal extension representation based on type */ |
140 | if(method->v2i) { | |
141 | if(*value == '@') nval = CONF_get_section(conf, value + 1); | |
142 | else nval = X509V3_parse_list(value); | |
143 | if(!nval) { | |
144 | X509V3err(X509V3_F_X509V3_EXT_CONF,X509V3_R_INVALID_EXTENSION_STRING); | |
145 | ERR_add_error_data(4, "name=", OBJ_nid2sn(ext_nid), ",section=", value); | |
146 | return NULL; | |
147 | } | |
148 | ext_struc = method->v2i(method, ctx, nval); | |
149 | if(*value != '@') sk_pop_free(nval, X509V3_conf_free); | |
150 | if(!ext_struc) return NULL; | |
151 | } else if(method->s2i) { | |
152 | if(!(ext_struc = method->s2i(method, ctx, value))) return NULL; | |
41b731f2 DSH |
153 | } else if(method->r2i) { |
154 | if(!ctx->db) { | |
155 | X509V3err(X509V3_F_X509V3_EXT_CONF,X509V3_R_NO_CONFIG_DATABASE); | |
156 | return NULL; | |
157 | } | |
158 | if(!(ext_struc = method->r2i(method, ctx, value))) return NULL; | |
9aeaf1b4 DSH |
159 | } else { |
160 | X509V3err(X509V3_F_X509V3_EXT_CONF,X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED); | |
161 | ERR_add_error_data(2, "name=", OBJ_nid2sn(ext_nid)); | |
162 | return NULL; | |
163 | } | |
164 | ||
165 | /* We've now got the internal representation: convert to DER */ | |
166 | ext_len = method->i2d(ext_struc, NULL); | |
167 | ext_der = Malloc(ext_len); | |
168 | p = ext_der; | |
169 | method->i2d(ext_struc, &p); | |
170 | method->ext_free(ext_struc); | |
171 | ext_oct = ASN1_OCTET_STRING_new(); | |
172 | ext_oct->data = ext_der; | |
173 | ext_oct->length = ext_len; | |
174 | ||
175 | ext = X509_EXTENSION_create_by_NID(NULL, ext_nid, crit, ext_oct); | |
176 | ASN1_OCTET_STRING_free(ext_oct); | |
177 | ||
178 | return ext; | |
179 | ||
180 | } | |
181 | ||
388ff0b0 | 182 | /* Check the extension string for critical flag */ |
6b691a5c | 183 | static int v3_check_critical(char **value) |
388ff0b0 DSH |
184 | { |
185 | char *p = *value; | |
186 | if((strlen(p) < 9) || strncmp(p, "critical,", 9)) return 0; | |
187 | p+=9; | |
188 | while(isspace(*p)) p++; | |
189 | *value = p; | |
190 | return 1; | |
191 | } | |
192 | ||
193 | /* Check extension string for generic extension and return the type */ | |
6b691a5c | 194 | static int v3_check_generic(char **value) |
388ff0b0 DSH |
195 | { |
196 | char *p = *value; | |
197 | if((strlen(p) < 4) || strncmp(p, "RAW:,", 4)) return 0; | |
198 | p+=4; | |
199 | while(isspace(*p)) p++; | |
200 | *value = p; | |
201 | return 1; | |
202 | } | |
203 | ||
204 | /* Create a generic extension: for now just handle RAW type */ | |
6b691a5c UM |
205 | static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, |
206 | int crit, int type) | |
388ff0b0 DSH |
207 | { |
208 | unsigned char *ext_der=NULL; | |
209 | long ext_len; | |
210 | ASN1_OBJECT *obj=NULL; | |
211 | ASN1_OCTET_STRING *oct=NULL; | |
212 | X509_EXTENSION *extension=NULL; | |
213 | if(!(obj = OBJ_txt2obj(ext, 0))) { | |
214 | X509V3err(X509V3_F_V3_GENERIC_EXTENSION,X509V3_R_EXTENSION_NAME_ERROR); | |
215 | ERR_add_error_data(2, "name=", ext); | |
216 | goto err; | |
217 | } | |
218 | ||
219 | if(!(ext_der = string_to_hex(value, &ext_len))) { | |
220 | X509V3err(X509V3_F_V3_GENERIC_EXTENSION,X509V3_R_EXTENSION_VALUE_ERROR); | |
221 | ERR_add_error_data(2, "value=", value); | |
222 | goto err; | |
223 | } | |
224 | ||
225 | if(!(oct = ASN1_OCTET_STRING_new())) { | |
226 | X509V3err(X509V3_F_V3_GENERIC_EXTENSION,ERR_R_MALLOC_FAILURE); | |
227 | goto err; | |
228 | } | |
229 | ||
230 | oct->data = ext_der; | |
231 | oct->length = ext_len; | |
232 | ext_der = NULL; | |
233 | ||
234 | extension = X509_EXTENSION_create_by_OBJ(NULL, obj, crit, oct); | |
235 | ||
236 | err: | |
237 | ASN1_OBJECT_free(obj); | |
238 | ASN1_OCTET_STRING_free(oct); | |
239 | if(ext_der) Free(ext_der); | |
240 | return extension; | |
241 | } | |
242 | ||
243 | ||
9aeaf1b4 DSH |
244 | /* This is the main function: add a bunch of extensions based on a config file |
245 | * section | |
246 | */ | |
247 | ||
6b691a5c UM |
248 | int X509V3_EXT_add_conf(LHASH *conf, X509V3_CTX *ctx, char *section, |
249 | X509 *cert) | |
9aeaf1b4 DSH |
250 | { |
251 | X509_EXTENSION *ext; | |
252 | STACK *nval; | |
253 | CONF_VALUE *val; | |
254 | int i; | |
255 | if(!(nval = CONF_get_section(conf, section))) return 0; | |
256 | for(i = 0; i < sk_num(nval); i++) { | |
257 | val = (CONF_VALUE *)sk_value(nval, i); | |
258 | if(!(ext = X509V3_EXT_conf(conf, ctx, val->name, val->value))) | |
259 | return 0; | |
260 | if(cert) X509_add_ext(cert, ext, -1); | |
261 | X509_EXTENSION_free(ext); | |
262 | } | |
263 | return 1; | |
264 | } | |
265 | ||
1756d405 DSH |
266 | /* Same as above but for a CRL */ |
267 | ||
6b691a5c UM |
268 | int X509V3_EXT_CRL_add_conf(LHASH *conf, X509V3_CTX *ctx, char *section, |
269 | X509_CRL *crl) | |
1756d405 DSH |
270 | { |
271 | X509_EXTENSION *ext; | |
272 | STACK *nval; | |
273 | CONF_VALUE *val; | |
274 | int i; | |
275 | if(!(nval = CONF_get_section(conf, section))) return 0; | |
276 | for(i = 0; i < sk_num(nval); i++) { | |
277 | val = (CONF_VALUE *)sk_value(nval, i); | |
278 | if(!(ext = X509V3_EXT_conf(conf, ctx, val->name, val->value))) | |
279 | return 0; | |
280 | if(crl) X509_CRL_add_ext(crl, ext, -1); | |
281 | X509_EXTENSION_free(ext); | |
282 | } | |
283 | return 1; | |
284 | } | |
285 | ||
1d48dd00 DSH |
286 | /* Config database functions */ |
287 | ||
6b691a5c | 288 | char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section) |
1d48dd00 DSH |
289 | { |
290 | if(ctx->db_meth->get_string) | |
291 | return ctx->db_meth->get_string(ctx->db, name, section); | |
292 | return NULL; | |
293 | } | |
294 | ||
6b691a5c | 295 | STACK * X509V3_get_section(X509V3_CTX *ctx, char *section) |
1d48dd00 DSH |
296 | { |
297 | if(ctx->db_meth->get_section) | |
298 | return ctx->db_meth->get_section(ctx->db, section); | |
299 | return NULL; | |
300 | } | |
301 | ||
6b691a5c | 302 | void X509V3_string_free(X509V3_CTX *ctx, char *str) |
1d48dd00 | 303 | { |
41b731f2 | 304 | if(!str) return; |
1d48dd00 | 305 | if(ctx->db_meth->free_string) |
f5fedc04 | 306 | ctx->db_meth->free_string(ctx->db, str); |
1d48dd00 DSH |
307 | } |
308 | ||
6b691a5c | 309 | void X509V3_section_free(X509V3_CTX *ctx, STACK *section) |
1d48dd00 | 310 | { |
41b731f2 | 311 | if(!section) return; |
1d48dd00 | 312 | if(ctx->db_meth->free_section) |
f5fedc04 | 313 | ctx->db_meth->free_section(ctx->db, section); |
1d48dd00 DSH |
314 | } |
315 | ||
6b691a5c | 316 | static char *conf_lhash_get_string(void *db, char *section, char *value) |
1d48dd00 DSH |
317 | { |
318 | return CONF_get_string(db, section, value); | |
319 | } | |
320 | ||
6b691a5c | 321 | static STACK *conf_lhash_get_section(void *db, char *section) |
1d48dd00 DSH |
322 | { |
323 | return CONF_get_section(db, section); | |
324 | } | |
325 | ||
326 | static X509V3_CONF_METHOD conf_lhash_method = { | |
327 | conf_lhash_get_string, | |
328 | conf_lhash_get_section, | |
329 | NULL, | |
330 | NULL | |
331 | }; | |
332 | ||
6b691a5c | 333 | void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH *lhash) |
1d48dd00 DSH |
334 | { |
335 | ctx->db_meth = &conf_lhash_method; | |
336 | ctx->db = lhash; | |
337 | } | |
338 | ||
6b691a5c UM |
339 | void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subj, X509_REQ *req, |
340 | X509_CRL *crl, int flags) | |
1d48dd00 DSH |
341 | { |
342 | ctx->issuer_cert = issuer; | |
343 | ctx->subject_cert = subj; | |
344 | ctx->crl = crl; | |
345 | ctx->subject_req = req; | |
346 | ctx->flags = flags; | |
347 | } |