Add support for nameRelativeToCRLIssuer field in distribution point name
[openssl.git] / crypto / x509v3 / v3_purp.c
index 8d0ebbeaef84e7c4f8cb86340738bdd35d401f95..caf80e6d3f971390fb92f3f1fe2891d6715da710 100644 (file)
@@ -71,6 +71,7 @@ static int purpose_smime(const X509 *x, int ca);
 static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
 static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca);
 static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
 static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca);
 static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca);
 
@@ -87,6 +88,7 @@ static X509_PURPOSE xstandard[] = {
        {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign, "CRL signing", "crlsign", NULL},
        {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any", NULL},
        {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper, "OCSP helper", "ocsphelper", NULL},
+       {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0, check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign", NULL},
 };
 
 #define X509_PURPOSE_COUNT (sizeof(xstandard)/sizeof(X509_PURPOSE))
@@ -285,7 +287,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,      /* 663 */
+               NID_inhibit_any_policy  /* 748 */
        };
 
        int ex_nid;
@@ -301,11 +311,41 @@ int X509_supported_extension(X509_EXTENSION *ex)
                return 1;
        return 0;
        }
+
+static void setup_dp(X509 *x, DIST_POINT *dp)
+       {
+       X509_NAME *iname = NULL;
+       int i;
+       if (!dp->distpoint || (dp->distpoint->type != 1))
+               return;
+       for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++)
+               {
+               GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i);
+               if (gen->type == GEN_DIRNAME)
+                       {
+                       iname = gen->d.directoryName;
+                       break;
+                       }
+               }
+       if (!iname)
+               iname = X509_get_issuer_name(x);
+
+       DIST_POINT_set_dpname(dp->distpoint, iname);
+
+       }
+
+static void setup_crldp(X509 *x)
+       {
+       int i;
+       x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL);
+       for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++)
+               setup_dp(x, sk_DIST_POINT_value(x->crldp, i));
+       }
 
 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 +358,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 +374,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 +448,14 @@ 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);
+       setup_crldp(x);
+                       
+                       
+#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);
@@ -441,8 +503,6 @@ static int check_ca(const 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;
        }
@@ -568,6 +628,41 @@ static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca)
        return 1;
 }
 
+static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
+                                       int ca)
+{
+       int i_ext;
+
+       /* If ca is true we must return if this is a valid CA certificate. */
+       if (ca) return check_ca(x);
+
+       /* 
+        * Check the optional key usage field:
+        * if Key Usage is present, it must be one of digitalSignature 
+        * and/or nonRepudiation (other values are not consistent and shall
+        * be rejected).
+        */
+       if ((x->ex_flags & EXFLAG_KUSAGE)
+           && ((x->ex_kusage & ~(KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)) ||
+               !(x->ex_kusage & (KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE))))
+               return 0;
+
+       /* Only time stamp key usage is permitted and it's required. */
+       if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP)
+               return 0;
+
+       /* Extended Key Usage MUST be critical */
+       i_ext = X509_get_ext_by_NID((X509 *) x, NID_ext_key_usage, 0);
+       if (i_ext >= 0)
+               {
+               X509_EXTENSION *ext = X509_get_ext((X509 *) x, i_ext);
+               if (!X509_EXTENSION_get_critical(ext))
+                       return 0;
+               }
+
+       return 1;
+}
+
 static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca)
 {
        return 1;
@@ -592,40 +687,63 @@ int X509_check_issued(X509 *issuer, X509 *subject)
                                return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
        x509v3_cache_extensions(issuer);
        x509v3_cache_extensions(subject);
-       if(subject->akid) {
-               /* Check key ids (if present) */
-               if(subject->akid->keyid && issuer->skid &&
-                ASN1_OCTET_STRING_cmp(subject->akid->keyid, issuer->skid) )
+
+       if(subject->akid)
+               {
+               int ret = X509_check_akid(issuer, subject->akid);
+               if (ret != X509_V_OK)
+                       return ret;
+               }
+
+       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;
+}
+
+int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid)
+       {
+
+       if(!akid)
+               return X509_V_OK;
+
+       /* Check key ids (if present) */
+       if(akid->keyid && issuer->skid &&
+                ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid) )
                                return X509_V_ERR_AKID_SKID_MISMATCH;
-               /* Check serial number */
-               if(subject->akid->serial &&
-                       ASN1_INTEGER_cmp(X509_get_serialNumber(issuer),
-                                               subject->akid->serial))
+       /* Check serial number */
+       if(akid->serial &&
+               ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial))
                                return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
-               /* Check issuer name */
-               if(subject->akid->issuer) {
-                       /* Ugh, for some peculiar reason AKID includes
-                        * SEQUENCE OF GeneralName. So look for a DirName.
-                        * There may be more than one but we only take any
-                        * notice of the first.
-                        */
-                       GENERAL_NAMES *gens;
-                       GENERAL_NAME *gen;
-                       X509_NAME *nm = NULL;
-                       int i;
-                       gens = subject->akid->issuer;
-                       for(i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
-                               gen = sk_GENERAL_NAME_value(gens, i);
-                               if(gen->type == GEN_DIRNAME) {
-                                       nm = gen->d.dirn;
-                                       break;
+       /* Check issuer name */
+       if(akid->issuer)
+               {
+               /* Ugh, for some peculiar reason AKID includes
+                * SEQUENCE OF GeneralName. So look for a DirName.
+                * There may be more than one but we only take any
+                * notice of the first.
+                */
+               GENERAL_NAMES *gens;
+               GENERAL_NAME *gen;
+               X509_NAME *nm = NULL;
+               int i;
+               gens = akid->issuer;
+               for(i = 0; i < sk_GENERAL_NAME_num(gens); i++)
+                       {
+                       gen = sk_GENERAL_NAME_value(gens, i);
+                       if(gen->type == GEN_DIRNAME)
+                               {
+                               nm = gen->d.dirn;
+                               break;
                                }
                        }
-                       if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
-                               return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
+               if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
+                       return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
                }
-       }
-       if(ku_reject(issuer, KU_KEY_CERT_SIGN)) return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
        return X509_V_OK;
-}
+       }