Support for policy mappings extension.
[openssl.git] / crypto / x509v3 / v3_purp.c
index 9f992c9087598a7125b140252baa7714106e6417..bdf72227e583af60a7e67303b4652b8e55755b97 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,8 +287,17 @@ int X509_supported_extension(X509_EXTENSION *ex)
                NID_key_usage,          /* 83 */
                NID_subject_alt_name,   /* 85 */
                NID_basic_constraints,  /* 87 */
+               NID_certificate_policies, /* 89 */
                NID_ext_key_usage,      /* 126 */
-               NID_proxyCertInfo       /* 661 */
+#ifndef OPENSSL_NO_RFC3779
+               NID_sbgp_ipAddrBlock,   /* 290 */
+               NID_sbgp_autonomousSysNum, /* 291 */
+#endif
+               NID_policy_constraints, /* 401 */
+               NID_proxyCertInfo,      /* 663 */
+               NID_name_constraints,   /* 666 */
+               NID_policy_mappings,    /* 747 */
+               NID_inhibit_any_policy  /* 748 */
        };
 
        int ex_nid;
@@ -302,7 +313,36 @@ 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)
 {
@@ -320,7 +360,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 */
@@ -338,7 +378,9 @@ static void x509v3_cache_extensions(X509 *x)
        }
        /* Handle proxy certificates */
        if((pci=X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) {
-               if (x->ex_flags & EXFLAG_CA) {
+               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) {
@@ -408,6 +450,18 @@ 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);
+       x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
+       x->nc = X509_get_ext_d2i(x, NID_name_constraints, &i, NULL);
+       if (!x->nc && (i != -1))
+               x->ex_flags |= EXFLAG_INVALID;
+       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);
@@ -580,6 +634,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;
@@ -604,39 +693,14 @@ 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) )
-                               return X509_V_ERR_AKID_SKID_MISMATCH;
-               /* Check serial number */
-               if(subject->akid->serial &&
-                       ASN1_INTEGER_cmp(X509_get_serialNumber(issuer),
-                                               subject->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;
-                               }
-                       }
-                       if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
-                               return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
+
+       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))
@@ -647,3 +711,45 @@ int X509_check_issued(X509 *issuer, X509 *subject)
        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(akid->serial &&
+               ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial))
+                               return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
+       /* 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;
+               }
+       return X509_V_OK;
+       }
+