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);
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);
{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))
NID_key_usage, /* 83 */
NID_subject_alt_name, /* 85 */
NID_basic_constraints, /* 87 */
- NID_ext_key_usage /* 126 */
+ NID_ext_key_usage, /* 126 */
+ NID_proxyCertInfo /* 661 */
};
int ex_nid;
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;
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) {
}
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->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL);
for (i = 0; i < X509_get_ext_count(x); i++)
{
ex = X509_get_ext(x, i);
#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;
/* 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;
}
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) {
{
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;
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;
}
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;
}