summaryrefslogtreecommitdiff
path: root/source4/heimdal/lib/hx509/cert.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/heimdal/lib/hx509/cert.c')
-rw-r--r--source4/heimdal/lib/hx509/cert.c169
1 files changed, 120 insertions, 49 deletions
diff --git a/source4/heimdal/lib/hx509/cert.c b/source4/heimdal/lib/hx509/cert.c
index 121847faaa..cd9ae01fac 100644
--- a/source4/heimdal/lib/hx509/cert.c
+++ b/source4/heimdal/lib/hx509/cert.c
@@ -32,7 +32,6 @@
*/
#include "hx_locl.h"
-RCSID("$Id$");
#include "crypto-headers.h"
#include <rtbl.h>
@@ -59,6 +58,7 @@ struct hx509_verify_ctx_data {
#define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
#define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
#define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
+#define HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK 32
time_t time_now;
unsigned int max_depth;
#define HX509_VERIFY_MAX_DEPTH 30
@@ -432,6 +432,7 @@ hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
* Set the trust anchors in the verification context, makes an
* reference to the keyset, so the consumer can free the keyset
* independent of the destruction of the verification context (ctx).
+ * If there already is a keyset attached, it's released.
*
* @param ctx a verification context
* @param set a keyset containing the trust anchors.
@@ -442,6 +443,8 @@ hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
void
hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
{
+ if (ctx->trust_anchors)
+ hx509_certs_free(&ctx->trust_anchors);
ctx->trust_anchors = _hx509_certs_ref(set);
}
@@ -569,6 +572,16 @@ hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
}
+void
+hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx,
+ int boolean)
+{
+ if (boolean)
+ ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
+ else
+ ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
+}
+
static const Extension *
find_extension(const Certificate *cert, const heim_oid *oid, int *idx)
{
@@ -594,7 +607,7 @@ find_extension_auth_key_id(const Certificate *subject,
memset(ai, 0, sizeof(*ai));
- e = find_extension(subject, oid_id_x509_ce_authorityKeyIdentifier(), &i);
+ e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i);
if (e == NULL)
return HX509_EXTENSION_NOT_FOUND;
@@ -613,7 +626,7 @@ _hx509_find_extension_subject_key_id(const Certificate *issuer,
memset(si, 0, sizeof(*si));
- e = find_extension(issuer, oid_id_x509_ce_subjectKeyIdentifier(), &i);
+ e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i);
if (e == NULL)
return HX509_EXTENSION_NOT_FOUND;
@@ -632,7 +645,7 @@ find_extension_name_constraints(const Certificate *subject,
memset(nc, 0, sizeof(*nc));
- e = find_extension(subject, oid_id_x509_ce_nameConstraints(), &i);
+ e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i);
if (e == NULL)
return HX509_EXTENSION_NOT_FOUND;
@@ -650,7 +663,7 @@ find_extension_subject_alt_name(const Certificate *cert, int *i,
memset(sa, 0, sizeof(*sa));
- e = find_extension(cert, oid_id_x509_ce_subjectAltName(), i);
+ e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i);
if (e == NULL)
return HX509_EXTENSION_NOT_FOUND;
@@ -668,7 +681,7 @@ find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
memset(eku, 0, sizeof(*eku));
- e = find_extension(cert, oid_id_x509_ce_extKeyUsage(), &i);
+ e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i);
if (e == NULL)
return HX509_EXTENSION_NOT_FOUND;
@@ -748,8 +761,7 @@ hx509_cert_find_subjectAltName_otherName(hx509_context context,
ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
i++;
if (ret == HX509_EXTENSION_NOT_FOUND) {
- ret = 0;
- break;
+ return 0;
} else if (ret != 0) {
hx509_set_error_string(context, 0, ret, "Error searching for SAN");
hx509_free_octet_string_list(list);
@@ -773,7 +785,6 @@ hx509_cert_find_subjectAltName_otherName(hx509_context context,
}
free_GeneralNames(&sa);
}
- return 0;
}
@@ -790,7 +801,7 @@ check_key_usage(hx509_context context, const Certificate *cert,
if (_hx509_cert_get_version(cert) < 3)
return 0;
- e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
+ e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
if (e == NULL) {
if (req_present) {
hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
@@ -847,7 +858,7 @@ check_basic_constraints(hx509_context context, const Certificate *cert,
if (_hx509_cert_get_version(cert) < 3)
return 0;
- e = find_extension(cert, oid_id_x509_ce_basicConstraints(), &i);
+ e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i);
if (e == NULL) {
switch(type) {
case PROXY_CERT:
@@ -1134,7 +1145,7 @@ is_proxy_cert(hx509_context context,
if (rinfo)
memset(rinfo, 0, sizeof(*rinfo));
- e = find_extension(cert, oid_id_pkix_pe_proxyCertInfo(), &i);
+ e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i);
if (e == NULL) {
hx509_clear_error_string(context);
return HX509_EXTENSION_NOT_FOUND;
@@ -1472,7 +1483,9 @@ hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *s
* @param context a hx509 context.
* @param p a hx509 certificate object.
* @param alg AlgorithmIdentifier, should be freed with
- * free_AlgorithmIdentifier().
+ * free_AlgorithmIdentifier(). The algorithmidentifier is
+ * typicly rsaEncryption, or id-ecPublicKey, or some other
+ * public key mechanism.
*
* @return An hx509 error code, see hx509_get_error_string().
*
@@ -2003,7 +2016,7 @@ hx509_verify_path(hx509_context context,
free_ProxyCertInfo(&info);
j = 0;
- if (find_extension(c, oid_id_x509_ce_subjectAltName(), &j)) {
+ if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) {
ret = HX509_PROXY_CERT_INVALID;
hx509_set_error_string(context, 0, ret,
"Proxy certificate have explicity "
@@ -2012,7 +2025,7 @@ hx509_verify_path(hx509_context context,
}
j = 0;
- if (find_extension(c, oid_id_x509_ce_issuerAltName(), &j)) {
+ if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) {
ret = HX509_PROXY_CERT_INVALID;
hx509_set_error_string(context, 0, ret,
"Proxy certificate have explicity "
@@ -2053,7 +2066,7 @@ hx509_verify_path(hx509_context context,
if (proxy_issuer.u.rdnSequence.len < 2
|| proxy_issuer.u.rdnSequence.val[j - 1].len > 1
|| der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
- oid_id_at_commonName()))
+ &asn1_oid_id_at_commonName))
{
ret = HX509_PROXY_CERT_NAME_WRONG;
hx509_set_error_string(context, 0, ret,
@@ -2263,6 +2276,24 @@ hx509_verify_path(hx509_context context,
"Failed to verify signature of certificate");
goto out;
}
+ /*
+ * Verify that the sigature algorithm "best-before" date is
+ * before the creation date of the certificate, do this for
+ * trust anchors too, since any trust anchor that is created
+ * after a algorithm is known to be bad deserved to be invalid.
+ *
+ * Skip the leaf certificate for now...
+ */
+
+ if (i != 0 && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) {
+ time_t notBefore =
+ _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
+ ret = _hx509_signature_best_before(context,
+ &c->signatureAlgorithm,
+ notBefore);
+ if (ret)
+ goto out;
+ }
}
out:
@@ -2329,6 +2360,7 @@ hx509_verify_hostname(hx509_context context,
/* XXX krb5_socklen_t */ int sa_size)
{
GeneralNames san;
+ const Name *name;
int ret, i, j;
if (sa && sa_size <= 0)
@@ -2339,11 +2371,10 @@ hx509_verify_hostname(hx509_context context,
i = 0;
do {
ret = find_extension_subject_alt_name(cert->data, &i, &san);
- if (ret == HX509_EXTENSION_NOT_FOUND) {
- ret = 0;
- break;
- } else if (ret != 0)
+ if (ret == HX509_EXTENSION_NOT_FOUND)
break;
+ else if (ret != 0)
+ return HX509_PARSING_NAME_FAILED;
for (j = 0; j < san.len; j++) {
switch (san.val[j].element) {
@@ -2360,31 +2391,31 @@ hx509_verify_hostname(hx509_context context,
free_GeneralNames(&san);
} while (1);
- {
- const Name *name = &cert->data->tbsCertificate.subject;
-
- /* match if first component is a CN= */
- if (name->u.rdnSequence.len > 0
- && name->u.rdnSequence.val[0].len == 1
- && der_heim_oid_cmp(&name->u.rdnSequence.val[0].val[0].type,
- oid_id_at_commonName()) == 0)
- {
- DirectoryString *ds = &name->u.rdnSequence.val[0].val[0].value;
-
- switch (ds->element) {
- case choice_DirectoryString_printableString:
- if (strcasecmp(ds->u.printableString, hostname) == 0)
- return 0;
- break;
- case choice_DirectoryString_ia5String:
- if (strcasecmp(ds->u.ia5String, hostname) == 0)
+ name = &cert->data->tbsCertificate.subject;
+
+ /* Find first CN= in the name, and try to match the hostname on that */
+ for (ret = 0, i = name->u.rdnSequence.len - 1; ret == 0 && i >= 0; i--) {
+ for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) {
+ AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j];
+
+ if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) {
+ DirectoryString *ds = &n->value;
+ switch (ds->element) {
+ case choice_DirectoryString_printableString:
+ if (strcasecmp(ds->u.printableString, hostname) == 0)
+ return 0;
+ break;
+ case choice_DirectoryString_ia5String:
+ if (strcasecmp(ds->u.ia5String, hostname) == 0)
return 0;
- break;
- case choice_DirectoryString_utf8String:
- if (strcasecmp(ds->u.utf8String, hostname) == 0)
- return 0;
- default:
- break;
+ break;
+ case choice_DirectoryString_utf8String:
+ if (strcasecmp(ds->u.utf8String, hostname) == 0)
+ return 0;
+ default:
+ break;
+ }
+ ret = HX509_NAME_CONSTRAINT_ERROR;
}
}
}
@@ -2495,7 +2526,7 @@ hx509_cert_get_friendly_name(hx509_cert cert)
if (cert->friendlyname)
return cert->friendlyname;
- a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_friendlyName());
+ a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName);
if (a == NULL) {
hx509_name name;
@@ -2746,7 +2777,7 @@ hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr)
int
hx509_query_match_cmp_func(hx509_query *q,
- int (*func)(void *, hx509_cert),
+ int (*func)(hx509_context, hx509_cert, void *),
void *ctx)
{
if (func)
@@ -2869,7 +2900,7 @@ _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert
if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
hx509_cert_attribute a;
- a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId());
+ a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId);
if (a == NULL)
return 0;
if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
@@ -2891,7 +2922,7 @@ _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert
return 0;
}
if (q->match & HX509_QUERY_MATCH_FUNCTION) {
- ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
+ ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx);
if (ret != 0)
return 0;
}
@@ -3163,7 +3194,7 @@ _hx509_cert_get_keyusage(hx509_context context,
if (_hx509_cert_get_version(cert) < 3)
return 0;
- e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
+ e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
if (e == NULL)
return HX509_KU_CERT_MISSING;
@@ -3348,6 +3379,46 @@ _hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env)
}
}
+ {
+ Certificate *c = _hx509_get_cert(cert);
+ heim_octet_string os, sig;
+ hx509_env envhash = NULL;
+ char *buf;
+
+ os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
+ os.length =
+ c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
+
+ ret = _hx509_create_signature(context,
+ NULL,
+ hx509_signature_sha1(),
+ &os,
+ NULL,
+ &sig);
+ if (ret != 0)
+ goto out;
+
+ ret = hex_encode(sig.data, sig.length, &buf);
+ der_free_octet_string(&sig);
+ if (ret < 0) {
+ ret = ENOMEM;
+ hx509_set_error_string(context, 0, ret,
+ "Out of memory");
+ goto out;
+ }
+
+ ret = hx509_env_add(context, &envhash, "sha1", buf);
+ free(buf);
+ if (ret)
+ goto out;
+
+ ret = hx509_env_add_binding(context, &envcert, "hash", envhash);
+ if (ret) {
+ hx509_env_free(&envhash);
+ goto out;
+ }
+ }
+
ret = hx509_env_add_binding(context, env, "certificate", envcert);
if (ret)
goto out;