From 9b261c008a395a323e0516f4cd3f3134aa050577 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 8 Jun 2009 19:06:16 +1000 Subject: s4:heimdal: import lorikeet-heimdal-200906080040 (commit 904d0124b46eed7a8ad6e5b73e892ff34b6865ba) Also including the supporting changes required to pass make test A number of heimdal functions and constants have changed since we last imported a tree (for the better, but inconvenient for us). Andrew Bartlett --- source4/heimdal/lib/hx509/ca.c | 32 +- source4/heimdal/lib/hx509/cert.c | 169 ++++-- source4/heimdal/lib/hx509/cms.c | 478 ++++++++++----- source4/heimdal/lib/hx509/collector.c | 5 +- source4/heimdal/lib/hx509/crypto.c | 995 ++++++++++++++++++++++++-------- source4/heimdal/lib/hx509/env.c | 1 - source4/heimdal/lib/hx509/error.c | 1 - source4/heimdal/lib/hx509/file.c | 1 - source4/heimdal/lib/hx509/hx509.h | 19 +- source4/heimdal/lib/hx509/hx509_err.et | 5 +- source4/heimdal/lib/hx509/hx_locl.h | 4 +- source4/heimdal/lib/hx509/keyset.c | 76 ++- source4/heimdal/lib/hx509/ks_dir.c | 3 +- source4/heimdal/lib/hx509/ks_file.c | 100 +++- source4/heimdal/lib/hx509/ks_keychain.c | 63 +- source4/heimdal/lib/hx509/ks_mem.c | 1 - source4/heimdal/lib/hx509/ks_null.c | 1 - source4/heimdal/lib/hx509/ks_p11.c | 11 +- source4/heimdal/lib/hx509/ks_p12.c | 45 +- source4/heimdal/lib/hx509/lock.c | 1 - source4/heimdal/lib/hx509/name.c | 63 +- source4/heimdal/lib/hx509/peer.c | 34 +- source4/heimdal/lib/hx509/print.c | 37 +- source4/heimdal/lib/hx509/req.c | 1 - source4/heimdal/lib/hx509/revoke.c | 8 +- source4/heimdal/lib/hx509/sel-gram.y | 1 - source4/heimdal/lib/hx509/test_name.c | 1 - 27 files changed, 1570 insertions(+), 586 deletions(-) (limited to 'source4/heimdal/lib/hx509') diff --git a/source4/heimdal/lib/hx509/ca.c b/source4/heimdal/lib/hx509/ca.c index cbd58ebd01..624d74289d 100644 --- a/source4/heimdal/lib/hx509/ca.c +++ b/source4/heimdal/lib/hx509/ca.c @@ -33,7 +33,6 @@ #include "hx_locl.h" #include -RCSID("$Id$"); /** * @page page_ca Hx509 CA functions @@ -672,7 +671,7 @@ hx509_ca_tbs_add_san_pkinit(hx509_context context, ret = hx509_ca_tbs_add_san_otherName(context, tbs, - oid_id_pkinit_san(), + &asn1_oid_id_pkinit_san, &os); free(os.data); out: @@ -736,7 +735,7 @@ hx509_ca_tbs_add_san_ms_upn(hx509_context context, hx509_ca_tbs tbs, const char *principal) { - return add_utf8_san(context, tbs, oid_id_pkinit_ms_san(), principal); + return add_utf8_san(context, tbs, &asn1_oid_id_pkinit_ms_san, principal); } /** @@ -757,7 +756,7 @@ hx509_ca_tbs_add_san_jid(hx509_context context, hx509_ca_tbs tbs, const char *jid) { - return add_utf8_san(context, tbs, oid_id_pkix_on_xmppAddr(), jid); + return add_utf8_san(context, tbs, &asn1_oid_id_pkix_on_xmppAddr, jid); } @@ -926,7 +925,7 @@ build_proxy_prefix(hx509_context context, const Name *issuer, Name *subject) return ENOMEM; } /* prefix with CN=,...*/ - ret = _hx509_name_modify(context, subject, 1, oid_id_at_commonName(), tstr); + ret = _hx509_name_modify(context, subject, 1, &asn1_oid_id_at_commonName, tstr); free(tstr); if (ret) free_Name(subject); @@ -1110,7 +1109,7 @@ ca_sign(hx509_context context, data.length = 34; ret = add_extension(context, tbsc, 0, - oid_id_ms_cert_enroll_domaincontroller(), + &asn1_oid_id_ms_cert_enroll_domaincontroller, &data); if (ret) goto out; @@ -1129,7 +1128,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, 1, - oid_id_x509_ce_keyUsage(), &data); + &asn1_oid_id_x509_ce_keyUsage, &data); free(data.data); if (ret) goto out; @@ -1146,7 +1145,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, 0, - oid_id_x509_ce_extKeyUsage(), &data); + &asn1_oid_id_x509_ce_extKeyUsage, &data); free(data.data); if (ret) goto out; @@ -1163,7 +1162,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, 0, - oid_id_x509_ce_subjectAltName(), + &asn1_oid_id_x509_ce_subjectAltName, &data); free(data.data); if (ret) @@ -1181,7 +1180,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, 0, - oid_id_x509_ce_authorityKeyIdentifier(), + &asn1_oid_id_x509_ce_authorityKeyIdentifier, &data); free(data.data); if (ret) @@ -1214,7 +1213,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, 0, - oid_id_x509_ce_subjectKeyIdentifier(), + &asn1_oid_id_x509_ce_subjectKeyIdentifier, &data); free(data.data); if (ret) @@ -1247,7 +1246,7 @@ ca_sign(hx509_context context, _hx509_abort("internal ASN.1 encoder error"); /* Critical if this is a CA */ ret = add_extension(context, tbsc, tbs->flags.ca, - oid_id_x509_ce_basicConstraints(), + &asn1_oid_id_x509_ce_basicConstraints, &data); free(data.data); if (ret) @@ -1271,7 +1270,7 @@ ca_sign(hx509_context context, *info.pCPathLenConstraint = tbs->pathLenConstraint; } - ret = der_copy_oid(oid_id_pkix_ppl_inheritAll(), + ret = der_copy_oid(&asn1_oid_id_pkix_ppl_inheritAll, &info.proxyPolicy.policyLanguage); if (ret) { free_ProxyCertInfo(&info); @@ -1289,7 +1288,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, 0, - oid_id_pkix_pe_proxyCertInfo(), + &asn1_oid_id_pkix_pe_proxyCertInfo, &data); free(data.data); if (ret) @@ -1307,7 +1306,7 @@ ca_sign(hx509_context context, if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); ret = add_extension(context, tbsc, FALSE, - oid_id_x509_ce_cRLDistributionPoints(), + &asn1_oid_id_x509_ce_cRLDistributionPoints, &data); free(data.data); if (ret) @@ -1399,8 +1398,7 @@ get_AuthorityKeyIdentifier(hx509_context context, */ ret = copy_Name(&certificate->tbsCertificate.subject, &name); - if (ai->authorityCertSerialNumber == NULL) { - ret = ENOMEM; + if (ret) { hx509_set_error_string(context, 0, ret, "Out of memory"); goto out; } 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 @@ -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; diff --git a/source4/heimdal/lib/hx509/cms.c b/source4/heimdal/lib/hx509/cms.c index ba1800ddf2..4766c34655 100644 --- a/source4/heimdal/lib/hx509/cms.c +++ b/source4/heimdal/lib/hx509/cms.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_cms CMS/PKCS7 message functions. @@ -474,6 +473,9 @@ hx509_cms_unenvelope(hx509_context context, if (ret) goto out; + if (flags & HX509_CMS_UE_ALLOW_WEAK) + hx509_crypto_allow_weak(crypto); + if (params) { ret = hx509_crypto_set_params(context, crypto, params, &ivec); if (ret) { @@ -527,7 +529,9 @@ out: * used to RSA. * * @param context A hx509 context. - * @param flags flags to control the behavior, no flags today + * @param flags flags to control the behavior. + * - HX509_CMS_EV_NO_KU_CHECK - Dont check KU on certificate + * - HX509_CMS_EV_ALLOW_WEAK - Allow weak crytpo * @param cert Certificate to encrypt the EnvelopedData encryption key * with. * @param data pointer the data to encrypt. @@ -565,16 +569,21 @@ hx509_cms_envelope_1(hx509_context context, memset(content, 0, sizeof(*content)); if (encryption_type == NULL) - encryption_type = oid_id_aes_256_cbc(); + encryption_type = &asn1_oid_id_aes_256_cbc; - ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE); - if (ret) - goto out; + if ((flags & HX509_CMS_EV_NO_KU_CHECK) == 0) { + ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE); + if (ret) + goto out; + } ret = hx509_crypto_init(context, NULL, encryption_type, &crypto); if (ret) goto out; + if (flags & HX509_CMS_EV_ALLOW_WEAK) + hx509_crypto_allow_weak(crypto); + ret = hx509_crypto_set_random_key(crypto, &key); if (ret) { hx509_set_error_string(context, 0, ret, @@ -738,12 +747,16 @@ find_attribute(const CMSAttributes *attr, const heim_oid *oid) * Decode SignedData and verify that the signature is correct. * * @param context A hx509 context. - * @param ctx a hx509 version context - * @param data + * @param ctx a hx509 verify context. + * @param flags to control the behaivor of the function. + * - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage + * - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch + * - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below. + * @param data pointer to CMS SignedData encoded data. * @param length length of the data that data point to. - * @param signedContent + * @param signedContent external data used for signature. * @param pool certificate pool to build certificates paths. - * @param contentType free with der_free_oid() + * @param contentType free with der_free_oid(). * @param content the output of the function, free with * der_free_octet_string(). * @param signer_certs list of the cerficates used to sign this @@ -755,6 +768,7 @@ find_attribute(const CMSAttributes *attr, const heim_oid *oid) int hx509_cms_verify_signed(hx509_context context, hx509_verify_ctx ctx, + unsigned int flags, const void *data, size_t length, const heim_octet_string *signedContent, @@ -797,8 +811,15 @@ hx509_cms_verify_signed(hx509_context context, "Both external and internal SignedData"); goto out; } + if (sd.encapContentInfo.eContent) - signedContent = sd.encapContentInfo.eContent; + ret = der_copy_octet_string(sd.encapContentInfo.eContent, content); + else + ret = der_copy_octet_string(signedContent, content); + if (ret) { + hx509_set_error_string(context, 0, ret, "malloc: out of memory"); + goto out; + } ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer", 0, NULL, &certs); @@ -823,7 +844,7 @@ hx509_cms_verify_signed(hx509_context context, } for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) { - heim_octet_string *signed_data; + heim_octet_string signed_data; const heim_oid *match_oid; heim_oid decode_oid; @@ -841,8 +862,22 @@ hx509_cms_verify_signed(hx509_context context, ret = find_CMSIdentifier(context, &signer_info->sid, certs, _hx509_verify_get_time(ctx), &cert, HX509_QUERY_KU_DIGITALSIGNATURE); - if (ret) - continue; + if (ret) { + /** + * If HX509_CMS_VS_NO_KU_CHECK is set, allow more liberal + * search for matching certificates by not considering + * KeyUsage bits on the certificates. + */ + if ((flags & HX509_CMS_VS_NO_KU_CHECK) == 0) + continue; + + ret = find_CMSIdentifier(context, &signer_info->sid, certs, + _hx509_verify_get_time(ctx), &cert, + 0); + if (ret) + continue; + + } if (signer_info->signedAttrs) { const Attribute *attr; @@ -854,7 +889,7 @@ hx509_cms_verify_signed(hx509_context context, sa.len = signer_info->signedAttrs->len; /* verify that sigature exists */ - attr = find_attribute(&sa, oid_id_pkcs9_messageDigest()); + attr = find_attribute(&sa, &asn1_oid_id_pkcs9_messageDigest); if (attr == NULL) { ret = HX509_CRYPTO_SIGNATURE_MISSING; hx509_set_error_string(context, 0, ret, @@ -885,7 +920,7 @@ hx509_cms_verify_signed(hx509_context context, ret = _hx509_verify_signature(context, NULL, &signer_info->digestAlgorithm, - signedContent, + content, &os); der_free_octet_string(&os); if (ret) { @@ -898,9 +933,9 @@ hx509_cms_verify_signed(hx509_context context, * Fetch content oid inside signedAttrs or set it to * id-pkcs7-data. */ - attr = find_attribute(&sa, oid_id_pkcs9_contentType()); + attr = find_attribute(&sa, &asn1_oid_id_pkcs9_contentType); if (attr == NULL) { - match_oid = oid_id_pkcs7_data(); + match_oid = &asn1_oid_id_pkcs7_data; } else { if (attr->value.len != 1) { ret = HX509_CMS_DATA_OID_MISMATCH; @@ -922,36 +957,36 @@ hx509_cms_verify_signed(hx509_context context, match_oid = &decode_oid; } - ALLOC(signed_data, 1); - if (signed_data == NULL) { - if (match_oid == &decode_oid) - der_free_oid(&decode_oid); - ret = ENOMEM; - hx509_clear_error_string(context); - goto next_sigature; - } - ASN1_MALLOC_ENCODE(CMSAttributes, - signed_data->data, - signed_data->length, + signed_data.data, + signed_data.length, &sa, &size, ret); if (ret) { if (match_oid == &decode_oid) der_free_oid(&decode_oid); - free(signed_data); hx509_clear_error_string(context); goto next_sigature; } - if (size != signed_data->length) + if (size != signed_data.length) _hx509_abort("internal ASN.1 encoder error"); } else { - signed_data = rk_UNCONST(signedContent); - match_oid = oid_id_pkcs7_data(); + signed_data.data = content->data; + signed_data.length = content->length; + match_oid = &asn1_oid_id_pkcs7_data; } - if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType)) { + /** + * If HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH, allow + * encapContentInfo mismatch with the oid in signedAttributes + * (or if no signedAttributes where use, pkcs7-data oid). + * This is only needed to work with broken CMS implementations + * that doesn't follow CMS signedAttributes rules. + */ + + if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType) && + (flags & HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH) == 0) { ret = HX509_CMS_DATA_OID_MISMATCH; hx509_set_error_string(context, 0, ret, "Oid in message mismatch from the expected"); @@ -963,23 +998,28 @@ hx509_cms_verify_signed(hx509_context context, ret = hx509_verify_signature(context, cert, &signer_info->signatureAlgorithm, - signed_data, + &signed_data, &signer_info->signature); if (ret) hx509_set_error_string(context, HX509_ERROR_APPEND, ret, - "Failed to verify sigature in " + "Failed to verify signature in " "CMS SignedData"); } - if (signed_data != signedContent) { - der_free_octet_string(signed_data); - free(signed_data); - } + if (signer_info->signedAttrs) + free(signed_data.data); if (ret) goto next_sigature; - ret = hx509_verify_path(context, ctx, cert, certs); - if (ret) - goto next_sigature; + /** + * If HX509_CMS_VS_NO_VALIDATE flags is set, do not verify the + * signing certificates and leave that up to the caller. + */ + + if ((flags & HX509_CMS_VS_NO_VALIDATE) == 0) { + ret = hx509_verify_path(context, ctx, cert, certs); + if (ret) + goto next_sigature; + } ret = hx509_certs_add(context, *signer_certs, cert); if (ret) @@ -992,7 +1032,18 @@ hx509_cms_verify_signed(hx509_context context, hx509_cert_free(cert); cert = NULL; } - if (found_valid_sig == 0) { + /** + * If HX509_CMS_VS_ALLOW_ZERO_SIGNER is set, allow empty + * SignerInfo (no signatures). If SignedData have no signatures, + * the function will return 0 with signer_certs set to NULL. Zero + * signers is allowed by the standard, but since its only useful + * in corner cases, it make into a flag that the caller have to + * turn on. + */ + if (sd.signerInfos.len == 0 && (flags & HX509_CMS_VS_ALLOW_ZERO_SIGNER)) { + if (*signer_certs) + hx509_certs_free(signer_certs); + } else if (found_valid_sig == 0) { if (ret == 0) { ret = HX509_CMS_SIGNER_NOT_FOUND; hx509_set_error_string(context, 0, ret, @@ -1007,20 +1058,13 @@ hx509_cms_verify_signed(hx509_context context, goto out; } - content->data = malloc(signedContent->length); - if (content->data == NULL) { - hx509_clear_error_string(context); - ret = ENOMEM; - goto out; - } - content->length = signedContent->length; - memcpy(content->data, signedContent->data, content->length); - out: free_SignedData(&sd); if (certs) hx509_certs_free(&certs); if (ret) { + if (content->data) + der_free_octet_string(content); if (*signer_certs) hx509_certs_free(signer_certs); der_free_oid(contentType); @@ -1097,26 +1141,55 @@ hx509_cms_create_signed_1(hx509_context context, hx509_certs pool, heim_octet_string *signed_data) { - AlgorithmIdentifier digest; - hx509_name name; - SignerInfo *signer_info; - heim_octet_string buf, content, sigdata = { 0, NULL }; + hx509_certs certs; + int ret = 0; + + signed_data->data = NULL; + signed_data->length = 0; + + ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs); + if (ret) + return ret; + ret = hx509_certs_add(context, certs, cert); + if (ret) + goto out; + + ret = hx509_cms_create_signed(context, flags, eContentType, data, length, + digest_alg, certs, peer, anchors, pool, + signed_data); + + out: + hx509_certs_free(&certs); + return ret; +} + +struct sigctx { SignedData sd; - int ret; + const AlgorithmIdentifier *digest_alg; + const heim_oid *eContentType; + heim_octet_string content; + hx509_peer_info peer; + int cmsidflag; + hx509_certs certs; + hx509_certs anchors; + hx509_certs pool; +}; + +static int +sig_process(hx509_context context, void *ctx, hx509_cert cert) +{ + struct sigctx *sigctx = ctx; + heim_octet_string buf, sigdata = { 0, NULL }; + SignerInfo *signer_info = NULL; + AlgorithmIdentifier digest; size_t size; + void *ptr; + int ret; + SignedData *sd = &sigctx->sd; hx509_path path; - int cmsidflag = CMS_ID_SKI; - memset(&sd, 0, sizeof(sd)); - memset(&name, 0, sizeof(name)); - memset(&path, 0, sizeof(path)); memset(&digest, 0, sizeof(digest)); - - content.data = rk_UNCONST(data); - content.length = length; - - if (flags & HX509_CMS_SIGATURE_ID_NAME) - cmsidflag = CMS_ID_NAME; + memset(&path, 0, sizeof(path)); if (_hx509_cert_private_key(cert) == NULL) { hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, @@ -1124,55 +1197,37 @@ hx509_cms_create_signed_1(hx509_context context, return HX509_PRIVATE_KEY_MISSING; } - if (digest_alg == NULL) { - ret = hx509_crypto_select(context, HX509_SELECT_DIGEST, - _hx509_cert_private_key(cert), peer, &digest); - } else { - ret = copy_AlgorithmIdentifier(digest_alg, &digest); + if (sigctx->digest_alg) { + ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest); if (ret) hx509_clear_error_string(context); + } else { + ret = hx509_crypto_select(context, HX509_SELECT_DIGEST, + _hx509_cert_private_key(cert), + sigctx->peer, &digest); } if (ret) goto out; - sd.version = CMSVersion_v3; - - if (eContentType == NULL) - eContentType = oid_id_pkcs7_data(); - - der_copy_oid(eContentType, &sd.encapContentInfo.eContentType); - - /* */ - if ((flags & HX509_CMS_SIGATURE_DETACHED) == 0) { - ALLOC(sd.encapContentInfo.eContent, 1); - if (sd.encapContentInfo.eContent == NULL) { - hx509_clear_error_string(context); - ret = ENOMEM; - goto out; - } - - sd.encapContentInfo.eContent->data = malloc(length); - if (sd.encapContentInfo.eContent->data == NULL) { - hx509_clear_error_string(context); - ret = ENOMEM; - goto out; - } - memcpy(sd.encapContentInfo.eContent->data, data, length); - sd.encapContentInfo.eContent->length = length; - } + /* + * Allocate on more signerInfo and do the signature processing + */ - ALLOC_SEQ(&sd.signerInfos, 1); - if (sd.signerInfos.val == NULL) { - hx509_clear_error_string(context); + ptr = realloc(sd->signerInfos.val, + (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0])); + if (ptr == NULL) { ret = ENOMEM; goto out; } + sd->signerInfos.val = ptr; - signer_info = &sd.signerInfos.val[0]; + signer_info = &sd->signerInfos.val[sd->signerInfos.len]; + + memset(signer_info, 0, sizeof(*signer_info)); signer_info->version = 1; - ret = fill_CMSIdentifier(cert, cmsidflag, &signer_info->sid); + ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid); if (ret) { hx509_clear_error_string(context); goto out; @@ -1181,7 +1236,6 @@ hx509_cms_create_signed_1(hx509_context context, signer_info->signedAttrs = NULL; signer_info->unsignedAttrs = NULL; - ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm); if (ret) { hx509_clear_error_string(context); @@ -1192,7 +1246,7 @@ hx509_cms_create_signed_1(hx509_context context, * If it isn't pkcs7-data send signedAttributes */ - if (der_heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) { + if (der_heim_oid_cmp(sigctx->eContentType, &asn1_oid_id_pkcs7_data) != 0) { CMSAttributes sa; heim_octet_string sig; @@ -1205,7 +1259,7 @@ hx509_cms_create_signed_1(hx509_context context, ret = _hx509_create_signature(context, NULL, &digest, - &content, + &sigctx->content, NULL, &sig); if (ret) @@ -1227,9 +1281,10 @@ hx509_cms_create_signed_1(hx509_context context, ret = add_one_attribute(&signer_info->signedAttrs->val, &signer_info->signedAttrs->len, - oid_id_pkcs9_messageDigest(), + &asn1_oid_id_pkcs9_messageDigest, &buf); if (ret) { + free(buf.data); hx509_clear_error_string(context); goto out; } @@ -1238,7 +1293,7 @@ hx509_cms_create_signed_1(hx509_context context, ASN1_MALLOC_ENCODE(ContentType, buf.data, buf.length, - eContentType, + sigctx->eContentType, &size, ret); if (ret) @@ -1248,9 +1303,10 @@ hx509_cms_create_signed_1(hx509_context context, ret = add_one_attribute(&signer_info->signedAttrs->val, &signer_info->signedAttrs->len, - oid_id_pkcs9_contentType(), + &asn1_oid_id_pkcs9_contentType, &buf); if (ret) { + free(buf.data); hx509_clear_error_string(context); goto out; } @@ -1271,16 +1327,15 @@ hx509_cms_create_signed_1(hx509_context context, if (size != sigdata.length) _hx509_abort("internal ASN.1 encoder error"); } else { - sigdata.data = content.data; - sigdata.length = content.length; + sigdata.data = sigctx->content.data; + sigdata.length = sigctx->content.length; } - { AlgorithmIdentifier sigalg; ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG, - _hx509_cert_private_key(cert), peer, + _hx509_cert_private_key(cert), sigctx->peer, &sigalg); if (ret) goto out; @@ -1296,54 +1351,165 @@ hx509_cms_create_signed_1(hx509_context context, goto out; } - ALLOC_SEQ(&sd.digestAlgorithms, 1); - if (sd.digestAlgorithms.val == NULL) { - ret = ENOMEM; - hx509_clear_error_string(context); - goto out; - } - - ret = copy_AlgorithmIdentifier(&digest, &sd.digestAlgorithms.val[0]); - if (ret) { - hx509_clear_error_string(context); - goto out; - } + sigctx->sd.signerInfos.len++; + signer_info = NULL; /* * Provide best effort path */ - if (pool) { - _hx509_calculate_path(context, - HX509_CALCULATE_PATH_NO_ANCHOR, - time(NULL), - anchors, - 0, - cert, - pool, - &path); - } else - _hx509_path_append(context, &path, cert); + if (sigctx->certs) { + unsigned int i; + + if (sigctx->pool) { + _hx509_calculate_path(context, + HX509_CALCULATE_PATH_NO_ANCHOR, + time(NULL), + sigctx->anchors, + 0, + cert, + sigctx->pool, + &path); + } else + _hx509_path_append(context, &path, cert); + + for (i = 0; i < path.len; i++) { + /* XXX remove dups */ + ret = hx509_certs_add(context, sigctx->certs, path.val[i]); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + } + } + + out: + if (signer_info) + free_SignerInfo(signer_info); + if (sigdata.data != sigctx->content.data) + der_free_octet_string(&sigdata); + _hx509_path_free(&path); + free_AlgorithmIdentifier(&digest); + + return ret; +} + +static int +cert_process(hx509_context context, void *ctx, hx509_cert cert) +{ + struct sigctx *sigctx = ctx; + const unsigned int i = sigctx->sd.certificates->len; + void *ptr; + int ret; + + ptr = realloc(sigctx->sd.certificates->val, + (i + 1) * sizeof(sigctx->sd.certificates->val[0])); + if (ptr == NULL) + return ENOMEM; + sigctx->sd.certificates->val = ptr; + + ret = hx509_cert_binary(context, cert, + &sigctx->sd.certificates->val[i]); + if (ret == 0) + sigctx->sd.certificates->len++; + + return ret; +} + +int +hx509_cms_create_signed(hx509_context context, + int flags, + const heim_oid *eContentType, + const void *data, size_t length, + const AlgorithmIdentifier *digest_alg, + hx509_certs certs, + hx509_peer_info peer, + hx509_certs anchors, + hx509_certs pool, + heim_octet_string *signed_data) +{ + unsigned int i; + hx509_name name; + int ret; + size_t size; + struct sigctx sigctx; + + memset(&sigctx, 0, sizeof(sigctx)); + memset(&name, 0, sizeof(name)); + + if (eContentType == NULL) + eContentType = &asn1_oid_id_pkcs7_data; + + sigctx.digest_alg = digest_alg; + sigctx.content.data = rk_UNCONST(data); + sigctx.content.length = length; + sigctx.eContentType = eContentType; + sigctx.peer = peer; + /** + * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name + * and serial number if possible. Otherwise subject key identifier + * will preferred. + */ + if (flags & HX509_CMS_SIGNATURE_ID_NAME) + sigctx.cmsidflag = CMS_ID_NAME; + else + sigctx.cmsidflag = CMS_ID_SKI; + + ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs); + if (ret) + return ret; + + sigctx.anchors = anchors; + sigctx.pool = pool; + sigctx.sd.version = CMSVersion_v3; - if (path.len) { - int i; + der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType); - ALLOC(sd.certificates, 1); - if (sd.certificates == NULL) { + /** + * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures. + */ + if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) { + ALLOC(sigctx.sd.encapContentInfo.eContent, 1); + if (sigctx.sd.encapContentInfo.eContent == NULL) { hx509_clear_error_string(context); ret = ENOMEM; goto out; } - ALLOC_SEQ(sd.certificates, path.len); - if (sd.certificates->val == NULL) { + + sigctx.sd.encapContentInfo.eContent->data = malloc(length); + if (sigctx.sd.encapContentInfo.eContent->data == NULL) { hx509_clear_error_string(context); ret = ENOMEM; goto out; } + memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length); + sigctx.sd.encapContentInfo.eContent->length = length; + } - for (i = 0; i < path.len; i++) { - ret = hx509_cert_binary(context, path.val[i], - &sd.certificates->val[i]); + /** + * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no + * signatures). + */ + if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) { + ret = hx509_certs_iter(context, certs, sig_process, &sigctx); + if (ret) + goto out; + } + + if (sigctx.sd.signerInfos.len) { + ALLOC_SEQ(&sigctx.sd.digestAlgorithms, sigctx.sd.signerInfos.len); + if (sigctx.sd.digestAlgorithms.val == NULL) { + ret = ENOMEM; + hx509_clear_error_string(context); + goto out; + } + + /* XXX remove dups */ + for (i = 0; i < sigctx.sd.signerInfos.len; i++) { + AlgorithmIdentifier *di = + &sigctx.sd.signerInfos.val[i].digestAlgorithm; + ret = copy_AlgorithmIdentifier(di, + &sigctx.sd.digestAlgorithms.val[i]); if (ret) { hx509_clear_error_string(context); goto out; @@ -1351,9 +1517,22 @@ hx509_cms_create_signed_1(hx509_context context, } } + if (sigctx.certs) { + ALLOC(sigctx.sd.certificates, 1); + if (sigctx.sd.certificates == NULL) { + hx509_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + ret = hx509_certs_iter(context, sigctx.certs, cert_process, &sigctx); + if (ret) + goto out; + } + ASN1_MALLOC_ENCODE(SignedData, signed_data->data, signed_data->length, - &sd, &size, ret); + &sigctx.sd, &size, ret); if (ret) { hx509_clear_error_string(context); goto out; @@ -1362,11 +1541,8 @@ hx509_cms_create_signed_1(hx509_context context, _hx509_abort("internal ASN.1 encoder error"); out: - if (sigdata.data != content.data) - der_free_octet_string(&sigdata); - free_AlgorithmIdentifier(&digest); - _hx509_path_free(&path); - free_SignedData(&sd); + hx509_certs_free(&sigctx.certs); + free_SignedData(&sigctx.sd); return ret; } diff --git a/source4/heimdal/lib/hx509/collector.c b/source4/heimdal/lib/hx509/collector.c index b59052bb4e..ab36fe2dc8 100644 --- a/source4/heimdal/lib/hx509/collector.c +++ b/source4/heimdal/lib/hx509/collector.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); struct private_key { AlgorithmIdentifier alg; @@ -144,7 +143,7 @@ _hx509_collector_private_key_add(hx509_context context, if (private_key) { key->private_key = private_key; } else { - ret = _hx509_parse_private_key(context, &alg->algorithm, + ret = _hx509_parse_private_key(context, alg, key_data->data, key_data->length, &key->private_key); if (ret) @@ -306,7 +305,7 @@ _hx509_collector_collect_private_keys(hx509_context context, c->val.data[i]->private_key = NULL; } } - (*keys)[nkeys++] = NULL; + (*keys)[nkeys] = NULL; return 0; } diff --git a/source4/heimdal/lib/hx509/crypto.c b/source4/heimdal/lib/hx509/crypto.c index 4a8ec8f756..8063100717 100644 --- a/source4/heimdal/lib/hx509/crypto.c +++ b/source4/heimdal/lib/hx509/crypto.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); struct hx509_crypto; @@ -50,40 +49,21 @@ struct hx509_generate_private_context { struct hx509_private_key_ops { const char *pemtype; - const heim_oid *(*key_oid)(void); + const heim_oid *key_oid; + int (*available)(const hx509_private_key, + const AlgorithmIdentifier *); int (*get_spki)(hx509_context, const hx509_private_key, SubjectPublicKeyInfo *); int (*export)(hx509_context context, const hx509_private_key, heim_octet_string *); - int (*import)(hx509_context, - const void *data, - size_t len, - hx509_private_key private_key); + int (*import)(hx509_context, const AlgorithmIdentifier *, + const void *, size_t, hx509_private_key); int (*generate_private_key)(hx509_context, struct hx509_generate_private_context *, hx509_private_key); BIGNUM *(*get_internal)(hx509_context, hx509_private_key, const char *); - int (*handle_alg)(const hx509_private_key, - const AlgorithmIdentifier *, - enum crypto_op_type); - int (*sign)(hx509_context context, - const hx509_private_key, - const AlgorithmIdentifier *, - const heim_octet_string *, - AlgorithmIdentifier *, - heim_octet_string *); -#if 0 - const AlgorithmIdentifier *(*preferred_sig_alg) - (const hx509_private_key, - const hx509_peer_info); - int (*unwrap)(hx509_context context, - const hx509_private_key, - const AlgorithmIdentifier *, - const heim_octet_string *, - heim_octet_string *); -#endif }; struct hx509_private_key { @@ -93,8 +73,10 @@ struct hx509_private_key { union { RSA *rsa; void *keydata; +#ifdef HAVE_OPENSSL + EC_KEY *ecdsa; +#endif } private_key; - /* new crypto layer */ hx509_private_key_ops *ops; }; @@ -104,10 +86,10 @@ struct hx509_private_key { struct signature_alg { const char *name; - const heim_oid *(*sig_oid)(void); - const AlgorithmIdentifier *(*sig_alg)(void); - const heim_oid *(*key_oid)(void); - const heim_oid *(*digest_oid)(void); + const heim_oid *sig_oid; + const AlgorithmIdentifier *sig_alg; + const heim_oid *key_oid; + const AlgorithmIdentifier *digest_alg; int flags; #define PROVIDE_CONF 1 #define REQUIRE_SIGNER 2 @@ -118,7 +100,7 @@ struct signature_alg { #define RA_RSA_USES_DIGEST_INFO 0x1000000 - + time_t best_before; /* refuse signature made after best before date */ int (*verify_signature)(hx509_context context, const struct signature_alg *, const Certificate *, @@ -132,6 +114,116 @@ struct signature_alg { const heim_octet_string *, AlgorithmIdentifier *, heim_octet_string *); + int digest_size; +}; + +static const struct signature_alg * +find_sig_alg(const heim_oid *oid); + +/* + * + */ + +static const heim_octet_string null_entry_oid = { 2, rk_UNCONST("\x05\x00") }; + +static const unsigned sha512_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 }; +const AlgorithmIdentifier _hx509_signature_sha512_data = { + { 9, rk_UNCONST(sha512_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned sha384_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 2 }; +const AlgorithmIdentifier _hx509_signature_sha384_data = { + { 9, rk_UNCONST(sha384_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned sha256_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }; +const AlgorithmIdentifier _hx509_signature_sha256_data = { + { 9, rk_UNCONST(sha256_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 }; +const AlgorithmIdentifier _hx509_signature_sha1_data = { + { 6, rk_UNCONST(sha1_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned md5_oid_tree[] = { 1, 2, 840, 113549, 2, 5 }; +const AlgorithmIdentifier _hx509_signature_md5_data = { + { 6, rk_UNCONST(md5_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned md2_oid_tree[] = { 1, 2, 840, 113549, 2, 2 }; +const AlgorithmIdentifier _hx509_signature_md2_data = { + { 6, rk_UNCONST(md2_oid_tree) }, rk_UNCONST(&null_entry_oid) +}; + +static const unsigned ecPublicKey[] ={ 1, 2, 840, 10045, 2, 1 }; +const AlgorithmIdentifier _hx509_signature_ecPublicKey = { + { 6, rk_UNCONST(ecPublicKey) }, NULL +}; + +static const unsigned ecdsa_with_sha256_oid[] ={ 1, 2, 840, 10045, 4, 3, 2 }; +const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha256_data = { + { 7, rk_UNCONST(ecdsa_with_sha256_oid) }, NULL +}; + +static const unsigned ecdsa_with_sha1_oid[] ={ 1, 2, 840, 10045, 4, 1 }; +const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha1_data = { + { 6, rk_UNCONST(ecdsa_with_sha1_oid) }, NULL +}; + +static const unsigned rsa_with_sha512_oid[] ={ 1, 2, 840, 113549, 1, 1, 13 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha512_data = { + { 7, rk_UNCONST(rsa_with_sha512_oid) }, NULL +}; + +static const unsigned rsa_with_sha384_oid[] ={ 1, 2, 840, 113549, 1, 1, 12 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha384_data = { + { 7, rk_UNCONST(rsa_with_sha384_oid) }, NULL +}; + +static const unsigned rsa_with_sha256_oid[] ={ 1, 2, 840, 113549, 1, 1, 11 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha256_data = { + { 7, rk_UNCONST(rsa_with_sha256_oid) }, NULL +}; + +static const unsigned rsa_with_sha1_oid[] ={ 1, 2, 840, 113549, 1, 1, 5 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_sha1_data = { + { 7, rk_UNCONST(rsa_with_sha1_oid) }, NULL +}; + +static const unsigned rsa_with_md5_oid[] ={ 1, 2, 840, 113549, 1, 1, 4 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_md5_data = { + { 7, rk_UNCONST(rsa_with_md5_oid) }, NULL +}; + +static const unsigned rsa_with_md2_oid[] ={ 1, 2, 840, 113549, 1, 1, 2 }; +const AlgorithmIdentifier _hx509_signature_rsa_with_md2_data = { + { 7, rk_UNCONST(rsa_with_md2_oid) }, NULL +}; + +static const unsigned rsa_oid[] ={ 1, 2, 840, 113549, 1, 1, 1 }; +const AlgorithmIdentifier _hx509_signature_rsa_data = { + { 7, rk_UNCONST(rsa_oid) }, NULL +}; + +static const unsigned rsa_pkcs1_x509_oid[] ={ 1, 2, 752, 43, 16, 1 }; +const AlgorithmIdentifier _hx509_signature_rsa_pkcs1_x509_data = { + { 6, rk_UNCONST(rsa_pkcs1_x509_oid) }, NULL +}; + +static const unsigned des_rsdi_ede3_cbc_oid[] ={ 1, 2, 840, 113549, 3, 7 }; +const AlgorithmIdentifier _hx509_des_rsdi_ede3_cbc_oid = { + { 6, rk_UNCONST(des_rsdi_ede3_cbc_oid) }, NULL +}; + +static const unsigned aes128_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 2 }; +const AlgorithmIdentifier _hx509_crypto_aes128_cbc_data = { + { 9, rk_UNCONST(aes128_cbc_oid) }, NULL +}; + +static const unsigned aes256_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 42 }; +const AlgorithmIdentifier _hx509_crypto_aes256_cbc_data = { + { 9, rk_UNCONST(aes256_cbc_oid) }, NULL }; /* @@ -184,6 +276,265 @@ set_digest_alg(DigestAlgorithmIdentifier *id, return 0; } +#ifdef HAVE_OPENSSL + +static int +heim_oid2ecnid(heim_oid *oid) +{ + /* + * Now map to openssl OID fun + */ + + if (der_heim_oid_cmp(oid, &asn1_oid_id_ec_group_secp256r1) == 0) + return NID_X9_62_prime256v1; + else if (der_heim_oid_cmp(oid, &asn1_oid_id_ec_group_secp160r1) == 0) + return NID_secp160r1; + else if (der_heim_oid_cmp(oid, &asn1_oid_id_ec_group_secp160r2) == 0) + return NID_secp160r2; + + return -1; +} + +static int +parse_ECParameters(hx509_context context, + heim_octet_string *parameters, int *nid) +{ + ECParameters ecparam; + size_t size; + int ret; + + if (parameters == NULL) { + ret = HX509_PARSING_KEY_FAILED; + hx509_set_error_string(context, 0, ret, + "EC parameters missing"); + return ret; + } + + ret = decode_ECParameters(parameters->data, parameters->length, + &ecparam, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode EC parameters"); + return ret; + } + + if (ecparam.element != choice_ECParameters_namedCurve) { + free_ECParameters(&ecparam); + hx509_set_error_string(context, 0, ret, + "EC parameters is not a named curve"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + *nid = heim_oid2ecnid(&ecparam.u.namedCurve); + free_ECParameters(&ecparam); + if (*nid == -1) { + hx509_set_error_string(context, 0, ret, + "Failed to find matcing NID for EC curve"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + return 0; +} + + +/* + * + */ + +static int +ecdsa_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + const AlgorithmIdentifier *digest_alg; + const SubjectPublicKeyInfo *spi; + heim_octet_string digest; + int ret; + EC_KEY *key = NULL; + int groupnid; + EC_GROUP *group; + const unsigned char *p; + long len; + + digest_alg = sig_alg->digest_alg; + + ret = _hx509_create_signature(context, + NULL, + digest_alg, + data, + NULL, + &digest); + if (ret) + return ret; + + /* set up EC KEY */ + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + if (der_heim_oid_cmp(&spi->algorithm.algorithm, &asn1_oid_id_ecPublicKey) != 0) + return HX509_CRYPTO_SIG_INVALID_FORMAT; + +#ifdef HAVE_OPENSSL + /* + * Find the group id + */ + + ret = parse_ECParameters(context, spi->algorithm.parameters, &groupnid); + if (ret) { + der_free_octet_string(&digest); + return ret; + } + + /* + * Create group, key, parse key + */ + + key = EC_KEY_new(); + group = EC_GROUP_new_by_curve_name(groupnid); + EC_KEY_set_group(key, group); + EC_GROUP_free(group); + + p = spi->subjectPublicKey.data; + len = spi->subjectPublicKey.length / 8; + + if (o2i_ECPublicKey(&key, &p, len) == NULL) { + EC_KEY_free(key); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } +#else + key = SubjectPublicKeyInfo2EC_KEY(spi); +#endif + + ret = ECDSA_verify(-1, digest.data, digest.length, + sig->data, sig->length, key); + der_free_octet_string(&digest); + EC_KEY_free(key); + if (ret != 1) { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + return ret; + } + + return 0; +} + +static int +ecdsa_create_signature(hx509_context context, + const struct signature_alg *sig_alg, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + const AlgorithmIdentifier *digest_alg; + heim_octet_string indata; + const heim_oid *sig_oid; + unsigned int siglen; + int ret; + + if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0) + _hx509_abort("internal error passing private key to wrong ops"); + + sig_oid = sig_alg->sig_oid; + digest_alg = sig_alg->digest_alg; + + if (signatureAlgorithm) { + ret = set_digest_alg(signatureAlgorithm, sig_oid, "\x05\x00", 2); + if (ret) { + hx509_clear_error_string(context); + goto error; + } + } + + ret = _hx509_create_signature(context, + NULL, + digest_alg, + data, + NULL, + &indata); + if (ret) { + if (signatureAlgorithm) + free_AlgorithmIdentifier(signatureAlgorithm); + goto error; + } + + sig->length = ECDSA_size(signer->private_key.ecdsa); + sig->data = malloc(sig->length); + if (sig->data == NULL) { + der_free_octet_string(&indata); + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto error; + } + + siglen = sig->length; + + ret = ECDSA_sign(-1, indata.data, indata.length, + sig->data, &siglen, signer->private_key.ecdsa); + der_free_octet_string(&indata); + if (ret != 1) { + ret = HX509_CMS_FAILED_CREATE_SIGATURE; + hx509_set_error_string(context, 0, ret, + "ECDSA sign failed: %d", ret); + goto error; + } + if (siglen > sig->length) + _hx509_abort("ECDSA signature prelen longer the output len"); + + sig->length = siglen; + + return 0; + error: + if (signatureAlgorithm) + free_AlgorithmIdentifier(signatureAlgorithm); + return ret; +} + +static int +ecdsa_available(const hx509_private_key signer, + const AlgorithmIdentifier *sig_alg) +{ + const struct signature_alg *sig; + const EC_GROUP *group; + BN_CTX *bnctx = NULL; + BIGNUM *order = NULL; + int ret = 0; + + if (der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0) + _hx509_abort("internal error passing private key to wrong ops"); + + sig = find_sig_alg(&sig_alg->algorithm); + + if (sig == NULL || sig->digest_size == 0) + return 0; + + group = EC_KEY_get0_group(signer->private_key.ecdsa); + if (group == NULL) + return 0; + + bnctx = BN_CTX_new(); + order = BN_new(); + if (order == NULL) + goto err; + + if (EC_GROUP_get_order(group, order, bnctx) != 1) + goto err; + + if (BN_num_bytes(order) > sig->digest_size) + ret = 1; + err: + if (bnctx) + BN_CTX_free(bnctx); + if (order) + BN_clear_free(order); + + return ret; +} + + +#endif /* HAVE_OPENSSL */ + /* * */ @@ -268,9 +619,9 @@ rsa_verify_signature(hx509_context context, goto out; } - if (sig_alg->digest_oid && + if (sig_alg->digest_alg && der_heim_oid_cmp(&di.digestAlgorithm.algorithm, - (*sig_alg->digest_oid)()) != 0) + &sig_alg->digest_alg->algorithm) != 0) { ret = HX509_CRYPTO_OID_MISMATCH; hx509_set_error_string(context, 0, ret, "object identifier in RSA sig mismatch"); @@ -324,24 +675,27 @@ rsa_create_signature(hx509_context context, size_t size; int ret; + if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_pkcs1_rsaEncryption) != 0) + return HX509_ALG_NOT_SUPP; + if (alg) sig_oid = &alg->algorithm; else sig_oid = signer->signature_alg; - if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_sha256WithRSAEncryption()) == 0) { + if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_sha256WithRSAEncryption) == 0) { digest_alg = hx509_signature_sha256(); - } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_sha1WithRSAEncryption()) == 0) { + } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_sha1WithRSAEncryption) == 0) { digest_alg = hx509_signature_sha1(); - } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_md5WithRSAEncryption()) == 0) { + } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_md5WithRSAEncryption) == 0) { digest_alg = hx509_signature_md5(); - } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_md5WithRSAEncryption()) == 0) { + } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_md5WithRSAEncryption) == 0) { digest_alg = hx509_signature_md5(); - } else if (der_heim_oid_cmp(sig_oid, oid_id_dsa_with_sha1()) == 0) { + } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_dsa_with_sha1) == 0) { digest_alg = hx509_signature_sha1(); - } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_rsaEncryption()) == 0) { + } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_pkcs1_rsaEncryption) == 0) { digest_alg = hx509_signature_sha1(); - } else if (der_heim_oid_cmp(sig_oid, oid_id_heim_rsa_pkcs1_x509()) == 0) { + } else if (der_heim_oid_cmp(sig_oid, &asn1_oid_id_heim_rsa_pkcs1_x509) == 0) { digest_alg = NULL; } else return HX509_ALG_NOT_SUPP; @@ -413,6 +767,7 @@ rsa_create_signature(hx509_context context, static int rsa_private_key_import(hx509_context context, + const AlgorithmIdentifier *keyai, const void *data, size_t len, hx509_private_key private_key) @@ -426,7 +781,7 @@ rsa_private_key_import(hx509_context context, "Failed to parse RSA key"); return HX509_PARSING_KEY_FAILED; } - private_key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption(); + private_key->signature_alg = &asn1_oid_id_pkcs1_sha1WithRSAEncryption; return 0; } @@ -449,7 +804,7 @@ rsa_private_key2SPKI(hx509_context context, } spki->subjectPublicKey.length = len * 8; - ret = set_digest_alg(&spki->algorithm,oid_id_pkcs1_rsaEncryption(), + ret = set_digest_alg(&spki->algorithm, &asn1_oid_id_pkcs1_rsaEncryption, "\x05\x00", 2); if (ret) { hx509_set_error_string(context, 0, ret, "malloc - out of memory"); @@ -503,7 +858,7 @@ rsa_generate_private_key(hx509_context context, "Failed to generate RSA key"); return HX509_PARSING_KEY_FAILED; } - private_key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption(); + private_key->signature_alg = &asn1_oid_id_pkcs1_sha1WithRSAEncryption; return 0; } @@ -543,7 +898,9 @@ rsa_private_key_export(hx509_context context, } static BIGNUM * -rsa_get_internal(hx509_context context, hx509_private_key key, const char *type) +rsa_get_internal(hx509_context context, + hx509_private_key key, + const char *type) { if (strcasecmp(type, "rsa-modulus") == 0) { return BN_dup(key->private_key.rsa->n); @@ -557,7 +914,8 @@ rsa_get_internal(hx509_context context, hx509_private_key key, const char *type) static hx509_private_key_ops rsa_private_key_ops = { "RSA PRIVATE KEY", - oid_id_pkcs1_rsaEncryption, + &asn1_oid_id_pkcs1_rsaEncryption, + NULL, rsa_private_key2SPKI, rsa_private_key_export, rsa_private_key_import, @@ -565,6 +923,104 @@ static hx509_private_key_ops rsa_private_key_ops = { rsa_get_internal }; +#ifdef HAVE_OPENSSL + +static int +ecdsa_private_key2SPKI(hx509_context context, + hx509_private_key private_key, + SubjectPublicKeyInfo *spki) +{ + memset(spki, 0, sizeof(*spki)); + return ENOMEM; +} + +static int +ecdsa_private_key_export(hx509_context context, + const hx509_private_key key, + heim_octet_string *data) +{ + return ENOMEM; +} + +static int +ecdsa_private_key_import(hx509_context context, + const AlgorithmIdentifier *keyai, + const void *data, + size_t len, + hx509_private_key private_key) +{ + const unsigned char *p = data; + EC_KEY **pkey = NULL; + + if (keyai->parameters) { + EC_GROUP *group; + int groupnid; + EC_KEY *key; + int ret; + + ret = parse_ECParameters(context, keyai->parameters, &groupnid); + if (ret) + return ret; + + key = EC_KEY_new(); + if (key == NULL) + return ENOMEM; + + group = EC_GROUP_new_by_curve_name(groupnid); + if (group == NULL) { + EC_KEY_free(key); + return ENOMEM; + } + EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); + if (EC_KEY_set_group(key, group) == 0) { + EC_KEY_free(key); + EC_GROUP_free(group); + return ENOMEM; + } + EC_GROUP_free(group); + pkey = &key; + } + + private_key->private_key.ecdsa = d2i_ECPrivateKey(pkey, &p, len); + if (private_key->private_key.ecdsa == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to parse EC private key"); + return HX509_PARSING_KEY_FAILED; + } + private_key->signature_alg = &asn1_oid_id_ecdsa_with_SHA256; + + return 0; +} + +static int +ecdsa_generate_private_key(hx509_context context, + struct hx509_generate_private_context *ctx, + hx509_private_key private_key) +{ + return ENOMEM; +} + +static BIGNUM * +ecdsa_get_internal(hx509_context context, + hx509_private_key key, + const char *type) +{ + return NULL; +} + + +static hx509_private_key_ops ecdsa_private_key_ops = { + "EC PRIVATE KEY", + &asn1_oid_id_ecPublicKey, + ecdsa_available, + ecdsa_private_key2SPKI, + ecdsa_private_key_export, + ecdsa_private_key_import, + ecdsa_generate_private_key, + ecdsa_get_internal +}; + +#endif /* HAVE_OPENSSL */ /* * @@ -668,7 +1124,7 @@ dsa_parse_private_key(hx509_context context, d2i_DSAPrivateKey(NULL, &p, len); if (private_key->private_key.dsa == NULL) return EINVAL; - private_key->signature_alg = oid_id_dsa_with_sha1(); + private_key->signature_alg = &asn1_oid_id_dsa_with_sha1; return 0; /* else */ @@ -724,7 +1180,7 @@ sha256_create_signature(hx509_context context, if (signatureAlgorithm) { int ret; - ret = set_digest_alg(signatureAlgorithm, (*sig_alg->sig_oid)(), + ret = set_digest_alg(signatureAlgorithm, sig_alg->sig_oid, "\x05\x00", 2); if (ret) return ret; @@ -790,7 +1246,7 @@ sha1_create_signature(hx509_context context, if (signatureAlgorithm) { int ret; - ret = set_digest_alg(signatureAlgorithm, (*sig_alg->sig_oid)(), + ret = set_digest_alg(signatureAlgorithm, sig_alg->sig_oid, "\x05\x00", 2); if (ret) return ret; @@ -871,131 +1327,176 @@ md2_verify_signature(hx509_context context, return 0; } +#ifdef HAVE_OPENSSL + +static const struct signature_alg ecdsa_with_sha256_alg = { + "ecdsa-with-sha256", + &asn1_oid_id_ecdsa_with_SHA256, + &_hx509_signature_ecdsa_with_sha256_data, + &asn1_oid_id_ecPublicKey, + &_hx509_signature_sha256_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 0, + ecdsa_verify_signature, + ecdsa_create_signature, + 32 +}; + +static const struct signature_alg ecdsa_with_sha1_alg = { + "ecdsa-with-sha1", + &asn1_oid_id_ecdsa_with_SHA1, + &_hx509_signature_ecdsa_with_sha1_data, + &asn1_oid_id_ecPublicKey, + &_hx509_signature_sha1_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 0, + ecdsa_verify_signature, + ecdsa_create_signature, + 20 +}; + +#endif + static const struct signature_alg heim_rsa_pkcs1_x509 = { "rsa-pkcs1-x509", - oid_id_heim_rsa_pkcs1_x509, - hx509_signature_rsa_pkcs1_x509, - oid_id_pkcs1_rsaEncryption, + &asn1_oid_id_heim_rsa_pkcs1_x509, + &_hx509_signature_rsa_pkcs1_x509_data, + &asn1_oid_id_pkcs1_rsaEncryption, NULL, PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, + 0, rsa_verify_signature, rsa_create_signature }; static const struct signature_alg pkcs1_rsa_sha1_alg = { "rsa", - oid_id_pkcs1_rsaEncryption, - hx509_signature_rsa_with_sha1, - oid_id_pkcs1_rsaEncryption, + &asn1_oid_id_pkcs1_rsaEncryption, + &_hx509_signature_rsa_with_sha1_data, + &asn1_oid_id_pkcs1_rsaEncryption, NULL, PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 0, rsa_verify_signature, rsa_create_signature }; static const struct signature_alg rsa_with_sha256_alg = { "rsa-with-sha256", - oid_id_pkcs1_sha256WithRSAEncryption, - hx509_signature_rsa_with_sha256, - oid_id_pkcs1_rsaEncryption, - oid_id_sha256, + &asn1_oid_id_pkcs1_sha256WithRSAEncryption, + &_hx509_signature_rsa_with_sha256_data, + &asn1_oid_id_pkcs1_rsaEncryption, + &_hx509_signature_sha256_data, PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 0, rsa_verify_signature, rsa_create_signature }; static const struct signature_alg rsa_with_sha1_alg = { "rsa-with-sha1", - oid_id_pkcs1_sha1WithRSAEncryption, - hx509_signature_rsa_with_sha1, - oid_id_pkcs1_rsaEncryption, - oid_id_secsig_sha_1, + &asn1_oid_id_pkcs1_sha1WithRSAEncryption, + &_hx509_signature_rsa_with_sha1_data, + &asn1_oid_id_pkcs1_rsaEncryption, + &_hx509_signature_sha1_data, PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 0, rsa_verify_signature, rsa_create_signature }; static const struct signature_alg rsa_with_md5_alg = { "rsa-with-md5", - oid_id_pkcs1_md5WithRSAEncryption, - hx509_signature_rsa_with_md5, - oid_id_pkcs1_rsaEncryption, - oid_id_rsa_digest_md5, + &asn1_oid_id_pkcs1_md5WithRSAEncryption, + &_hx509_signature_rsa_with_md5_data, + &asn1_oid_id_pkcs1_rsaEncryption, + &_hx509_signature_md5_data, PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 1230739889, rsa_verify_signature, rsa_create_signature }; static const struct signature_alg rsa_with_md2_alg = { "rsa-with-md2", - oid_id_pkcs1_md2WithRSAEncryption, - hx509_signature_rsa_with_md2, - oid_id_pkcs1_rsaEncryption, - oid_id_rsa_digest_md2, + &asn1_oid_id_pkcs1_md2WithRSAEncryption, + &_hx509_signature_rsa_with_md2_data, + &asn1_oid_id_pkcs1_rsaEncryption, + &_hx509_signature_md2_data, PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG, + 1230739889, rsa_verify_signature, rsa_create_signature }; static const struct signature_alg dsa_sha1_alg = { "dsa-with-sha1", - oid_id_dsa_with_sha1, + &asn1_oid_id_dsa_with_sha1, NULL, - oid_id_dsa, - oid_id_secsig_sha_1, + &asn1_oid_id_dsa, + &_hx509_signature_sha1_data, PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, + 0, dsa_verify_signature, /* create_signature */ NULL, }; static const struct signature_alg sha256_alg = { "sha-256", - oid_id_sha256, - hx509_signature_sha256, + &asn1_oid_id_sha256, + &_hx509_signature_sha256_data, NULL, NULL, SIG_DIGEST, + 0, sha256_verify_signature, sha256_create_signature }; static const struct signature_alg sha1_alg = { "sha1", - oid_id_secsig_sha_1, - hx509_signature_sha1, + &asn1_oid_id_secsig_sha_1, + &_hx509_signature_sha1_data, NULL, NULL, SIG_DIGEST, + 0, sha1_verify_signature, sha1_create_signature }; static const struct signature_alg md5_alg = { "rsa-md5", - oid_id_rsa_digest_md5, - hx509_signature_md5, + &asn1_oid_id_rsa_digest_md5, + &_hx509_signature_md5_data, NULL, NULL, SIG_DIGEST, + 0, md5_verify_signature }; static const struct signature_alg md2_alg = { "rsa-md2", - oid_id_rsa_digest_md2, - hx509_signature_md2, + &asn1_oid_id_rsa_digest_md2, + &_hx509_signature_md2_data, NULL, NULL, SIG_DIGEST, + 0, md2_verify_signature }; /* * Order matter in this structure, "best" first for each "key - * compatible" type (type is RSA, DSA, none, etc) + * compatible" type (type is ECDSA, RSA, DSA, none, etc) */ static const struct signature_alg *sig_algs[] = { +#ifdef HAVE_OPENSSL + &ecdsa_with_sha256_alg, + &ecdsa_with_sha1_alg, +#endif &rsa_with_sha256_alg, &rsa_with_sha1_alg, &pkcs1_rsa_sha1_alg, @@ -1013,19 +1514,51 @@ static const struct signature_alg *sig_algs[] = { static const struct signature_alg * find_sig_alg(const heim_oid *oid) { - int i; + unsigned int i; for (i = 0; sig_algs[i]; i++) - if (der_heim_oid_cmp((*sig_algs[i]->sig_oid)(), oid) == 0) + if (der_heim_oid_cmp(sig_algs[i]->sig_oid, oid) == 0) return sig_algs[i]; return NULL; } +static const AlgorithmIdentifier * +alg_for_privatekey(const hx509_private_key pk, int type) +{ + const heim_oid *keytype; + unsigned int i; + + if (pk->ops == NULL) + return NULL; + + keytype = pk->ops->key_oid; + + for (i = 0; sig_algs[i]; i++) { + if (sig_algs[i]->key_oid == NULL) + continue; + if (der_heim_oid_cmp(sig_algs[i]->key_oid, keytype) != 0) + continue; + if (pk->ops->available && + pk->ops->available(pk, sig_algs[i]->sig_alg) == 0) + continue; + if (type == HX509_SELECT_PUBLIC_SIG) + return sig_algs[i]->sig_alg; + if (type == HX509_SELECT_DIGEST) + return sig_algs[i]->digest_alg; + + return NULL; + } + return NULL; +} + /* * */ static struct hx509_private_key_ops *private_algs[] = { &rsa_private_key_ops, +#ifdef HAVE_OPENSSL + &ecdsa_private_key_ops, +#endif NULL }; @@ -1036,12 +1569,37 @@ find_private_alg(const heim_oid *oid) for (i = 0; private_algs[i]; i++) { if (private_algs[i]->key_oid == NULL) continue; - if (der_heim_oid_cmp((*private_algs[i]->key_oid)(), oid) == 0) + if (der_heim_oid_cmp(private_algs[i]->key_oid, oid) == 0) return private_algs[i]; } return NULL; } +/* + * Check if the algorithm `alg' have a best before date, and if it + * des, make sure the its before the time `t'. + */ + +int +_hx509_signature_best_before(hx509_context context, + const AlgorithmIdentifier *alg, + time_t t) +{ + const struct signature_alg *md; + + md = find_sig_alg(&alg->algorithm); + if (md == NULL) { + hx509_clear_error_string(context); + return HX509_SIG_ALG_NO_SUPPORTED; + } + if (md->best_before && md->best_before < t) { + hx509_set_error_string(context, 0, HX509_CRYPTO_ALGORITHM_BEST_BEFORE, + "Algorithm %s has passed it best before date", + md->name); + return HX509_CRYPTO_ALGORITHM_BEST_BEFORE; + } + return 0; +} int _hx509_verify_signature(hx509_context context, @@ -1069,7 +1627,7 @@ _hx509_verify_signature(hx509_context context, const SubjectPublicKeyInfo *spi; spi = &signer->tbsCertificate.subjectPublicKeyInfo; - if (der_heim_oid_cmp(&spi->algorithm.algorithm, (*md->key_oid)()) != 0) { + if (der_heim_oid_cmp(&spi->algorithm.algorithm, md->key_oid) != 0) { hx509_clear_error_string(context); return HX509_SIG_ALG_DONT_MATCH_KEY_ALG; } @@ -1108,13 +1666,6 @@ _hx509_create_signature(hx509_context context, { const struct signature_alg *md; - if (signer && signer->ops && signer->ops->handle_alg && - (*signer->ops->handle_alg)(signer, alg, COT_SIGN)) - { - return (*signer->ops->sign)(context, signer, alg, data, - signatureAlgorithm, sig); - } - md = find_sig_alg(&alg->algorithm); if (md == NULL) { hx509_set_error_string(context, 0, HX509_SIG_ALG_NO_SUPPORTED, @@ -1221,7 +1772,7 @@ _hx509_public_encrypt(hx509_context context, ciphertext->length = ret; ciphertext->data = to; - ret = der_copy_oid(oid_id_pkcs1_rsaEncryption(), encryption_oid); + ret = der_copy_oid(&asn1_oid_id_pkcs1_rsaEncryption, encryption_oid); if (ret) { der_free_octet_string(ciphertext); hx509_set_error_string(context, 0, ENOMEM, "out of memory"); @@ -1276,7 +1827,7 @@ _hx509_private_key_private_decrypt(hx509_context context, int _hx509_parse_private_key(hx509_context context, - const heim_oid *key_oid, + const AlgorithmIdentifier *keyai, const void *data, size_t len, hx509_private_key *private_key) @@ -1286,7 +1837,7 @@ _hx509_parse_private_key(hx509_context context, *private_key = NULL; - ops = find_private_alg(key_oid); + ops = find_private_alg(&keyai->algorithm); if (ops == NULL) { hx509_clear_error_string(context); return HX509_SIG_ALG_NO_SUPPORTED; @@ -1298,7 +1849,7 @@ _hx509_parse_private_key(hx509_context context, return ret; } - ret = (*ops->import)(context, data, len, *private_key); + ret = (*ops->import)(context, keyai, data, len, *private_key); if (ret) _hx509_private_key_free(private_key); @@ -1330,7 +1881,7 @@ _hx509_generate_private_key_init(hx509_context context, { *ctx = NULL; - if (der_heim_oid_cmp(oid, oid_id_pkcs1_rsaEncryption()) != 0) { + if (der_heim_oid_cmp(oid, &asn1_oid_id_pkcs1_rsaEncryption) != 0) { hx509_set_error_string(context, 0, EINVAL, "private key not an RSA key"); return EINVAL; @@ -1400,98 +1951,10 @@ _hx509_generate_private_key(hx509_context context, return ret; } - /* * */ -static const heim_octet_string null_entry_oid = { 2, rk_UNCONST("\x05\x00") }; - -static const unsigned sha512_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 }; -const AlgorithmIdentifier _hx509_signature_sha512_data = { - { 9, rk_UNCONST(sha512_oid_tree) }, rk_UNCONST(&null_entry_oid) -}; - -static const unsigned sha384_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 2 }; -const AlgorithmIdentifier _hx509_signature_sha384_data = { - { 9, rk_UNCONST(sha384_oid_tree) }, rk_UNCONST(&null_entry_oid) -}; - -static const unsigned sha256_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }; -const AlgorithmIdentifier _hx509_signature_sha256_data = { - { 9, rk_UNCONST(sha256_oid_tree) }, rk_UNCONST(&null_entry_oid) -}; - -static const unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 }; -const AlgorithmIdentifier _hx509_signature_sha1_data = { - { 6, rk_UNCONST(sha1_oid_tree) }, rk_UNCONST(&null_entry_oid) -}; - -static const unsigned md5_oid_tree[] = { 1, 2, 840, 113549, 2, 5 }; -const AlgorithmIdentifier _hx509_signature_md5_data = { - { 6, rk_UNCONST(md5_oid_tree) }, rk_UNCONST(&null_entry_oid) -}; - -static const unsigned md2_oid_tree[] = { 1, 2, 840, 113549, 2, 2 }; -const AlgorithmIdentifier _hx509_signature_md2_data = { - { 6, rk_UNCONST(md2_oid_tree) }, rk_UNCONST(&null_entry_oid) -}; - -static const unsigned rsa_with_sha512_oid[] ={ 1, 2, 840, 113549, 1, 1, 13 }; -const AlgorithmIdentifier _hx509_signature_rsa_with_sha512_data = { - { 7, rk_UNCONST(rsa_with_sha512_oid) }, NULL -}; - -static const unsigned rsa_with_sha384_oid[] ={ 1, 2, 840, 113549, 1, 1, 12 }; -const AlgorithmIdentifier _hx509_signature_rsa_with_sha384_data = { - { 7, rk_UNCONST(rsa_with_sha384_oid) }, NULL -}; - -static const unsigned rsa_with_sha256_oid[] ={ 1, 2, 840, 113549, 1, 1, 11 }; -const AlgorithmIdentifier _hx509_signature_rsa_with_sha256_data = { - { 7, rk_UNCONST(rsa_with_sha256_oid) }, NULL -}; - -static const unsigned rsa_with_sha1_oid[] ={ 1, 2, 840, 113549, 1, 1, 5 }; -const AlgorithmIdentifier _hx509_signature_rsa_with_sha1_data = { - { 7, rk_UNCONST(rsa_with_sha1_oid) }, NULL -}; - -static const unsigned rsa_with_md5_oid[] ={ 1, 2, 840, 113549, 1, 1, 4 }; -const AlgorithmIdentifier _hx509_signature_rsa_with_md5_data = { - { 7, rk_UNCONST(rsa_with_md5_oid) }, NULL -}; - -static const unsigned rsa_with_md2_oid[] ={ 1, 2, 840, 113549, 1, 1, 2 }; -const AlgorithmIdentifier _hx509_signature_rsa_with_md2_data = { - { 7, rk_UNCONST(rsa_with_md2_oid) }, NULL -}; - -static const unsigned rsa_oid[] ={ 1, 2, 840, 113549, 1, 1, 1 }; -const AlgorithmIdentifier _hx509_signature_rsa_data = { - { 7, rk_UNCONST(rsa_oid) }, NULL -}; - -static const unsigned rsa_pkcs1_x509_oid[] ={ 1, 2, 752, 43, 16, 1 }; -const AlgorithmIdentifier _hx509_signature_rsa_pkcs1_x509_data = { - { 6, rk_UNCONST(rsa_pkcs1_x509_oid) }, NULL -}; - -static const unsigned des_rsdi_ede3_cbc_oid[] ={ 1, 2, 840, 113549, 3, 7 }; -const AlgorithmIdentifier _hx509_des_rsdi_ede3_cbc_oid = { - { 6, rk_UNCONST(des_rsdi_ede3_cbc_oid) }, NULL -}; - -static const unsigned aes128_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 2 }; -const AlgorithmIdentifier _hx509_crypto_aes128_cbc_data = { - { 9, rk_UNCONST(aes128_cbc_oid) }, NULL -}; - -static const unsigned aes256_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 42 }; -const AlgorithmIdentifier _hx509_crypto_aes256_cbc_data = { - { 9, rk_UNCONST(aes256_cbc_oid) }, NULL -}; - const AlgorithmIdentifier * hx509_signature_sha512(void) { return &_hx509_signature_sha512_data; } @@ -1516,6 +1979,18 @@ const AlgorithmIdentifier * hx509_signature_md2(void) { return &_hx509_signature_md2_data; } +const AlgorithmIdentifier * +hx509_signature_ecPublicKey(void) +{ return &_hx509_signature_ecPublicKey; } + +const AlgorithmIdentifier * +hx509_signature_ecdsa_with_sha256(void) +{ return &_hx509_signature_ecdsa_with_sha256_data; } + +const AlgorithmIdentifier * +hx509_signature_ecdsa_with_sha1(void) +{ return &_hx509_signature_ecdsa_with_sha1_data; } + const AlgorithmIdentifier * hx509_signature_rsa_with_sha512(void) { return &_hx509_signature_rsa_with_sha512_data; } @@ -1565,9 +2040,9 @@ hx509_crypto_aes256_cbc(void) */ const AlgorithmIdentifier * _hx509_crypto_default_sig_alg = - &_hx509_signature_rsa_with_sha1_data; + &_hx509_signature_rsa_with_sha256_data; const AlgorithmIdentifier * _hx509_crypto_default_digest_alg = - &_hx509_signature_sha1_data; + &_hx509_signature_sha256_data; const AlgorithmIdentifier * _hx509_crypto_default_secret_alg = &_hx509_crypto_aes128_cbc_data; @@ -1617,8 +2092,15 @@ _hx509_private_key_free(hx509_private_key *key) if (--(*key)->ref > 0) return 0; - if ((*key)->private_key.rsa) - RSA_free((*key)->private_key.rsa); + if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid, &asn1_oid_id_pkcs1_rsaEncryption) == 0) { + if ((*key)->private_key.rsa) + RSA_free((*key)->private_key.rsa); +#ifdef HAVE_OPENSSL + } else if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid, &asn1_oid_id_ecPublicKey) == 0) { + if ((*key)->private_key.ecdsa) + EC_KEY_free((*key)->private_key.ecdsa); +#endif + } (*key)->private_key.rsa = NULL; free(*key); *key = NULL; @@ -1631,7 +2113,7 @@ _hx509_private_key_assign_rsa(hx509_private_key key, void *ptr) if (key->private_key.rsa) RSA_free(key->private_key.rsa); key->private_key.rsa = ptr; - key->signature_alg = oid_id_pkcs1_sha1WithRSAEncryption(); + key->signature_alg = &asn1_oid_id_pkcs1_sha1WithRSAEncryption; key->md = &pkcs1_rsa_sha1_alg; } @@ -1641,7 +2123,7 @@ _hx509_private_key_oid(hx509_context context, heim_oid *data) { int ret; - ret = der_copy_oid((*key->ops->key_oid)(), data); + ret = der_copy_oid(key->ops->key_oid, data); if (ret) hx509_set_error_string(context, 0, ret, "malloc out of memory"); return ret; @@ -1683,7 +2165,9 @@ _hx509_private_key_export(hx509_context context, struct hx509cipher { const char *name; - const heim_oid *(*oid_func)(void); + int flags; +#define CIPHER_WEAK 1 + const heim_oid *oid; const AlgorithmIdentifier *(*ai_func)(void); const EVP_CIPHER *(*evp_func)(void); int (*get_params)(hx509_context, const hx509_crypto, @@ -1694,6 +2178,8 @@ struct hx509cipher { struct hx509_crypto_data { char *name; + int flags; +#define ALLOW_WEAK 1 const struct hx509cipher *cipher; const EVP_CIPHER *c; heim_octet_string key; @@ -1705,15 +2191,10 @@ struct hx509_crypto_data { * */ -static const heim_oid * -oid_private_rc2_40(void) -{ - static unsigned oid_data[] = { 127, 1 }; - static const heim_oid oid = { 2, oid_data }; - - return &oid; -} +static unsigned private_rc2_40_oid_data[] = { 127, 1 }; +static heim_oid asn1_oid_private_rc2_40 = + { 2, private_rc2_40_oid_data }; /* * @@ -1853,7 +2334,8 @@ CMSRC2CBCParam_set(hx509_context context, const heim_octet_string *param, static const struct hx509cipher ciphers[] = { { "rc2-cbc", - oid_id_pkcs3_rc2_cbc, + CIPHER_WEAK, + &asn1_oid_id_pkcs3_rc2_cbc, NULL, EVP_rc2_cbc, CMSRC2CBCParam_get, @@ -1861,7 +2343,8 @@ static const struct hx509cipher ciphers[] = { }, { "rc2-cbc", - oid_id_rsadsi_rc2_cbc, + CIPHER_WEAK, + &asn1_oid_id_rsadsi_rc2_cbc, NULL, EVP_rc2_cbc, CMSRC2CBCParam_get, @@ -1869,7 +2352,8 @@ static const struct hx509cipher ciphers[] = { }, { "rc2-40-cbc", - oid_private_rc2_40, + CIPHER_WEAK, + &asn1_oid_private_rc2_40, NULL, EVP_rc2_40_cbc, CMSRC2CBCParam_get, @@ -1877,7 +2361,8 @@ static const struct hx509cipher ciphers[] = { }, { "des-ede3-cbc", - oid_id_pkcs3_des_ede3_cbc, + 0, + &asn1_oid_id_pkcs3_des_ede3_cbc, NULL, EVP_des_ede3_cbc, CMSCBCParam_get, @@ -1885,7 +2370,8 @@ static const struct hx509cipher ciphers[] = { }, { "des-ede3-cbc", - oid_id_rsadsi_des_ede3_cbc, + 0, + &asn1_oid_id_rsadsi_des_ede3_cbc, hx509_crypto_des_rsdi_ede3_cbc, EVP_des_ede3_cbc, CMSCBCParam_get, @@ -1893,7 +2379,8 @@ static const struct hx509cipher ciphers[] = { }, { "aes-128-cbc", - oid_id_aes_128_cbc, + 0, + &asn1_oid_id_aes_128_cbc, hx509_crypto_aes128_cbc, EVP_aes_128_cbc, CMSCBCParam_get, @@ -1901,7 +2388,8 @@ static const struct hx509cipher ciphers[] = { }, { "aes-192-cbc", - oid_id_aes_192_cbc, + 0, + &asn1_oid_id_aes_192_cbc, NULL, EVP_aes_192_cbc, CMSCBCParam_get, @@ -1909,7 +2397,8 @@ static const struct hx509cipher ciphers[] = { }, { "aes-256-cbc", - oid_id_aes_256_cbc, + 0, + &asn1_oid_id_aes_256_cbc, hx509_crypto_aes256_cbc, EVP_aes_256_cbc, CMSCBCParam_get, @@ -1923,7 +2412,7 @@ find_cipher_by_oid(const heim_oid *oid) int i; for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++) - if (der_heim_oid_cmp(oid, (*ciphers[i].oid_func)()) == 0) + if (der_heim_oid_cmp(oid, ciphers[i].oid) == 0) return &ciphers[i]; return NULL; @@ -1950,7 +2439,7 @@ hx509_crypto_enctype_by_name(const char *name) cipher = find_cipher_by_name(name); if (cipher == NULL) return NULL; - return (*cipher->oid_func)(); + return cipher->oid; } int @@ -2015,6 +2504,12 @@ hx509_crypto_set_key_name(hx509_crypto crypto, const char *name) return 0; } +void +hx509_crypto_allow_weak(hx509_crypto crypto) +{ + crypto->flags |= ALLOW_WEAK; +} + int hx509_crypto_set_key_data(hx509_crypto crypto, const void *data, size_t length) { @@ -2111,6 +2606,10 @@ hx509_crypto_encrypt(hx509_crypto crypto, *ciphertext = NULL; + if ((crypto->cipher->flags & CIPHER_WEAK) && + (crypto->flags & ALLOW_WEAK) == 0) + return HX509_CRYPTO_ALGORITHM_BEST_BEFORE; + assert(EVP_CIPHER_iv_length(crypto->c) == ivec->length); EVP_CIPHER_CTX_init(&evp); @@ -2189,6 +2688,10 @@ hx509_crypto_decrypt(hx509_crypto crypto, clear->data = NULL; clear->length = 0; + if ((crypto->cipher->flags & CIPHER_WEAK) && + (crypto->flags & ALLOW_WEAK) == 0) + return HX509_CRYPTO_ALGORITHM_BEST_BEFORE; + if (ivec && EVP_CIPHER_iv_length(crypto->c) < ivec->length) return HX509_CRYPTO_INTERNAL_ERROR; @@ -2312,6 +2815,8 @@ PBE_string2key(hx509_context context, if (ret) goto out; + hx509_crypto_allow_weak(c); + ret = hx509_crypto_set_key_data(c, key->data, key->length); if (ret) { hx509_crypto_destroy(c); @@ -2330,33 +2835,33 @@ find_string2key(const heim_oid *oid, const EVP_MD **md, PBE_string2key_func *s2k) { - if (der_heim_oid_cmp(oid, oid_id_pbewithSHAAnd40BitRC2_CBC()) == 0) { + if (der_heim_oid_cmp(oid, &asn1_oid_id_pbewithSHAAnd40BitRC2_CBC) == 0) { *c = EVP_rc2_40_cbc(); *md = EVP_sha1(); *s2k = PBE_string2key; - return oid_private_rc2_40(); - } else if (der_heim_oid_cmp(oid, oid_id_pbeWithSHAAnd128BitRC2_CBC()) == 0) { + return &asn1_oid_private_rc2_40; + } else if (der_heim_oid_cmp(oid, &asn1_oid_id_pbeWithSHAAnd128BitRC2_CBC) == 0) { *c = EVP_rc2_cbc(); *md = EVP_sha1(); *s2k = PBE_string2key; - return oid_id_pkcs3_rc2_cbc(); + return &asn1_oid_id_pkcs3_rc2_cbc; #if 0 - } else if (der_heim_oid_cmp(oid, oid_id_pbeWithSHAAnd40BitRC4()) == 0) { + } else if (der_heim_oid_cmp(oid, &asn1_oid_id_pbeWithSHAAnd40BitRC4) == 0) { *c = EVP_rc4_40(); *md = EVP_sha1(); *s2k = PBE_string2key; return NULL; - } else if (der_heim_oid_cmp(oid, oid_id_pbeWithSHAAnd128BitRC4()) == 0) { + } else if (der_heim_oid_cmp(oid, &asn1_oid_id_pbeWithSHAAnd128BitRC4) == 0) { *c = EVP_rc4(); *md = EVP_sha1(); *s2k = PBE_string2key; - return oid_id_pkcs3_rc4(); + return &asn1_oid_id_pkcs3_rc4; #endif - } else if (der_heim_oid_cmp(oid, oid_id_pbeWithSHAAnd3_KeyTripleDES_CBC()) == 0) { + } else if (der_heim_oid_cmp(oid, &asn1_oid_id_pbeWithSHAAnd3_KeyTripleDES_CBC) == 0) { *c = EVP_des_ede3_cbc(); *md = EVP_sha1(); *s2k = PBE_string2key; - return oid_id_pkcs3_des_ede3_cbc(); + return &asn1_oid_id_pkcs3_des_ede3_cbc; } return NULL; @@ -2467,8 +2972,8 @@ out: */ -int -_hx509_match_keys(hx509_cert c, hx509_private_key private_key) +static int +match_keys_rsa(hx509_cert c, hx509_private_key private_key) { const Certificate *cert; const SubjectPublicKeyInfo *spi; @@ -2523,6 +3028,25 @@ _hx509_match_keys(hx509_cert c, hx509_private_key private_key) return ret == 1; } +static int +match_keys_ec(hx509_cert c, hx509_private_key private_key) +{ + return 1; /* XXX use EC_KEY_check_key */ +} + + +int +_hx509_match_keys(hx509_cert c, hx509_private_key key) +{ + if (der_heim_oid_cmp(key->ops->key_oid, &asn1_oid_id_pkcs1_rsaEncryption) == 0) + return match_keys_rsa(c, key); + if (der_heim_oid_cmp(key->ops->key_oid, &asn1_oid_id_ecPublicKey) == 0) + return match_keys_ec(c, key); + return 0; + +} + + static const heim_oid * find_keytype(const hx509_private_key key) { @@ -2534,10 +3058,9 @@ find_keytype(const hx509_private_key key) md = find_sig_alg(key->signature_alg); if (md == NULL) return NULL; - return (*md->key_oid)(); + return md->key_oid; } - int hx509_crypto_select(const hx509_context context, int type, @@ -2545,7 +3068,7 @@ hx509_crypto_select(const hx509_context context, hx509_peer_info peer, AlgorithmIdentifier *selected) { - const AlgorithmIdentifier *def; + const AlgorithmIdentifier *def = NULL; size_t i, j; int ret, bits; @@ -2553,11 +3076,17 @@ hx509_crypto_select(const hx509_context context, if (type == HX509_SELECT_DIGEST) { bits = SIG_DIGEST; - def = _hx509_crypto_default_digest_alg; + if (source) + def = alg_for_privatekey(source, type); + if (def == NULL) + def = _hx509_crypto_default_digest_alg; } else if (type == HX509_SELECT_PUBLIC_SIG) { bits = SIG_PUBLIC_SIG; /* XXX depend on `source´ and `peer´ */ - def = _hx509_crypto_default_sig_alg; + if (source) + def = alg_for_privatekey(source, type); + if (def == NULL) + def = _hx509_crypto_default_sig_alg; } else if (type == HX509_SELECT_SECRET_ENC) { bits = SIG_SECRET; def = _hx509_crypto_default_secret_alg; @@ -2576,11 +3105,11 @@ hx509_crypto_select(const hx509_context context, for (j = 0; sig_algs[j]; j++) { if ((sig_algs[j]->flags & bits) != bits) continue; - if (der_heim_oid_cmp((*sig_algs[j]->sig_oid)(), + if (der_heim_oid_cmp(sig_algs[j]->sig_oid, &peer->val[i].algorithm) != 0) continue; if (keytype && sig_algs[j]->key_oid && - der_heim_oid_cmp(keytype, (*sig_algs[j]->key_oid)())) + der_heim_oid_cmp(keytype, sig_algs[j]->key_oid)) continue; /* found one, use that */ @@ -2648,7 +3177,7 @@ hx509_crypto_available(hx509_context context, if (sig_algs[i]->sig_alg == NULL) continue; if (keytype && sig_algs[i]->key_oid && - der_heim_oid_cmp((*sig_algs[i]->key_oid)(), keytype)) + der_heim_oid_cmp(sig_algs[i]->key_oid, keytype)) continue; /* found one, add that to the list */ @@ -2657,7 +3186,7 @@ hx509_crypto_available(hx509_context context, goto out; *val = ptr; - ret = copy_AlgorithmIdentifier((*sig_algs[i]->sig_alg)(), &(*val)[len]); + ret = copy_AlgorithmIdentifier(sig_algs[i]->sig_alg, &(*val)[len]); if (ret) goto out; len++; @@ -2667,7 +3196,9 @@ hx509_crypto_available(hx509_context context, if (bits & SIG_SECRET) { for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++) { - + + if (ciphers[i].flags & CIPHER_WEAK) + continue; if (ciphers[i].ai_func == NULL) continue; diff --git a/source4/heimdal/lib/hx509/env.c b/source4/heimdal/lib/hx509/env.c index 0b0a68ceae..7598aebaae 100644 --- a/source4/heimdal/lib/hx509/env.c +++ b/source4/heimdal/lib/hx509/env.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_env Hx509 enviroment functions diff --git a/source4/heimdal/lib/hx509/error.c b/source4/heimdal/lib/hx509/error.c index 6f25404145..45813efb38 100644 --- a/source4/heimdal/lib/hx509/error.c +++ b/source4/heimdal/lib/hx509/error.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_error Hx509 error reporting functions diff --git a/source4/heimdal/lib/hx509/file.c b/source4/heimdal/lib/hx509/file.c index a364dd2179..ba7a23f471 100644 --- a/source4/heimdal/lib/hx509/file.c +++ b/source4/heimdal/lib/hx509/file.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$ID$"); int _hx509_map_file_os(const char *fn, heim_octet_string *os) diff --git a/source4/heimdal/lib/hx509/hx509.h b/source4/heimdal/lib/hx509/hx509.h index 5e5a2f811b..86aad7ec9c 100644 --- a/source4/heimdal/lib/hx509/hx509.h +++ b/source4/heimdal/lib/hx509/hx509.h @@ -36,8 +36,9 @@ #ifndef HEIMDAL_HX509_H #define HEIMDAL_HX509_H 1 -#include #include +#include +#include typedef struct hx509_cert_attribute_data *hx509_cert_attribute; typedef struct hx509_cert_data *hx509_cert; @@ -124,6 +125,17 @@ typedef enum { /* flags to hx509_cms_unenvelope */ #define HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT 0x01 +#define HX509_CMS_UE_ALLOW_WEAK 0x02 + +/* flags to hx509_cms_envelope_1 */ +#define HX509_CMS_EV_NO_KU_CHECK 0x01 +#define HX509_CMS_EV_ALLOW_WEAK 0x02 + +/* flags to hx509_cms_verify_signed */ +#define HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH 0x01 +#define HX509_CMS_VS_NO_KU_CHECK 0x02 +#define HX509_CMS_VS_ALLOW_ZERO_SIGNER 0x04 +#define HX509_CMS_VS_NO_VALIDATE 0x08 /* selectors passed to hx509_crypto_select and hx509_crypto_available */ #define HX509_SELECT_ALL 0 @@ -142,8 +154,9 @@ typedef enum { #define HX509_CA_TEMPLATE_EKU 64 /* flags hx509_cms_create_signed* */ -#define HX509_CMS_SIGATURE_DETACHED 1 -#define HX509_CMS_SIGATURE_ID_NAME 2 +#define HX509_CMS_SIGNATURE_DETACHED 0x01 +#define HX509_CMS_SIGNATURE_ID_NAME 0x02 +#define HX509_CMS_SIGNATURE_NO_SIGNER 0x04 /* hx509_verify_hostname nametype */ typedef enum { diff --git a/source4/heimdal/lib/hx509/hx509_err.et b/source4/heimdal/lib/hx509/hx509_err.et index c1dfaf587e..76bbfaeaba 100644 --- a/source4/heimdal/lib/hx509/hx509_err.et +++ b/source4/heimdal/lib/hx509/hx509_err.et @@ -62,9 +62,10 @@ error_code OID_MISMATCH, "Mismatch bewteen oids" error_code NO_PROMPTER, "No prompter function defined" error_code SIGNATURE_WITHOUT_SIGNER, "Signature require signer, but non available" error_code RSA_PUBLIC_ENCRYPT, "RSA public encyption failed" -error_code RSA_PRIVATE_ENCRYPT, "RSA public encyption failed" -error_code RSA_PUBLIC_DECRYPT, "RSA private decryption failed" +error_code RSA_PRIVATE_ENCRYPT, "RSA private encyption failed" +error_code RSA_PUBLIC_DECRYPT, "RSA public decryption failed" error_code RSA_PRIVATE_DECRYPT, "RSA private decryption failed" +error_code ALGORITHM_BEST_BEFORE, "Algorithm has passed its best before date" # revoke related errors index 96 diff --git a/source4/heimdal/lib/hx509/hx_locl.h b/source4/heimdal/lib/hx509/hx_locl.h index 8de2353f15..2d1c036d53 100644 --- a/source4/heimdal/lib/hx509/hx_locl.h +++ b/source4/heimdal/lib/hx509/hx_locl.h @@ -33,9 +33,7 @@ /* $Id$ */ -#ifdef HAVE_CONFIG_H #include -#endif #include #include @@ -145,7 +143,7 @@ struct hx509_query_data { Name *subject_name; hx509_path *path; char *friendlyname; - int (*cmp_func)(void *, hx509_cert); + int (*cmp_func)(hx509_context, hx509_cert, void *); void *cmp_func_ctx; heim_octet_string *keyhash_sha1; time_t timenow; diff --git a/source4/heimdal/lib/hx509/keyset.c b/source4/heimdal/lib/hx509/keyset.c index b68064b512..c4f035ab87 100644 --- a/source4/heimdal/lib/hx509/keyset.c +++ b/source4/heimdal/lib/hx509/keyset.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_keyset Certificate store operations @@ -481,6 +480,10 @@ hx509_certs_find(hx509_context context, hx509_certs_end_seq(context, certs, cursor); if (ret) return ret; + /** + * Return HX509_CERT_NOT_FOUND if no certificate in certs matched + * the query. + */ if (c == NULL) { hx509_clear_error_string(context); return HX509_CERT_NOT_FOUND; @@ -489,6 +492,77 @@ hx509_certs_find(hx509_context context, return 0; } +/** + * Filter certificate matching the query. + * + * @param context a hx509 context. + * @param certs certificate store to search. + * @param q query allocated with @ref hx509_query functions. + * @param result the filtered certificate store, caller must free with + * hx509_certs_free(). + * + * @return Returns an hx509 error code. + * + * @ingroup hx509_keyset + */ + +int +hx509_certs_filter(hx509_context context, + hx509_certs certs, + const hx509_query *q, + hx509_certs *result) +{ + hx509_cursor cursor; + hx509_cert c; + int ret, found = 0; + + _hx509_query_statistic(context, 0, q); + + ret = hx509_certs_init(context, "MEMORY:filter-certs", 0, + NULL, result); + if (ret) + return ret; + + ret = hx509_certs_start_seq(context, certs, &cursor); + if (ret) { + hx509_certs_free(result); + return ret; + } + + c = NULL; + while (1) { + ret = hx509_certs_next_cert(context, certs, cursor, &c); + if (ret) + break; + if (c == NULL) + break; + if (_hx509_query_match_cert(context, q, c)) { + hx509_certs_add(context, *result, c); + found = 1; + } + hx509_cert_free(c); + } + + hx509_certs_end_seq(context, certs, cursor); + if (ret) { + hx509_certs_free(result); + return ret; + } + + /** + * Return HX509_CERT_NOT_FOUND if no certificate in certs matched + * the query. + */ + if (!found) { + hx509_certs_free(result); + hx509_clear_error_string(context); + return HX509_CERT_NOT_FOUND; + } + + return 0; +} + + static int certs_merge_func(hx509_context context, void *ctx, hx509_cert c) { diff --git a/source4/heimdal/lib/hx509/ks_dir.c b/source4/heimdal/lib/hx509/ks_dir.c index 76c0c42633..a627fc65a2 100644 --- a/source4/heimdal/lib/hx509/ks_dir.c +++ b/source4/heimdal/lib/hx509/ks_dir.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); #include /* @@ -71,7 +70,7 @@ dir_init(hx509_context context, return ENOENT; } - if ((sb.st_mode & S_IFDIR) == 0) { + if (!S_ISDIR(sb.st_mode)) { hx509_set_error_string(context, 0, ENOTDIR, "%s is not a directory", residue); return ENOTDIR; diff --git a/source4/heimdal/lib/hx509/ks_file.c b/source4/heimdal/lib/hx509/ks_file.c index ca0171f8b9..74808f7607 100644 --- a/source4/heimdal/lib/hx509/ks_file.c +++ b/source4/heimdal/lib/hx509/ks_file.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); typedef enum { USE_PEM, USE_DER } outformat; @@ -50,7 +49,8 @@ static int parse_certificate(hx509_context context, const char *fn, struct hx509_collector *c, const hx509_pem_header *headers, - const void *data, size_t len) + const void *data, size_t len, + const AlgorithmIdentifier *ai) { hx509_cert cert; int ret; @@ -130,10 +130,40 @@ out: } static int -parse_rsa_private_key(hx509_context context, const char *fn, +parse_pkcs8_private_key(hx509_context context, const char *fn, + struct hx509_collector *c, + const hx509_pem_header *headers, + const void *data, size_t length, + const AlgorithmIdentifier *ai) +{ + PKCS8PrivateKeyInfo ki; + heim_octet_string keydata; + + int ret; + + ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL); + if (ret) + return ret; + + keydata.data = rk_UNCONST(data); + keydata.length = length; + + ret = _hx509_collector_private_key_add(context, + c, + &ki.privateKeyAlgorithm, + NULL, + &ki.privateKey, + &keydata); + free_PKCS8PrivateKeyInfo(&ki); + return ret; +} + +static int +parse_pem_private_key(hx509_context context, const char *fn, struct hx509_collector *c, const hx509_pem_header *headers, - const void *data, size_t len) + const void *data, size_t len, + const AlgorithmIdentifier *ai) { int ret = 0; const char *enc; @@ -159,7 +189,7 @@ parse_rsa_private_key(hx509_context context, const char *fn, if (strcmp(enc, "4,ENCRYPTED") != 0) { hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, - "RSA key encrypted in unknown method %s " + "Private key encrypted in unknown method %s " "in file", enc, fn); hx509_clear_error_string(context); @@ -169,7 +199,7 @@ parse_rsa_private_key(hx509_context context, const char *fn, dek = hx509_pem_find_header(headers, "DEK-Info"); if (dek == NULL) { hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, - "Encrypted RSA missing DEK-Info"); + "Encrypted private key missing DEK-Info"); return HX509_PARSING_KEY_FAILED; } @@ -201,7 +231,7 @@ parse_rsa_private_key(hx509_context context, const char *fn, if (cipher == NULL) { free(ivdata); hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP, - "RSA key encrypted with " + "Private key encrypted with " "unsupported cipher: %s", type); free(type); @@ -218,7 +248,8 @@ parse_rsa_private_key(hx509_context context, const char *fn, if (ssize < 0 || ssize < PKCS5_SALT_LEN || ssize < EVP_CIPHER_iv_length(cipher)) { free(ivdata); hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, - "Salt have wrong length in RSA key file"); + "Salt have wrong length in " + "private key file"); return HX509_PARSING_KEY_FAILED; } @@ -231,9 +262,8 @@ parse_rsa_private_key(hx509_context context, const char *fn, password = pw->val[i]; passwordlen = strlen(password); - ret = try_decrypt(context, c, hx509_signature_rsa(), - cipher, ivdata, password, passwordlen, - data, len); + ret = try_decrypt(context, c, ai, cipher, ivdata, + password, passwordlen, data, len); if (ret == 0) { decrypted = 1; break; @@ -253,9 +283,8 @@ parse_rsa_private_key(hx509_context context, const char *fn, ret = hx509_lock_prompt(lock, &prompt); if (ret == 0) - ret = try_decrypt(context, c, hx509_signature_rsa(), - cipher, ivdata, password, strlen(password), - data, len); + ret = try_decrypt(context, c, ai, cipher, ivdata, password, + strlen(password), data, len); /* XXX add password to lock password collection ? */ memset(password, 0, sizeof(password)); } @@ -267,12 +296,8 @@ parse_rsa_private_key(hx509_context context, const char *fn, keydata.data = rk_UNCONST(data); keydata.length = len; - ret = _hx509_collector_private_key_add(context, - c, - hx509_signature_rsa(), - NULL, - &keydata, - NULL); + ret = _hx509_collector_private_key_add(context, c, ai, NULL, + &keydata, NULL); } return ret; @@ -282,10 +307,14 @@ parse_rsa_private_key(hx509_context context, const char *fn, struct pem_formats { const char *name; int (*func)(hx509_context, const char *, struct hx509_collector *, - const hx509_pem_header *, const void *, size_t); + const hx509_pem_header *, const void *, size_t, + const AlgorithmIdentifier *); + const AlgorithmIdentifier *(*ai)(void); } formats[] = { - { "CERTIFICATE", parse_certificate }, - { "RSA PRIVATE KEY", parse_rsa_private_key } + { "CERTIFICATE", parse_certificate, NULL }, + { "PRIVATE KEY", parse_pkcs8_private_key, NULL }, + { "RSA PRIVATE KEY", parse_pem_private_key, hx509_signature_rsa }, + { "EC PRIVATE KEY", parse_pem_private_key, hx509_signature_ecPublicKey } }; @@ -305,9 +334,18 @@ pem_func(hx509_context context, const char *type, for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) { const char *q = formats[j].name; if (strcasecmp(type, q) == 0) { - ret = (*formats[j].func)(context, NULL, pem_ctx->c, header, data, len); - if (ret == 0) - break; + const AlgorithmIdentifier *ai = NULL; + if (formats[j].ai != NULL) + ai = (*formats[j].ai)(); + + ret = (*formats[j].func)(context, NULL, pem_ctx->c, + header, data, len, ai); + if (ret) { + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "Failed parseing PEM format %s", type); + return ret; + } + break; } } if (j == sizeof(formats)/sizeof(formats[0])) { @@ -409,13 +447,19 @@ file_init_common(hx509_context context, } for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) { - ret = (*formats[i].func)(context, p, pem_ctx.c, NULL, ptr, length); + const AlgorithmIdentifier *ai = NULL; + if (formats[i].ai != NULL) + ai = (*formats[i].ai)(); + + ret = (*formats[i].func)(context, p, pem_ctx.c, NULL, ptr, length, ai); if (ret == 0) break; } rk_xfree(ptr); - if (ret) + if (ret) { + hx509_clear_error_string(context); goto out; + } } } diff --git a/source4/heimdal/lib/hx509/ks_keychain.c b/source4/heimdal/lib/hx509/ks_keychain.c index 2dc0721563..01d0c55d1c 100644 --- a/source4/heimdal/lib/hx509/ks_keychain.c +++ b/source4/heimdal/lib/hx509/ks_keychain.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); #ifdef HAVE_FRAMEWORK_SECURITY @@ -119,6 +118,8 @@ kc_rsa_private_encrypt(int flen, CSSM_DATA sig, in; int fret = 0; + if (padding != RSA_PKCS1_PADDING) + return -1; cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); if(cret) abort(); @@ -157,7 +158,62 @@ static int kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA * rsa, int padding) { - return -1; + struct kc_rsa *kc = RSA_get_app_data(rsa); + + CSSM_RETURN cret; + OSStatus ret; + const CSSM_ACCESS_CREDENTIALS *creds; + SecKeyRef privKeyRef = (SecKeyRef)kc->item; + CSSM_CSP_HANDLE cspHandle; + const CSSM_KEY *cssmKey; + CSSM_CC_HANDLE handle = 0; + CSSM_DATA out, in, rem; + int fret = 0; + CSSM_SIZE outlen = 0; + char remdata[1024]; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); + if(cret) abort(); + + cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); + if(cret) abort(); + + ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT, + kSecCredentialTypeDefault, &creds); + if(ret) abort(); + + + ret = CSSM_CSP_CreateAsymmetricContext (cspHandle, + CSSM_ALGID_RSA, + creds, + cssmKey, + CSSM_PADDING_PKCS1, + &handle); + if(ret) abort(); + + in.Data = (uint8 *)from; + in.Length = flen; + + out.Data = (uint8 *)to; + out.Length = kc->keysize; + + rem.Data = (uint8 *)remdata; + rem.Length = sizeof(remdata); + + cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem); + if(cret) { + /* cssmErrorString(cret); */ + fret = -1; + } else + fret = out.Length; + + if(handle) + CSSM_DeleteContext(handle); + + return fret; } static int @@ -504,8 +560,7 @@ keychain_iter_end(hx509_context context, struct iter *iter = cursor; if (iter->certs) { - int ret; - ret = hx509_certs_end_seq(context, iter->certs, iter->cursor); + hx509_certs_end_seq(context, iter->certs, iter->cursor); hx509_certs_free(&iter->certs); } else { CFRelease(iter->searchRef); diff --git a/source4/heimdal/lib/hx509/ks_mem.c b/source4/heimdal/lib/hx509/ks_mem.c index bf952fbeee..299a3932c9 100644 --- a/source4/heimdal/lib/hx509/ks_mem.c +++ b/source4/heimdal/lib/hx509/ks_mem.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("Id$"); /* * Should use two hash/tree certificates intead of a array. Criteria diff --git a/source4/heimdal/lib/hx509/ks_null.c b/source4/heimdal/lib/hx509/ks_null.c index fae631fb3f..136d2d4345 100644 --- a/source4/heimdal/lib/hx509/ks_null.c +++ b/source4/heimdal/lib/hx509/ks_null.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); static int diff --git a/source4/heimdal/lib/hx509/ks_p11.c b/source4/heimdal/lib/hx509/ks_p11.c index 652cdc2210..52697f834b 100644 --- a/source4/heimdal/lib/hx509/ks_p11.c +++ b/source4/heimdal/lib/hx509/ks_p11.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); #ifdef HAVE_DLFCN_H #include #endif @@ -332,7 +331,7 @@ p11_init_slot(hx509_context context, } asprintf(&slot->name, "%.*s", - i, slot_info.slotDescription); + (int)i, slot_info.slotDescription); if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0) return 0; @@ -711,7 +710,7 @@ collect_cert(hx509_context context, _hx509_set_cert_attribute(context, cert, - oid_id_pkcs_9_at_localKeyId(), + &asn1_oid_id_pkcs_9_at_localKeyId, &data); } @@ -945,11 +944,7 @@ p11_release_module(struct p11_module *p) if (p->slot[i].flags & P11_SESSION_IN_USE) _hx509_abort("pkcs11 module release while session in use"); if (p->slot[i].flags & P11_SESSION) { - int ret; - - ret = P11FUNC(p, CloseSession, (p->slot[i].session)); - if (ret != CKR_OK) - ; + P11FUNC(p, CloseSession, (p->slot[i].session)); } if (p->slot[i].name) diff --git a/source4/heimdal/lib/hx509/ks_p12.c b/source4/heimdal/lib/hx509/ks_p12.c index b59bd215f0..c17ce3f6ac 100644 --- a/source4/heimdal/lib/hx509/ks_p12.c +++ b/source4/heimdal/lib/hx509/ks_p12.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); struct ks_pkcs12 { hx509_certs certs; @@ -45,7 +44,7 @@ typedef int (*collector_func)(hx509_context, const PKCS12_Attributes *); struct type { - const heim_oid * (*oid)(void); + const heim_oid *oid; collector_func func; }; @@ -77,7 +76,7 @@ keyBag_parser(hx509_context context, const heim_octet_string *os = NULL; int ret; - attr = find_attribute(attrs, oid_id_pkcs_9_at_localKeyId()); + attr = find_attribute(attrs, &asn1_oid_id_pkcs_9_at_localKeyId); if (attr) os = &attr->attrValues; @@ -140,7 +139,7 @@ certBag_parser(hx509_context context, if (ret) return ret; - if (der_heim_oid_cmp(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType)) { + if (der_heim_oid_cmp(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType)) { free_PKCS12_CertBag(&cb); return 0; } @@ -166,13 +165,13 @@ certBag_parser(hx509_context context, { const PKCS12_Attribute *attr; - const heim_oid * (*oids[])(void) = { - oid_id_pkcs_9_at_localKeyId, oid_id_pkcs_9_at_friendlyName + const heim_oid *oids[] = { + &asn1_oid_id_pkcs_9_at_localKeyId, &asn1_oid_id_pkcs_9_at_friendlyName }; int i; - for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) { - const heim_oid *oid = (*(oids[i]))(); + for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) { + const heim_oid *oid = oids[i]; attr = find_attribute(attrs, oid); if (attr) _hx509_set_cert_attribute(context, cert, oid, @@ -248,7 +247,7 @@ encryptedData_parser(hx509_context context, if (ret) return ret; - if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0) + if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0) ret = parse_safe_content(context, c, content.data, content.length); der_free_octet_string(&content); @@ -285,7 +284,7 @@ envelopedData_parser(hx509_context context, return ret; } - if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0) + if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0) ret = parse_safe_content(context, c, content.data, content.length); der_free_octet_string(&content); @@ -296,12 +295,12 @@ envelopedData_parser(hx509_context context, struct type bagtypes[] = { - { oid_id_pkcs12_keyBag, keyBag_parser }, - { oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser }, - { oid_id_pkcs12_certBag, certBag_parser }, - { oid_id_pkcs7_data, safeContent_parser }, - { oid_id_pkcs7_encryptedData, encryptedData_parser }, - { oid_id_pkcs7_envelopedData, envelopedData_parser } + { &asn1_oid_id_pkcs12_keyBag, keyBag_parser }, + { &asn1_oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser }, + { &asn1_oid_id_pkcs12_certBag, certBag_parser }, + { &asn1_oid_id_pkcs7_data, safeContent_parser }, + { &asn1_oid_id_pkcs7_encryptedData, encryptedData_parser }, + { &asn1_oid_id_pkcs7_envelopedData, envelopedData_parser } }; static void @@ -314,7 +313,7 @@ parse_pkcs12_type(hx509_context context, int i; for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++) - if (der_heim_oid_cmp((*bagtypes[i].oid)(), oid) == 0) + if (der_heim_oid_cmp(bagtypes[i].oid, oid) == 0) (*bagtypes[i].func)(context, c, data, length, attrs); } @@ -376,7 +375,7 @@ p12_init(hx509_context context, goto out; } - if (der_heim_oid_cmp(&pfx.authSafe.contentType, oid_id_pkcs7_data()) != 0) { + if (der_heim_oid_cmp(&pfx.authSafe.contentType, &asn1_oid_id_pkcs7_data) != 0) { free_PKCS12_PFX(&pfx); ret = EINVAL; hx509_set_error_string(context, 0, ret, @@ -506,7 +505,7 @@ store_func(hx509_context context, void *ctx, hx509_cert c) free(os.data); if (ret) goto out; - ret = der_copy_oid(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType); + ret = der_copy_oid(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType); if (ret) { free_PKCS12_CertBag(&cb); goto out; @@ -517,7 +516,7 @@ store_func(hx509_context context, void *ctx, hx509_cert c) if (ret) goto out; - ret = addBag(context, as, oid_id_pkcs12_certBag(), os.data, os.length); + ret = addBag(context, as, &asn1_oid_id_pkcs12_certBag, os.data, os.length); if (_hx509_cert_private_key_exportable(c)) { hx509_private_key key = _hx509_cert_private_key(c); @@ -541,7 +540,7 @@ store_func(hx509_context context, void *ctx, hx509_cert c) free_PKCS8PrivateKeyInfo(&pki); return ret; } - /* set attribute, oid_id_pkcs_9_at_localKeyId() */ + /* set attribute, asn1_oid_id_pkcs_9_at_localKeyId */ ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length, &pki, &size, ret); @@ -549,7 +548,7 @@ store_func(hx509_context context, void *ctx, hx509_cert c) if (ret) return ret; - ret = addBag(context, as, oid_id_pkcs12_keyBag(), os.data, os.length); + ret = addBag(context, as, &asn1_oid_id_pkcs12_keyBag, os.data, os.length); if (ret) return ret; } @@ -598,7 +597,7 @@ p12_store(hx509_context context, if (ret) goto out; - ret = der_copy_oid(oid_id_pkcs7_data(), &pfx.authSafe.contentType); + ret = der_copy_oid(&asn1_oid_id_pkcs7_data, &pfx.authSafe.contentType); if (ret) goto out; diff --git a/source4/heimdal/lib/hx509/lock.c b/source4/heimdal/lib/hx509/lock.c index e2ceedecb8..219a301928 100644 --- a/source4/heimdal/lib/hx509/lock.c +++ b/source4/heimdal/lib/hx509/lock.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_lock Locking and unlocking certificates and encrypted data. diff --git a/source4/heimdal/lib/hx509/name.c b/source4/heimdal/lib/hx509/name.c index 069eed6062..b8f48d5236 100644 --- a/source4/heimdal/lib/hx509/name.c +++ b/source4/heimdal/lib/hx509/name.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * Copyright (c) 2004 - 2009 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,6 @@ #include "hx_locl.h" #include -RCSID("$Id$"); /** * @page page_name PKIX/X.509 Names @@ -63,20 +62,20 @@ RCSID("$Id$"); static const struct { const char *n; - const heim_oid *(*o)(void); + const heim_oid *o; wind_profile_flags flags; } no[] = { - { "C", oid_id_at_countryName }, - { "CN", oid_id_at_commonName }, - { "DC", oid_id_domainComponent }, - { "L", oid_id_at_localityName }, - { "O", oid_id_at_organizationName }, - { "OU", oid_id_at_organizationalUnitName }, - { "S", oid_id_at_stateOrProvinceName }, - { "STREET", oid_id_at_streetAddress }, - { "UID", oid_id_Userid }, - { "emailAddress", oid_id_pkcs9_emailAddress }, - { "serialNumber", oid_id_at_serialNumber } + { "C", &asn1_oid_id_at_countryName }, + { "CN", &asn1_oid_id_at_commonName }, + { "DC", &asn1_oid_id_domainComponent }, + { "L", &asn1_oid_id_at_localityName }, + { "O", &asn1_oid_id_at_organizationName }, + { "OU", &asn1_oid_id_at_organizationalUnitName }, + { "S", &asn1_oid_id_at_stateOrProvinceName }, + { "STREET", &asn1_oid_id_at_streetAddress }, + { "UID", &asn1_oid_id_Userid }, + { "emailAddress", &asn1_oid_id_pkcs9_emailAddress }, + { "serialNumber", &asn1_oid_id_at_serialNumber } }; static char * @@ -145,7 +144,7 @@ oidtostring(const heim_oid *type) size_t i; for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { - if (der_heim_oid_cmp((*no[i].o)(), type) == 0) + if (der_heim_oid_cmp(no[i].o, type) == 0) return strdup(no[i].n); } if (der_print_heim_oid(type, '.', &s) != 0) @@ -163,7 +162,7 @@ stringtooid(const char *name, size_t len, heim_oid *oid) for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { if (strncasecmp(no[i].n, name, len) == 0) - return der_copy_oid((*no[i].o)(), oid); + return der_copy_oid(no[i].o, oid); } s = malloc(len + 1); if (s == NULL) @@ -197,7 +196,7 @@ int _hx509_Name_to_string(const Name *n, char **str) { size_t total_len = 0; - int i, j; + int i, j, ret; *str = strdup(""); if (*str == NULL) @@ -224,15 +223,20 @@ _hx509_Name_to_string(const Name *n, char **str) ss = ds->u.utf8String; break; case choice_DirectoryString_bmpString: { - uint16_t *bmp = ds->u.bmpString.data; + const uint16_t *bmp = ds->u.bmpString.data; size_t bmplen = ds->u.bmpString.length; size_t k; - ss = malloc(bmplen + 1); + ret = wind_ucs2utf8_length(bmp, bmplen, &k); + if (ret) + return ret; + + ss = malloc(k + 1); if (ss == NULL) _hx509_abort("allocation failure"); /* XXX */ - for (k = 0; k < bmplen; k++) - ss[k] = bmp[k] & 0xff; /* XXX */ + ret = wind_ucs2utf8(bmp, bmplen, ss, NULL); + if (ret) + return ret; ss[k] = '\0'; break; } @@ -244,15 +248,20 @@ _hx509_Name_to_string(const Name *n, char **str) ss[ds->u.teletexString.length] = '\0'; break; case choice_DirectoryString_universalString: { - uint32_t *uni = ds->u.universalString.data; + const uint32_t *uni = ds->u.universalString.data; size_t unilen = ds->u.universalString.length; size_t k; - ss = malloc(unilen + 1); + ret = wind_ucs4utf8_length(uni, unilen, &k); + if (ret) + return ret; + + ss = malloc(k + 1); if (ss == NULL) _hx509_abort("allocation failure"); /* XXX */ - for (k = 0; k < unilen; k++) - ss[k] = uni[k] & 0xff; /* XXX */ + ret = wind_ucs4utf8(uni, unilen, ss, NULL); + if (ret) + return ret; ss[k] = '\0'; break; } @@ -344,8 +353,10 @@ dsstringprep(const DirectoryString *ds, uint32_t **rname, size_t *rlen) if (name == NULL) return ENOMEM; ret = wind_utf8ucs4(ds->u.utf8String, name, &len); - if (ret) + if (ret) { + free(name); return ret; + } break; default: _hx509_abort("unknown directory type: %d", ds->element); diff --git a/source4/heimdal/lib/hx509/peer.c b/source4/heimdal/lib/hx509/peer.c index f5841e497b..c796e19173 100644 --- a/source4/heimdal/lib/hx509/peer.c +++ b/source4/heimdal/lib/hx509/peer.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_peer Hx509 crypto selecting functions @@ -120,6 +119,39 @@ hx509_peer_info_set_cert(hx509_peer_info peer, return 0; } +/** + * Add an additional algorithm that the peer supports. + * + * @param context A hx509 context. + * @param peer the peer to set the new algorithms for + * @param val an AlgorithmsIdentier to add + * + * @return An hx509 error code, see hx509_get_error_string(). + * + * @ingroup hx509_peer + */ + +int +hx509_peer_info_add_cms_alg(hx509_context context, + hx509_peer_info peer, + const AlgorithmIdentifier *val) +{ + void *ptr; + int ret; + + ptr = realloc(peer->val, sizeof(peer->val[0]) * (peer->len + 1)); + if (ptr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + ret = copy_AlgorithmIdentifier(val, &peer->val[peer->len]); + if (ret == 0) + peer->len += 1; + else + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; +} + /** * Set the algorithms that the peer supports. * diff --git a/source4/heimdal/lib/hx509/print.c b/source4/heimdal/lib/hx509/print.c index 38d103905f..ddafb7f46e 100644 --- a/source4/heimdal/lib/hx509/print.c +++ b/source4/heimdal/lib/hx509/print.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); /** * @page page_print Hx509 printing functions @@ -547,14 +546,14 @@ check_CRLDistributionPoints(hx509_validate_ctx ctx, struct { const char *name; - const heim_oid *(*oid)(void); + const heim_oid *oid; int (*func)(hx509_validate_ctx, heim_any *); -} check_altname[] = { - { "pk-init", oid_id_pkinit_san, check_pkinit_san }, - { "jabber", oid_id_pkix_on_xmppAddr, check_utf8_string_san }, - { "dns-srv", oid_id_pkix_on_dnsSRV, check_altnull }, - { "card-id", oid_id_uspkicommon_card_id, check_altnull }, - { "Microsoft NT-PRINCIPAL-NAME", oid_id_pkinit_ms_san, check_utf8_string_san } +} altname_types[] = { + { "pk-init", &asn1_oid_id_pkinit_san, check_pkinit_san }, + { "jabber", &asn1_oid_id_pkix_on_xmppAddr, check_utf8_string_san }, + { "dns-srv", &asn1_oid_id_pkix_on_dnsSRV, check_altnull }, + { "card-id", &asn1_oid_id_uspkicommon_card_id, check_altnull }, + { "Microsoft NT-PRINCIPAL-NAME", &asn1_oid_id_pkinit_ms_san, check_utf8_string_san } }; static int @@ -597,17 +596,17 @@ check_altName(hx509_validate_ctx ctx, validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%sAltName otherName ", name); - for (j = 0; j < sizeof(check_altname)/sizeof(check_altname[0]); j++) { - if (der_heim_oid_cmp((*check_altname[j].oid)(), + for (j = 0; j < sizeof(altname_types)/sizeof(altname_types[0]); j++) { + if (der_heim_oid_cmp(altname_types[j].oid, &gn.val[i].u.otherName.type_id) != 0) continue; validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s: ", - check_altname[j].name); - (*check_altname[j].func)(ctx, &gn.val[i].u.otherName.value); + altname_types[j].name); + (*altname_types[j].func)(ctx, &gn.val[i].u.otherName.value); break; } - if (j == sizeof(check_altname)/sizeof(check_altname[0])) { + if (j == sizeof(altname_types)/sizeof(altname_types[0])) { hx509_oid_print(&gn.val[i].u.otherName.type_id, validate_vprint, ctx); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " unknown"); @@ -751,14 +750,14 @@ check_authorityInfoAccess(hx509_validate_ctx ctx, struct { const char *name; - const heim_oid *(*oid)(void); + const heim_oid *oid; int (*func)(hx509_validate_ctx ctx, struct cert_status *status, enum critical_flag cf, const Extension *); enum critical_flag cf; } check_extension[] = { -#define ext(name, checkname) #name, &oid_id_x509_ce_##name, check_##checkname +#define ext(name, checkname) #name, &asn1_oid_id_x509_ce_##name, check_##checkname { ext(subjectDirectoryAttributes, Null), M_N_C }, { ext(subjectKeyIdentifier, subjectKeyIdentifier), M_N_C }, { ext(keyUsage, Null), S_C }, @@ -782,13 +781,13 @@ struct { { ext(freshestCRL, Null), M_N_C }, { ext(inhibitAnyPolicy, Null), M_C }, #undef ext -#define ext(name, checkname) #name, &oid_id_pkix_pe_##name, check_##checkname +#define ext(name, checkname) #name, &asn1_oid_id_pkix_pe_##name, check_##checkname { ext(proxyCertInfo, proxyCertInfo), M_C }, { ext(authorityInfoAccess, authorityInfoAccess), M_C }, #undef ext - { "US Fed PKI - PIV Interim", oid_id_uspkicommon_piv_interim, + { "US Fed PKI - PIV Interim", &asn1_oid_id_uspkicommon_piv_interim, check_Null, D_C }, - { "Netscape cert comment", oid_id_netscape_cert_comment, + { "Netscape cert comment", &asn1_oid_id_netscape_cert_comment, check_Null, D_C }, { NULL } }; @@ -949,7 +948,7 @@ hx509_validate_cert(hx509_context context, for (i = 0; i < t->extensions->len; i++) { for (j = 0; check_extension[j].name; j++) - if (der_heim_oid_cmp((*check_extension[j].oid)(), + if (der_heim_oid_cmp(check_extension[j].oid, &t->extensions->val[i].extnID) == 0) break; if (check_extension[j].name == NULL) { diff --git a/source4/heimdal/lib/hx509/req.c b/source4/heimdal/lib/hx509/req.c index 9836777143..0d174e0cec 100644 --- a/source4/heimdal/lib/hx509/req.c +++ b/source4/heimdal/lib/hx509/req.c @@ -33,7 +33,6 @@ #include "hx_locl.h" #include -RCSID("$Id$"); struct hx509_request_data { hx509_name name; diff --git a/source4/heimdal/lib/hx509/revoke.c b/source4/heimdal/lib/hx509/revoke.c index 3f35b0d190..adb31164c1 100644 --- a/source4/heimdal/lib/hx509/revoke.c +++ b/source4/heimdal/lib/hx509/revoke.c @@ -50,7 +50,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); struct revoke_crl { char *path; @@ -235,7 +234,7 @@ verify_ocsp(hx509_context context, } ret = hx509_cert_check_eku(context, signer, - oid_id_pkix_kp_OCSPSigning(), 0); + &asn1_oid_id_pkix_kp_OCSPSigning, 0); if (ret) goto out; } @@ -295,7 +294,7 @@ parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic) } ret = der_heim_oid_cmp(&resp.responseBytes->responseType, - oid_id_pkix_ocsp_basic()); + &asn1_oid_id_pkix_ocsp_basic); if (ret != 0) { free_OCSPResponse(&resp); return HX509_REVOKE_WRONG_DATA; @@ -1011,8 +1010,7 @@ hx509_ocsp_request(hx509_context context, goto out; } es->len = 1; - - ret = der_copy_oid(oid_id_pkix_ocsp_nonce(), &es->val[0].extnID); + ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID); if (ret) { free_OCSPRequest(&req); return ret; diff --git a/source4/heimdal/lib/hx509/sel-gram.y b/source4/heimdal/lib/hx509/sel-gram.y index e529479724..7f7c9980e0 100644 --- a/source4/heimdal/lib/hx509/sel-gram.y +++ b/source4/heimdal/lib/hx509/sel-gram.y @@ -39,7 +39,6 @@ #include #include -RCSID("$Id$"); %} diff --git a/source4/heimdal/lib/hx509/test_name.c b/source4/heimdal/lib/hx509/test_name.c index da83e52786..2cdcdf85f6 100644 --- a/source4/heimdal/lib/hx509/test_name.c +++ b/source4/heimdal/lib/hx509/test_name.c @@ -32,7 +32,6 @@ */ #include "hx_locl.h" -RCSID("$Id$"); static int test_name(hx509_context context, const char *name) -- cgit