summaryrefslogtreecommitdiff
path: root/source4/heimdal/lib/krb5/pkinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/heimdal/lib/krb5/pkinit.c')
-rwxr-xr-xsource4/heimdal/lib/krb5/pkinit.c193
1 files changed, 171 insertions, 22 deletions
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;
}