Make one verify context per client, this way we can add our own trust
anchors for each client, so that self registed/special certificate are allowed as trust anchors. git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@24987 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
144
kdc/pkinit.c
144
kdc/pkinit.c
@@ -66,6 +66,7 @@ struct pk_client_params {
|
|||||||
char *dh_group_name;
|
char *dh_group_name;
|
||||||
hx509_peer_info peer;
|
hx509_peer_info peer;
|
||||||
hx509_certs client_anchors;
|
hx509_certs client_anchors;
|
||||||
|
hx509_verify_ctx verify_ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pk_principal_mapping {
|
struct pk_principal_mapping {
|
||||||
@@ -166,34 +167,37 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_kdc_pk_free_client_param(krb5_context context,
|
_kdc_pk_free_client_param(krb5_context context, pk_client_params *cp)
|
||||||
pk_client_params *client_params)
|
|
||||||
{
|
{
|
||||||
if (client_params == NULL)
|
if (cp == NULL)
|
||||||
return;
|
return;
|
||||||
if (client_params->cert)
|
if (cp->cert)
|
||||||
hx509_cert_free(client_params->cert);
|
hx509_cert_free(cp->cert);
|
||||||
if (client_params->keyex == USE_DH) {
|
if (cp->verify_ctx)
|
||||||
if (client_params->u.dh.key)
|
hx509_verify_destroy_ctx(cp->verify_ctx);
|
||||||
DH_free(client_params->u.dh.key);
|
if (cp->keyex == USE_DH) {
|
||||||
if (client_params->u.dh.public_key)
|
if (cp->u.dh.key)
|
||||||
BN_free(client_params->u.dh.public_key);
|
DH_free(cp->u.dh.key);
|
||||||
|
if (cp->u.dh.public_key)
|
||||||
|
BN_free(cp->u.dh.public_key);
|
||||||
}
|
}
|
||||||
if (client_params->keyex == USE_ECDH) {
|
#ifdef HAVE_OPENSSL
|
||||||
if (client_params->u.ecdh.key)
|
if (cp->keyex == USE_ECDH) {
|
||||||
EC_KEY_free(client_params->u.ecdh.key);
|
if (cp->u.ecdh.key)
|
||||||
if (client_params->u.ecdh.public_key)
|
EC_KEY_free(cp->u.ecdh.key);
|
||||||
EC_KEY_free(client_params->u.ecdh.public_key);
|
if (cp->u.ecdh.public_key)
|
||||||
|
EC_KEY_free(cp->u.ecdh.public_key);
|
||||||
}
|
}
|
||||||
krb5_free_keyblock_contents(context, &client_params->reply_key);
|
#endif
|
||||||
if (client_params->dh_group_name)
|
krb5_free_keyblock_contents(context, &cp->reply_key);
|
||||||
free(client_params->dh_group_name);
|
if (cp->dh_group_name)
|
||||||
if (client_params->peer)
|
free(cp->dh_group_name);
|
||||||
hx509_peer_info_free(client_params->peer);
|
if (cp->peer)
|
||||||
if (client_params->client_anchors)
|
hx509_peer_info_free(cp->peer);
|
||||||
hx509_certs_free(&client_params->client_anchors);
|
if (cp->client_anchors)
|
||||||
memset(client_params, 0, sizeof(*client_params));
|
hx509_certs_free(&cp->client_anchors);
|
||||||
free(client_params);
|
memset(cp, 0, sizeof(*cp));
|
||||||
|
free(cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
@@ -246,6 +250,7 @@ generate_dh_keyblock(krb5_context context,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
} else if (client_params->keyex == USE_ECDH) {
|
} else if (client_params->keyex == USE_ECDH) {
|
||||||
|
|
||||||
if (client_params->u.ecdh.public_key == NULL) {
|
if (client_params->u.ecdh.public_key == NULL) {
|
||||||
@@ -280,6 +285,7 @@ generate_dh_keyblock(krb5_context context,
|
|||||||
EC_KEY_get0_public_key(client_params->u.ecdh.public_key),
|
EC_KEY_get0_public_key(client_params->u.ecdh.public_key),
|
||||||
client_params->u.ecdh.key, NULL);
|
client_params->u.ecdh.key, NULL);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
#endif /* HAVE_OPENSSL */
|
||||||
} else {
|
} else {
|
||||||
ret = KRB5KRB_ERR_GENERIC;
|
ret = KRB5KRB_ERR_GENERIC;
|
||||||
krb5_set_error_message(context, ret,
|
krb5_set_error_message(context, ret,
|
||||||
@@ -479,6 +485,7 @@ _kdc_pk_rd_padata(krb5_context context,
|
|||||||
krb5_kdc_configuration *config,
|
krb5_kdc_configuration *config,
|
||||||
const KDC_REQ *req,
|
const KDC_REQ *req,
|
||||||
const PA_DATA *pa,
|
const PA_DATA *pa,
|
||||||
|
hdb_entry_ex *client,
|
||||||
pk_client_params **ret_params)
|
pk_client_params **ret_params)
|
||||||
{
|
{
|
||||||
pk_client_params *client_params;
|
pk_client_params *client_params;
|
||||||
@@ -487,7 +494,9 @@ _kdc_pk_rd_padata(krb5_context context,
|
|||||||
krb5_data eContent = { 0, NULL };
|
krb5_data eContent = { 0, NULL };
|
||||||
krb5_data signed_content = { 0, NULL };
|
krb5_data signed_content = { 0, NULL };
|
||||||
const char *type = "unknown type";
|
const char *type = "unknown type";
|
||||||
|
hx509_certs trust_anchors;
|
||||||
int have_data = 0;
|
int have_data = 0;
|
||||||
|
const HDB_Ext_PKINIT_cert *pc;
|
||||||
|
|
||||||
*ret_params = NULL;
|
*ret_params = NULL;
|
||||||
|
|
||||||
@@ -497,8 +506,6 @@ _kdc_pk_rd_padata(krb5_context context,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
hx509_verify_set_time(kdc_identity->verify_ctx, kdc_time);
|
|
||||||
|
|
||||||
client_params = calloc(1, sizeof(*client_params));
|
client_params = calloc(1, sizeof(*client_params));
|
||||||
if (client_params == NULL) {
|
if (client_params == NULL) {
|
||||||
krb5_clear_error_message(context);
|
krb5_clear_error_message(context);
|
||||||
@@ -506,6 +513,54 @@ _kdc_pk_rd_padata(krb5_context context,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = hx509_certs_init(kdc_identity->hx509ctx,
|
||||||
|
"MEMORY:trust-anchors",
|
||||||
|
0, NULL, &trust_anchors);
|
||||||
|
if (ret) {
|
||||||
|
krb5_set_error_message(context, ret, "failed to create trust anchors");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hx509_certs_merge(kdc_identity->hx509ctx, trust_anchors,
|
||||||
|
kdc_identity->anchors);
|
||||||
|
if (ret) {
|
||||||
|
hx509_certs_free(&trust_anchors);
|
||||||
|
krb5_set_error_message(context, ret, "failed to create verify context");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add any registered certificates for this client as trust anchors */
|
||||||
|
ret = hdb_entry_get_pkinit_cert(&client->entry, &pc);
|
||||||
|
if (ret == 0 && pc != NULL) {
|
||||||
|
hx509_cert cert;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < pc->len; i++) {
|
||||||
|
ret = hx509_cert_init_data(kdc_identity->hx509ctx,
|
||||||
|
pc->val[i].cert.data,
|
||||||
|
pc->val[i].cert.length,
|
||||||
|
&cert);
|
||||||
|
if (ret)
|
||||||
|
continue;
|
||||||
|
hx509_certs_add(kdc_identity->hx509ctx, trust_anchors, cert);
|
||||||
|
hx509_cert_free(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hx509_verify_init_ctx(kdc_identity->hx509ctx, &client_params->verify_ctx);
|
||||||
|
if (ret) {
|
||||||
|
hx509_certs_free(&trust_anchors);
|
||||||
|
krb5_set_error_message(context, ret, "failed to create verify context");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
hx509_verify_set_time(client_params->verify_ctx, kdc_time);
|
||||||
|
hx509_verify_attach_anchors(client_params->verify_ctx, trust_anchors);
|
||||||
|
hx509_certs_free(&trust_anchors);
|
||||||
|
|
||||||
|
if (config->pkinit_allow_proxy_certs)
|
||||||
|
hx509_verify_set_proxy_certificate(kdc_identity->verify_ctx, 1);
|
||||||
|
|
||||||
if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
|
if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
|
||||||
PA_PK_AS_REQ_Win2k r;
|
PA_PK_AS_REQ_Win2k r;
|
||||||
|
|
||||||
@@ -654,7 +709,7 @@ _kdc_pk_rd_padata(krb5_context context,
|
|||||||
flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER;
|
flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER;
|
||||||
|
|
||||||
ret = hx509_cms_verify_signed(kdc_identity->hx509ctx,
|
ret = hx509_cms_verify_signed(kdc_identity->hx509ctx,
|
||||||
kdc_identity->verify_ctx,
|
client_params->verify_ctx,
|
||||||
flags,
|
flags,
|
||||||
signed_content.data,
|
signed_content.data,
|
||||||
signed_content.length,
|
signed_content.length,
|
||||||
@@ -760,10 +815,12 @@ _kdc_pk_rd_padata(krb5_context context,
|
|||||||
client_params->keyex = USE_DH;
|
client_params->keyex = USE_DH;
|
||||||
ret = get_dh_param(context, config,
|
ret = get_dh_param(context, config,
|
||||||
ap.clientPublicValue, client_params);
|
ap.clientPublicValue, client_params);
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
} else if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_ecPublicKey) == 0) {
|
} else if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_ecPublicKey) == 0) {
|
||||||
client_params->keyex = USE_ECDH;
|
client_params->keyex = USE_ECDH;
|
||||||
ret = get_ecdh_param(context, config,
|
ret = get_ecdh_param(context, config,
|
||||||
ap.clientPublicValue, client_params);
|
ap.clientPublicValue, client_params);
|
||||||
|
#endif /* HAVE_OPENSSL */
|
||||||
} else {
|
} else {
|
||||||
ret = KRB5_BADMSGTYPE;
|
ret = KRB5_BADMSGTYPE;
|
||||||
krb5_set_error_message(context, ret, "PKINIT unknown DH mechanism");
|
krb5_set_error_message(context, ret, "PKINIT unknown DH mechanism");
|
||||||
@@ -1052,8 +1109,8 @@ pk_mk_pa_reply_dh(krb5_context context,
|
|||||||
dh_info.subjectPublicKey.length = buf.length * 8;
|
dh_info.subjectPublicKey.length = buf.length * 8;
|
||||||
dh_info.subjectPublicKey.data = buf.data;
|
dh_info.subjectPublicKey.data = buf.data;
|
||||||
krb5_data_zero(&buf);
|
krb5_data_zero(&buf);
|
||||||
} else if (client_params->keyex == USE_ECDH) {
|
|
||||||
#ifdef HAVE_OPENSSL
|
#ifdef HAVE_OPENSSL
|
||||||
|
} else if (client_params->keyex == USE_ECDH) {
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
@@ -1071,8 +1128,6 @@ pk_mk_pa_reply_dh(krb5_context context,
|
|||||||
len = i2o_ECPublicKey(client_params->u.ecdh.key, &p);
|
len = i2o_ECPublicKey(client_params->u.ecdh.key, &p);
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
abort();
|
abort();
|
||||||
#else
|
|
||||||
return ENOMEM;
|
|
||||||
#endif
|
#endif
|
||||||
} else
|
} else
|
||||||
krb5_abortx(context, "no keyex selected ?");
|
krb5_abortx(context, "no keyex selected ?");
|
||||||
@@ -1252,7 +1307,9 @@ _kdc_pk_mk_pa_reply(krb5_context context,
|
|||||||
|
|
||||||
switch (client_params->keyex) {
|
switch (client_params->keyex) {
|
||||||
case USE_DH: type = "dh"; break;
|
case USE_DH: type = "dh"; break;
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
case USE_ECDH: type = "ecdh"; break;
|
case USE_ECDH: type = "ecdh"; break;
|
||||||
|
#endif
|
||||||
default: krb5_abortx(context, "unknown keyex"); break;
|
default: krb5_abortx(context, "unknown keyex"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1598,6 +1655,7 @@ _kdc_pk_check_client(krb5_context context,
|
|||||||
char **subject_name)
|
char **subject_name)
|
||||||
{
|
{
|
||||||
const HDB_Ext_PKINIT_acl *acl;
|
const HDB_Ext_PKINIT_acl *acl;
|
||||||
|
const HDB_Ext_PKINIT_cert *pc;
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
hx509_name name;
|
hx509_name name;
|
||||||
int i;
|
int i;
|
||||||
@@ -1625,6 +1683,29 @@ _kdc_pk_check_client(krb5_context context,
|
|||||||
"Trying to authorize PK-INIT subject DN %s",
|
"Trying to authorize PK-INIT subject DN %s",
|
||||||
*subject_name);
|
*subject_name);
|
||||||
|
|
||||||
|
ret = hdb_entry_get_pkinit_cert(&client->entry, &pc);
|
||||||
|
if (ret == 0 && pc) {
|
||||||
|
hx509_cert cert;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < pc->len; i++) {
|
||||||
|
ret = hx509_cert_init_data(kdc_identity->hx509ctx,
|
||||||
|
pc->val[i].cert.data,
|
||||||
|
pc->val[i].cert.length,
|
||||||
|
&cert);
|
||||||
|
if (ret)
|
||||||
|
continue;
|
||||||
|
ret = hx509_cert_cmp(cert, client_params->cert);
|
||||||
|
hx509_cert_free(cert);
|
||||||
|
if (ret == 0) {
|
||||||
|
kdc_log(context, config, 5,
|
||||||
|
"Found matching PK-INIT cert in hdb");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (config->pkinit_princ_in_cert) {
|
if (config->pkinit_princ_in_cert) {
|
||||||
ret = match_rfc_san(context, config,
|
ret = match_rfc_san(context, config,
|
||||||
kdc_identity->hx509ctx,
|
kdc_identity->hx509ctx,
|
||||||
@@ -1891,7 +1972,8 @@ _kdc_pk_initialize(krb5_context context,
|
|||||||
"kdc",
|
"kdc",
|
||||||
"pkinit_allow_proxy_certificate",
|
"pkinit_allow_proxy_certificate",
|
||||||
NULL);
|
NULL);
|
||||||
_krb5_pk_allow_proxy_certificate(kdc_identity, ret);
|
if (ret != 0)
|
||||||
|
config->pkinit_allow_proxy_certs = 1;
|
||||||
|
|
||||||
file = krb5_config_get_string(context,
|
file = krb5_config_get_string(context,
|
||||||
NULL,
|
NULL,
|
||||||
|
Reference in New Issue
Block a user