2 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
5 /* ====================================================================
6 * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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
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/)"
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.
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.
34 * 6. Redistributions of any form whatsoever must retain the following
36 * "This product includes software developed by the OpenSSL Project
37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
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 * ====================================================================
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).
61 #include <openssl/x509v3.h>
64 static int x509_purpose_get_idx(int id
);
65 void x509v3_cache_extensions(X509
*x
);
67 static int ca_check(X509
*x
);
68 static int check_purpose_ssl_client(X509_PURPOSE
*xp
, X509
*x
, int ca
);
69 static int check_purpose_ssl_server(X509_PURPOSE
*xp
, X509
*x
, int ca
);
70 static int check_purpose_ns_ssl_server(X509_PURPOSE
*xp
, X509
*x
, int ca
);
71 static int purpose_smime(X509
*x
, int ca
);
72 static int check_purpose_smime_sign(X509_PURPOSE
*xp
, X509
*x
, int ca
);
73 static int check_purpose_smime_encrypt(X509_PURPOSE
*xp
, X509
*x
, int ca
);
74 static int check_purpose_crl_sign(X509_PURPOSE
*xp
, X509
*x
, int ca
);
76 static int xp_cmp(X509_PURPOSE
**a
, X509_PURPOSE
**b
);
78 static X509_PURPOSE xstandard
[] = {
79 {1, 0, check_purpose_ssl_client
, "SSL client", /* NULL */},
80 {2, 0, check_purpose_ssl_server
, "SSL server", /* NULL */},
81 {3, 0, check_purpose_ns_ssl_server
, "Netscape SSL server", /* NULL */},
82 {4, 0, check_purpose_smime_sign
, "S/MIME signing", /* NULL */},
83 {5, 0, check_purpose_smime_encrypt
, "S/MIME encryption", /* NULL */},
84 {6, 0, check_purpose_crl_sign
, "CRL signing", /* NULL */},
85 {-1, 0, NULL
, NULL
, /* NULL */}
88 IMPLEMENT_STACK_OF(X509_PURPOSE
)
90 static STACK_OF(X509_PURPOSE
) *xptable
= NULL
;
92 static int xp_cmp(X509_PURPOSE
**a
, X509_PURPOSE
**b
)
94 return (*a
)->purpose_id
- (*b
)->purpose_id
;
97 int X509_check_purpose(X509
*x
, int id
, int ca
)
101 if(!(x
->ex_flags
& EXFLAG_SET
)) {
102 CRYPTO_w_lock(CRYPTO_LOCK_X509
);
103 x509v3_cache_extensions(x
);
104 CRYPTO_w_unlock(CRYPTO_LOCK_X509
);
106 idx
= x509_purpose_get_idx(id
);
107 if(idx
== -1) return -1;
108 pt
= sk_X509_PURPOSE_value(xptable
, idx
);
109 return pt
->check_purpose(pt
, x
,ca
);
115 static int x509_purpose_get_idx(int id
)
119 if(!xptable
) return -1;
120 return sk_X509_PURPOSE_find(xptable
, &tmp
);
123 int X509_PURPOSE_add(X509_PURPOSE
*xp
)
128 xptable
= sk_X509_PURPOSE_new(xp_cmp
);
131 X509V3err(X509V3_F_X509_PURPOSE_ADD
,ERR_R_MALLOC_FAILURE
);
136 idx
= x509_purpose_get_idx(xp
->purpose_id
);
138 sk_X509_PURPOSE_set(xptable
, idx
, xp
);
140 if (!sk_X509_PURPOSE_push(xptable
, xp
))
142 X509V3err(X509V3_F_X509_PURPOSE_ADD
,ERR_R_MALLOC_FAILURE
);
148 static void xptable_free(X509_PURPOSE
*p
)
150 if (p
->purpose_flags
& X509_PURPOSE_DYNAMIC
)
152 if (p
->purpose_flags
& X509_PURPOSE_DYNAMIC_NAME
)
153 Free(p
->purpose_name
);
158 void X509_PURPOSE_cleanup(void)
160 sk_X509_PURPOSE_pop_free(xptable
, xptable_free
);
164 void X509_PURPOSE_add_standard(void)
167 for(xp
= xstandard
; xp
->purpose_name
; xp
++)
168 X509_PURPOSE_add(xp
);
171 int X509_PURPOSE_enum(int (*efunc
)(X509_PURPOSE
*, void *), void *usr
)
175 if(!xptable
) return 0;
176 for(i
= 0; i
< sk_X509_PURPOSE_num(xptable
); i
++) {
177 xp
= sk_X509_PURPOSE_value(xptable
, i
);
178 if(!efunc(xp
, usr
)) return i
;
184 int X509_PURPOSE_get_id(X509_PURPOSE
*xp
)
186 return xp
->purpose_id
;
189 char *X509_PURPOSE_get_name(X509_PURPOSE
*xp
)
191 return xp
->purpose_name
;
194 void x509v3_cache_extensions(X509
*x
)
196 BASIC_CONSTRAINTS
*bs
;
197 ASN1_BIT_STRING
*usage
;
199 STACK_OF(ASN1_OBJECT
) *extusage
;
201 if(x
->ex_flags
& EXFLAG_SET
) return;
202 /* Does subject name match issuer ? */
203 if(X509_NAME_cmp(X509_get_subject_name(x
), X509_get_issuer_name(x
)))
204 x
->ex_flags
|= EXFLAG_SS
;
205 /* V1 should mean no extensions ... */
206 if(!X509_get_version(x
)) x
->ex_flags
|= EXFLAG_V1
;
207 /* Handle basic constraints */
208 if((bs
=X509V3_X509_get_d2i(x
, NID_basic_constraints
, NULL
, NULL
))) {
209 if(bs
->ca
) x
->ex_flags
|= EXFLAG_CA
;
211 if((bs
->pathlen
->type
== V_ASN1_NEG_INTEGER
)
213 x
->ex_flags
|= EXFLAG_INVALID
;
215 } else x
->ex_pathlen
= ASN1_INTEGER_get(bs
->pathlen
);
216 } else x
->ex_pathlen
= -1;
217 BASIC_CONSTRAINTS_free(bs
);
218 x
->ex_flags
|= EXFLAG_BCONS
;
220 /* Handle key usage */
221 if((usage
=X509V3_X509_get_d2i(x
, NID_key_usage
, NULL
, NULL
))) {
222 if(usage
->length
> 0) {
223 x
->ex_kusage
= usage
->data
[0];
224 if(usage
->length
> 1)
225 x
->ex_kusage
|= usage
->data
[1] << 8;
226 } else x
->ex_kusage
= 0;
227 x
->ex_flags
|= EXFLAG_KUSAGE
;
228 ASN1_BIT_STRING_free(usage
);
231 if((extusage
=X509V3_X509_get_d2i(x
, NID_ext_key_usage
, NULL
, NULL
))) {
232 x
->ex_flags
|= EXFLAG_XKUSAGE
;
233 for(i
= 0; i
< sk_ASN1_OBJECT_num(extusage
); i
++) {
234 switch(OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage
,i
))) {
235 case NID_server_auth
:
236 x
->ex_xkusage
|= XKU_SSL_SERVER
;
239 case NID_client_auth
:
240 x
->ex_xkusage
|= XKU_SSL_CLIENT
;
243 case NID_email_protect
:
244 x
->ex_xkusage
|= XKU_SMIME
;
248 x
->ex_xkusage
|= XKU_CODE_SIGN
;
253 x
->ex_xkusage
|= XKU_SGC
;
256 sk_ASN1_OBJECT_pop_free(extusage
, ASN1_OBJECT_free
);
259 if((ns
=X509V3_X509_get_d2i(x
, NID_netscape_cert_type
, NULL
, NULL
))) {
260 if(ns
->length
> 0) x
->ex_nscert
= ns
->data
[0];
261 else x
->ex_nscert
= 0;
262 x
->ex_flags
|= EXFLAG_NSCERT
;
263 ASN1_BIT_STRING_free(ns
);
265 x
->ex_flags
|= EXFLAG_SET
;
268 /* CA checks common to all purposes
272 * 2 basicConstraints absent so "maybe" a CA
273 * 3 basicConstraints absent but self signed V1.
276 #define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
277 #define ku_reject(x, usage) \
278 (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
279 #define xku_reject(x, usage) \
280 (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage)))
281 #define ns_reject(x, usage) \
282 (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
284 static int ca_check(X509
*x
)
286 /* keyUsage if present should allow cert signing */
287 if(ku_reject(x
, KU_KEY_CERT_SIGN
)) return 0;
288 if(x
->ex_flags
& EXFLAG_BCONS
) {
289 if(x
->ex_flags
& EXFLAG_CA
) return 1;
290 /* If basicConstraints says not a CA then say so */
293 if((x
->ex_flags
& V1_ROOT
) == V1_ROOT
) return 3;
299 static int check_purpose_ssl_client(X509_PURPOSE
*xp
, X509
*x
, int ca
)
301 if(xku_reject(x
,XKU_SSL_CLIENT
)) return 0;
304 ca_ret
= ca_check(x
);
305 if(!ca_ret
) return 0;
306 /* check nsCertType if present */
307 if(x
->ex_flags
& EXFLAG_NSCERT
) {
308 if(x
->ex_nscert
& NS_SSL_CA
) return ca_ret
;
311 if(ca_ret
!= 2) return ca_ret
;
314 /* We need to do digital signatures with it */
315 if(ku_reject(x
,KU_DIGITAL_SIGNATURE
)) return 0;
316 /* nsCertType if present should allow SSL client use */
317 if(ns_reject(x
, NS_SSL_CLIENT
)) return 0;
321 static int check_purpose_ssl_server(X509_PURPOSE
*xp
, X509
*x
, int ca
)
323 if(xku_reject(x
,XKU_SSL_SERVER
|XKU_SGC
)) return 0;
324 /* Otherwise same as SSL client for a CA */
325 if(ca
) return check_purpose_ssl_client(xp
, x
, 1);
327 if(ns_reject(x
, NS_SSL_SERVER
)) return 0;
328 /* Now as for keyUsage: we'll at least need to sign OR encipher */
329 if(ku_reject(x
, KU_DIGITAL_SIGNATURE
|KU_KEY_ENCIPHERMENT
)) return 0;
335 static int check_purpose_ns_ssl_server(X509_PURPOSE
*xp
, X509
*x
, int ca
)
338 ret
= check_purpose_ssl_server(xp
, x
, ca
);
339 if(!ret
|| ca
) return ret
;
340 /* We need to encipher or Netscape complains */
341 if(ku_reject(x
, KU_KEY_ENCIPHERMENT
)) return 0;
345 /* common S/MIME checks */
346 static int purpose_smime(X509
*x
, int ca
)
348 if(xku_reject(x
,XKU_SMIME
)) return 0;
351 ca_ret
= ca_check(x
);
352 if(!ca_ret
) return 0;
353 /* check nsCertType if present */
354 if(x
->ex_flags
& EXFLAG_NSCERT
) {
355 if(x
->ex_nscert
& NS_SMIME_CA
) return ca_ret
;
358 if(ca_ret
!= 2) return ca_ret
;
361 if(x
->ex_flags
& EXFLAG_NSCERT
) {
362 if(x
->ex_nscert
& NS_SMIME
) return 1;
363 /* Workaround for some buggy certificates */
364 if(x
->ex_nscert
& NS_SSL_CLIENT
) return 2;
370 static int check_purpose_smime_sign(X509_PURPOSE
*xp
, X509
*x
, int ca
)
373 ret
= purpose_smime(x
, ca
);
374 if(!ret
|| ca
) return ret
;
375 if(ku_reject(x
, KU_DIGITAL_SIGNATURE
)) return 0;
379 static int check_purpose_smime_encrypt(X509_PURPOSE
*xp
, X509
*x
, int ca
)
382 ret
= purpose_smime(x
, ca
);
383 if(!ret
|| ca
) return ret
;
384 if(ku_reject(x
, KU_KEY_ENCIPHERMENT
)) return 0;
388 static int check_purpose_crl_sign(X509_PURPOSE
*xp
, X509
*x
, int ca
)
392 if((ca_ret
= ca_check(x
)) != 2) return ca_ret
;
395 if(ku_reject(x
, KU_CRL_SIGN
)) return 0;