From 835926c87921a0f4186a9331b6e31b2e6f1c0d90 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sun, 7 May 2006 04:51:30 +0000 Subject: r15481: Update heimdal/ to match current lorikeet-heimdal. This includes many useful upstream changes, many of which should reduce warnings in our compile. It also includes a change to the HDB interface, which removes the need for Samba4/lorikeet-heimdal to deviate from upstream for hdb_fetch(). The new flags replace the old entry type enum. (This required the rework in hdb-ldb.c included in this commit) Andrew Bartlett (This used to be commit ef5604b87744c89e66e4d845f45b23563754ec05) --- source4/heimdal/lib/krb5/pkinit.c | 193 +++++++++++++++++++++++++++++++++----- 1 file changed, 171 insertions(+), 22 deletions(-) (limited to 'source4/heimdal/lib/krb5/pkinit.c') diff --git a/source4/heimdal/lib/krb5/pkinit.c b/source4/heimdal/lib/krb5/pkinit.c index fa4fb4699e..7e91946095 100755 --- a/source4/heimdal/lib/krb5/pkinit.c +++ b/source4/heimdal/lib/krb5/pkinit.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: pkinit.c,v 1.88 2006/04/23 21:30:17 lha Exp $"); +RCSID("$Id: pkinit.c,v 1.98 2006/05/06 13:24:54 lha Exp $"); struct krb5_dh_moduli { char *name; @@ -84,6 +84,7 @@ struct krb5_pk_init_ctx_data { int require_binding; int require_eku; int require_krbtgt_otherName; + int require_hostname_match; }; void KRB5_LIB_FUNCTION @@ -161,6 +162,109 @@ _krb5_pk_create_sign(krb5_context context, return ret; } +static int +cert2epi(hx509_context context, void *ctx, hx509_cert c) +{ + ExternalPrincipalIdentifiers *ids = ctx; + ExternalPrincipalIdentifier id; + hx509_name subject = NULL; + void *p; + int ret; + + memset(&id, 0, sizeof(id)); + + ret = hx509_cert_get_subject(c, &subject); + if (ret) + return ret; + + if (hx509_name_is_null_p(subject) != 0) { + + id.subjectName = calloc(1, sizeof(*id.subjectName)); + if (id.subjectName == NULL) { + hx509_name_free(&subject); + free_ExternalPrincipalIdentifier(&id); + return ENOMEM; + } + + ret = hx509_name_to_der_name(subject, &id.subjectName->data, + &id.subjectName->length); + if (ret) { + hx509_name_free(&subject); + free_ExternalPrincipalIdentifier(&id); + return ret; + } + } + hx509_name_free(&subject); + + + id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber)); + if (id.issuerAndSerialNumber == NULL) { + free_ExternalPrincipalIdentifier(&id); + return ENOMEM; + } + + { + IssuerAndSerialNumber iasn; + hx509_name issuer; + size_t size; + + memset(&iasn, 0, sizeof(iasn)); + + ret = hx509_cert_get_issuer(c, &issuer); + if (ret) { + free_ExternalPrincipalIdentifier(&id); + return ret; + } + + ret = hx509_name_to_Name(issuer, &iasn.issuer); + hx509_name_free(&issuer); + if (ret) { + free_ExternalPrincipalIdentifier(&id); + return ret; + } + + ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber); + if (ret) { + free_IssuerAndSerialNumber(&iasn); + free_ExternalPrincipalIdentifier(&id); + return ret; + } + + ASN1_MALLOC_ENCODE(IssuerAndSerialNumber, + id.issuerAndSerialNumber->data, + id.issuerAndSerialNumber->length, + &iasn, &size, ret); + free_IssuerAndSerialNumber(&iasn); + if (ret) + return ret; + if (id.issuerAndSerialNumber->length != size) + abort(); + } + + id.subjectKeyIdentifier = NULL; + + p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1)); + if (p == NULL) { + free_ExternalPrincipalIdentifier(&id); + return ENOMEM; + } + + ids->val = p; + ids->val[ids->len] = id; + ids->len++; + + return 0; +} + +static krb5_error_code +build_edi(krb5_context context, + hx509_context hx509ctx, + hx509_certs certs, + ExternalPrincipalIdentifiers *ids) +{ + return hx509_certs_iter(hx509ctx, certs, cert2epi, ids); +} + static krb5_error_code build_auth_pack(krb5_context context, unsigned nonce, @@ -446,8 +550,19 @@ pk_mk_padata(krb5_context context, memset(&req, 0, sizeof(req)); req.signedAuthPack = buf; - /* XXX tell the kdc what CAs the client is willing to accept */ - req.trustedCertifiers = NULL; + req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers)); + if (req.trustedCertifiers == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + free_PA_PK_AS_REQ(&req); + goto out; + } + ret = build_edi(context, ctx->id->hx509ctx, + ctx->id->anchors, req.trustedCertifiers); + if (ret) { + krb5_set_error_string(context, "pk-init: failed to build trustedCertifiers"); + free_PA_PK_AS_REQ(&req); + goto out; + } req.kdcPkId = NULL; ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length, @@ -524,6 +639,13 @@ _krb5_pk_mk_padata(krb5_context context, "pkinit_require_krbtgt_otherName", NULL); + ctx->require_hostname_match = + krb5_config_get_bool_default(context, NULL, + FALSE, + "realms", + req_body->realm, + "pkinit_require_hostname_match", + NULL); return pk_mk_padata(context, type, ctx, req_body, nonce, md); } @@ -710,6 +832,8 @@ get_reply_key(krb5_context context, static krb5_error_code pk_verify_host(krb5_context context, + const char *realm, + const krb5_krbhst_info *hi, struct krb5_pk_init_ctx_data *ctx, struct krb5_pk_cert *host) { @@ -719,13 +843,12 @@ pk_verify_host(krb5_context context, ret = hx509_cert_check_eku(ctx->id->hx509ctx, host->cert, oid_id_pkkdcekuoid(), 0); if (ret) { - krb5_clear_error_string(context); + krb5_set_error_string(context, "No PK-INIT KDC EKU in kdc certificate"); return ret; } } if (ctx->require_krbtgt_otherName) { hx509_octet_string_list list; - krb5_error_code ret; int i; ret = hx509_cert_find_subjectAltName_otherName(host->cert, @@ -738,6 +861,7 @@ pk_verify_host(krb5_context context, for (i = 0; i < list.len; i++) { KRB5PrincipalName r; + ret = decode_KRB5PrincipalName(list.val[i].data, list.val[i].length, &r, @@ -747,13 +871,15 @@ pk_verify_host(krb5_context context, break; } -#if 0 - if (r.principalName.name.len != 2) { - krb5_clear_error_string(context); + if (r.principalName.name_string.len != 2 || + strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) != 0 || + strcmp(r.principalName.name_string.val[1], realm) != 0 || + strcmp(r.realm, realm) != 0) + { + krb5_set_error_string(context, "KDC have wrong realm name in " + "the certificate"); ret = EINVAL; } -#endif - /* XXX verify realm */ free_KRB5PrincipalName(&r); if (ret) @@ -761,14 +887,26 @@ pk_verify_host(krb5_context context, } hx509_free_octet_string_list(&list); } + if (ret) + return ret; + + if (hi) { + ret = hx509_verify_hostname(ctx->id->hx509ctx, host->cert, + ctx->require_hostname_match, + hi->hostname, + hi->ai->ai_addr, hi->ai->ai_addrlen); + if (ret) + krb5_set_error_string(context, "Address mismatch in the KDC certificate"); + } return ret; } static krb5_error_code pk_rd_pa_reply_enckey(krb5_context context, int type, - ContentInfo *rep, + const ContentInfo *rep, + const char *realm, krb5_pk_init_ctx ctx, krb5_enctype etype, const krb5_krbhst_info *hi, @@ -846,7 +984,7 @@ pk_rd_pa_reply_enckey(krb5_context context, goto out; /* make sure that it is the kdc's certificate */ - ret = pk_verify_host(context, ctx, host); + ret = pk_verify_host(context, realm, hi, ctx, host); if (ret) { krb5_set_error_string(context, "PKINIT: failed verify host: %d", ret); goto out; @@ -894,7 +1032,8 @@ pk_rd_pa_reply_enckey(krb5_context context, static krb5_error_code pk_rd_pa_reply_dh(krb5_context context, - ContentInfo *rep, + const ContentInfo *rep, + const char *realm, krb5_pk_init_ctx ctx, krb5_enctype etype, const krb5_krbhst_info *hi, @@ -938,7 +1077,7 @@ pk_rd_pa_reply_dh(krb5_context context, goto out; /* make sure that it is the kdc's certificate */ - ret = pk_verify_host(context, ctx, host); + ret = pk_verify_host(context, realm, hi, ctx, host); if (ret) goto out; @@ -1066,6 +1205,7 @@ pk_rd_pa_reply_dh(krb5_context context, krb5_error_code KRB5_LIB_FUNCTION _krb5_pk_rd_pa_reply(krb5_context context, + const char *realm, void *c, krb5_enctype etype, const krb5_krbhst_info *hi, @@ -1106,7 +1246,7 @@ _krb5_pk_rd_pa_reply(krb5_context context, free_PA_PK_AS_REP(&rep); break; } - ret = pk_rd_pa_reply_dh(context, &ci, ctx, etype, hi, + ret = pk_rd_pa_reply_dh(context, &ci, realm, ctx, etype, hi, ctx->clientDHNonce, rep.u.dhInfo.serverDHNonce, nonce, pa, key); @@ -1126,7 +1266,7 @@ _krb5_pk_rd_pa_reply(krb5_context context, "ContentInfo: %d", ret); break; } - ret = pk_rd_pa_reply_enckey(context, COMPAT_IETF, &ci, ctx, + ret = pk_rd_pa_reply_enckey(context, COMPAT_IETF, &ci, realm, ctx, etype, hi, nonce, req_buffer, pa, key); free_ContentInfo(&ci); return ret; @@ -1173,7 +1313,7 @@ _krb5_pk_rd_pa_reply(krb5_context context, ret); return ret; } - ret = pk_rd_pa_reply_enckey(context, COMPAT_WIN2K, &ci, ctx, + ret = pk_rd_pa_reply_enckey(context, COMPAT_WIN2K, &ci, realm, ctx, etype, hi, nonce, req_buffer, pa, key); free_ContentInfo(&ci); break; @@ -1204,8 +1344,8 @@ hx_pass_prompter(void *data, const hx509_prompt *prompter) krb5_data password_data; struct prompter *p = data; - password_data.data = prompter->reply->data; - password_data.length = prompter->reply->length; + password_data.data = prompter->reply.data; + password_data.length = prompter->reply.length; prompt.prompt = "Enter your private key passphrase: "; prompt.hidden = 1; prompt.reply = &password_data; @@ -1216,12 +1356,21 @@ hx_pass_prompter(void *data, const hx509_prompt *prompter) ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt); if (ret) { - memset (prompter->reply->data, 0, prompter->reply->length); + memset (prompter->reply.data, 0, prompter->reply.length); return 0; } - return strlen(prompter->reply->data); + return strlen(prompter->reply.data); +} + + +void KRB5_LIB_FUNCTION +_krb5_pk_allow_proxy_certificate(struct krb5_pk_identity *id, + int boolean) +{ + hx509_verify_set_proxy_certificate(id->verify_ctx, boolean); } + krb5_error_code KRB5_LIB_FUNCTION _krb5_pk_load_id(krb5_context context, struct krb5_pk_identity **ret_id, @@ -1715,7 +1864,7 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, } if (DH_generate_key(opt->opt_private->pk_init_ctx->dh) != 1) { - krb5_set_error_string(context, "malloc: out of memory"); + krb5_set_error_string(context, "pkinit: failed to generate DH key"); _krb5_get_init_creds_opt_free_pkinit(opt); return ENOMEM; } -- cgit