X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fx509v3%2Fv3_purp.c;h=1ca370dc0b86caacf76af44c5c3e74a4eba4433b;hp=67596862ab3c213de2670975f5ea99b633ee20b0;hb=d43c4497ce1611373c3a3e5b433dfde4907d1a69;hpb=bc501570109e7837e1de1689de1eec9420e4cf89 diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c index 67596862ab..1ca370dc0b 100644 --- a/crypto/x509v3/v3_purp.c +++ b/crypto/x509v3/v3_purp.c @@ -63,7 +63,6 @@ static void x509v3_cache_extensions(X509 *x); -static int ca_check(const X509 *x); static int check_ssl_ca(const X509 *x); static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca); static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca); @@ -72,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); @@ -88,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)) @@ -286,7 +287,17 @@ 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_name_constraints, /* 666 */ + NID_policy_mappings, /* 747 */ + NID_inhibit_any_policy /* 748 */ }; int ex_nid; @@ -302,11 +313,51 @@ 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->reasons) + { + if (dp->reasons->length > 0) + dp->dp_reasons = dp->reasons->data[0]; + if (dp->reasons->length > 1) + dp->dp_reasons |= (dp->reasons->data[1] << 8); + dp->dp_reasons &= CRLDP_ALL_REASONS; + } + else + dp->dp_reasons = CRLDP_ALL_REASONS; + 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; @@ -319,7 +370,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 */ @@ -335,6 +386,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) { @@ -395,11 +460,25 @@ 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); if (!X509_EXTENSION_get_critical(ex)) continue; + if (OBJ_obj2nid(X509_EXTENSION_get_object(ex)) + == NID_freshest_crl) + x->ex_flags |= EXFLAG_FRESHEST; if (!X509_supported_extension(ex)) { x->ex_flags |= EXFLAG_CRITICAL; @@ -426,7 +505,7 @@ static void x509v3_cache_extensions(X509 *x) #define ns_reject(x, usage) \ (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage))) -static int ca_check(const X509 *x) +static int check_ca(const X509 *x) { /* keyUsage if present should allow cert signing */ if(ku_reject(x, KU_KEY_CERT_SIGN)) return 0; @@ -435,25 +514,37 @@ static int ca_check(const X509 *x) /* If basicConstraints says not a CA then say so */ else return 0; } else { + /* we support V1 roots for... uh, I don't really know why. */ if((x->ex_flags & V1_ROOT) == V1_ROOT) return 3; /* If key usage present it must have certSign so tolerate it */ else if (x->ex_flags & EXFLAG_KUSAGE) return 4; - else return 2; + /* Older certificates could have Netscape-specific CA types */ + else if (x->ex_flags & EXFLAG_NSCERT + && x->ex_nscert & NS_ANY_CA) return 5; + /* 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 = ca_check(x); + ca_ret = check_ca(x); if(!ca_ret) return 0; /* check nsCertType if present */ - if(x->ex_flags & EXFLAG_NSCERT) { - if(x->ex_nscert & NS_SSL_CA) return ca_ret; - return 0; - } - if(ca_ret != 2) return ca_ret; + if(ca_ret != 5 || x->ex_nscert & NS_SSL_CA) return ca_ret; else return 0; } @@ -498,14 +589,10 @@ static int purpose_smime(const X509 *x, int ca) if(xku_reject(x,XKU_SMIME)) return 0; if(ca) { int ca_ret; - ca_ret = ca_check(x); + ca_ret = check_ca(x); if(!ca_ret) return 0; /* check nsCertType if present */ - if(x->ex_flags & EXFLAG_NSCERT) { - if(x->ex_nscert & NS_SMIME_CA) return ca_ret; - return 0; - } - if(ca_ret != 2) return ca_ret; + if(ca_ret != 5 || x->ex_nscert & NS_SMIME_CA) return ca_ret; else return 0; } if(x->ex_flags & EXFLAG_NSCERT) { @@ -539,7 +626,7 @@ static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca) { if(ca) { int ca_ret; - if((ca_ret = ca_check(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; @@ -552,18 +639,45 @@ static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca) static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca) { - /* Must be a valid CA */ - if(ca) { - int ca_ret; - ca_ret = ca_check(x); - if(ca_ret != 2) return ca_ret; - if(x->ex_flags & EXFLAG_NSCERT) { - if(x->ex_nscert & NS_ANY_CA) return ca_ret; + /* Must be a valid CA. Should we really support the "I don't know" + value (2)? */ + if(ca) return check_ca(x); + /* leaf certificate is checked in OCSP_verify() */ + 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 0; - } - /* leaf certificate is checked in OCSP_verify() */ + return 1; } @@ -591,40 +705,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; -} + }