3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
6 /* ====================================================================
7 * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
21 * 3. All advertising materials mentioning features or use of this
22 * software must display the following acknowledgment:
23 * "This product includes software developed by the OpenSSL Project
24 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 * endorse or promote products derived from this software without
28 * prior written permission. For written permission, please contact
29 * licensing@OpenSSL.org.
31 * 5. Products derived from this software may not be called "OpenSSL"
32 * nor may "OpenSSL" appear in their names without prior written
33 * permission of the OpenSSL Project.
35 * 6. Redistributions of any form whatsoever must retain the following
37 * "This product includes software developed by the OpenSSL Project
38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 * OF THE POSSIBILITY OF SUCH DAMAGE.
52 * ====================================================================
54 * This product includes cryptographic software written by Eric Young
55 * (eay@cryptsoft.com). This product includes software written by Tim
56 * Hudson (tjh@cryptsoft.com).
62 #include <openssl/x509v3.h>
63 #include <openssl/x509_vfy.h>
65 static void x509v3_cache_extensions(X509 *x);
67 static int check_ssl_ca(const X509 *x);
68 static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
70 static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x,
72 static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x,
74 static int purpose_smime(const X509 *x, int ca);
75 static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x,
77 static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x,
79 static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x,
81 static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca);
82 static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca);
84 static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b);
85 static void xptable_free(X509_PURPOSE *p);
87 static X509_PURPOSE xstandard[] = {
88 {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0,
89 check_purpose_ssl_client, "SSL client", "sslclient", NULL},
90 {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0,
91 check_purpose_ssl_server, "SSL server", "sslserver", NULL},
92 {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0,
93 check_purpose_ns_ssl_server, "Netscape SSL server", "nssslserver", NULL},
94 {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign,
95 "S/MIME signing", "smimesign", NULL},
96 {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0,
97 check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL},
98 {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign,
99 "CRL signing", "crlsign", NULL},
100 {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any",
102 {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper,
103 "OCSP helper", "ocsphelper", NULL},
106 #define X509_PURPOSE_COUNT (sizeof(xstandard)/sizeof(X509_PURPOSE))
108 IMPLEMENT_STACK_OF(X509_PURPOSE)
110 static STACK_OF(X509_PURPOSE) *xptable = NULL;
112 static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b)
114 return (*a)->purpose - (*b)->purpose;
118 * As much as I'd like to make X509_check_purpose use a "const" X509* I
119 * really can't because it does recalculate hashes and do other non-const
122 int X509_check_purpose(X509 *x, int id, int ca)
125 const X509_PURPOSE *pt;
126 if (!(x->ex_flags & EXFLAG_SET)) {
127 CRYPTO_w_lock(CRYPTO_LOCK_X509);
128 x509v3_cache_extensions(x);
129 CRYPTO_w_unlock(CRYPTO_LOCK_X509);
133 idx = X509_PURPOSE_get_by_id(id);
136 pt = X509_PURPOSE_get0(idx);
137 return pt->check_purpose(pt, x, ca);
140 int X509_PURPOSE_set(int *p, int purpose)
142 if (X509_PURPOSE_get_by_id(purpose) == -1) {
143 X509V3err(X509V3_F_X509_PURPOSE_SET, X509V3_R_INVALID_PURPOSE);
150 int X509_PURPOSE_get_count(void)
153 return X509_PURPOSE_COUNT;
154 return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT;
157 X509_PURPOSE *X509_PURPOSE_get0(int idx)
161 if (idx < (int)X509_PURPOSE_COUNT)
162 return xstandard + idx;
163 return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT);
166 int X509_PURPOSE_get_by_sname(char *sname)
170 for (i = 0; i < X509_PURPOSE_get_count(); i++) {
171 xptmp = X509_PURPOSE_get0(i);
172 if (!strcmp(xptmp->sname, sname))
178 int X509_PURPOSE_get_by_id(int purpose)
182 if ((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX))
183 return purpose - X509_PURPOSE_MIN;
184 tmp.purpose = purpose;
187 idx = sk_X509_PURPOSE_find(xptable, &tmp);
190 return idx + X509_PURPOSE_COUNT;
193 int X509_PURPOSE_add(int id, int trust, int flags,
194 int (*ck) (const X509_PURPOSE *, const X509 *, int),
195 char *name, char *sname, void *arg)
200 * This is set according to what we change: application can't set it
202 flags &= ~X509_PURPOSE_DYNAMIC;
203 /* This will always be set for application modified trust entries */
204 flags |= X509_PURPOSE_DYNAMIC_NAME;
205 /* Get existing entry if any */
206 idx = X509_PURPOSE_get_by_id(id);
207 /* Need a new entry */
209 if (!(ptmp = OPENSSL_malloc(sizeof(X509_PURPOSE)))) {
210 X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
213 ptmp->flags = X509_PURPOSE_DYNAMIC;
215 ptmp = X509_PURPOSE_get0(idx);
217 /* OPENSSL_free existing name if dynamic */
218 if (ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) {
219 OPENSSL_free(ptmp->name);
220 OPENSSL_free(ptmp->sname);
222 /* dup supplied name */
223 ptmp->name = BUF_strdup(name);
224 ptmp->sname = BUF_strdup(sname);
225 if (!ptmp->name || !ptmp->sname) {
226 X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
229 /* Keep the dynamic flag of existing entry */
230 ptmp->flags &= X509_PURPOSE_DYNAMIC;
231 /* Set all other flags */
232 ptmp->flags |= flags;
236 ptmp->check_purpose = ck;
237 ptmp->usr_data = arg;
239 /* If its a new entry manage the dynamic table */
241 if (!xptable && !(xptable = sk_X509_PURPOSE_new(xp_cmp))) {
242 X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
245 if (!sk_X509_PURPOSE_push(xptable, ptmp)) {
246 X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
253 static void xptable_free(X509_PURPOSE *p)
257 if (p->flags & X509_PURPOSE_DYNAMIC) {
258 if (p->flags & X509_PURPOSE_DYNAMIC_NAME) {
259 OPENSSL_free(p->name);
260 OPENSSL_free(p->sname);
266 void X509_PURPOSE_cleanup(void)
269 sk_X509_PURPOSE_pop_free(xptable, xptable_free);
270 for (i = 0; i < X509_PURPOSE_COUNT; i++)
271 xptable_free(xstandard + i);
275 int X509_PURPOSE_get_id(X509_PURPOSE *xp)
280 char *X509_PURPOSE_get0_name(X509_PURPOSE *xp)
285 char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp)
290 int X509_PURPOSE_get_trust(X509_PURPOSE *xp)
295 static int nid_cmp(int *a, int *b)
300 int X509_supported_extension(X509_EXTENSION *ex)
303 * This table is a list of the NIDs of supported extensions: that is
304 * those which are used by the verify process. If an extension is
305 * critical and doesn't appear in this list then the verify process will
306 * normally reject the certificate. The list must be kept in numerical
307 * order because it will be searched using bsearch.
310 static int supported_nids[] = {
311 NID_netscape_cert_type, /* 71 */
312 NID_key_usage, /* 83 */
313 NID_subject_alt_name, /* 85 */
314 NID_basic_constraints, /* 87 */
315 NID_certificate_policies, /* 89 */
316 NID_ext_key_usage, /* 126 */
317 #ifndef OPENSSL_NO_RFC3779
318 NID_sbgp_ipAddrBlock, /* 290 */
319 NID_sbgp_autonomousSysNum, /* 291 */
321 NID_policy_constraints, /* 401 */
322 NID_proxyCertInfo, /* 661 */
323 NID_inhibit_any_policy /* 748 */
328 ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex));
330 if (ex_nid == NID_undef)
333 if (OBJ_bsearch((char *)&ex_nid, (char *)supported_nids,
334 sizeof(supported_nids) / sizeof(int), sizeof(int),
335 (int (*)(const void *, const void *))nid_cmp))
340 static void x509v3_cache_extensions(X509 *x)
342 BASIC_CONSTRAINTS *bs;
343 PROXY_CERT_INFO_EXTENSION *pci;
344 ASN1_BIT_STRING *usage;
346 EXTENDED_KEY_USAGE *extusage;
350 if (x->ex_flags & EXFLAG_SET)
352 #ifndef OPENSSL_NO_SHA
353 X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
355 /* Does subject name match issuer ? */
356 if (!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)))
357 x->ex_flags |= EXFLAG_SI;
358 /* V1 should mean no extensions ... */
359 if (!X509_get_version(x))
360 x->ex_flags |= EXFLAG_V1;
361 /* Handle basic constraints */
362 if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL))) {
364 x->ex_flags |= EXFLAG_CA;
366 if ((bs->pathlen->type == V_ASN1_NEG_INTEGER)
368 x->ex_flags |= EXFLAG_INVALID;
371 x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen);
374 BASIC_CONSTRAINTS_free(bs);
375 x->ex_flags |= EXFLAG_BCONS;
377 /* Handle proxy certificates */
378 if ((pci = X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) {
379 if (x->ex_flags & EXFLAG_CA
380 || X509_get_ext_by_NID(x, NID_subject_alt_name, 0) >= 0
381 || X509_get_ext_by_NID(x, NID_issuer_alt_name, 0) >= 0) {
382 x->ex_flags |= EXFLAG_INVALID;
384 if (pci->pcPathLengthConstraint) {
385 x->ex_pcpathlen = ASN1_INTEGER_get(pci->pcPathLengthConstraint);
387 x->ex_pcpathlen = -1;
388 PROXY_CERT_INFO_EXTENSION_free(pci);
389 x->ex_flags |= EXFLAG_PROXY;
391 /* Handle key usage */
392 if ((usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) {
393 if (usage->length > 0) {
394 x->ex_kusage = usage->data[0];
395 if (usage->length > 1)
396 x->ex_kusage |= usage->data[1] << 8;
399 x->ex_flags |= EXFLAG_KUSAGE;
400 ASN1_BIT_STRING_free(usage);
403 if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL))) {
404 x->ex_flags |= EXFLAG_XKUSAGE;
405 for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
406 switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) {
407 case NID_server_auth:
408 x->ex_xkusage |= XKU_SSL_SERVER;
411 case NID_client_auth:
412 x->ex_xkusage |= XKU_SSL_CLIENT;
415 case NID_email_protect:
416 x->ex_xkusage |= XKU_SMIME;
420 x->ex_xkusage |= XKU_CODE_SIGN;
425 x->ex_xkusage |= XKU_SGC;
429 x->ex_xkusage |= XKU_OCSP_SIGN;
433 x->ex_xkusage |= XKU_TIMESTAMP;
437 x->ex_xkusage |= XKU_DVCS;
441 sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
444 if ((ns = X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL))) {
446 x->ex_nscert = ns->data[0];
449 x->ex_flags |= EXFLAG_NSCERT;
450 ASN1_BIT_STRING_free(ns);
452 x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL);
453 x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL);
454 #ifndef OPENSSL_NO_RFC3779
455 x->rfc3779_addr = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, NULL, NULL);
456 x->rfc3779_asid = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum,
459 for (i = 0; i < X509_get_ext_count(x); i++) {
460 ex = X509_get_ext(x, i);
461 if (!X509_EXTENSION_get_critical(ex))
463 if (!X509_supported_extension(ex)) {
464 x->ex_flags |= EXFLAG_CRITICAL;
468 x->ex_flags |= EXFLAG_SET;
472 * CA checks common to all purposes
476 * 2 basicConstraints absent so "maybe" a CA
477 * 3 basicConstraints absent but self signed V1.
478 * 4 basicConstraints absent but keyUsage present and keyCertSign asserted.
481 #define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
482 #define ku_reject(x, usage) \
483 (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
484 #define xku_reject(x, usage) \
485 (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage)))
486 #define ns_reject(x, usage) \
487 (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
489 static int check_ca(const X509 *x)
491 /* keyUsage if present should allow cert signing */
492 if (ku_reject(x, KU_KEY_CERT_SIGN))
494 if (x->ex_flags & EXFLAG_BCONS) {
495 if (x->ex_flags & EXFLAG_CA)
497 /* If basicConstraints says not a CA then say so */
501 /* we support V1 roots for... uh, I don't really know why. */
502 if ((x->ex_flags & V1_ROOT) == V1_ROOT)
505 * If key usage present it must have certSign so tolerate it
507 else if (x->ex_flags & EXFLAG_KUSAGE)
509 /* Older certificates could have Netscape-specific CA types */
510 else if (x->ex_flags & EXFLAG_NSCERT && x->ex_nscert & NS_ANY_CA)
512 /* can this still be regarded a CA certificate? I doubt it */
517 int X509_check_ca(X509 *x)
519 if (!(x->ex_flags & EXFLAG_SET)) {
520 CRYPTO_w_lock(CRYPTO_LOCK_X509);
521 x509v3_cache_extensions(x);
522 CRYPTO_w_unlock(CRYPTO_LOCK_X509);
528 /* Check SSL CA: common checks for SSL client and server */
529 static int check_ssl_ca(const X509 *x)
532 ca_ret = check_ca(x);
535 /* check nsCertType if present */
536 if (ca_ret != 5 || x->ex_nscert & NS_SSL_CA)
542 static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
545 if (xku_reject(x, XKU_SSL_CLIENT))
548 return check_ssl_ca(x);
549 /* We need to do digital signatures with it */
550 if (ku_reject(x, KU_DIGITAL_SIGNATURE))
552 /* nsCertType if present should allow SSL client use */
553 if (ns_reject(x, NS_SSL_CLIENT))
558 static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x,
561 if (xku_reject(x, XKU_SSL_SERVER | XKU_SGC))
564 return check_ssl_ca(x);
566 if (ns_reject(x, NS_SSL_SERVER))
568 /* Now as for keyUsage: we'll at least need to sign OR encipher */
569 if (ku_reject(x, KU_DIGITAL_SIGNATURE | KU_KEY_ENCIPHERMENT))
576 static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x,
580 ret = check_purpose_ssl_server(xp, x, ca);
583 /* We need to encipher or Netscape complains */
584 if (ku_reject(x, KU_KEY_ENCIPHERMENT))
589 /* common S/MIME checks */
590 static int purpose_smime(const X509 *x, int ca)
592 if (xku_reject(x, XKU_SMIME))
596 ca_ret = check_ca(x);
599 /* check nsCertType if present */
600 if (ca_ret != 5 || x->ex_nscert & NS_SMIME_CA)
605 if (x->ex_flags & EXFLAG_NSCERT) {
606 if (x->ex_nscert & NS_SMIME)
608 /* Workaround for some buggy certificates */
609 if (x->ex_nscert & NS_SSL_CLIENT)
616 static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x,
620 ret = purpose_smime(x, ca);
623 if (ku_reject(x, KU_DIGITAL_SIGNATURE | KU_NON_REPUDIATION))
628 static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x,
632 ret = purpose_smime(x, ca);
635 if (ku_reject(x, KU_KEY_ENCIPHERMENT))
640 static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x,
645 if ((ca_ret = check_ca(x)) != 2)
650 if (ku_reject(x, KU_CRL_SIGN))
656 * OCSP helper: this is *not* a full OCSP check. It just checks that each CA
657 * is valid. Additional checks must be made on the chain.
660 static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca)
663 * Must be a valid CA. Should we really support the "I don't know" value
668 /* leaf certificate is checked in OCSP_verify() */
672 static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca)
678 * Various checks to see if one certificate issued the second.
679 * This can be used to prune a set of possible issuer certificates
680 * which have been looked up using some simple method such as by
683 * 1. Check issuer_name(subject) == subject_name(issuer)
684 * 2. If akid(subject) exists check it matches issuer
685 * 3. If key_usage(issuer) exists check it supports certificate signing
686 * returns 0 for OK, positive for reason for mismatch, reasons match
687 * codes for X509_verify_cert()
690 int X509_check_issued(X509 *issuer, X509 *subject)
692 if (X509_NAME_cmp(X509_get_subject_name(issuer),
693 X509_get_issuer_name(subject)))
694 return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
695 x509v3_cache_extensions(issuer);
696 x509v3_cache_extensions(subject);
698 /* Check key ids (if present) */
699 if (subject->akid->keyid && issuer->skid &&
700 ASN1_OCTET_STRING_cmp(subject->akid->keyid, issuer->skid))
701 return X509_V_ERR_AKID_SKID_MISMATCH;
702 /* Check serial number */
703 if (subject->akid->serial &&
704 ASN1_INTEGER_cmp(X509_get_serialNumber(issuer),
705 subject->akid->serial))
706 return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
707 /* Check issuer name */
708 if (subject->akid->issuer) {
710 * Ugh, for some peculiar reason AKID includes SEQUENCE OF
711 * GeneralName. So look for a DirName. There may be more than one
712 * but we only take any notice of the first.
716 X509_NAME *nm = NULL;
718 gens = subject->akid->issuer;
719 for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
720 gen = sk_GENERAL_NAME_value(gens, i);
721 if (gen->type == GEN_DIRNAME) {
726 if (nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
727 return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
730 if (subject->ex_flags & EXFLAG_PROXY) {
731 if (ku_reject(issuer, KU_DIGITAL_SIGNATURE))
732 return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
733 } else if (ku_reject(issuer, KU_KEY_CERT_SIGN))
734 return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;