PR: 2411
[oweals/openssl.git] / crypto / x509v3 / v3_purp.c
index d37e79481a9baacdeb3e182750b013f67d6f6aa1..e18751e01cbcdbca14bc8ed6d6bb0c2c162f1d77 100644 (file)
@@ -1,5 +1,5 @@
 /* v3_purp.c */
-/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
  * project 2001.
  */
 /* ====================================================================
@@ -285,7 +285,15 @@ int X509_supported_extension(X509_EXTENSION *ex)
                NID_key_usage,          /* 83 */
                NID_subject_alt_name,   /* 85 */
                NID_basic_constraints,  /* 87 */
-               NID_ext_key_usage       /* 126 */
+               NID_certificate_policies, /* 89 */
+               NID_ext_key_usage,      /* 126 */
+#ifndef OPENSSL_NO_RFC3779
+               NID_sbgp_ipAddrBlock,   /* 290 */
+               NID_sbgp_autonomousSysNum, /* 291 */
+#endif
+               NID_policy_constraints, /* 401 */
+               NID_proxyCertInfo,      /* 661 */
+               NID_inhibit_any_policy  /* 748 */
        };
 
        int ex_nid;
@@ -306,6 +314,7 @@ int X509_supported_extension(X509_EXTENSION *ex)
 static void x509v3_cache_extensions(X509 *x)
 {
        BASIC_CONSTRAINTS *bs;
+       PROXY_CERT_INFO_EXTENSION *pci;
        ASN1_BIT_STRING *usage;
        ASN1_BIT_STRING *ns;
        EXTENDED_KEY_USAGE *extusage;
@@ -318,7 +327,7 @@ static void x509v3_cache_extensions(X509 *x)
 #endif
        /* Does subject name match issuer ? */
        if(!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)))
-                        x->ex_flags |= EXFLAG_SS;
+                        x->ex_flags |= EXFLAG_SI;
        /* V1 should mean no extensions ... */
        if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1;
        /* Handle basic constraints */
@@ -334,6 +343,20 @@ static void x509v3_cache_extensions(X509 *x)
                BASIC_CONSTRAINTS_free(bs);
                x->ex_flags |= EXFLAG_BCONS;
        }
+       /* Handle proxy certificates */
+       if((pci=X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) {
+               if (x->ex_flags & EXFLAG_CA
+                   || X509_get_ext_by_NID(x, NID_subject_alt_name, 0) >= 0
+                   || X509_get_ext_by_NID(x, NID_issuer_alt_name, 0) >= 0) {
+                       x->ex_flags |= EXFLAG_INVALID;
+               }
+               if (pci->pcPathLengthConstraint) {
+                       x->ex_pcpathlen =
+                               ASN1_INTEGER_get(pci->pcPathLengthConstraint);
+               } else x->ex_pcpathlen = -1;
+               PROXY_CERT_INFO_EXTENSION_free(pci);
+               x->ex_flags |= EXFLAG_PROXY;
+       }
        /* Handle key usage */
        if((usage=X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) {
                if(usage->length > 0) {
@@ -394,6 +417,11 @@ static void x509v3_cache_extensions(X509 *x)
        }
        x->skid =X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL);
        x->akid =X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL);
+#ifndef OPENSSL_NO_RFC3779
+       x->rfc3779_addr =X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, NULL, NULL);
+       x->rfc3779_asid =X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum,
+                                         NULL, NULL);
+#endif
        for (i = 0; i < X509_get_ext_count(x); i++)
                {
                ex = X509_get_ext(x, i);
@@ -425,14 +453,8 @@ static void x509v3_cache_extensions(X509 *x)
 #define ns_reject(x, usage) \
        (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
 
-int X509_check_ca(X509 *x)
+static int check_ca(const X509 *x)
 {
-       if(!(x->ex_flags & EXFLAG_SET)) {
-               CRYPTO_w_lock(CRYPTO_LOCK_X509);
-               x509v3_cache_extensions(x);
-               CRYPTO_w_unlock(CRYPTO_LOCK_X509);
-       }
-
        /* keyUsage if present should allow cert signing */
        if(ku_reject(x, KU_KEY_CERT_SIGN)) return 0;
        if(x->ex_flags & EXFLAG_BCONS) {
@@ -447,18 +469,27 @@ int X509_check_ca(X509 *x)
                /* Older certificates could have Netscape-specific CA types */
                else if (x->ex_flags & EXFLAG_NSCERT
                         && x->ex_nscert & NS_ANY_CA) return 5;
-               /* 2 means "I don't know...", which is legal for V1 and V2 */
-               else if (x->ex_flags & EXFLAG_V1) return 2;
                /* can this still be regarded a CA certificate?  I doubt it */
                return 0;
        }
 }
 
+int X509_check_ca(X509 *x)
+{
+       if(!(x->ex_flags & EXFLAG_SET)) {
+               CRYPTO_w_lock(CRYPTO_LOCK_X509);
+               x509v3_cache_extensions(x);
+               CRYPTO_w_unlock(CRYPTO_LOCK_X509);
+       }
+
+       return check_ca(x);
+}
+
 /* Check SSL CA: common checks for SSL client and server */
 static int check_ssl_ca(const X509 *x)
 {
        int ca_ret;
-       ca_ret = X509_check_ca(x);
+       ca_ret = check_ca(x);
        if(!ca_ret) return 0;
        /* check nsCertType if present */
        if(ca_ret != 5 || x->ex_nscert & NS_SSL_CA) return ca_ret;
@@ -506,7 +537,7 @@ static int purpose_smime(const X509 *x, int ca)
        if(xku_reject(x,XKU_SMIME)) return 0;
        if(ca) {
                int ca_ret;
-               ca_ret = X509_check_ca(x);
+               ca_ret = check_ca(x);
                if(!ca_ret) return 0;
                /* check nsCertType if present */
                if(ca_ret != 5 || x->ex_nscert & NS_SMIME_CA) return ca_ret;
@@ -543,7 +574,7 @@ static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca)
 {
        if(ca) {
                int ca_ret;
-               if((ca_ret = X509_check_ca(x)) != 2) return ca_ret;
+               if((ca_ret = check_ca(x)) != 2) return ca_ret;
                else return 0;
        }
        if(ku_reject(x, KU_CRL_SIGN)) return 0;
@@ -558,7 +589,7 @@ static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca)
 {
        /* Must be a valid CA.  Should we really support the "I don't know"
           value (2)? */
-       if(ca) return X509_check_ca(x);
+       if(ca) return check_ca(x);
        /* leaf certificate is checked in OCSP_verify() */
        return 1;
 }
@@ -620,7 +651,13 @@ int X509_check_issued(X509 *issuer, X509 *subject)
                                return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
                }
        }
-       if(ku_reject(issuer, KU_KEY_CERT_SIGN)) return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
+       if(subject->ex_flags & EXFLAG_PROXY)
+               {
+               if(ku_reject(issuer, KU_DIGITAL_SIGNATURE))
+                       return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
+               }
+       else if(ku_reject(issuer, KU_KEY_CERT_SIGN))
+               return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
        return X509_V_OK;
 }