diff options
author | Andrew Bartlett <abartlet@samba.org> | 2007-06-13 05:44:24 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 14:53:18 -0500 |
commit | 91adebe749beb0dc23cacaea316cb2b724776aad (patch) | |
tree | 133d480f5b23b99fcf1149861136103dc4525cb1 /source4/heimdal/lib/hx509 | |
parent | f7110d928afd61cee203d07fd85968af993a327f (diff) | |
download | samba-91adebe749beb0dc23cacaea316cb2b724776aad.tar.gz samba-91adebe749beb0dc23cacaea316cb2b724776aad.tar.bz2 samba-91adebe749beb0dc23cacaea316cb2b724776aad.zip |
r23456: Update Samba4 to current lorikeet-heimdal.
Andrew Bartlett
(This used to be commit ae0f81ab235c72cceb120bcdeb051a483cf3cc4f)
Diffstat (limited to 'source4/heimdal/lib/hx509')
31 files changed, 2728 insertions, 365 deletions
diff --git a/source4/heimdal/lib/hx509/ca.c b/source4/heimdal/lib/hx509/ca.c index 1a5b4947be..0e48269aa4 100644 --- a/source4/heimdal/lib/hx509/ca.c +++ b/source4/heimdal/lib/hx509/ca.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "hx_locl.h" #include <pkinit_asn1.h> -RCSID("$Id: ca.c,v 1.12 2007/01/05 18:40:46 lha Exp $"); +RCSID("$Id: ca.c 20904 2007-06-05 01:58:45Z lha $"); struct hx509_ca_tbs { hx509_name subject; @@ -47,10 +47,12 @@ struct hx509_ca_tbs { unsigned int ca:1; unsigned int key:1; unsigned int serial:1; + unsigned int domaincontroller:1; } flags; time_t notBefore; time_t notAfter; int pathLenConstraint; /* both for CA and Proxy */ + CRLDistributionPoints crldp; }; int @@ -66,6 +68,8 @@ hx509_ca_tbs_init(hx509_context context, hx509_ca_tbs *tbs) (*tbs)->eku.len = 0; (*tbs)->eku.val = NULL; (*tbs)->pathLenConstraint = 0; + (*tbs)->crldp.len = 0; + (*tbs)->crldp.val = NULL; return 0; } @@ -80,6 +84,7 @@ hx509_ca_tbs_free(hx509_ca_tbs *tbs) free_GeneralNames(&(*tbs)->san); free_ExtKeyUsage(&(*tbs)->eku); der_free_heim_integer(&(*tbs)->serial); + free_CRLDistributionPoints(&(*tbs)->crldp); hx509_name_free(&(*tbs)->subject); @@ -114,6 +119,89 @@ hx509_ca_tbs_set_notAfter_lifetime(hx509_context context, return hx509_ca_tbs_set_notAfter(context, tbs, time(NULL) + delta); } +static const struct units templatebits[] = { + { "ExtendedKeyUsage", HX509_CA_TEMPLATE_EKU }, + { "KeyUsage", HX509_CA_TEMPLATE_KU }, + { "SPKI", HX509_CA_TEMPLATE_SPKI }, + { "notAfter", HX509_CA_TEMPLATE_NOTAFTER }, + { "notBefore", HX509_CA_TEMPLATE_NOTBEFORE }, + { "serial", HX509_CA_TEMPLATE_SERIAL }, + { "subject", HX509_CA_TEMPLATE_SUBJECT }, + { NULL, 0 } +}; + +const struct units * +hx509_ca_tbs_template_units(void) +{ + return templatebits; +} + +int +hx509_ca_tbs_set_template(hx509_context context, + hx509_ca_tbs tbs, + int flags, + hx509_cert cert) +{ + int ret; + + if (flags & HX509_CA_TEMPLATE_SUBJECT) { + if (tbs->subject) + hx509_name_free(&tbs->subject); + ret = hx509_cert_get_subject(cert, &tbs->subject); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to get subject from template"); + return ret; + } + } + if (flags & HX509_CA_TEMPLATE_SERIAL) { + der_free_heim_integer(&tbs->serial); + ret = hx509_cert_get_serialnumber(cert, &tbs->serial); + tbs->flags.serial = !ret; + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to copy serial number"); + return ret; + } + } + if (flags & HX509_CA_TEMPLATE_NOTBEFORE) + tbs->notBefore = hx509_cert_get_notBefore(cert); + if (flags & HX509_CA_TEMPLATE_NOTAFTER) + tbs->notAfter = hx509_cert_get_notAfter(cert); + if (flags & HX509_CA_TEMPLATE_SPKI) { + free_SubjectPublicKeyInfo(&tbs->spki); + ret = hx509_cert_get_SPKI(cert, &tbs->spki); + tbs->flags.key = !ret; + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to copy SPKI"); + return ret; + } + } + if (flags & HX509_CA_TEMPLATE_KU) { + KeyUsage ku; + ret = _hx509_cert_get_keyusage(context, cert, &ku); + if (ret) + return ret; + tbs->key_usage = KeyUsage2int(ku); + } + if (flags & HX509_CA_TEMPLATE_EKU) { + ExtKeyUsage eku; + int i; + ret = _hx509_cert_get_eku(context, cert, &eku); + if (ret) + return ret; + for (i = 0; i < eku.len; i++) { + ret = hx509_ca_tbs_add_eku(context, tbs, &eku.val[i]); + if (ret) { + free_ExtKeyUsage(&eku); + return ret; + } + } + free_ExtKeyUsage(&eku); + } + return 0; +} + int hx509_ca_tbs_set_ca(hx509_context context, hx509_ca_tbs tbs, @@ -136,6 +224,14 @@ hx509_ca_tbs_set_proxy(hx509_context context, int +hx509_ca_tbs_set_domaincontroller(hx509_context context, + hx509_ca_tbs tbs) +{ + tbs->flags.domaincontroller = 1; + return 0; +} + +int hx509_ca_tbs_set_spki(hx509_context context, hx509_ca_tbs tbs, const SubjectPublicKeyInfo *spki) @@ -160,25 +256,123 @@ hx509_ca_tbs_set_serialnumber(hx509_context context, } int -hx509_ca_tbs_add_eku(hx509_context contex, +hx509_ca_tbs_add_eku(hx509_context context, hx509_ca_tbs tbs, const heim_oid *oid) { void *ptr; int ret; + unsigned i; + + /* search for duplicates */ + for (i = 0; i < tbs->eku.len; i++) { + if (der_heim_oid_cmp(oid, &tbs->eku.val[i]) == 0) + return 0; + } ptr = realloc(tbs->eku.val, sizeof(tbs->eku.val[0]) * (tbs->eku.len + 1)); - if (ptr == NULL) + if (ptr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); return ENOMEM; + } tbs->eku.val = ptr; ret = der_copy_oid(oid, &tbs->eku.val[tbs->eku.len]); - if (ret) + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); return ret; + } tbs->eku.len += 1; return 0; } int +hx509_ca_tbs_add_crl_dp_uri(hx509_context context, + hx509_ca_tbs tbs, + const char *uri, + hx509_name issuername) +{ + DistributionPoint dp; + int ret; + + memset(&dp, 0, sizeof(dp)); + + dp.distributionPoint = ecalloc(1, sizeof(*dp.distributionPoint)); + + { + DistributionPointName name; + GeneralName gn; + size_t size; + + name.element = choice_DistributionPointName_fullName; + name.u.fullName.len = 1; + name.u.fullName.val = &gn; + + gn.element = choice_GeneralName_uniformResourceIdentifier; + gn.u.uniformResourceIdentifier = rk_UNCONST(uri); + + ASN1_MALLOC_ENCODE(DistributionPointName, + dp.distributionPoint->data, + dp.distributionPoint->length, + &name, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to encoded DistributionPointName"); + goto out; + } + if (dp.distributionPoint->length != size) + _hx509_abort("internal ASN.1 encoder error"); + } + + if (issuername) { +#if 1 + hx509_set_error_string(context, 0, EINVAL, + "CRLDistributionPoints.name.issuername not yet supported"); + return EINVAL; +#else + GeneralNames *crlissuer; + GeneralName gn; + Name n; + + crlissuer = calloc(1, sizeof(*crlissuer)); + if (crlissuer == NULL) { + return ENOMEM; + } + memset(&gn, 0, sizeof(gn)); + + gn.element = choice_GeneralName_directoryName; + ret = hx509_name_to_Name(issuername, &n); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + gn.u.directoryName.element = n.element; + gn.u.directoryName.u.rdnSequence = n.u.rdnSequence; + + ret = add_GeneralNames(&crlissuer, &gn); + free_Name(&n); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + + dp.cRLIssuer = &crlissuer; +#endif + } + + ret = add_CRLDistributionPoints(&tbs->crldp, &dp); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + goto out; + } + +out: + free_DistributionPoint(&dp); + + return ret; +} + +int hx509_ca_tbs_add_san_otherName(hx509_context context, hx509_ca_tbs tbs, const heim_oid *oid, @@ -282,6 +476,58 @@ out: return ret; } +/* + * + */ + +static int +add_utf8_san(hx509_context context, + hx509_ca_tbs tbs, + const heim_oid *oid, + const char *string) +{ + const PKIXXmppAddr ustring = (const PKIXXmppAddr)string; + heim_octet_string os; + size_t size; + int ret; + + os.length = 0; + os.data = NULL; + + ASN1_MALLOC_ENCODE(PKIXXmppAddr, os.data, os.length, &ustring, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != os.length) + _hx509_abort("internal ASN.1 encoder error"); + + ret = hx509_ca_tbs_add_san_otherName(context, + tbs, + oid, + &os); + free(os.data); +out: + return ret; +} + +int +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); +} + +int +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); +} + + int hx509_ca_tbs_add_san_hostname(hx509_context context, hx509_ca_tbs tbs, @@ -321,6 +567,14 @@ hx509_ca_tbs_set_subject(hx509_context context, return hx509_name_copy(context, subject, &tbs->subject); } +int +hx509_ca_tbs_subject_expand(hx509_context context, + hx509_ca_tbs tbs, + hx509_env env) +{ + return hx509_name_expand(context, tbs->subject, env); +} + static int add_extension(hx509_context context, TBSCertificate *tbsc, @@ -410,7 +664,7 @@ ca_sign(hx509_context context, time_t notAfter; unsigned key_usage; - sigalg = hx509_signature_rsa_with_sha1(); + sigalg = _hx509_crypto_default_sig_alg; memset(&c, 0, sizeof(c)); @@ -439,6 +693,7 @@ ca_sign(hx509_context context, KeyUsage ku; memset(&ku, 0, sizeof(ku)); ku.keyCertSign = 1; + ku.cRLSign = 1; key_usage |= KeyUsage2int(ku); } @@ -453,16 +708,25 @@ ca_sign(hx509_context context, hx509_set_error_string(context, 0, ret, "No public key set"); return ret; } - if (tbs->subject == NULL && !tbs->flags.proxy) { - ret = EINVAL; - hx509_set_error_string(context, 0, ret, "No subject name set"); - return ret; + /* + * Don't put restrictions on proxy certificate's subject name, it + * will be generated below. + */ + if (!tbs->flags.proxy) { + if (tbs->subject == NULL) { + hx509_set_error_string(context, 0, EINVAL, "No subject name set"); + return EINVAL; + } + if (hx509_name_is_null_p(tbs->subject) && tbs->san.len == 0) { + hx509_set_error_string(context, 0, EINVAL, + "NULL subject and no SubjectAltNames"); + return EINVAL; + } } if (tbs->flags.ca && tbs->flags.proxy) { - ret = EINVAL; - hx509_set_error_string(context, 0, ret, "Can't be proxy and CA " + hx509_set_error_string(context, 0, EINVAL, "Can't be proxy and CA " "at the same time"); - return ret; + return EINVAL; } if (tbs->flags.proxy) { if (tbs->san.len > 0) { @@ -549,6 +813,22 @@ ca_sign(hx509_context context, goto out; } + /* Add the text BMP string Domaincontroller to the cert */ + if (tbs->flags.domaincontroller) { + data.data = rk_UNCONST("\x1e\x20\x00\x44\x00\x6f\x00\x6d" + "\x00\x61\x00\x69\x00\x6e\x00\x43" + "\x00\x6f\x00\x6e\x00\x74\x00\x72" + "\x00\x6f\x00\x6c\x00\x6c\x00\x65" + "\x00\x72"); + data.length = 34; + + ret = add_extension(context, tbsc, 0, + oid_id_ms_cert_enroll_domaincontroller(), + &data); + if (ret) + goto out; + } + /* add KeyUsage */ { KeyUsage ku; @@ -561,7 +841,7 @@ ca_sign(hx509_context context, } if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); - ret = add_extension(context, tbsc, 1, + ret = add_extension(context, tbsc, 1, oid_id_x509_ce_keyUsage(), &data); free(data.data); if (ret) @@ -678,7 +958,8 @@ ca_sign(hx509_context context, } if (size != data.length) _hx509_abort("internal ASN.1 encoder error"); - ret = add_extension(context, tbsc, 0, + /* Critical if this is a CA */ + ret = add_extension(context, tbsc, tbs->flags.ca, oid_id_x509_ce_basicConstraints(), &data); free(data.data); @@ -728,6 +1009,23 @@ ca_sign(hx509_context context, goto out; } + if (tbs->crldp.len) { + + ASN1_MALLOC_ENCODE(CRLDistributionPoints, data.data, data.length, + &tbs->crldp, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "Out of memory"); + goto out; + } + if (size != data.length) + _hx509_abort("internal ASN.1 encoder error"); + ret = add_extension(context, tbsc, FALSE, + oid_id_x509_ce_cRLDistributionPoints(), + &data); + free(data.data); + if (ret) + goto out; + } ASN1_MALLOC_ENCODE(TBSCertificate, data.data, data.length,tbsc, &size, ret); if (ret) { @@ -772,11 +1070,13 @@ get_AuthorityKeyIdentifier(hx509_context context, if (ret == 0) { ai->keyIdentifier = calloc(1, sizeof(*ai->keyIdentifier)); if (ai->keyIdentifier == NULL) { + free_SubjectKeyIdentifier(&si); ret = ENOMEM; hx509_set_error_string(context, 0, ret, "Out of memory"); goto out; } ret = der_copy_octet_string(&si, ai->keyIdentifier); + free_SubjectKeyIdentifier(&si); if (ret) { hx509_set_error_string(context, 0, ret, "Out of memory"); goto out; @@ -818,6 +1118,7 @@ get_AuthorityKeyIdentifier(hx509_context context, goto out; } + memset(&gn, 0, sizeof(gn)); gn.element = choice_GeneralName_directoryName; gn.u.directoryName.element = choice_GeneralName_directoryName_rdnSequence; diff --git a/source4/heimdal/lib/hx509/cert.c b/source4/heimdal/lib/hx509/cert.c index f84c61a798..27b17a0204 100644 --- a/source4/heimdal/lib/hx509/cert.c +++ b/source4/heimdal/lib/hx509/cert.c @@ -32,8 +32,9 @@ */ #include "hx_locl.h" -RCSID("$Id: cert.c,v 1.82 2007/01/09 10:52:03 lha Exp $"); +RCSID("$Id: cert.c 20915 2007-06-05 03:58:56Z lha $"); #include "crypto-headers.h" +#include <rtbl.h> struct hx509_verify_ctx_data { hx509_certs trust_anchors; @@ -102,11 +103,13 @@ hx509_context_init(hx509_context *context) if (*context == NULL) return ENOMEM; + _hx509_ks_null_register(*context); _hx509_ks_mem_register(*context); _hx509_ks_file_register(*context); _hx509_ks_pkcs12_register(*context); _hx509_ks_pkcs11_register(*context); _hx509_ks_dir_register(*context); + _hx509_ks_keychain_register(*context); ENGINE_add_conf_module(); OpenSSL_add_all_algorithms(); @@ -116,6 +119,11 @@ hx509_context_init(hx509_context *context) initialize_hx_error_table_r(&(*context)->et_list); initialize_asn1_error_table_r(&(*context)->et_list); +#ifdef HX509_DEFAULT_ANCHORS + (void)hx509_certs_init(*context, HX509_DEFAULT_ANCHORS, 0, + NULL, &(*context)->default_trust_anchors); +#endif + return 0; } @@ -138,6 +146,9 @@ hx509_context_free(hx509_context *context) } (*context)->ks_num_ops = 0; free_error_table ((*context)->et_list); + if ((*context)->querystat) + free((*context)->querystat); + memset(*context, 0, sizeof(**context)); free(*context); *context = NULL; } @@ -836,7 +847,7 @@ find_parent(hx509_context context, hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND, "Failed to find issuer for " - "certificate with subject: %s", str); + "certificate with subject: '%s'", str); free(str); } return HX509_ISSUER_NOT_FOUND; @@ -847,7 +858,9 @@ find_parent(hx509_context context, */ static int -is_proxy_cert(hx509_context context, const Certificate *cert, ProxyCertInfo *rinfo) +is_proxy_cert(hx509_context context, + const Certificate *cert, + ProxyCertInfo *rinfo) { ProxyCertInfo info; const Extension *e; @@ -876,7 +889,9 @@ is_proxy_cert(hx509_context context, const Certificate *cert, ProxyCertInfo *rin hx509_clear_error_string(context); return HX509_EXTRA_DATA_AFTER_STRUCTURE; } - if (rinfo) + if (rinfo == NULL) + free_ProxyCertInfo(&info); + else *rinfo = info; return 0; @@ -969,8 +984,10 @@ _hx509_calculate_path(hx509_context context, current = parent; if (path->len > max_depth) { + hx509_cert_free(current); hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG, - "Path too long while bulding certificate chain"); + "Path too long while bulding " + "certificate chain"); return HX509_PATH_TOO_LONG; } } @@ -1065,6 +1082,25 @@ hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i) return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i); } +time_t +hx509_cert_get_notBefore(hx509_cert p) +{ + return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore); +} + +time_t +hx509_cert_get_notAfter(hx509_cert p) +{ + return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter); +} + +int +hx509_cert_get_SPKI(hx509_cert p, SubjectPublicKeyInfo *spki) +{ + return copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, + spki); +} + hx509_private_key _hx509_cert_private_key(hx509_cert p) { @@ -1349,7 +1385,7 @@ match_tree(const GeneralSubtrees *t, const Certificate *c, int *match) { GeneralName certname; - + memset(&certname, 0, sizeof(certname)); certname.element = choice_GeneralName_directoryName; certname.u.directoryName.element = c->tbsCertificate.subject.element; @@ -1435,6 +1471,7 @@ hx509_verify_path(hx509_context context, int ret, i, proxy_cert_depth; enum certtype type; Name proxy_issuer; + hx509_certs anchors = NULL; memset(&proxy_issuer, 0, sizeof(proxy_issuer)); @@ -1449,11 +1486,24 @@ hx509_verify_path(hx509_context context, ctx->time_now = time(NULL); /* + * + */ + ret = hx509_certs_init(context, "MEMORY:trust-anchors", 0, NULL, &anchors); + if (ret) + goto out; + ret = hx509_certs_merge(context, anchors, ctx->trust_anchors); + if (ret) + goto out; + ret = hx509_certs_merge(context, anchors, context->default_trust_anchors); + if (ret) + goto out; + + /* * Calculate the path from the certificate user presented to the * to an anchor. */ ret = _hx509_calculate_path(context, 0, ctx->time_now, - ctx->trust_anchors, ctx->max_depth, + anchors, ctx->max_depth, cert, pool, &path); if (ret) goto out; @@ -1775,6 +1825,7 @@ hx509_verify_path(hx509_context context, } out: + hx509_certs_free(&anchors); free_Name(&proxy_issuer); free_name_constraints(&nc); _hx509_path_free(&path); @@ -2030,6 +2081,8 @@ _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert { Certificate *c = _hx509_get_cert(cert); + _hx509_query_statistic(context, 1, q); + if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) && _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0) return 0; @@ -2154,6 +2207,139 @@ _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert return 1; } +void +hx509_query_statistic_file(hx509_context context, const char *fn) +{ + if (context->querystat) + free(context->querystat); + context->querystat = strdup(fn); +} + +void +_hx509_query_statistic(hx509_context context, int type, const hx509_query *q) +{ + FILE *f; + if (context->querystat == NULL) + return; + f = fopen(context->querystat, "a"); + if (f == NULL) + return; + fprintf(f, "%d %d\n", type, q->match); + fclose(f); +} + +static const char *statname[] = { + "find issuer cert", + "match serialnumber", + "match issuer name", + "match subject name", + "match subject key id", + "match issuer id", + "private key", + "ku encipherment", + "ku digitalsignature", + "ku keycertsign", + "ku crlsign", + "ku nonrepudiation", + "ku keyagreement", + "ku dataencipherment", + "anchor", + "match certificate", + "match local key id", + "no match path", + "match friendly name", + "match function", + "match key hash sha1", + "match time" +}; + +struct stat_el { + unsigned long stats; + unsigned int index; +}; + + +static int +stat_sort(const void *a, const void *b) +{ + const struct stat_el *ae = a; + const struct stat_el *be = b; + return be->stats - ae->stats; +} + +void +hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out) +{ + rtbl_t t; + FILE *f; + int type, mask, i, num; + unsigned long multiqueries = 0, totalqueries = 0; + struct stat_el stats[32]; + + if (context->querystat == NULL) + return; + f = fopen(context->querystat, "r"); + if (f == NULL) { + fprintf(out, "No statistic file %s: %s.\n", + context->querystat, strerror(errno)); + return; + } + + for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) { + stats[i].index = i; + stats[i].stats = 0; + } + + while (fscanf(f, "%d %d\n", &type, &mask) == 2) { + if (type != printtype) + continue; + num = i = 0; + while (mask && i < sizeof(stats)/sizeof(stats[0])) { + if (mask & 1) { + stats[i].stats++; + num++; + } + mask = mask >>1 ; + i++; + } + if (num > 1) + multiqueries++; + totalqueries++; + } + fclose(f); + + qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort); + + t = rtbl_create(); + if (t == NULL) + errx(1, "out of memory"); + + rtbl_set_separator (t, " "); + + rtbl_add_column_by_id (t, 0, "Name", 0); + rtbl_add_column_by_id (t, 1, "Counter", 0); + + + for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) { + char str[10]; + + if (stats[i].index < sizeof(statname)/sizeof(statname[0])) + rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]); + else { + snprintf(str, sizeof(str), "%d", stats[i].index); + rtbl_add_column_entry_by_id (t, 0, str); + } + snprintf(str, sizeof(str), "%lu", stats[i].stats); + rtbl_add_column_entry_by_id (t, 1, str); + } + + rtbl_format(t, out); + rtbl_destroy(t); + + fprintf(out, "\nQueries: multi %lu total %lu\n", + multiqueries, totalqueries); +} + int hx509_cert_check_eku(hx509_context context, hx509_cert cert, const heim_oid *eku, int allow_any_eku) @@ -2212,3 +2398,39 @@ _hx509_cert_get_keyusage(hx509_context context, return ret; return 0; } + +int +_hx509_cert_get_eku(hx509_context context, + hx509_cert cert, + ExtKeyUsage *e) +{ + int ret; + + memset(e, 0, sizeof(*e)); + + ret = find_extension_eku(_hx509_get_cert(cert), e); + if (ret && ret != HX509_EXTENSION_NOT_FOUND) { + hx509_clear_error_string(context); + return ret; + } + return 0; +} + +int +hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os) +{ + size_t size; + int ret; + + os->data = NULL; + os->length = 0; + + ASN1_MALLOC_ENCODE(Certificate, os->data, os->length, + _hx509_get_cert(c), &size, ret); + if (ret) + return ret; + if (os->length != size) + _hx509_abort("internal ASN.1 encoder error"); + + return ret; +} diff --git a/source4/heimdal/lib/hx509/cms.c b/source4/heimdal/lib/hx509/cms.c index 4ed70b8f84..29ca80e194 100644 --- a/source4/heimdal/lib/hx509/cms.c +++ b/source4/heimdal/lib/hx509/cms.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: cms.c,v 1.48 2007/01/08 18:45:03 lha Exp $"); +RCSID("$Id: cms.c 20937 2007-06-06 20:50:55Z lha $"); #define ALLOC(X, N) (X) = calloc((N), sizeof(*(X))) #define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0) @@ -302,6 +302,11 @@ hx509_cms_unenvelope(hx509_context context, goto out; } enccontent = encryptedContent; + } else if (encryptedContent != NULL) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + hx509_set_error_string(context, 0, ret, + "Both internal and external encrypted data"); + goto out; } cert = NULL; @@ -423,6 +428,7 @@ out: int hx509_cms_envelope_1(hx509_context context, + int flags, hx509_cert cert, const void *data, size_t length, @@ -621,6 +627,7 @@ hx509_cms_verify_signed(hx509_context context, hx509_verify_ctx ctx, const void *data, size_t length, + const heim_octet_string *signedContent, hx509_certs store, heim_oid *contentType, heim_octet_string *content, @@ -648,12 +655,20 @@ hx509_cms_verify_signed(hx509_context context, goto out; } - if (sd.encapContentInfo.eContent == NULL) { + if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) { ret = HX509_CMS_NO_DATA_AVAILABLE; hx509_set_error_string(context, 0, ret, "No content data in SignedData"); goto out; } + if (sd.encapContentInfo.eContent && signedContent) { + ret = HX509_CMS_NO_DATA_AVAILABLE; + hx509_set_error_string(context, 0, ret, + "Both external and internal SignedData"); + goto out; + } + if (sd.encapContentInfo.eContent) + signedContent = sd.encapContentInfo.eContent; ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer", 0, NULL, &certs); @@ -739,7 +754,7 @@ hx509_cms_verify_signed(hx509_context context, ret = _hx509_verify_signature(context, NULL, &signer_info->digestAlgorithm, - sd.encapContentInfo.eContent, + signedContent, &os); der_free_octet_string(&os); if (ret) { @@ -801,7 +816,7 @@ hx509_cms_verify_signed(hx509_context context, _hx509_abort("internal ASN.1 encoder error"); } else { - signed_data = sd.encapContentInfo.eContent; + signed_data = rk_UNCONST(signedContent); match_oid = oid_id_pkcs7_data(); } @@ -824,7 +839,7 @@ hx509_cms_verify_signed(hx509_context context, "Failed to verify sigature in " "CMS SignedData"); } - if (signed_data != sd.encapContentInfo.eContent) { + if (signed_data != signedContent) { der_free_octet_string(signed_data); free(signed_data); } @@ -861,14 +876,14 @@ hx509_cms_verify_signed(hx509_context context, goto out; } - content->data = malloc(sd.encapContentInfo.eContent->length); + content->data = malloc(signedContent->length); if (content->data == NULL) { hx509_clear_error_string(context); ret = ENOMEM; goto out; } - content->length = sd.encapContentInfo.eContent->length; - memcpy(content->data,sd.encapContentInfo.eContent->data,content->length); + content->length = signedContent->length; + memcpy(content->data, signedContent->data, content->length); out: free_SignedData(&sd); @@ -884,38 +899,6 @@ out: return ret; } -int -_hx509_set_digest_alg(DigestAlgorithmIdentifier *id, - const heim_oid *oid, - void *param, size_t length) -{ - int ret; - if (param) { - id->parameters = malloc(sizeof(*id->parameters)); - if (id->parameters == NULL) - return ENOMEM; - id->parameters->data = malloc(length); - if (id->parameters->data == NULL) { - free(id->parameters); - id->parameters = NULL; - return ENOMEM; - } - memcpy(id->parameters->data, param, length); - id->parameters->length = length; - } else - id->parameters = NULL; - ret = der_copy_oid(oid, &id->algorithm); - if (ret) { - if (id->parameters) { - free(id->parameters->data); - free(id->parameters); - id->parameters = NULL; - } - return ret; - } - return 0; -} - static int add_one_attribute(Attribute **attr, unsigned int *len, @@ -950,6 +933,7 @@ add_one_attribute(Attribute **attr, int hx509_cms_create_signed_1(hx509_context context, + int flags, const heim_oid *eContentType, const void *data, size_t length, const AlgorithmIdentifier *digest_alg, @@ -962,7 +946,7 @@ hx509_cms_create_signed_1(hx509_context context, AlgorithmIdentifier digest; hx509_name name; SignerInfo *signer_info; - heim_octet_string buf; + heim_octet_string buf, content, sigdata = { 0, NULL }; SignedData sd; int ret; size_t size; @@ -973,6 +957,9 @@ hx509_cms_create_signed_1(hx509_context context, memset(&path, 0, sizeof(path)); memset(&digest, 0, sizeof(digest)); + content.data = rk_UNCONST(data); + content.length = length; + if (_hx509_cert_private_key(cert) == NULL) { hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, "Private key missing for signing"); @@ -992,22 +979,29 @@ hx509_cms_create_signed_1(hx509_context context, sd.version = CMSVersion_v3; + if (eContentType == NULL) + eContentType = oid_id_pkcs7_data(); + der_copy_oid(eContentType, &sd.encapContentInfo.eContentType); - 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; + /* */ + 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; } - memcpy(sd.encapContentInfo.eContent->data, data, length); - sd.encapContentInfo.eContent->length = length; ALLOC_SEQ(&sd.signerInfos, 1); if (sd.signerInfos.val == NULL) { @@ -1029,39 +1023,43 @@ hx509_cms_create_signed_1(hx509_context context, signer_info->signedAttrs = NULL; signer_info->unsignedAttrs = NULL; - ALLOC(signer_info->signedAttrs, 1); - if (signer_info->signedAttrs == NULL) { - ret = ENOMEM; + + ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm); + if (ret) { + hx509_clear_error_string(context); goto out; } - { - heim_octet_string data; + /* + * If its not pkcs7-data send signedAttributes + */ - ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm); - if (ret) { - hx509_clear_error_string(context); + if (der_heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) { + CMSAttributes sa; + heim_octet_string sig; + + ALLOC(signer_info->signedAttrs, 1); + if (signer_info->signedAttrs == NULL) { + ret = ENOMEM; goto out; } ret = _hx509_create_signature(context, NULL, &digest, - sd.encapContentInfo.eContent, + &content, NULL, - &data); - if (ret) { - hx509_clear_error_string(context); + &sig); + if (ret) goto out; - } ASN1_MALLOC_ENCODE(MessageDigest, buf.data, buf.length, - &data, + &sig, &size, ret); - der_free_octet_string(&data); + der_free_octet_string(&sig); if (ret) { hx509_clear_error_string(context); goto out; @@ -1078,9 +1076,6 @@ hx509_cms_create_signed_1(hx509_context context, goto out; } - } - - if (der_heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) { ASN1_MALLOC_ENCODE(ContentType, buf.data, @@ -1101,19 +1096,13 @@ hx509_cms_create_signed_1(hx509_context context, hx509_clear_error_string(context); goto out; } - } - - { - CMSAttributes sa; - heim_octet_string os; - sa.val = signer_info->signedAttrs->val; sa.len = signer_info->signedAttrs->len; ASN1_MALLOC_ENCODE(CMSAttributes, - os.data, - os.length, + sigdata.data, + sigdata.length, &sa, &size, ret); @@ -1121,21 +1110,32 @@ hx509_cms_create_signed_1(hx509_context context, hx509_clear_error_string(context); goto out; } - if (size != os.length) + if (size != sigdata.length) _hx509_abort("internal ASN.1 encoder error"); - + } else { + sigdata.data = content.data; + sigdata.length = content.length; + } + + + { + AlgorithmIdentifier sigalg; + + ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG, + _hx509_cert_private_key(cert), peer, + &sigalg); + if (ret) + goto out; + ret = _hx509_create_signature(context, _hx509_cert_private_key(cert), - hx509_signature_rsa_with_sha1(), - &os, + &sigalg, + &sigdata, &signer_info->signatureAlgorithm, &signer_info->signature); - - der_free_octet_string(&os); - if (ret) { - hx509_clear_error_string(context); + free_AlgorithmIdentifier(&sigalg); + if (ret) goto out; - } } ALLOC_SEQ(&sd.digestAlgorithms, 1); @@ -1184,17 +1184,12 @@ hx509_cms_create_signed_1(hx509_context context, } for (i = 0; i < path.len; i++) { - ASN1_MALLOC_ENCODE(Certificate, - sd.certificates->val[i].data, - sd.certificates->val[i].length, - _hx509_get_cert(path.val[i]), - &size, ret); + ret = hx509_cert_binary(context, path.val[i], + &sd.certificates->val[i]); if (ret) { hx509_clear_error_string(context); goto out; } - if (sd.certificates->val[i].length != size) - _hx509_abort("internal ASN.1 encoder error"); } } @@ -1209,6 +1204,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); diff --git a/source4/heimdal/lib/hx509/collector.c b/source4/heimdal/lib/hx509/collector.c index ec172f46f4..8b6ffcb945 100644 --- a/source4/heimdal/lib/hx509/collector.c +++ b/source4/heimdal/lib/hx509/collector.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: collector.c,v 1.16 2007/01/09 10:52:04 lha Exp $"); +RCSID("$Id: collector.c 20778 2007-06-01 22:04:13Z lha $"); struct private_key { AlgorithmIdentifier alg; @@ -51,22 +51,26 @@ struct hx509_collector { }; -struct hx509_collector * -_hx509_collector_alloc(hx509_context context, hx509_lock lock) +int +_hx509_collector_alloc(hx509_context context, hx509_lock lock, struct hx509_collector **collector) { struct hx509_collector *c; int ret; + *collector = NULL; + c = calloc(1, sizeof(*c)); - if (c == NULL) - return NULL; + if (c == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } c->lock = lock; ret = hx509_certs_init(context, "MEMORY:collector-unenvelop-cert", 0,NULL, &c->unenvelop_certs); if (ret) { free(c); - return NULL; + return ret; } c->val.data = NULL; c->val.len = 0; @@ -75,10 +79,11 @@ _hx509_collector_alloc(hx509_context context, hx509_lock lock) if (ret) { hx509_certs_free(&c->unenvelop_certs); free(c); - return NULL; + return ret; } - return c; + *collector = c; + return 0; } hx509_lock diff --git a/source4/heimdal/lib/hx509/crmf.asn1 b/source4/heimdal/lib/hx509/crmf.asn1 index 4f02b26872..97ade264ae 100644 --- a/source4/heimdal/lib/hx509/crmf.asn1 +++ b/source4/heimdal/lib/hx509/crmf.asn1 @@ -1,4 +1,4 @@ --- $Id: crmf.asn1,v 1.1 2006/04/18 13:05:21 lha Exp $ +-- $Id: crmf.asn1 17102 2006-04-18 13:05:21Z lha $ PKCS10 DEFINITIONS ::= BEGIN diff --git a/source4/heimdal/lib/hx509/crypto.c b/source4/heimdal/lib/hx509/crypto.c index dac0a8160b..96d9693cc2 100644 --- a/source4/heimdal/lib/hx509/crypto.c +++ b/source4/heimdal/lib/hx509/crypto.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: crypto.c,v 1.63 2007/01/09 10:52:05 lha Exp $"); +RCSID("$Id: crypto.c 20939 2007-06-06 20:53:02Z lha $"); struct hx509_crypto; @@ -42,6 +42,11 @@ enum crypto_op_type { COT_SIGN }; +struct hx509_generate_private_context { + const heim_oid *key_oid; + int isCA; + unsigned long num_bits; +}; struct hx509_private_key_ops { const char *pemtype; @@ -56,8 +61,9 @@ struct hx509_private_key_ops { const void *data, size_t len, hx509_private_key private_key); - int (*generate_private_key)(hx509_context context, - hx509_private_key private_key); + int (*generate_private_key)(hx509_context, + struct hx509_generate_private_context *, + hx509_private_key); int (*handle_alg)(const hx509_private_key, const AlgorithmIdentifier *, enum crypto_op_type); @@ -96,7 +102,7 @@ struct hx509_private_key { */ struct signature_alg { - char *name; + const char *name; const heim_oid *(*sig_oid)(void); const AlgorithmIdentifier *(*sig_alg)(void); const heim_oid *(*key_oid)(void); @@ -107,8 +113,7 @@ struct signature_alg { #define SIG_DIGEST 0x100 #define SIG_PUBLIC_SIG 0x200 -#define SIG_PUBLIC_ENC 0x400 -#define SIG_SECRET 0x800 +#define SIG_SECRET 0x400 int (*verify_signature)(hx509_context context, const struct signature_alg *, @@ -123,9 +128,6 @@ struct signature_alg { const heim_octet_string *, AlgorithmIdentifier *, heim_octet_string *); - int (*private_key2SPKI)(hx509_context, - hx509_private_key, - SubjectPublicKeyInfo *); }; /* @@ -142,6 +144,46 @@ heim_int2BN(const heim_integer *i) return bn; } +/* + * + */ + +static int +set_digest_alg(DigestAlgorithmIdentifier *id, + const heim_oid *oid, + const void *param, size_t length) +{ + int ret; + if (param) { + id->parameters = malloc(sizeof(*id->parameters)); + if (id->parameters == NULL) + return ENOMEM; + id->parameters->data = malloc(length); + if (id->parameters->data == NULL) { + free(id->parameters); + id->parameters = NULL; + return ENOMEM; + } + memcpy(id->parameters->data, param, length); + id->parameters->length = length; + } else + id->parameters = NULL; + ret = der_copy_oid(oid, &id->algorithm); + if (ret) { + if (id->parameters) { + free(id->parameters->data); + free(id->parameters); + id->parameters = NULL; + } + return ret; + } + return 0; +} + +/* + * + */ + static int rsa_verify_signature(hx509_context context, const struct signature_alg *sig_alg, @@ -280,12 +322,13 @@ rsa_create_signature(hx509_context context, digest_alg = hx509_signature_md5(); } else if (der_heim_oid_cmp(sig_oid, oid_id_dsa_with_sha1()) == 0) { digest_alg = hx509_signature_sha1(); + } else if (der_heim_oid_cmp(sig_oid, oid_id_pkcs1_rsaEncryption()) == 0) { + digest_alg = hx509_signature_sha1(); } else return HX509_ALG_NOT_SUPP; if (signatureAlgorithm) { - ret = _hx509_set_digest_alg(signatureAlgorithm, - sig_oid, "\x05\x00", 2); + ret = set_digest_alg(signatureAlgorithm, sig_oid, "\x05\x00", 2); if (ret) { hx509_clear_error_string(context); return ret; @@ -380,9 +423,8 @@ rsa_private_key2SPKI(hx509_context context, } spki->subjectPublicKey.length = len * 8; - ret = _hx509_set_digest_alg(&spki->algorithm, - oid_id_pkcs1_rsaEncryption(), - "\x05\x00", 2); + ret = set_digest_alg(&spki->algorithm,oid_id_pkcs1_rsaEncryption(), + "\x05\x00", 2); if (ret) { hx509_set_error_string(context, 0, ret, "malloc - out of memory"); free(spki->subjectPublicKey.data); @@ -400,17 +442,13 @@ rsa_private_key2SPKI(hx509_context context, } static int -cb_func(int a, int b, BN_GENCB *c) +rsa_generate_private_key(hx509_context context, + struct hx509_generate_private_context *ctx, + hx509_private_key private_key) { - return 1; -} - -static int -rsa_generate_private_key(hx509_context context, hx509_private_key private_key) -{ - BN_GENCB cb; BIGNUM *e; int ret; + unsigned long bits; static const int default_rsa_e = 65537; static const int default_rsa_bits = 1024; @@ -425,9 +463,14 @@ rsa_generate_private_key(hx509_context context, hx509_private_key private_key) e = BN_new(); BN_set_word(e, default_rsa_e); - BN_GENCB_set(&cb, cb_func, NULL); - ret = RSA_generate_key_ex(private_key->private_key.rsa, - default_rsa_bits, e, &cb); + bits = default_rsa_bits; + + if (ctx->num_bits) + bits = ctx->num_bits; + else if (ctx->isCA) + bits *= 2; + + ret = RSA_generate_key_ex(private_key->private_key.rsa, bits, e, NULL); BN_free(e); if (ret != 1) { hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, @@ -642,8 +685,8 @@ sha256_create_signature(hx509_context context, if (signatureAlgorithm) { int ret; - ret = _hx509_set_digest_alg(signatureAlgorithm, - (*sig_alg->sig_oid)(), "\x05\x00", 2); + ret = set_digest_alg(signatureAlgorithm, (*sig_alg->sig_oid)(), + "\x05\x00", 2); if (ret) return ret; } @@ -708,8 +751,8 @@ sha1_create_signature(hx509_context context, if (signatureAlgorithm) { int ret; - ret = _hx509_set_digest_alg(signatureAlgorithm, - (*sig_alg->sig_oid)(), "\x05\x00", 2); + ret = set_digest_alg(signatureAlgorithm, (*sig_alg->sig_oid)(), + "\x05\x00", 2); if (ret) return ret; } @@ -789,7 +832,7 @@ md2_verify_signature(hx509_context context, return 0; } -static struct signature_alg pkcs1_rsa_sha1_alg = { +static const struct signature_alg pkcs1_rsa_sha1_alg = { "rsa", oid_id_pkcs1_rsaEncryption, hx509_signature_rsa_with_sha1, @@ -797,11 +840,10 @@ static struct signature_alg pkcs1_rsa_sha1_alg = { NULL, PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, rsa_verify_signature, - rsa_create_signature, - rsa_private_key2SPKI + rsa_create_signature }; -static struct signature_alg rsa_with_sha256_alg = { +static const struct signature_alg rsa_with_sha256_alg = { "rsa-with-sha256", oid_id_pkcs1_sha256WithRSAEncryption, hx509_signature_rsa_with_sha256, @@ -809,11 +851,10 @@ static struct signature_alg rsa_with_sha256_alg = { oid_id_sha256, PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, rsa_verify_signature, - rsa_create_signature, - rsa_private_key2SPKI + rsa_create_signature }; -static struct signature_alg rsa_with_sha1_alg = { +static const struct signature_alg rsa_with_sha1_alg = { "rsa-with-sha1", oid_id_pkcs1_sha1WithRSAEncryption, hx509_signature_rsa_with_sha1, @@ -821,11 +862,10 @@ static struct signature_alg rsa_with_sha1_alg = { oid_id_secsig_sha_1, PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, rsa_verify_signature, - rsa_create_signature, - rsa_private_key2SPKI + rsa_create_signature }; -static struct signature_alg rsa_with_md5_alg = { +static const struct signature_alg rsa_with_md5_alg = { "rsa-with-md5", oid_id_pkcs1_md5WithRSAEncryption, hx509_signature_rsa_with_md5, @@ -833,11 +873,10 @@ static struct signature_alg rsa_with_md5_alg = { oid_id_rsa_digest_md5, PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, rsa_verify_signature, - rsa_create_signature, - rsa_private_key2SPKI + rsa_create_signature }; -static struct signature_alg rsa_with_md2_alg = { +static const struct signature_alg rsa_with_md2_alg = { "rsa-with-md2", oid_id_pkcs1_md2WithRSAEncryption, hx509_signature_rsa_with_md2, @@ -845,11 +884,10 @@ static struct signature_alg rsa_with_md2_alg = { oid_id_rsa_digest_md2, PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG, rsa_verify_signature, - rsa_create_signature, - rsa_private_key2SPKI + rsa_create_signature }; -static struct signature_alg dsa_sha1_alg = { +static const struct signature_alg dsa_sha1_alg = { "dsa-with-sha1", oid_id_dsa_with_sha1, NULL, @@ -860,7 +898,7 @@ static struct signature_alg dsa_sha1_alg = { /* create_signature */ NULL, }; -static struct signature_alg sha256_alg = { +static const struct signature_alg sha256_alg = { "sha-256", oid_id_sha256, hx509_signature_sha256, @@ -871,7 +909,7 @@ static struct signature_alg sha256_alg = { sha256_create_signature }; -static struct signature_alg sha1_alg = { +static const struct signature_alg sha1_alg = { "sha1", oid_id_secsig_sha_1, hx509_signature_sha1, @@ -882,7 +920,7 @@ static struct signature_alg sha1_alg = { sha1_create_signature }; -static struct signature_alg md5_alg = { +static const struct signature_alg md5_alg = { "rsa-md5", oid_id_rsa_digest_md5, hx509_signature_md5, @@ -892,7 +930,7 @@ static struct signature_alg md5_alg = { md5_verify_signature }; -static struct signature_alg md2_alg = { +static const struct signature_alg md2_alg = { "rsa-md2", oid_id_rsa_digest_md2, hx509_signature_md2, @@ -907,12 +945,13 @@ static struct signature_alg md2_alg = { * compatible" type (type is RSA, DSA, none, etc) */ -static struct signature_alg *sig_algs[] = { +static const struct signature_alg *sig_algs[] = { &rsa_with_sha256_alg, &rsa_with_sha1_alg, &pkcs1_rsa_sha1_alg, &rsa_with_md5_alg, &rsa_with_md2_alg, + &pkcs1_rsa_sha1_alg, &dsa_sha1_alg, &sha256_alg, &sha1_alg, @@ -1235,8 +1274,56 @@ _hx509_private_key2SPKI(hx509_context context, } int +_hx509_generate_private_key_init(hx509_context context, + const heim_oid *oid, + struct hx509_generate_private_context **ctx) +{ + *ctx = NULL; + + if (der_heim_oid_cmp(oid, oid_id_pkcs1_rsaEncryption()) != 0) { + hx509_set_error_string(context, 0, EINVAL, + "private key not an RSA key"); + return EINVAL; + } + + *ctx = calloc(1, sizeof(**ctx)); + if (*ctx == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + (*ctx)->key_oid = oid; + + return 0; +} + +int +_hx509_generate_private_key_is_ca(hx509_context context, + struct hx509_generate_private_context *ctx) +{ + ctx->isCA = 1; + return 0; +} + +int +_hx509_generate_private_key_bits(hx509_context context, + struct hx509_generate_private_context *ctx, + unsigned long bits) +{ + ctx->num_bits = bits; + return 0; +} + + +void +_hx509_generate_private_key_free(struct hx509_generate_private_context **ctx) +{ + free(*ctx); + *ctx = NULL; +} + +int _hx509_generate_private_key(hx509_context context, - const heim_oid *key_oid, + struct hx509_generate_private_context *ctx, hx509_private_key *private_key) { struct hx509_private_key_ops *ops; @@ -1244,7 +1331,7 @@ _hx509_generate_private_key(hx509_context context, *private_key = NULL; - ops = find_private_alg(key_oid); + ops = find_private_alg(ctx->key_oid); if (ops == NULL) { hx509_clear_error_string(context); return HX509_SIG_ALG_NO_SUPPORTED; @@ -1256,7 +1343,7 @@ _hx509_generate_private_key(hx509_context context, return ret; } - ret = (*ops->generate_private_key)(context, *private_key); + ret = (*ops->generate_private_key)(context, ctx, *private_key); if (ret) _hx509_private_key_free(private_key); @@ -1268,21 +1355,21 @@ _hx509_generate_private_key(hx509_context context, * */ -static const heim_octet_string null_entry_oid = { 2, "\x05\x00" }; +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, 3 }; +static const unsigned sha512_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 }; const AlgorithmIdentifier _hx509_signature_sha512_data = { - { 8, rk_UNCONST(sha512_oid_tree) }, rk_UNCONST(&null_entry_oid) + { 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 }; +static const unsigned sha384_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 2 }; const AlgorithmIdentifier _hx509_signature_sha384_data = { - { 8, rk_UNCONST(sha384_oid_tree) }, rk_UNCONST(&null_entry_oid) + { 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 = { - { 8, rk_UNCONST(sha256_oid_tree) }, rk_UNCONST(&null_entry_oid) + { 9, rk_UNCONST(sha256_oid_tree) }, rk_UNCONST(&null_entry_oid) }; static const unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 }; @@ -1335,6 +1422,20 @@ const AlgorithmIdentifier _hx509_signature_rsa_data = { { 7, rk_UNCONST(rsa_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) @@ -1388,6 +1489,33 @@ const AlgorithmIdentifier * hx509_signature_rsa(void) { return &_hx509_signature_rsa_data; } +const AlgorithmIdentifier * +hx509_crypto_des_rsdi_ede3_cbc(void) +{ return &_hx509_des_rsdi_ede3_cbc_oid; } + +const AlgorithmIdentifier * +hx509_crypto_aes128_cbc(void) +{ return &_hx509_crypto_aes128_cbc_data; } + +const AlgorithmIdentifier * +hx509_crypto_aes256_cbc(void) +{ return &_hx509_crypto_aes256_cbc_data; } + +/* + * + */ + +const AlgorithmIdentifier * _hx509_crypto_default_sig_alg = + &_hx509_signature_rsa_with_sha1_data; +const AlgorithmIdentifier * _hx509_crypto_default_digest_alg = + &_hx509_signature_sha1_data; +const AlgorithmIdentifier * _hx509_crypto_default_secret_alg = + &_hx509_crypto_aes128_cbc_data; + +/* + * + */ + int _hx509_private_key_init(hx509_private_key *key, hx509_private_key_ops *ops, @@ -1487,6 +1615,7 @@ _hx509_private_key_export(hx509_context context, struct hx509cipher { const char *name; const heim_oid *(*oid_func)(void); + const AlgorithmIdentifier *(*ai_func)(void); const EVP_CIPHER *(*evp_func)(void); int (*get_params)(hx509_context, const hx509_crypto, const heim_octet_string *, heim_octet_string *); @@ -1654,6 +1783,7 @@ static const struct hx509cipher ciphers[] = { { "rc2-cbc", oid_id_pkcs3_rc2_cbc, + NULL, EVP_rc2_cbc, CMSRC2CBCParam_get, CMSRC2CBCParam_set @@ -1661,6 +1791,7 @@ static const struct hx509cipher ciphers[] = { { "rc2-cbc", oid_id_rsadsi_rc2_cbc, + NULL, EVP_rc2_cbc, CMSRC2CBCParam_get, CMSRC2CBCParam_set @@ -1668,6 +1799,7 @@ static const struct hx509cipher ciphers[] = { { "rc2-40-cbc", oid_private_rc2_40, + NULL, EVP_rc2_40_cbc, CMSRC2CBCParam_get, CMSRC2CBCParam_set @@ -1675,6 +1807,7 @@ static const struct hx509cipher ciphers[] = { { "des-ede3-cbc", oid_id_pkcs3_des_ede3_cbc, + NULL, EVP_des_ede3_cbc, CMSCBCParam_get, CMSCBCParam_set @@ -1682,6 +1815,7 @@ static const struct hx509cipher ciphers[] = { { "des-ede3-cbc", oid_id_rsadsi_des_ede3_cbc, + hx509_crypto_des_rsdi_ede3_cbc, EVP_des_ede3_cbc, CMSCBCParam_get, CMSCBCParam_set @@ -1689,6 +1823,7 @@ static const struct hx509cipher ciphers[] = { { "aes-128-cbc", oid_id_aes_128_cbc, + hx509_crypto_aes128_cbc, EVP_aes_128_cbc, CMSCBCParam_get, CMSCBCParam_set @@ -1696,6 +1831,7 @@ static const struct hx509cipher ciphers[] = { { "aes-192-cbc", oid_id_aes_192_cbc, + NULL, EVP_aes_192_cbc, CMSCBCParam_get, CMSCBCParam_set @@ -1703,6 +1839,7 @@ static const struct hx509cipher ciphers[] = { { "aes-256-cbc", oid_id_aes_256_cbc, + hx509_crypto_aes256_cbc, EVP_aes_256_cbc, CMSCBCParam_get, CMSCBCParam_set @@ -2060,11 +2197,13 @@ PBE_string2key(hx509_context context, const EVP_MD *md) { PKCS12_PBEParams p12params; - int passwordlen = strlen(password); + int passwordlen; hx509_crypto c; int iter, saltlen, ret; unsigned char *salt; + passwordlen = password ? strlen(password) : 0; + if (parameters == NULL) return HX509_ALG_NOT_SUPP; @@ -2081,10 +2220,6 @@ PBE_string2key(hx509_context context, salt = p12params.salt.data; saltlen = p12params.salt.length; - /* XXX It needs to be here, but why ? */ - if (passwordlen == 0) - password = NULL; - if (!PKCS12_key_gen (password, passwordlen, salt, saltlen, PKCS12_KEY_ID, iter, key->length, key->data, md)) { ret = HX509_CRYPTO_INTERNAL_ERROR; @@ -2205,8 +2340,10 @@ _hx509_pbe_decrypt(hx509_context context, if (i < pw->len) password = pw->val[i]; - else + else if (i < pw->len + 1) password = ""; + else + password = NULL; ret = (*s2k)(context, password, ai->parameters, &crypto, &key, &iv, enc_oid, md); @@ -2314,7 +2451,6 @@ hx509_crypto_select(const hx509_context context, hx509_peer_info peer, AlgorithmIdentifier *selected) { - const heim_oid *keytype = NULL; const AlgorithmIdentifier *def; size_t i, j; int ret, bits; @@ -2323,20 +2459,25 @@ hx509_crypto_select(const hx509_context context, if (type == HX509_SELECT_DIGEST) { bits = SIG_DIGEST; - def = hx509_signature_sha1(); + 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_signature_rsa_with_sha1(); + def = _hx509_crypto_default_sig_alg; + } else if (type == HX509_SELECT_SECRET_ENC) { + bits = SIG_SECRET; + def = _hx509_crypto_default_secret_alg; } else { hx509_set_error_string(context, 0, EINVAL, "Unknown type %d of selection", type); return EINVAL; } - keytype = find_keytype(source); - if (peer) { + const heim_oid *keytype = NULL; + + keytype = find_keytype(source); + for (i = 0; i < peer->len; i++) { for (j = 0; sig_algs[j]; j++) { if ((sig_algs[j]->flags & bits) != bits) @@ -2354,6 +2495,19 @@ hx509_crypto_select(const hx509_context context, hx509_clear_error_string(context); return ret; } + if (bits & SIG_SECRET) { + const struct hx509cipher *cipher; + + cipher = find_cipher_by_oid(&peer->val[i].algorithm); + if (cipher == NULL) + continue; + if (cipher->ai_func == NULL) + continue; + ret = copy_AlgorithmIdentifier(cipher->ai_func(), selected); + if (ret) + hx509_clear_error_string(context); + return ret; + } } } @@ -2379,7 +2533,7 @@ hx509_crypto_available(hx509_context context, *val = NULL; if (type == HX509_SELECT_ALL) { - bits = SIG_DIGEST | SIG_PUBLIC_SIG; + bits = SIG_DIGEST | SIG_PUBLIC_SIG | SIG_SECRET; } else if (type == HX509_SELECT_DIGEST) { bits = SIG_DIGEST; } else if (type == HX509_SELECT_PUBLIC_SIG) { @@ -2415,6 +2569,26 @@ hx509_crypto_available(hx509_context context, len++; } + /* Add AES */ + if (bits & SIG_SECRET) { + + for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++) { + + if (ciphers[i].ai_func == NULL) + continue; + + ptr = realloc(*val, sizeof(**val) * (len + 1)); + if (ptr == NULL) + goto out; + *val = ptr; + + ret = copy_AlgorithmIdentifier((ciphers[i].ai_func)(), &(*val)[len]); + if (ret) + goto out; + len++; + } + } + *plen = len; return 0; diff --git a/source4/heimdal/lib/hx509/env.c b/source4/heimdal/lib/hx509/env.c new file mode 100644 index 0000000000..4cb2f9f4b1 --- /dev/null +++ b/source4/heimdal/lib/hx509/env.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: env.c 19878 2007-01-13 00:58:39Z lha $"); + +struct hx509_env { + struct { + char *key; + char *value; + } *val; + size_t len; +}; + +int +hx509_env_init(hx509_context context, hx509_env *env) +{ + *env = calloc(1, sizeof(**env)); + if (*env == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + return 0; +} + +int +hx509_env_add(hx509_context context, hx509_env env, + const char *key, const char *value) +{ + void *ptr; + + ptr = realloc(env->val, sizeof(env->val[0]) * (env->len + 1)); + if (ptr == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + env->val = ptr; + env->val[env->len].key = strdup(key); + if (env->val[env->len].key == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + env->val[env->len].value = strdup(value); + if (env->val[env->len].value == NULL) { + free(env->val[env->len].key); + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + env->len++; + return 0; +} + +const char * +hx509_env_lfind(hx509_context context, hx509_env env, + const char *key, size_t len) +{ + size_t i; + + for (i = 0; i < env->len; i++) { + char *s = env->val[i].key; + if (strncmp(key, s, len) == 0 && s[len] == '\0') + return env->val[i].value; + } + return NULL; +} + + +void +hx509_env_free(hx509_env *env) +{ + size_t i; + + for (i = 0; i < (*env)->len; i++) { + free((*env)->val[i].key); + free((*env)->val[i].value); + } + free((*env)->val); + free(*env); + *env = NULL; +} + diff --git a/source4/heimdal/lib/hx509/error.c b/source4/heimdal/lib/hx509/error.c index 770b71981a..9f3a014873 100644 --- a/source4/heimdal/lib/hx509/error.c +++ b/source4/heimdal/lib/hx509/error.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: error.c,v 1.4 2006/11/16 15:08:09 lha Exp $"); +RCSID("$Id: error.c 20912 2007-06-05 03:53:52Z lha $"); struct hx509_error_data { hx509_error next; @@ -87,7 +87,8 @@ hx509_set_error_stringv(hx509_context context, int flags, int code, } void -hx509_set_error_string(hx509_context context, int flags, int code, const char *fmt, ...) +hx509_set_error_string(hx509_context context, int flags, int code, + const char *fmt, ...) { va_list ap; @@ -100,9 +101,9 @@ char * hx509_get_error_string(hx509_context context, int error_code) { struct rk_strpool *p = NULL; - hx509_error msg; + hx509_error msg = context->error; - if (context->error == NULL) { + if (msg == NULL || msg->code != error_code) { const char *cstr; char *str; @@ -125,10 +126,12 @@ hx509_get_error_string(hx509_context context, int error_code) } void -hx509_err(hx509_context context, int exit_code, int error_code, char *fmt, ...) +hx509_err(hx509_context context, int exit_code, + int error_code, const char *fmt, ...) { va_list ap; - char *msg, *str; + const char *msg; + char *str; va_start(ap, fmt); vasprintf(&str, fmt, ap); diff --git a/source4/heimdal/lib/hx509/file.c b/source4/heimdal/lib/hx509/file.c index 39497fc3a9..1152af2423 100644 --- a/source4/heimdal/lib/hx509/file.c +++ b/source4/heimdal/lib/hx509/file.c @@ -35,6 +35,27 @@ RCSID("$ID$"); int +_hx509_map_file_os(const char *fn, heim_octet_string *os, struct stat *rsb) +{ + size_t length; + void *data; + int ret; + + ret = _hx509_map_file(fn, &data, &length, rsb); + + os->data = data; + os->length = length; + + return ret; +} + +void +_hx509_unmap_file_os(heim_octet_string *os) +{ + _hx509_unmap_file(os->data, os->length); +} + +int _hx509_map_file(const char *fn, void **data, size_t *length, struct stat *rsb) { struct stat sb; diff --git a/source4/heimdal/lib/hx509/hx509-private.h b/source4/heimdal/lib/hx509/hx509-private.h index 2db3f4f932..2763df957f 100644 --- a/source4/heimdal/lib/hx509/hx509-private.h +++ b/source4/heimdal/lib/hx509/hx509-private.h @@ -39,6 +39,12 @@ _hx509_cert_assign_key ( hx509_private_key /*private_key*/); int +_hx509_cert_get_eku ( + hx509_context /*context*/, + hx509_cert /*cert*/, + ExtKeyUsage */*e*/); + +int _hx509_cert_get_keyusage ( hx509_context /*context*/, hx509_cert /*c*/, @@ -105,10 +111,11 @@ _hx509_check_key_usage ( unsigned /*flags*/, int /*req_present*/); -struct hx509_collector * +int _hx509_collector_alloc ( hx509_context /*context*/, - hx509_lock /*lock*/); + hx509_lock /*lock*/, + struct hx509_collector **/*collector*/); int _hx509_collector_certs_add ( @@ -169,9 +176,29 @@ _hx509_find_extension_subject_key_id ( int _hx509_generate_private_key ( hx509_context /*context*/, - const heim_oid */*key_oid*/, + struct hx509_generate_private_context */*ctx*/, hx509_private_key */*private_key*/); +int +_hx509_generate_private_key_bits ( + hx509_context /*context*/, + struct hx509_generate_private_context */*ctx*/, + unsigned long /*bits*/); + +void +_hx509_generate_private_key_free (struct hx509_generate_private_context **/*ctx*/); + +int +_hx509_generate_private_key_init ( + hx509_context /*context*/, + const heim_oid */*oid*/, + struct hx509_generate_private_context **/*ctx*/); + +int +_hx509_generate_private_key_is_ca ( + hx509_context /*context*/, + struct hx509_generate_private_context */*ctx*/); + Certificate * _hx509_get_cert (hx509_cert /*cert*/); @@ -182,9 +209,15 @@ void _hx509_ks_file_register (hx509_context /*context*/); void +_hx509_ks_keychain_register (hx509_context /*context*/); + +void _hx509_ks_mem_register (hx509_context /*context*/); void +_hx509_ks_null_register (hx509_context /*context*/); + +void _hx509_ks_pkcs11_register (hx509_context /*context*/); void @@ -215,6 +248,12 @@ _hx509_map_file ( struct stat */*rsb*/); int +_hx509_map_file_os ( + const char */*fn*/, + heim_octet_string */*os*/, + struct stat */*rsb*/); + +int _hx509_match_keys ( hx509_cert /*c*/, hx509_private_key /*private_key*/); @@ -269,9 +308,9 @@ _hx509_pbe_decrypt ( void _hx509_pi_printf ( - int (*/*func*/)(void *, char *), + int (*/*func*/)(void *, const char *), void */*ctx*/, - char */*fmt*/, + const char */*fmt*/, ...); int @@ -340,6 +379,12 @@ _hx509_query_match_cert ( const hx509_query */*q*/, hx509_cert /*cert*/); +void +_hx509_query_statistic ( + hx509_context /*context*/, + int /*type*/, + const hx509_query */*q*/); + int _hx509_request_add_dns_name ( hx509_context /*context*/, @@ -392,18 +437,14 @@ _hx509_set_cert_attribute ( const heim_oid */*oid*/, const heim_octet_string */*attr*/); -int -_hx509_set_digest_alg ( - DigestAlgorithmIdentifier */*id*/, - const heim_oid */*oid*/, - void */*param*/, - size_t /*length*/); - void _hx509_unmap_file ( void */*data*/, size_t /*len*/); +void +_hx509_unmap_file_os (heim_octet_string */*os*/); + int _hx509_unparse_Name ( const Name */*aname*/, diff --git a/source4/heimdal/lib/hx509/hx509-protos.h b/source4/heimdal/lib/hx509/hx509-protos.h index 4fcab70ff8..ab312cdbdf 100644 --- a/source4/heimdal/lib/hx509/hx509-protos.h +++ b/source4/heimdal/lib/hx509/hx509-protos.h @@ -8,6 +8,14 @@ extern "C" { #endif +#ifndef HX509_LIB_FUNCTION +#if defined(_WIN32) +#define HX509_LIB_FUNCTION _stdcall +#else +#define HX509_LIB_FUNCTION +#endif +#endif + void hx509_bitstring_print ( const heim_bit_string */*b*/, @@ -29,8 +37,15 @@ hx509_ca_sign_self ( hx509_cert */*certificate*/); int +hx509_ca_tbs_add_crl_dp_uri ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + const char */*uri*/, + hx509_name /*issuername*/); + +int hx509_ca_tbs_add_eku ( - hx509_context /*contex*/, + hx509_context /*context*/, hx509_ca_tbs /*tbs*/, const heim_oid */*oid*/); @@ -41,6 +56,18 @@ hx509_ca_tbs_add_san_hostname ( const char */*dnsname*/); int +hx509_ca_tbs_add_san_jid ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + const char */*jid*/); + +int +hx509_ca_tbs_add_san_ms_upn ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + const char */*principal*/); + +int hx509_ca_tbs_add_san_otherName ( hx509_context /*context*/, hx509_ca_tbs /*tbs*/, @@ -74,6 +101,11 @@ hx509_ca_tbs_set_ca ( int /*pathLenConstraint*/); int +hx509_ca_tbs_set_domaincontroller ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/); + +int hx509_ca_tbs_set_notAfter ( hx509_context /*context*/, hx509_ca_tbs /*tbs*/, @@ -116,6 +148,28 @@ hx509_ca_tbs_set_subject ( hx509_name /*subject*/); int +hx509_ca_tbs_set_template ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + int /*flags*/, + hx509_cert /*cert*/); + +int +hx509_ca_tbs_subject_expand ( + hx509_context /*context*/, + hx509_ca_tbs /*tbs*/, + hx509_env /*env*/); + +const struct units * +hx509_ca_tbs_template_units (void); + +int +hx509_cert_binary ( + hx509_context /*context*/, + hx509_cert /*c*/, + heim_octet_string */*os*/); + +int hx509_cert_check_eku ( hx509_context /*context*/, hx509_cert /*cert*/, @@ -136,6 +190,11 @@ hx509_cert_find_subjectAltName_otherName ( void hx509_cert_free (hx509_cert /*cert*/); +int +hx509_cert_get_SPKI ( + hx509_cert /*p*/, + SubjectPublicKeyInfo */*spki*/); + hx509_cert_attribute hx509_cert_get_attribute ( hx509_cert /*cert*/, @@ -155,6 +214,12 @@ hx509_cert_get_issuer ( hx509_cert /*p*/, hx509_name */*name*/); +time_t +hx509_cert_get_notAfter (hx509_cert /*p*/); + +time_t +hx509_cert_get_notBefore (hx509_cert /*p*/); + int hx509_cert_get_serialnumber ( hx509_cert /*p*/, @@ -218,7 +283,7 @@ int hx509_certs_info ( hx509_context /*context*/, hx509_certs /*certs*/, - int (*/*func*/)(void *, char *), + int (*/*func*/)(void *, const char *), void */*ctx*/); int @@ -274,6 +339,7 @@ hx509_clear_error_string (hx509_context /*context*/); int hx509_cms_create_signed_1 ( hx509_context /*context*/, + int /*flags*/, const heim_oid */*eContentType*/, const void */*data*/, size_t /*length*/, @@ -296,6 +362,7 @@ hx509_cms_decrypt_encrypted ( int hx509_cms_envelope_1 ( hx509_context /*context*/, + int /*flags*/, hx509_cert /*cert*/, const void */*data*/, size_t /*length*/, @@ -327,6 +394,7 @@ hx509_cms_verify_signed ( hx509_verify_ctx /*ctx*/, const void */*data*/, size_t /*length*/, + const heim_octet_string */*signedContent*/, hx509_certs /*store*/, heim_oid */*contentType*/, heim_octet_string */*content*/, @@ -350,6 +418,41 @@ hx509_context_set_missing_revoke ( int /*flag*/); int +hx509_crl_add_revoked_certs ( + hx509_context /*context*/, + hx509_crl /*crl*/, + hx509_certs /*certs*/); + +int +hx509_crl_alloc ( + hx509_context /*context*/, + hx509_crl */*crl*/); + +void +hx509_crl_free ( + hx509_context /*context*/, + hx509_crl */*crl*/); + +int +hx509_crl_lifetime ( + hx509_context /*context*/, + hx509_crl /*crl*/, + int /*delta*/); + +int +hx509_crl_sign ( + hx509_context /*context*/, + hx509_cert /*signer*/, + hx509_crl /*crl*/, + heim_octet_string */*os*/); + +const AlgorithmIdentifier * +hx509_crypto_aes128_cbc (void); + +const AlgorithmIdentifier * +hx509_crypto_aes256_cbc (void); + +int hx509_crypto_available ( hx509_context /*context*/, int /*type*/, @@ -365,6 +468,9 @@ hx509_crypto_decrypt ( heim_octet_string */*ivec*/, heim_octet_string */*clear*/); +const AlgorithmIdentifier * +hx509_crypto_des_rsdi_ede3_cbc (void); + void hx509_crypto_destroy (hx509_crypto /*crypto*/); @@ -432,17 +538,44 @@ hx509_crypto_set_random_key ( hx509_crypto /*crypto*/, heim_octet_string */*key*/); +int +hx509_env_add ( + hx509_context /*context*/, + hx509_env /*env*/, + const char */*key*/, + const char */*value*/); + +void +hx509_env_free (hx509_env */*env*/); + +int +hx509_env_init ( + hx509_context /*context*/, + hx509_env */*env*/); + +const char * +hx509_env_lfind ( + hx509_context /*context*/, + hx509_env /*env*/, + const char */*key*/, + size_t /*len*/); + void hx509_err ( hx509_context /*context*/, int /*exit_code*/, int /*error_code*/, - char */*fmt*/, + const char */*fmt*/, ...); void hx509_free_octet_string_list (hx509_octet_string_list */*list*/); +int +hx509_general_name_unparse ( + GeneralName */*name*/, + char **/*str*/); + char * hx509_get_error_string ( hx509_context /*context*/, @@ -507,11 +640,22 @@ hx509_lock_set_prompter ( void */*data*/); int +hx509_name_cmp ( + hx509_name /*n1*/, + hx509_name /*n2*/); + +int hx509_name_copy ( hx509_context /*context*/, const hx509_name /*from*/, hx509_name */*to*/); +int +hx509_name_expand ( + hx509_context /*context*/, + hx509_name /*name*/, + hx509_env /*env*/); + void hx509_name_free (hx509_name */*name*/); @@ -519,6 +663,11 @@ int hx509_name_is_null_p (const hx509_name /*name*/); int +hx509_name_normalize ( + hx509_context /*context*/, + hx509_name /*name*/); + +int hx509_name_to_Name ( const hx509_name /*from*/, Name */*to*/); @@ -576,7 +725,7 @@ hx509_peer_info_alloc ( hx509_context /*context*/, hx509_peer_info */*peer*/); -int +void hx509_peer_info_free (hx509_peer_info /*peer*/); int @@ -639,6 +788,17 @@ hx509_query_match_option ( hx509_query */*q*/, hx509_query_option /*option*/); +void +hx509_query_statistic_file ( + hx509_context /*context*/, + const char */*fn*/); + +void +hx509_query_unparse_stats ( + hx509_context /*context*/, + int /*printtype*/, + FILE */*out*/); + int hx509_revoke_add_crl ( hx509_context /*context*/, diff --git a/source4/heimdal/lib/hx509/hx509.h b/source4/heimdal/lib/hx509/hx509.h index 70f29ea92d..664c12e045 100644 --- a/source4/heimdal/lib/hx509/hx509.h +++ b/source4/heimdal/lib/hx509/hx509.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: hx509.h,v 1.16 2007/01/09 10:52:05 lha Exp $ */ +/* $Id: hx509.h 20798 2007-06-02 03:28:55Z lha $ */ typedef struct hx509_cert_attribute_data *hx509_cert_attribute; typedef struct hx509_cert_data *hx509_cert; @@ -50,6 +50,8 @@ typedef struct hx509_request_data *hx509_request; typedef struct hx509_error_data *hx509_error; typedef struct hx509_peer_info *hx509_peer_info; typedef struct hx509_ca_tbs *hx509_ca_tbs; +typedef struct hx509_env *hx509_env; +typedef struct hx509_crl *hx509_crl; typedef void (*hx509_vprint_func)(void *, const char *, va_list); @@ -107,5 +109,18 @@ typedef enum { #define HX509_SELECT_DIGEST 1 #define HX509_SELECT_PUBLIC_SIG 2 #define HX509_SELECT_PUBLIC_ENC 3 +#define HX509_SELECT_SECRET_ENC 4 + +/* flags to hx509_ca_tbs_set_template */ +#define HX509_CA_TEMPLATE_SUBJECT 1 +#define HX509_CA_TEMPLATE_SERIAL 2 +#define HX509_CA_TEMPLATE_NOTBEFORE 4 +#define HX509_CA_TEMPLATE_NOTAFTER 8 +#define HX509_CA_TEMPLATE_SPKI 16 +#define HX509_CA_TEMPLATE_KU 32 +#define HX509_CA_TEMPLATE_EKU 64 + +/* flags hx509_cms_create_signed* */ +#define HX509_CMS_SIGATURE_DETACHED 1 #include <hx509-protos.h> diff --git a/source4/heimdal/lib/hx509/hx509_err.et b/source4/heimdal/lib/hx509/hx509_err.et index 54ec177e47..90f3b3d907 100644 --- a/source4/heimdal/lib/hx509/hx509_err.et +++ b/source4/heimdal/lib/hx509/hx509_err.et @@ -3,7 +3,7 @@ # # This might look like a com_err file, but is not # -id "$Id: hx509_err.et,v 1.19 2006/12/30 23:05:39 lha Exp $" +id "$Id: hx509_err.et 20807 2007-06-03 03:11:20Z lha $" error_table hx prefix HX509 @@ -76,7 +76,8 @@ error_code CRL_CERT_REVOKED, "Certificate is included in CRL" error_code REVOKE_STATUS_MISSING, "No revoke status found for certificates" error_code CRL_UNKNOWN_EXTENSION, "Unknown extension" error_code REVOKE_WRONG_DATA, "Got wrong CRL/OCSP data from server" -error_code REVOKE_NOT_SAME_PARENT, "Doesn't have same parent as other certificaes" +error_code REVOKE_NOT_SAME_PARENT, "Doesn't have same parent as other certificates" +error_code CERT_NOT_IN_OCSP, "Certificates not in OCSP reply" # misc error index 108 diff --git a/source4/heimdal/lib/hx509/hx_locl.h b/source4/heimdal/lib/hx509/hx_locl.h index 78d158f8b1..bfbee0943e 100644 --- a/source4/heimdal/lib/hx509/hx_locl.h +++ b/source4/heimdal/lib/hx509/hx_locl.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: hx_locl.h,v 1.30 2007/01/09 10:52:06 lha Exp $ */ +/* $Id: hx_locl.h 20930 2007-06-06 00:23:42Z lha $ */ #ifdef HAVE_CONFIG_H #include <config.h> @@ -71,6 +71,7 @@ struct hx509_keyset_ops; struct hx509_collector; +struct hx509_generate_private_context; typedef struct hx509_path hx509_path; #include <hx509.h> @@ -144,7 +145,7 @@ struct hx509_query_data { }; struct hx509_keyset_ops { - char *name; + const char *name; int flags; int (*init)(hx509_context, hx509_certs, void **, int, const char *, hx509_lock); @@ -157,7 +158,7 @@ struct hx509_keyset_ops { int (*iter)(hx509_context, hx509_certs, void *, void *, hx509_cert *); int (*iter_end)(hx509_context, hx509_certs, void *, void *); int (*printinfo)(hx509_context, hx509_certs, - void *, int (*)(void *, char *), void *); + void *, int (*)(void *, const char *), void *); int (*getkeys)(hx509_context, hx509_certs, void *, hx509_private_key **); int (*addkey)(hx509_context, hx509_certs, void *, hx509_private_key); }; @@ -178,7 +179,21 @@ struct hx509_context_data { #define HX509_DEFAULT_OCSP_TIME_DIFF (5*60) hx509_error error; struct et_list *et_list; + char *querystat; + hx509_certs default_trust_anchors; }; /* _hx509_calculate_path flag field */ #define HX509_CALCULATE_PATH_NO_ANCHOR 1 + +extern const AlgorithmIdentifier * _hx509_crypto_default_sig_alg; +extern const AlgorithmIdentifier * _hx509_crypto_default_digest_alg; +extern const AlgorithmIdentifier * _hx509_crypto_default_secret_alg; + +/* + * Configurable options + */ + +#if 0 /* fdef __APPLE__*/ +#define HX509_DEFAULT_ANCHORS "KEYCHAIN:system" +#endif diff --git a/source4/heimdal/lib/hx509/keyset.c b/source4/heimdal/lib/hx509/keyset.c index c3d5ee210c..475835b9b0 100644 --- a/source4/heimdal/lib/hx509/keyset.c +++ b/source4/heimdal/lib/hx509/keyset.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: keyset.c,v 1.18 2007/01/09 10:52:07 lha Exp $"); +RCSID("$Id: keyset.c 20911 2007-06-05 03:41:17Z lha $"); struct hx509_certs_data { struct hx509_keyset_ops *ops; @@ -276,6 +276,8 @@ hx509_certs_find(hx509_context context, *r = NULL; + _hx509_query_statistic(context, 0, q); + if (certs->ops->query) return (*certs->ops->query)(context, certs, certs->ops_data, q, r); @@ -317,6 +319,8 @@ certs_merge_func(hx509_context context, void *ctx, hx509_cert c) int hx509_certs_merge(hx509_context context, hx509_certs to, hx509_certs from) { + if (from == NULL) + return 0; return hx509_certs_iter(context, from, certs_merge_func, to); } @@ -358,7 +362,7 @@ hx509_get_one_cert(hx509_context context, hx509_certs certs, hx509_cert *c) } static int -certs_info_stdio(void *ctx, char *str) +certs_info_stdio(void *ctx, const char *str) { FILE *f = ctx; fprintf(f, "%s\n", str); @@ -368,7 +372,7 @@ certs_info_stdio(void *ctx, char *str) int hx509_certs_info(hx509_context context, hx509_certs certs, - int (*func)(void *, char *), + int (*func)(void *, const char *), void *ctx) { if (func == NULL) { @@ -385,8 +389,8 @@ hx509_certs_info(hx509_context context, } void -_hx509_pi_printf(int (*func)(void *, char *), void *ctx, - char *fmt, ...) +_hx509_pi_printf(int (*func)(void *, const char *), void *ctx, + const char *fmt, ...) { va_list ap; char *str; diff --git a/source4/heimdal/lib/hx509/ks_dir.c b/source4/heimdal/lib/hx509/ks_dir.c index 01dcf5795b..a0bc875e5b 100644 --- a/source4/heimdal/lib/hx509/ks_dir.c +++ b/source4/heimdal/lib/hx509/ks_dir.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: ks_dir.c,v 1.7 2007/01/09 10:52:08 lha Exp $"); +RCSID("$Id: ks_dir.c 19778 2007-01-09 10:52:13Z lha $"); #include <dirent.h> /* diff --git a/source4/heimdal/lib/hx509/ks_file.c b/source4/heimdal/lib/hx509/ks_file.c index db0f475129..f9a3580880 100644 --- a/source4/heimdal/lib/hx509/ks_file.c +++ b/source4/heimdal/lib/hx509/ks_file.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: ks_file.c,v 1.31 2007/01/09 10:52:08 lha Exp $"); +RCSID("$Id: ks_file.c 20776 2007-06-01 22:02:01Z lha $"); struct ks_file { hx509_certs certs; @@ -542,12 +542,9 @@ file_init(hx509_context context, return 0; } - c = _hx509_collector_alloc(context, lock); - if (c == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "out of memory"); + ret = _hx509_collector_alloc(context, lock, &c); + if (ret) goto out; - } for (p = f->fn; p != NULL; p = pnext) { int found_data; @@ -678,16 +675,12 @@ static int store_func(hx509_context context, void *ctx, hx509_cert c) { FILE *f = (FILE *)ctx; - size_t size; heim_octet_string data; int ret; - ASN1_MALLOC_ENCODE(Certificate, data.data, data.length, - _hx509_get_cert(c), &size, ret); + ret = hx509_cert_binary(context, c, &data); if (ret) return ret; - if (data.length != size) - _hx509_abort("internal ASN.1 encoder error"); dump_pem_file(context, "CERTIFICATE", f, data.data, data.length); free(data.data); diff --git a/source4/heimdal/lib/hx509/ks_keychain.c b/source4/heimdal/lib/hx509/ks_keychain.c new file mode 100644 index 0000000000..2f0f72cd14 --- /dev/null +++ b/source4/heimdal/lib/hx509/ks_keychain.c @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hx_locl.h" +RCSID("$Id: ks_keychain.c 20945 2007-06-06 22:17:17Z lha $"); + +#ifdef HAVE_FRAMEWORK_SECURITY + +#include <Security/Security.h> + +/* Missing function decls */ +OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *); +OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG, + int, const CSSM_ACCESS_CREDENTIALS **); +#define kSecCredentialTypeDefault 0 + + +static int +getAttribute(SecKeychainItemRef itemRef, SecItemAttr item, + SecKeychainAttributeList **attrs) +{ + SecKeychainAttributeInfo attrInfo; + uint32 attrFormat = 0; + OSStatus ret; + + *attrs = NULL; + + attrInfo.count = 1; + attrInfo.tag = &item; + attrInfo.format = &attrFormat; + + ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, + attrs, NULL, NULL); + if (ret) + return EINVAL; + return 0; +} + + +/* + * + */ + +struct kc_rsa { + SecKeychainItemRef item; + size_t keysize; +}; + + +static int +kc_rsa_public_encrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + return -1; +} + +static int +kc_rsa_public_decrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + return -1; +} + + +static int +kc_rsa_private_encrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + 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 sigHandle = 0; + CSSM_DATA sig, in; + int fret = 0; + + + cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); + if(cret) abort(); + + cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); + if(cret) abort(); + + ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN, + kSecCredentialTypeDefault, &creds); + if(ret) abort(); + + ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, + creds, cssmKey, &sigHandle); + if(ret) abort(); + + in.Data = (uint8 *)from; + in.Length = flen; + + sig.Data = (uint8 *)to; + sig.Length = kc->keysize; + + cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig); + if(cret) { + /* cssmErrorString(cret); */ + fret = -1; + } else + fret = sig.Length; + + if(sigHandle) + CSSM_DeleteContext(sigHandle); + + return fret; +} + +static int +kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, + RSA * rsa, int padding) +{ + return -1; +} + +static int +kc_rsa_init(RSA *rsa) +{ + return 1; +} + +static int +kc_rsa_finish(RSA *rsa) +{ + struct kc_rsa *kc_rsa = RSA_get_app_data(rsa); + CFRelease(kc_rsa->item); + memset(kc_rsa, 0, sizeof(*kc_rsa)); + free(kc_rsa); + return 1; +} + +static const RSA_METHOD kc_rsa_pkcs1_method = { + "hx509 Keychain PKCS#1 RSA", + kc_rsa_public_encrypt, + kc_rsa_public_decrypt, + kc_rsa_private_encrypt, + kc_rsa_private_decrypt, + NULL, + NULL, + kc_rsa_init, + kc_rsa_finish, + 0, + NULL, + NULL, + NULL +}; + +static int +set_private_key(hx509_context context, + SecKeychainItemRef itemRef, + hx509_cert cert) +{ + struct kc_rsa *kc; + hx509_private_key key; + RSA *rsa; + int ret; + + ret = _hx509_private_key_init(&key, NULL, NULL); + if (ret) + return ret; + + kc = calloc(1, sizeof(*kc)); + if (kc == NULL) + _hx509_abort("out of memory"); + + kc->item = itemRef; + + rsa = RSA_new(); + if (rsa == NULL) + _hx509_abort("out of memory"); + + /* Argh, fake modulus since OpenSSL API is on crack */ + { + SecKeychainAttributeList *attrs = NULL; + uint32_t size; + void *data; + + rsa->n = BN_new(); + if (rsa->n == NULL) abort(); + + ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs); + if (ret) abort(); + + size = *(uint32_t *)attrs->attr[0].data; + SecKeychainItemFreeAttributesAndData(attrs, NULL); + + kc->keysize = (size + 7) / 8; + + data = malloc(kc->keysize); + memset(data, 0xe0, kc->keysize); + BN_bin2bn(data, kc->keysize, rsa->n); + free(data); + } + rsa->e = NULL; + + RSA_set_method(rsa, &kc_rsa_pkcs1_method); + ret = RSA_set_app_data(rsa, kc); + if (ret != 1) + _hx509_abort("RSA_set_app_data"); + + _hx509_private_key_assign_rsa(key, rsa); + _hx509_cert_assign_key(cert, key); + + return 0; +} + +/* + * + */ + +struct ks_keychain { + SecKeychainRef keychain; +}; + +static int +keychain_init(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + struct ks_keychain *ctx; + OSStatus ret; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + + if (residue) { + if (strcasecmp(residue, "system") == 0) + residue = "/System/Library/Keychains/X509Anchors"; + + ret = SecKeychainOpen(residue, &ctx->keychain); + if (ret != noErr) { + hx509_set_error_string(context, 0, ENOENT, + "Failed to open %s", residue); + return ENOENT; + } + } + + *data = ctx; + return 0; +} + +/* + * + */ + +static int +keychain_free(hx509_certs certs, void *data) +{ + struct ks_keychain *ctx = data; + if (ctx->keychain) + CFRelease(ctx->keychain); + memset(ctx, 0, sizeof(*ctx)); + free(ctx); + return 0; +} + +/* + * + */ + +struct iter { + SecKeychainSearchRef searchRef; +}; + +static int +keychain_iter_start(hx509_context context, + hx509_certs certs, void *data, void **cursor) +{ + struct ks_keychain *ctx = data; + struct iter *iter; + OSStatus ret; + + iter = calloc(1, sizeof(*iter)); + if (iter == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + ret = SecKeychainSearchCreateFromAttributes(ctx->keychain, + kSecCertificateItemClass, + NULL, + &iter->searchRef); + if (ret) { + free(iter); + hx509_set_error_string(context, 0, ret, + "Failed to start search for attributes"); + return ENOMEM; + } + + *cursor = iter; + return 0; +} + +/* + * + */ + +static int +keychain_iter(hx509_context context, + hx509_certs certs, void *data, void *cursor, hx509_cert *cert) +{ + SecKeychainAttributeList *attrs = NULL; + SecKeychainAttributeInfo attrInfo; + uint32 attrFormat = 0; + SecKeychainItemRef itemRef; + SecItemAttr item; + struct iter *iter = cursor; + Certificate t; + OSStatus ret; + UInt32 len; + void *ptr = NULL; + size_t size; + + *cert = NULL; + + ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef); + if (ret == errSecItemNotFound) + return 0; + else if (ret != 0) + return EINVAL; + + /* + * Pick out certificate and matching "keyid" + */ + + item = kSecPublicKeyHashItemAttr; + + attrInfo.count = 1; + attrInfo.tag = &item; + attrInfo.format = &attrFormat; + + ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, + &attrs, &len, &ptr); + if (ret) + return EINVAL; + + ret = decode_Certificate(ptr, len, &t, &size); + CFRelease(itemRef); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to parse certificate"); + goto out; + } + + ret = hx509_cert_init(context, &t, cert); + free_Certificate(&t); + if (ret) + goto out; + + /* + * Find related private key if there is one by looking at + * kSecPublicKeyHashItemAttr == kSecKeyLabel + */ + { + SecKeychainSearchRef search; + SecKeychainAttribute attrKeyid; + SecKeychainAttributeList attrList; + + attrKeyid.tag = kSecKeyLabel; + attrKeyid.length = attrs->attr[0].length; + attrKeyid.data = attrs->attr[0].data; + + attrList.count = 1; + attrList.attr = &attrKeyid; + + ret = SecKeychainSearchCreateFromAttributes(NULL, + CSSM_DL_DB_RECORD_PRIVATE_KEY, + &attrList, + &search); + if (ret) { + ret = 0; + goto out; + } + + ret = SecKeychainSearchCopyNext(search, &itemRef); + CFRelease(search); + if (ret == errSecItemNotFound) { + ret = 0; + goto out; + } else if (ret) { + ret = EINVAL; + goto out; + } + set_private_key(context, itemRef, *cert); + } + +out: + SecKeychainItemFreeAttributesAndData(attrs, ptr); + + return ret; +} + +/* + * + */ + +static int +keychain_iter_end(hx509_context context, + hx509_certs certs, + void *data, + void *cursor) +{ + struct iter *iter = cursor; + + CFRelease(iter->searchRef); + memset(iter, 0, sizeof(*iter)); + free(iter); + return 0; +} + +/* + * + */ + +struct hx509_keyset_ops keyset_keychain = { + "KEYCHAIN", + 0, + keychain_init, + NULL, + keychain_free, + NULL, + NULL, + keychain_iter_start, + keychain_iter, + keychain_iter_end +}; + +#endif /* HAVE_FRAMEWORK_SECURITY */ + +/* + * + */ + +void +_hx509_ks_keychain_register(hx509_context context) +{ +#ifdef HAVE_FRAMEWORK_SECURITY + _hx509_ks_register(context, &keyset_keychain); +#endif +} diff --git a/source4/heimdal/lib/hx509/ks_mem.c b/source4/heimdal/lib/hx509/ks_mem.c index dd7b7166bc..efa19eb19c 100644 --- a/source4/heimdal/lib/hx509/ks_mem.c +++ b/source4/heimdal/lib/hx509/ks_mem.c @@ -80,6 +80,7 @@ mem_free(hx509_certs certs, void *data) free(mem->certs.val); for (i = 0; mem->keys && mem->keys[i]; i++) _hx509_private_key_free(&mem->keys[i]); + free(mem->keys); free(mem->name); free(mem); @@ -162,7 +163,7 @@ mem_getkeys(hx509_context context, for (i = 0; mem->keys && mem->keys[i]; i++) ; - *keys = calloc(i, sizeof(**keys)); + *keys = calloc(i + 1, sizeof(**keys)); for (i = 0; mem->keys && mem->keys[i]; i++) { (*keys)[i] = _hx509_private_key_ref(mem->keys[i]); if ((*keys)[i] == NULL) { diff --git a/source4/heimdal/lib/hx509/ks_null.c b/source4/heimdal/lib/hx509/ks_null.c index 1e6c2ea3fb..3be259fc60 100644 --- a/source4/heimdal/lib/hx509/ks_null.c +++ b/source4/heimdal/lib/hx509/ks_null.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: ks_null.c,v 1.5 2007/01/09 10:52:10 lha Exp $"); +RCSID("$Id: ks_null.c 20901 2007-06-04 23:14:08Z lha $"); static int @@ -90,3 +90,9 @@ struct hx509_keyset_ops keyset_null = { null_iter, null_iter_end }; + +void +_hx509_ks_null_register(hx509_context context) +{ + _hx509_ks_register(context, &keyset_null); +} diff --git a/source4/heimdal/lib/hx509/ks_p11.c b/source4/heimdal/lib/hx509/ks_p11.c index b103264b7a..90c716213f 100644 --- a/source4/heimdal/lib/hx509/ks_p11.c +++ b/source4/heimdal/lib/hx509/ks_p11.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: ks_p11.c,v 1.45 2007/01/09 19:43:35 lha Exp $"); +RCSID("$Id: ks_p11.c 20920 2007-06-05 05:47:06Z lha $"); #ifdef HAVE_DLFCN_H #include <dlfcn.h> #endif @@ -214,7 +214,7 @@ p11_rsa_finish(RSA *rsa) return 1; } -static const RSA_METHOD rsa_pkcs1_method = { +static const RSA_METHOD p11_rsa_pkcs1_method = { "hx509 PKCS11 PKCS#1 RSA", p11_rsa_public_encrypt, p11_rsa_public_decrypt, @@ -644,7 +644,7 @@ collect_private_key(hx509_context context, if (p->refcount == 0) _hx509_abort("pkcs11 refcount to high"); - RSA_set_method(rsa, &rsa_pkcs1_method); + RSA_set_method(rsa, &p11_rsa_pkcs1_method); ret = RSA_set_app_data(rsa, p11rsa); if (ret != 1) _hx509_abort("RSA_set_app_data"); @@ -766,11 +766,9 @@ p11_list_keys(hx509_context context, if (lock == NULL) lock = _hx509_empty_lock; - collector = _hx509_collector_alloc(context, lock); - if (collector == NULL) { - hx509_set_error_string(context, 0, ENOMEM, "out of memory"); - return ENOMEM; - } + ret = _hx509_collector_alloc(context, lock, &collector); + if (ret) + return ret; key_class = CKO_PRIVATE_KEY; ret = iterate_entries(context, p, slot, session, @@ -1113,7 +1111,7 @@ static int p11_printinfo(hx509_context context, hx509_certs certs, void *data, - int (*func)(void *, char *), + int (*func)(void *, const char *), void *ctx) { struct p11_module *p = data; @@ -1140,6 +1138,17 @@ p11_printinfo(hx509_context context, MECHNAME(CKM_RSA_X_509, "rsa-x-509"); MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs"); MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs"); + MECHNAME(CKM_RIPEMD160_RSA_PKCS, "ripemd160-rsa-pkcs"); + MECHNAME(CKM_RSA_PKCS_OAEP, "rsa-pkcs-oaep"); + MECHNAME(CKM_SHA_1, "sha1"); + MECHNAME(CKM_MD5, "md5"); + MECHNAME(CKM_MD2, "md2"); + MECHNAME(CKM_RIPEMD160, "ripemd-160"); + MECHNAME(CKM_DES_ECB, "des-ecb"); + MECHNAME(CKM_DES_CBC, "des-cbc"); + MECHNAME(CKM_AES_ECB, "aes-ecb"); + MECHNAME(CKM_AES_CBC, "aes-cbc"); + MECHNAME(CKM_DH_PKCS_PARAMETER_GEN, "dh-pkcs-parameter-gen"); default: snprintf(unknownname, sizeof(unknownname), "unknown-mech-%lu", diff --git a/source4/heimdal/lib/hx509/ks_p12.c b/source4/heimdal/lib/hx509/ks_p12.c index 69dba802e5..5fddbd07de 100644 --- a/source4/heimdal/lib/hx509/ks_p12.c +++ b/source4/heimdal/lib/hx509/ks_p12.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: ks_p12.c,v 1.18 2007/01/09 10:52:11 lha Exp $"); +RCSID("$Id: ks_p12.c 20909 2007-06-05 03:09:13Z lha $"); struct ks_pkcs12 { hx509_certs certs; @@ -341,39 +341,45 @@ p12_init(hx509_context context, if (lock == NULL) lock = _hx509_empty_lock; - c = _hx509_collector_alloc(context, lock); - if (c == NULL) - return ENOMEM; + ret = _hx509_collector_alloc(context, lock, &c); + if (ret) + return ret; p12 = calloc(1, sizeof(*p12)); if (p12 == NULL) { ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); goto out; } p12->fn = strdup(residue); if (p12->fn == NULL) { ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); goto out; } if (flags & HX509_CERTS_CREATE) { - ret = hx509_certs_init(context, "MEMORY:ks-file-create", + ret = hx509_certs_init(context, "MEMORY:ks-file-create", 0, lock, &p12->certs); - if (ret) - goto out; - *data = p12; - return 0; + if (ret == 0) + *data = p12; + goto out; } ret = _hx509_map_file(residue, &buf, &len, NULL); - if (ret) + if (ret) { + hx509_clear_error_string(context); goto out; + } ret = decode_PKCS12_PFX(buf, len, &pfx, NULL); _hx509_unmap_file(buf, len); - if (ret) + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode the PFX in %s", residue); goto out; + } if (der_heim_oid_cmp(&pfx.authSafe.contentType, oid_id_pkcs7_data()) != 0) { free_PKCS12_PFX(&pfx); @@ -452,15 +458,20 @@ addBag(hx509_context context, ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1)); if (ptr == NULL) { - hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory"); + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); return ENOMEM; } as->val = ptr; ret = der_copy_oid(oid, &as->val[as->len].contentType); + if (ret) { + hx509_set_error_string(context, 0, ret, "out of memory"); + return ret; + } as->val[as->len].content = calloc(1, sizeof(*as->val[0].content)); if (as->val[as->len].content == NULL) { + der_free_oid(&as->val[as->len].contentType); hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory"); return ENOMEM; } @@ -488,11 +499,11 @@ store_func(hx509_context context, void *ctx, hx509_cert c) os.data = NULL; os.length = 0; - ASN1_MALLOC_ENCODE(Certificate, os.data, os.length, - _hx509_get_cert(c), &size, ret); + ret = hx509_cert_binary(context, c, &os); if (ret) - goto out; - ASN1_MALLOC_ENCODE(PKCS12_OctetString, + return ret; + + ASN1_MALLOC_ENCODE(PKCS12_OctetString, cb.certValue.data,cb.certValue.length, &os, &size, ret); free(os.data); @@ -505,7 +516,7 @@ store_func(hx509_context context, void *ctx, hx509_cert c) } ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length, &cb, &size, ret); - free(cb.certValue.data); + free_PKCS12_CertBag(&cb); if (ret) goto out; diff --git a/source4/heimdal/lib/hx509/lock.c b/source4/heimdal/lib/hx509/lock.c index 95fc0aa26d..de326f2e2d 100644 --- a/source4/heimdal/lib/hx509/lock.c +++ b/source4/heimdal/lib/hx509/lock.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: lock.c,v 1.13 2006/10/14 09:41:05 lha Exp $"); +RCSID("$Id: lock.c 18452 2006-10-14 09:41:05Z lha $"); struct hx509_lock_data { struct _hx509_password password; diff --git a/source4/heimdal/lib/hx509/name.c b/source4/heimdal/lib/hx509/name.c index 92e9e6f974..5198633b1e 100644 --- a/source4/heimdal/lib/hx509/name.c +++ b/source4/heimdal/lib/hx509/name.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: name.c,v 1.33 2006/12/30 23:04:11 lha Exp $"); +RCSID("$Id: name.c 20891 2007-06-04 22:51:41Z lha $"); /* * name parsing from rfc2253 @@ -41,7 +41,7 @@ RCSID("$Id: name.c,v 1.33 2006/12/30 23:04:11 lha Exp $"); */ static const struct { - char *n; + const char *n; const heim_oid *(*o)(void); } no[] = { { "C", oid_id_at_countryName }, @@ -51,6 +51,7 @@ static const struct { { "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 } @@ -81,25 +82,27 @@ quote_string(const char *f, size_t len, size_t *rlen) to[j++] = from[i]; } else { int l = snprintf(&to[j], tolen - j - 1, - "#%02x", (unsigned int)from[i]); + "#%02x", (unsigned char)from[i]); j += l; } } to[j] = '\0'; + assert(j < tolen); *rlen = j; return to; } static int -append_string(char **str, size_t *total_len, char *ss, size_t len, int quote) +append_string(char **str, size_t *total_len, const char *ss, + size_t len, int quote) { char *s, *qs; if (quote) qs = quote_string(ss, len, &len); else - qs = ss; + qs = rk_UNCONST(ss); s = realloc(*str, len + *total_len + 1); if (s == NULL) @@ -181,10 +184,10 @@ _hx509_Name_to_string(const Name *n, char **str) ss = ds->u.ia5String; break; case choice_DirectoryString_printableString: - ss = ds->u.ia5String; + ss = ds->u.printableString; break; case choice_DirectoryString_utf8String: - ss = ds->u.ia5String; + ss = ds->u.utf8String; break; case choice_DirectoryString_bmpString: { uint16_t *bmp = ds->u.bmpString.data; @@ -200,11 +203,25 @@ _hx509_Name_to_string(const Name *n, char **str) break; } case choice_DirectoryString_teletexString: - ss = "teletex-string"; /* XXX */ + ss = malloc(ds->u.teletexString.length + 1); + if (ss == NULL) + _hx509_abort("allocation failure"); /* XXX */ + memcpy(ss, ds->u.teletexString.data, ds->u.teletexString.length); + ss[ds->u.teletexString.length] = '\0'; break; - case choice_DirectoryString_universalString: - ss = "universalString"; /* XXX */ + case choice_DirectoryString_universalString: { + uint32_t *uni = ds->u.universalString.data; + size_t unilen = ds->u.universalString.length; + size_t k; + + ss = malloc(unilen + 1); + if (ss == NULL) + _hx509_abort("allocation failure"); /* XXX */ + for (k = 0; k < unilen; k++) + ss[k] = uni[k] & 0xff; /* XXX */ + ss[k] = '\0'; break; + } default: _hx509_abort("unknown directory type: %d", ds->element); exit(1); @@ -214,8 +231,12 @@ _hx509_Name_to_string(const Name *n, char **str) append_string(str, &total_len, "=", 1, 0); len = strlen(ss); append_string(str, &total_len, ss, len, 1); - if (ds->element == choice_DirectoryString_bmpString) + if (ds->element == choice_DirectoryString_universalString || + ds->element == choice_DirectoryString_bmpString || + ds->element == choice_DirectoryString_teletexString) + { free(ss); + } if (j + 1 < n->u.rdnSequence.val[i].len) append_string(str, &total_len, "+", 1, 0); } @@ -299,6 +320,13 @@ _hx509_name_cmp(const Name *n1, const Name *n2) } int +hx509_name_cmp(hx509_name n1, hx509_name n2) +{ + return _hx509_name_cmp(&n1->der_name, &n2->der_name); +} + + +int _hx509_name_from_Name(const Name *n, hx509_name *name) { int ret; @@ -487,6 +515,106 @@ hx509_name_to_Name(const hx509_name from, Name *to) return copy_Name(&from->der_name, to); } +int +hx509_name_normalize(hx509_context context, hx509_name name) +{ + return 0; +} + +int +hx509_name_expand(hx509_context context, + hx509_name name, + hx509_env env) +{ + Name *n = &name->der_name; + int i, j; + + if (env == NULL) + return 0; + + if (n->element != choice_Name_rdnSequence) { + hx509_set_error_string(context, 0, EINVAL, "RDN not of supported type"); + return EINVAL; + } + + for (i = 0 ; i < n->u.rdnSequence.len; i++) { + for (j = 0; j < n->u.rdnSequence.val[i].len; j++) { + /* + THIS SHOULD REALLY BE: + COMP = n->u.rdnSequence.val[i].val[j]; + normalize COMP to utf8 + check if there are variables + expand variables + convert back to orignal format, store in COMP + free normalized utf8 string + */ + DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value; + char *p, *p2; + struct rk_strpool *strpool = NULL; + + if (ds->element != choice_DirectoryString_utf8String) { + hx509_set_error_string(context, 0, EINVAL, "unsupported type"); + return EINVAL; + } + p = strstr(ds->u.utf8String, "${"); + if (p) { + strpool = rk_strpoolprintf(strpool, "%.*s", + (int)(p - ds->u.utf8String), + ds->u.utf8String); + if (strpool == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + } + while (p != NULL) { + /* expand variables */ + const char *value; + p2 = strchr(p, '}'); + if (p2 == NULL) { + hx509_set_error_string(context, 0, EINVAL, "missing }"); + rk_strpoolfree(strpool); + return EINVAL; + } + p += 2; + value = hx509_env_lfind(context, env, p, p2 - p); + if (value == NULL) { + hx509_set_error_string(context, 0, EINVAL, + "variable %.*s missing", + (int)(p2 - p), p); + rk_strpoolfree(strpool); + return EINVAL; + } + strpool = rk_strpoolprintf(strpool, "%s", value); + if (strpool == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + p2++; + + p = strstr(p2, "${"); + if (p) + strpool = rk_strpoolprintf(strpool, "%.*s", + (int)(p - p2), p2); + else + strpool = rk_strpoolprintf(strpool, "%s", p2); + if (strpool == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + } + if (strpool) { + free(ds->u.utf8String); + ds->u.utf8String = rk_strpoolcollect(strpool); + if (ds->u.utf8String == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + } + } + } + return 0; +} + void hx509_name_free(hx509_name *name) @@ -548,3 +676,91 @@ hx509_name_is_null_p(const hx509_name name) { return name->der_name.u.rdnSequence.len == 0; } + +int +hx509_general_name_unparse(GeneralName *name, char **str) +{ + struct rk_strpool *strpool = NULL; + + *str = NULL; + + switch (name->element) { + case choice_GeneralName_otherName: { + char *str; + hx509_oid_sprint(&name->u.otherName.type_id, &str); + if (str == NULL) + return ENOMEM; + strpool = rk_strpoolprintf(strpool, "otherName: %s", str); + free(str); + break; + } + case choice_GeneralName_rfc822Name: + strpool = rk_strpoolprintf(strpool, "rfc822Name: %s\n", + name->u.rfc822Name); + break; + case choice_GeneralName_dNSName: + strpool = rk_strpoolprintf(strpool, "dNSName: %s\n", + name->u.dNSName); + break; + case choice_GeneralName_directoryName: { + Name dir; + char *s; + int ret; + memset(&dir, 0, sizeof(dir)); + dir.element = name->u.directoryName.element; + dir.u.rdnSequence = name->u.directoryName.u.rdnSequence; + ret = _hx509_unparse_Name(&dir, &s); + if (ret) + return ret; + strpool = rk_strpoolprintf(strpool, "directoryName: %s", s); + free(s); + break; + } + case choice_GeneralName_uniformResourceIdentifier: + strpool = rk_strpoolprintf(strpool, "URI: %s", + name->u.uniformResourceIdentifier); + break; + case choice_GeneralName_iPAddress: { + unsigned char *a = name->u.iPAddress.data; + + strpool = rk_strpoolprintf(strpool, "IPAddress: "); + if (strpool == NULL) + break; + if (name->u.iPAddress.length == 4) + strpool = rk_strpoolprintf(strpool, "%d.%d.%d.%d", + a[0], a[1], a[2], a[3]); + else if (name->u.iPAddress.length == 16) + strpool = rk_strpoolprintf(strpool, + "%02X:%02X:%02X:%02X:" + "%02X:%02X:%02X:%02X:" + "%02X:%02X:%02X:%02X:" + "%02X:%02X:%02X:%02X", + a[0], a[1], a[2], a[3], + a[4], a[5], a[6], a[7], + a[8], a[9], a[10], a[11], + a[12], a[13], a[14], a[15]); + else + strpool = rk_strpoolprintf(strpool, + "unknown IP address of length %lu", + (unsigned long)name->u.iPAddress.length); + break; + } + case choice_GeneralName_registeredID: { + char *str; + hx509_oid_sprint(&name->u.registeredID, &str); + if (str == NULL) + return ENOMEM; + strpool = rk_strpoolprintf(strpool, "registeredID: %s", str); + free(str); + break; + } + default: + return EINVAL; + } + if (strpool == NULL) + return ENOMEM; + + *str = rk_strpoolcollect(strpool); + + return 0; +} diff --git a/source4/heimdal/lib/hx509/ocsp.asn1 b/source4/heimdal/lib/hx509/ocsp.asn1 index 62a2750b96..d8ecd66ccf 100644 --- a/source4/heimdal/lib/hx509/ocsp.asn1 +++ b/source4/heimdal/lib/hx509/ocsp.asn1 @@ -1,5 +1,5 @@ -- From rfc2560 --- $Id: ocsp.asn1,v 1.4 2006/12/30 12:38:44 lha Exp $ +-- $Id: ocsp.asn1 19576 2006-12-30 12:40:43Z lha $ OCSP DEFINITIONS EXPLICIT TAGS::= BEGIN diff --git a/source4/heimdal/lib/hx509/peer.c b/source4/heimdal/lib/hx509/peer.c index f82f2877f6..eccedf1043 100644 --- a/source4/heimdal/lib/hx509/peer.c +++ b/source4/heimdal/lib/hx509/peer.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: peer.c,v 1.1 2006/11/26 15:49:01 lha Exp $"); +RCSID("$Id: peer.c 20938 2007-06-06 20:51:34Z lha $"); int hx509_peer_info_alloc(hx509_context context, hx509_peer_info *peer) @@ -59,14 +59,16 @@ free_cms_alg(hx509_peer_info peer) } } -int +void hx509_peer_info_free(hx509_peer_info peer) { + if (peer == NULL) + return; if (peer->cert) hx509_cert_free(peer->cert); free_cms_alg(peer); memset(peer, 0, sizeof(*peer)); - return 0; + free(peer); } int diff --git a/source4/heimdal/lib/hx509/pkcs10.asn1 b/source4/heimdal/lib/hx509/pkcs10.asn1 index c33fd36cb2..518fe3bfa3 100644 --- a/source4/heimdal/lib/hx509/pkcs10.asn1 +++ b/source4/heimdal/lib/hx509/pkcs10.asn1 @@ -1,4 +1,4 @@ --- $Id: pkcs10.asn1,v 1.1 2006/04/01 09:46:57 lha Exp $ +-- $Id: pkcs10.asn1 16918 2006-04-01 09:46:57Z lha $ PKCS10 DEFINITIONS ::= BEGIN diff --git a/source4/heimdal/lib/hx509/print.c b/source4/heimdal/lib/hx509/print.c index 802ac12b4e..dc9d4cfa58 100644 --- a/source4/heimdal/lib/hx509/print.c +++ b/source4/heimdal/lib/hx509/print.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: print.c,v 1.15 2006/12/07 20:37:57 lha Exp $"); +RCSID("$Id: print.c 20908 2007-06-05 02:59:33Z lha $"); struct hx509_validate_ctx_data { @@ -41,6 +41,18 @@ struct hx509_validate_ctx_data { void *ctx; }; +struct cert_status { + unsigned int selfsigned:1; + unsigned int isca:1; + unsigned int isproxy:1; + unsigned int haveSAN:1; + unsigned int haveIAN:1; + unsigned int haveSKI:1; + unsigned int haveAKI:1; + unsigned int haveCRLDP:1; +}; + + /* * */ @@ -155,10 +167,16 @@ validate_print(hx509_validate_ctx ctx, int flags, const char *fmt, ...) va_end(va); } +/* + * Dont Care, SHOULD critical, SHOULD NOT critical, MUST critical, + * MUST NOT critical + */ enum critical_flag { D_C = 0, S_C, S_N_C, M_C, M_N_C }; static int -check_Null(hx509_validate_ctx ctx, enum critical_flag cf, const Extension *e) +check_Null(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, const Extension *e) { switch(cf) { case D_C: @@ -191,13 +209,96 @@ check_Null(hx509_validate_ctx ctx, enum critical_flag cf, const Extension *e) static int check_subjectKeyIdentifier(hx509_validate_ctx ctx, + struct cert_status *status, enum critical_flag cf, const Extension *e) { - check_Null(ctx, cf, e); + SubjectKeyIdentifier si; + size_t size; + int ret; + + status->haveSKI = 1; + check_Null(ctx, status, cf, e); + + ret = decode_SubjectKeyIdentifier(e->extnValue.data, + e->extnValue.length, + &si, &size); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding SubjectKeyIdentifier failed: %d", ret); + return 1; + } + if (size != e->extnValue.length) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding SKI ahve extra bits on the end"); + return 1; + } + if (si.length == 0) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "SKI is too short (0 bytes)"); + if (si.length > 20) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "SKI is too long"); + + { + char *id; + hex_encode(si.data, si.length, &id); + if (id) { + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tsubject key id: %s\n", id); + free(id); + } + } + + free_SubjectKeyIdentifier(&si); + + return 0; +} + +static int +check_authorityKeyIdentifier(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + AuthorityKeyIdentifier ai; + size_t size; + int ret; + + status->haveAKI = 1; + check_Null(ctx, status, cf, e); + + status->haveSKI = 1; + check_Null(ctx, status, cf, e); + + ret = decode_AuthorityKeyIdentifier(e->extnValue.data, + e->extnValue.length, + &ai, &size); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding AuthorityKeyIdentifier failed: %d", ret); + return 1; + } + if (size != e->extnValue.length) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding SKI ahve extra bits on the end"); + return 1; + } + + if (ai.keyIdentifier) { + char *id; + hex_encode(ai.keyIdentifier->data, ai.keyIdentifier->length, &id); + if (id) { + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tauthority key id: %s\n", id); + free(id); + } + } + return 0; } + static int check_pkinit_san(hx509_validate_ctx ctx, heim_any *a) { @@ -206,15 +307,16 @@ check_pkinit_san(hx509_validate_ctx ctx, heim_any *a) size_t size; int ret; - ret = decode_KRB5PrincipalName(a->data, a->length, - &kn, &size); + ret = decode_KRB5PrincipalName(a->data, a->length, &kn, &size); if (ret) { - printf("Decoding kerberos name in SAN failed: %d", ret); + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding kerberos name in SAN failed: %d", ret); return 1; } if (size != a->length) { - printf("Decoding kerberos name have extra bits on the end"); + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding kerberos name have extra bits on the end"); return 1; } @@ -233,22 +335,117 @@ check_pkinit_san(hx509_validate_ctx ctx, heim_any *a) } static int -check_dnssrv_san(hx509_validate_ctx ctx, heim_any *a) +check_utf8_string_san(hx509_validate_ctx ctx, heim_any *a) { + PKIXXmppAddr jid; + size_t size; + int ret; + + ret = decode_PKIXXmppAddr(a->data, a->length, &jid, &size); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding JID in SAN failed: %d", ret); + return 1; + } + + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", jid); + free_PKIXXmppAddr(&jid); + return 0; } +static int +check_altnull(hx509_validate_ctx ctx, heim_any *a) +{ + return 0; +} + +static int +check_CRLDistributionPoints(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + CRLDistributionPoints dp; + size_t size; + int ret, i; + + check_Null(ctx, status, cf, e); + + ret = decode_CRLDistributionPoints(e->extnValue.data, + e->extnValue.length, + &dp, &size); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Decoding CRL Distribution Points failed: %d\n", ret); + return 1; + } + + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "CRL Distribution Points:\n"); + for (i = 0 ; i < dp.len; i++) { + if (dp.val[i].distributionPoint) { + DistributionPointName dpname; + heim_any *data = dp.val[i].distributionPoint; + int j; + + ret = decode_DistributionPointName(data->data, data->length, + &dpname, NULL); + if (ret) { + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Failed to parse CRL Distribution Point Name: %d\n", ret); + continue; + } + + switch (dpname.element) { + case choice_DistributionPointName_fullName: + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Fullname:\n"); + + for (j = 0 ; j < dpname.u.fullName.len; j++) { + char *s; + GeneralName *name = &dpname.u.fullName.val[j]; + + ret = hx509_general_name_unparse(name, &s); + if (ret == 0 && s != NULL) { + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " %s\n", s); + free(s); + } + } + break; + case choice_DistributionPointName_nameRelativeToCRLIssuer: + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "Unknown nameRelativeToCRLIssuer"); + break; + default: + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Unknown DistributionPointName"); + break; + } + free_DistributionPointName(&dpname); + } + } + free_CRLDistributionPoints(&dp); + + status->haveCRLDP = 1; + + return 0; +} + + struct { const char *name; const heim_oid *(*oid)(void); int (*func)(hx509_validate_ctx, heim_any *); } check_altname[] = { { "pk-init", oid_id_pkinit_san, check_pkinit_san }, - { "dns-srv", oid_id_pkix_on_dnsSRV, check_dnssrv_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 } }; static int check_altName(hx509_validate_ctx ctx, + struct cert_status *status, const char *name, enum critical_flag cf, const Extension *e) @@ -257,20 +454,24 @@ check_altName(hx509_validate_ctx ctx, size_t size; int ret, i; - check_Null(ctx, cf, e); + check_Null(ctx, status, cf, e); if (e->extnValue.length == 0) { - printf("%sAltName empty, not allowed", name); + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "%sAltName empty, not allowed", name); return 1; } ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length, &gn, &size); if (ret) { - printf("\tret = %d while decoding %s GeneralNames\n", ret, name); + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "\tret = %d while decoding %s GeneralNames\n", + ret, name); return 1; } if (gn.len == 0) { - printf("%sAltName generalName empty, not allowed", name); + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "%sAltName generalName empty, not allowed\n", name); return 1; } @@ -278,7 +479,9 @@ check_altName(hx509_validate_ctx ctx, switch (gn.val[i].element) { case choice_GeneralName_otherName: { unsigned j; - validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%sAltName otherName ", name); + + 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)(), @@ -298,41 +501,18 @@ check_altName(hx509_validate_ctx ctx, validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n"); break; } - case choice_GeneralName_rfc822Name: - validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "rfc822Name: %s\n", - gn.val[i].u.rfc822Name); - break; - case choice_GeneralName_dNSName: - validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "dNSName: %s\n", - gn.val[i].u.dNSName); - break; - case choice_GeneralName_directoryName: { - Name dir; + default: { char *s; - dir.element = gn.val[i].u.directoryName.element; - dir.u.rdnSequence = gn.val[i].u.directoryName.u.rdnSequence; - ret = _hx509_unparse_Name(&dir, &s); + ret = hx509_general_name_unparse(&gn.val[i], &s); if (ret) { - printf("unable to parse %sAltName directoryName\n", name); + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "ret = %d unparsing GeneralName\n", ret); return 1; } - validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "directoryName: %s\n", s); + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s\n", s); free(s); break; } - case choice_GeneralName_uniformResourceIdentifier: - validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "uri: %s\n", - gn.val[i].u.uniformResourceIdentifier); - break; - case choice_GeneralName_iPAddress: - validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "ip address\n"); - break; - case choice_GeneralName_registeredID: - validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "registered id: "); - hx509_oid_print(&gn.val[i].u.registeredID, - validate_vprint, ctx); - validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n"); - break; } } @@ -343,23 +523,28 @@ check_altName(hx509_validate_ctx ctx, static int check_subjectAltName(hx509_validate_ctx ctx, + struct cert_status *status, enum critical_flag cf, const Extension *e) { - return check_altName(ctx, "subject", cf, e); + status->haveSAN = 1; + return check_altName(ctx, status, "subject", cf, e); } static int check_issuerAltName(hx509_validate_ctx ctx, + struct cert_status *status, enum critical_flag cf, const Extension *e) { - return check_altName(ctx, "issuer", cf, e); + status->haveIAN = 1; + return check_altName(ctx, status, "issuer", cf, e); } static int check_basicConstraints(hx509_validate_ctx ctx, + struct cert_status *status, enum critical_flag cf, const Extension *e) { @@ -367,7 +552,7 @@ check_basicConstraints(hx509_validate_ctx ctx, size_t size; int ret; - check_Null(ctx, cf, e); + check_Null(ctx, status, cf, e); ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length, &b, &size); @@ -384,6 +569,30 @@ check_basicConstraints(hx509_validate_ctx ctx, validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tpathLenConstraint: %d\n", *b.pathLenConstraint); + if (b.cA) { + if (*b.cA) { + if (!e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Is a CA and not BasicConstraints CRITICAL\n"); + status->isca = 1; + } + else + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "cA is FALSE, not allowed to be\n"); + } + free_BasicConstraints(&b); + + return 0; +} + +static int +check_proxyCertInfo(hx509_validate_ctx ctx, + struct cert_status *status, + enum critical_flag cf, + const Extension *e) +{ + status->isproxy = 1; + return 0; } @@ -391,6 +600,7 @@ struct { const char *name; const heim_oid *(*oid)(void); int (*func)(hx509_validate_ctx ctx, + struct cert_status *status, enum critical_flag cf, const Extension *); enum critical_flag cf; @@ -401,7 +611,7 @@ struct { { ext(keyUsage, Null), S_C }, { ext(subjectAltName, subjectAltName), M_N_C }, { ext(issuerAltName, issuerAltName), S_N_C }, - { ext(basicConstraints, basicConstraints), M_C }, + { ext(basicConstraints, basicConstraints), D_C }, { ext(cRLNumber, Null), M_N_C }, { ext(cRLReason, Null), M_N_C }, { ext(holdInstructionCode, Null), M_N_C }, @@ -410,14 +620,20 @@ struct { { ext(issuingDistributionPoint, Null), M_C }, { ext(certificateIssuer, Null), M_C }, { ext(nameConstraints, Null), M_C }, - { ext(cRLDistributionPoints, Null), S_N_C }, + { ext(cRLDistributionPoints, CRLDistributionPoints), S_N_C }, { ext(certificatePolicies, Null) }, { ext(policyMappings, Null), M_N_C }, - { ext(authorityKeyIdentifier, Null), M_N_C }, + { ext(authorityKeyIdentifier, authorityKeyIdentifier), M_N_C }, { ext(policyConstraints, Null), D_C }, { ext(extKeyUsage, Null), D_C }, { ext(freshestCRL, Null), M_N_C }, { ext(inhibitAnyPolicy, Null), M_C }, + { "proxyCertInfo", oid_id_pe_proxyCertInfo, + check_proxyCertInfo, M_C }, + { "US Fed PKI - PIV Interim", oid_id_uspkicommon_piv_interim, + check_Null, D_C }, + { "Netscape cert comment", oid_id_netscape_cert_comment, + check_Null, D_C }, { NULL } }; @@ -459,31 +675,45 @@ hx509_validate_cert(hx509_context context, { Certificate *c = _hx509_get_cert(cert); TBSCertificate *t = &c->tbsCertificate; - hx509_name name; + hx509_name issuer, subject; char *str; + struct cert_status status; + int ret; + + memset(&status, 0, sizeof(status)); if (_hx509_cert_get_version(c) != 3) validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Not version 3 certificate\n"); - if (t->version && *t->version < 2 && t->extensions) + if ((t->version == NULL || *t->version < 2) && t->extensions) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Not version 3 certificate with extensions\n"); - _hx509_name_from_Name(&t->subject, &name); - hx509_name_to_string(name, &str); - hx509_name_free(&name); + if (_hx509_cert_get_version(c) >= 3 && t->extensions == NULL) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Version 3 certificate without extensions\n"); + + ret = hx509_cert_get_subject(cert, &subject); + if (ret) abort(); + hx509_name_to_string(subject, &str); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "subject name: %s\n", str); free(str); - _hx509_name_from_Name(&t->issuer, &name); - hx509_name_to_string(name, &str); - hx509_name_free(&name); + ret = hx509_cert_get_issuer(cert, &issuer); + if (ret) abort(); + hx509_name_to_string(issuer, &str); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "issuer name: %s\n", str); free(str); + if (hx509_name_cmp(subject, issuer) == 0) { + status.selfsigned = 1; + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "\tis a self-signed certificate\n"); + } + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Validity:\n"); @@ -528,11 +758,68 @@ hx509_validate_cert(hx509_context context, "checking extention: %s\n", check_extension[j].name); (*check_extension[j].func)(ctx, + &status, check_extension[j].cf, &t->extensions->val[i]); } } else validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extentions\n"); + if (status.isca) { + if (!status.haveSKI) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "CA certificate have no SubjectKeyIdentifier\n"); + + } else { + if (!status.haveAKI) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Is not CA and doesn't have " + "AuthorityKeyIdentifier\n"); + } + + + if (!status.haveSKI) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Doesn't have SubjectKeyIdentifier\n"); + + if (status.isproxy && status.isca) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Proxy and CA at the same time!\n"); + + if (status.isproxy) { + if (status.haveSAN) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Proxy and have SAN\n"); + if (status.haveIAN) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Proxy and have IAN\n"); + } + + if (hx509_name_is_null_p(subject) && !status.haveSAN) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "NULL subject DN and doesn't have a SAN\n"); + + if (!status.selfsigned && !status.haveCRLDP) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Not a CA nor PROXY and doesn't have" + "CRL Dist Point\n"); + + if (status.selfsigned) { + ret = _hx509_verify_signature_bitstring(context, + c, + &c->signatureAlgorithm, + &c->tbsCertificate._save, + &c->signatureValue); + if (ret == 0) + validate_print(ctx, HX509_VALIDATE_F_VERBOSE, + "Self-signed certificate was self-signed\n"); + else + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Self-signed certificate NOT really self-signed!\n"); + } + + hx509_name_free(&subject); + hx509_name_free(&issuer); + return 0; } diff --git a/source4/heimdal/lib/hx509/req.c b/source4/heimdal/lib/hx509/req.c index ca7baa514b..34e3a4ea27 100644 --- a/source4/heimdal/lib/hx509/req.c +++ b/source4/heimdal/lib/hx509/req.c @@ -33,7 +33,7 @@ #include "hx_locl.h" #include <pkcs10_asn1.h> -RCSID("$Id: req.c,v 1.7 2007/01/04 20:20:11 lha Exp $"); +RCSID("$Id: req.c 20934 2007-06-06 15:30:02Z lha $"); struct hx509_request_data { hx509_name name; @@ -191,7 +191,7 @@ _hx509_request_to_pkcs10(hx509_context context, ret = _hx509_create_signature(context, signer, - hx509_signature_rsa_with_sha1(), + _hx509_crypto_default_sig_alg, &data, &r.signatureAlgorithm, &os); diff --git a/source4/heimdal/lib/hx509/revoke.c b/source4/heimdal/lib/hx509/revoke.c index 8067b29c10..0d477945c8 100644 --- a/source4/heimdal/lib/hx509/revoke.c +++ b/source4/heimdal/lib/hx509/revoke.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: revoke.c,v 1.32 2006/12/30 17:09:06 lha Exp $"); +RCSID("$Id: revoke.c 20871 2007-06-03 21:22:51Z lha $"); struct revoke_crl { char *path; @@ -281,8 +281,11 @@ load_ocsp(hx509_context context, struct revoke_ocsp *ocsp) ret = parse_ocsp_basic(data, length, &basic); _hx509_unmap_file(data, length); - if (ret) + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to parse OCSP response"); return ret; + } if (basic.certs) { int i; @@ -442,7 +445,8 @@ verify_crl(hx509_context context, &crl->tbsCertList._save, &crl->signatureValue); if (ret) { - hx509_set_error_string(context, HX509_ERROR_APPEND, ret, "CRL signature invalid"); + hx509_set_error_string(context, HX509_ERROR_APPEND, ret, + "CRL signature invalid"); goto out; } @@ -800,7 +804,7 @@ hx509_ocsp_request(hx509_context context, memset(&req, 0, sizeof(req)); if (digest == NULL) - digest = hx509_signature_sha1(); + digest = _hx509_crypto_default_digest_alg; ctx.req = &req.tbsRequest; ctx.certs = pool; @@ -922,7 +926,7 @@ hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len); for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) { - char *status; + const char *status; switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) { case choice_OCSPCertStatus_good: status = "good"; @@ -955,6 +959,12 @@ hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) return ret; } +/* + * Verify that the `cert' is part of the OCSP reply and its not + * expired. Doesn't verify signature the OCSP reply or its done by a + * authorized sender, that is assumed to be already done. + */ + int hx509_ocsp_verify(hx509_context context, time_t now, @@ -967,12 +977,17 @@ hx509_ocsp_verify(hx509_context context, OCSPBasicOCSPResponse basic; int ret, i; + if (now == 0) + now = time(NULL); + *expiration = 0; ret = parse_ocsp_basic(data, length, &basic); - if (ret) + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to parse OCSP response"); return ret; - + } for (i = 0; i < basic.tbsResponseData.responses.len; i++) { @@ -1003,18 +1018,244 @@ hx509_ocsp_verify(hx509_context context, now + context->ocsp_time_diff) continue; - /* don't allow the next updte to be in the past */ + /* don't allow the next update to be in the past */ if (basic.tbsResponseData.responses.val[i].nextUpdate) { if (*basic.tbsResponseData.responses.val[i].nextUpdate < now) continue; + *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate; } else - continue; - - *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate; + *expiration = now; + free_OCSPBasicOCSPResponse(&basic); return 0; } + free_OCSPBasicOCSPResponse(&basic); + { + hx509_name name; + char *subject; + + ret = hx509_cert_get_subject(cert, &name); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + ret = hx509_name_to_string(name, &subject); + hx509_name_free(&name); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP, + "Certificate %s not in OCSP response " + "or not good", + subject); + free(subject); + } +out: + return HX509_CERT_NOT_IN_OCSP; +} + +struct hx509_crl { + hx509_certs revoked; + time_t expire; +}; + +int +hx509_crl_alloc(hx509_context context, hx509_crl *crl) +{ + int ret; + + *crl = calloc(1, sizeof(**crl)); + if (*crl == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked); + if (ret) { + free(*crl); + *crl = NULL; + } + (*crl)->expire = 0; + return ret; +} + +int +hx509_crl_add_revoked_certs(hx509_context context, + hx509_crl crl, + hx509_certs certs) +{ + return hx509_certs_merge(context, crl->revoked, certs); +} + +int +hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta) +{ + crl->expire = time(NULL) + delta; + return 0; +} + + +void +hx509_crl_free(hx509_context context, hx509_crl *crl) +{ + if (*crl == NULL) + return; + hx509_certs_free(&(*crl)->revoked); + memset(*crl, 0, sizeof(**crl)); + free(*crl); + *crl = NULL; +} + +static int +add_revoked(hx509_context context, void *ctx, hx509_cert cert) +{ + TBSCRLCertList *c = ctx; + unsigned int num; + void *ptr; + int ret; + + num = c->revokedCertificates->len; + ptr = realloc(c->revokedCertificates->val, + (num + 1) * sizeof(c->revokedCertificates->val[0])); + if (ptr == NULL) { + hx509_clear_error_string(context); + return ENOMEM; + } + c->revokedCertificates->val = ptr; + + ret = hx509_cert_get_serialnumber(cert, + &c->revokedCertificates->val[num].userCertificate); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + c->revokedCertificates->val[num].revocationDate.element = + choice_Time_generalTime; + c->revokedCertificates->val[num].revocationDate.u.generalTime = + time(NULL) - 3600 * 24; + c->revokedCertificates->val[num].crlEntryExtensions = NULL; + + c->revokedCertificates->len++; + + return 0; +} + + +int +hx509_crl_sign(hx509_context context, + hx509_cert signer, + hx509_crl crl, + heim_octet_string *os) +{ + const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg; + CRLCertificateList c; + size_t size; + int ret; + hx509_private_key signerkey; + + memset(&c, 0, sizeof(c)); + + signerkey = _hx509_cert_private_key(signer); + if (signerkey == NULL) { + ret = HX509_PRIVATE_KEY_MISSING; + hx509_set_error_string(context, 0, ret, + "Private key missing for CRL signing"); + return ret; + } + + c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version)); + if (c.tbsCertList.version == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + return ENOMEM; + } + + *c.tbsCertList.version = 1; + + ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer, + &c.tbsCertList.issuer); + if (ret) { + hx509_clear_error_string(context); + goto out; + } + + c.tbsCertList.thisUpdate.element = choice_Time_generalTime; + c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600; + + c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate)); + if (c.tbsCertList.nextUpdate == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + ret = ENOMEM; + goto out; + } + + { + time_t next = crl->expire; + if (next == 0) + next = time(NULL) + 24 * 3600 * 365; + + c.tbsCertList.nextUpdate->element = choice_Time_generalTime; + c.tbsCertList.nextUpdate->u.generalTime = next; + } + + c.tbsCertList.revokedCertificates = + calloc(1, sizeof(*c.tbsCertList.revokedCertificates)); + if (c.tbsCertList.revokedCertificates == NULL) { + hx509_set_error_string(context, 0, ENOMEM, "out of memory"); + ret = ENOMEM; + goto out; + } + c.tbsCertList.crlExtensions = NULL; + + ret = hx509_certs_iter(context, crl->revoked, add_revoked, &c.tbsCertList); + if (ret) + goto out; + + /* if not revoked certs, remove OPTIONAL entry */ + if (c.tbsCertList.revokedCertificates->len == 0) { + free(c.tbsCertList.revokedCertificates); + c.tbsCertList.revokedCertificates = NULL; + } + + ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length, + &c.tbsCertList, &size, ret); + if (ret) { + hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL"); + goto out; + } + if (size != os->length) + _hx509_abort("internal ASN.1 encoder error"); + + + ret = _hx509_create_signature_bitstring(context, + signerkey, + sigalg, + os, + &c.signatureAlgorithm, + &c.signatureValue); + free(os->data); + + ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length, + &c, &size, ret); + free_CRLCertificateList(&c); + if (ret) { + hx509_set_error_string(context, 0, ret, "failed to encode CRL"); + goto out; + } + if (size != os->length) + _hx509_abort("internal ASN.1 encoder error"); + return 0; + +out: + free_CRLCertificateList(&c); + return ret; } diff --git a/source4/heimdal/lib/hx509/test_name.c b/source4/heimdal/lib/hx509/test_name.c index 9017e54ab1..2c6dd516cb 100644 --- a/source4/heimdal/lib/hx509/test_name.c +++ b/source4/heimdal/lib/hx509/test_name.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: test_name.c,v 1.6 2006/12/30 23:04:54 lha Exp $"); +RCSID("$Id: test_name.c 19882 2007-01-13 01:02:57Z lha $"); static int test_name(hx509_context context, const char *name) @@ -69,6 +69,39 @@ test_name_fail(hx509_context context, const char *name) return 1; } +static int +test_expand(hx509_context context, const char *name, const char *expected) +{ + hx509_env env; + hx509_name n; + char *s; + int ret; + + hx509_env_init(context, &env); + hx509_env_add(context, env, "uid", "lha"); + + ret = hx509_parse_name(context, name, &n); + if (ret) + return 1; + + ret = hx509_name_expand(context, n, env); + hx509_env_free(&env); + if (ret) + return 1; + + ret = hx509_name_to_string(n, &s); + hx509_name_free(&n); + if (ret) + return 1; + + ret = strcmp(s, expected) != 0; + free(s); + if (ret) + return 1; + + return 0; +} + int main(int argc, char **argv) { @@ -86,6 +119,13 @@ main(int argc, char **argv) ret += test_name_fail(context, "CN=foo,=foo"); ret += test_name_fail(context, "CN=foo,really-unknown-type=foo"); + ret += test_expand(context, "UID=${uid},C=SE", "UID=lha,C=SE"); + ret += test_expand(context, "UID=foo${uid},C=SE", "UID=foolha,C=SE"); + ret += test_expand(context, "UID=${uid}bar,C=SE", "UID=lhabar,C=SE"); + ret += test_expand(context, "UID=f${uid}b,C=SE", "UID=flhab,C=SE"); + ret += test_expand(context, "UID=${uid}${uid},C=SE", "UID=lhalha,C=SE"); + ret += test_expand(context, "UID=${uid}{uid},C=SE", "UID=lha{uid},C=SE"); + hx509_context_free(&context); return ret; |