Redo client key handling for AS

Pick the replykey to be the same as the preauth key, this allows
us to delay the picking of client key to when its needed, this
means that we can have a reply keys for PKINIT that is independant
of what keys the client have.
This commit is contained in:
Love Hornquist Astrand
2009-09-23 00:14:57 -07:00
committed by Love Hornquist Astrand
parent 9a5b9ed720
commit 6df0783c7e
2 changed files with 68 additions and 91 deletions

View File

@@ -59,17 +59,6 @@ realloc_method_data(METHOD_DATA *md)
return 0; return 0;
} }
static void
set_salt_padata (METHOD_DATA *md, Salt *salt)
{
if (salt) {
realloc_method_data(md);
md->val[md->len - 1].padata_type = salt->type;
der_copy_octet_string(&salt->salt,
&md->val[md->len - 1].padata_value);
}
}
const PA_DATA* const PA_DATA*
_kdc_find_padata(const KDC_REQ *req, int *start, int type) _kdc_find_padata(const KDC_REQ *req, int *start, int type)
{ {
@@ -127,7 +116,7 @@ is_default_salt_p(const krb5_salt *default_salt, const Key *key)
krb5_error_code krb5_error_code
_kdc_find_etype(krb5_context context, const hdb_entry_ex *princ, _kdc_find_etype(krb5_context context, const hdb_entry_ex *princ,
krb5_enctype *etypes, unsigned len, krb5_enctype *etypes, unsigned len,
Key **ret_key, krb5_enctype *ret_etype) Key **ret_key)
{ {
int i; int i;
krb5_error_code ret = KRB5KDC_ERR_ETYPE_NOSUPP; krb5_error_code ret = KRB5KDC_ERR_ETYPE_NOSUPP;
@@ -148,7 +137,6 @@ _kdc_find_etype(krb5_context context, const hdb_entry_ex *princ,
continue; continue;
} }
*ret_key = key; *ret_key = key;
*ret_etype = etypes[i];
ret = 0; ret = 0;
if (is_default_salt_p(&def_salt, key)) { if (is_default_salt_p(&def_salt, key)) {
krb5_free_salt (context, def_salt); krb5_free_salt (context, def_salt);
@@ -912,13 +900,14 @@ _kdc_as_rep(krb5_context context,
const char *e_text = NULL; const char *e_text = NULL;
krb5_crypto crypto; krb5_crypto crypto;
Key *ckey, *skey; Key *ckey, *skey;
EncryptionKey *reply_key; EncryptionKey *reply_key, session_key;
int flags = 0; int flags = 0;
#ifdef PKINIT #ifdef PKINIT
pk_client_params *pkp = NULL; pk_client_params *pkp = NULL;
#endif #endif
memset(&rep, 0, sizeof(rep)); memset(&rep, 0, sizeof(rep));
memset(&session_key, 0, sizeof(session_key));
krb5_data_zero(&e_data); krb5_data_zero(&e_data);
if (f.canonicalize) if (f.canonicalize)
@@ -1009,19 +998,59 @@ _kdc_as_rep(krb5_context context,
memset(&ek, 0, sizeof(ek)); memset(&ek, 0, sizeof(ek));
/* /*
* Find the client key for reply encryption and pa-type salt, Pick * Select a session enctype from the list of the crypto systems
* the client key upfront before the other keys because that is * supported enctype, is supported by the client and is one of the
* going to affect what enctypes we are going to use in * enctype of the enctype of the krbtgt.
* ETYPE-INFO{,2}. *
* The later is used as a hint what enctype all KDC are supporting
* to make sure a newer version of KDC wont generate a session
* enctype that and older version of a KDC in the same realm can't
* decrypt.
*
* But if the KDC admin is paranoid and doesn't want to have "no
* the best" enctypes on the krbtgt, lets save the best pick from
* the client list and hope that that will work for any other
* KDCs.
*/ */
{
const krb5_enctype *p;
krb5_enctype clientbest = ETYPE_NULL;
int i, j;
ret = _kdc_find_etype(context, client, b->etype.val, b->etype.len, p = krb5_kerberos_enctypes(context);
&ckey, &cetype);
if (ret) { sessionetype = ETYPE_NULL;
for (i = 0; p[i] != ETYPE_NULL && sessionetype == ETYPE_NULL; i++) {
if (krb5_enctype_valid(context, p[i]) != 0)
continue;
for (j = 0; j < b->etype.len && sessionetype == ETYPE_NULL; j++) {
Key *dummy;
/* check with client */
if (p[i] != b->etype.val[j])
continue;
/* save best of union of { client, crypto system } */
if (clientbest == ETYPE_NULL)
clientbest = p[i];
/* check with krbtgt */
ret = hdb_enctype2key(context, &server->entry, p[i], &dummy);
if (ret)
continue;
sessionetype = p[i];
}
}
/* if krbtgt had no shared keys with client, pick clients best */
if (clientbest != ETYPE_NULL && sessionetype == ETYPE_NULL) {
sessionetype = clientbest;
} else if (sessionetype == ETYPE_NULL) {
kdc_log(context, config, 0, kdc_log(context, config, 0,
"Client (%s) has no support for etypes", client_name); "Client (%s) from %s has no common enctypes with KDC"
"to use for the session key",
client_name, from);
goto out; goto out;
} }
}
/* /*
* Pre-auth processing * Pre-auth processing
@@ -1230,6 +1259,8 @@ _kdc_as_rep(krb5_context context,
} }
et.flags.pre_authent = 1; et.flags.pre_authent = 1;
reply_key = &pa_key->key;
ret = krb5_enctype_to_string(context, pa_key->key.keytype, &str); ret = krb5_enctype_to_string(context, pa_key->key.keytype, &str);
if (ret) if (ret)
str = NULL; str = NULL;
@@ -1300,7 +1331,9 @@ _kdc_as_rep(krb5_context context,
/* /*
* If there is a client key, send ETYPE_INFO{,2} * If there is a client key, send ETYPE_INFO{,2}
*/ */
if (ckey) { ret = _kdc_find_etype(context, client, b->etype.val, b->etype.len,
&ckey);
if (ret == 0) {
/* /*
* RFC4120 requires: * RFC4120 requires:
@@ -1371,63 +1404,6 @@ _kdc_as_rep(krb5_context context,
if(ret) if(ret)
goto out; goto out;
/*
* Select a session enctype from the list of the crypto systems
* supported enctype, is supported by the client and is one of the
* enctype of the enctype of the krbtgt.
*
* The later is used as a hint what enctype all KDC are supporting
* to make sure a newer version of KDC wont generate a session
* enctype that and older version of a KDC in the same realm can't
* decrypt.
*
* But if the KDC admin is paranoid and doesn't want to have "no
* the best" enctypes on the krbtgt, lets save the best pick from
* the client list and hope that that will work for any other
* KDCs.
*/
{
const krb5_enctype *p;
krb5_enctype clientbest = ETYPE_NULL;
int i, j;
p = krb5_kerberos_enctypes(context);
sessionetype = ETYPE_NULL;
for (i = 0; p[i] != ETYPE_NULL && sessionetype == ETYPE_NULL; i++) {
if (krb5_enctype_valid(context, p[i]) != 0)
continue;
for (j = 0; j < b->etype.len && sessionetype == ETYPE_NULL; j++) {
Key *dummy;
/* check with client */
if (p[i] != b->etype.val[j])
continue;
/* save best of union of { client, crypto system } */
if (clientbest == ETYPE_NULL)
clientbest = p[i];
/* check with krbtgt */
ret = hdb_enctype2key(context, &server->entry, p[i], &dummy);
if (ret)
continue;
sessionetype = p[i];
}
}
/* if krbtgt had no shared keys with client, pick clients best */
if (clientbest != ETYPE_NULL && sessionetype == ETYPE_NULL) {
sessionetype = clientbest;
} else if (sessionetype == ETYPE_NULL) {
kdc_log(context, config, 0,
"Client (%s) from %s has no common enctypes with KDC"
"to use for the session key",
client_name, from);
goto out;
}
}
log_as_req(context, config, cetype, setype, b);
if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
|| (f.request_anonymous && !config->allow_anonymous)) { || (f.request_anonymous && !config->allow_anonymous)) {
ret = KRB5KDC_ERR_BADOPTION; ret = KRB5KDC_ERR_BADOPTION;
@@ -1642,12 +1618,13 @@ _kdc_as_rep(krb5_context context,
goto out; goto out;
} else } else
#endif #endif
if (ckey) { {
reply_key = &ckey->key;
ret = krb5_generate_random_keyblock(context, sessionetype, &et.key); ret = krb5_generate_random_keyblock(context, sessionetype, &et.key);
if (ret) if (ret)
goto out; goto out;
} else { }
if (reply_key == NULL) {
e_text = "Client have no reply key"; e_text = "Client have no reply key";
ret = KRB5KDC_ERR_CLIENT_NOTYET; ret = KRB5KDC_ERR_CLIENT_NOTYET;
goto out; goto out;
@@ -1657,9 +1634,6 @@ _kdc_as_rep(krb5_context context,
if (ret) if (ret)
goto out; goto out;
if (ckey)
set_salt_padata (rep.padata, ckey->salt);
/* Add signing of alias referral */ /* Add signing of alias referral */
if (f.canonicalize) { if (f.canonicalize) {
PA_ClientCanonicalized canon; PA_ClientCanonicalized canon;
@@ -1765,6 +1739,8 @@ _kdc_as_rep(krb5_context context,
if (ret) if (ret)
goto out; goto out;
log_as_req(context, config, reply_key->keytype, setype, b);
ret = _kdc_encode_reply(context, config, ret = _kdc_encode_reply(context, config,
&rep, &et, &ek, setype, server->entry.kvno, &rep, &et, &ek, setype, server->entry.kvno,
&skey->key, client->entry.kvno, &skey->key, client->entry.kvno,

View File

@@ -1633,14 +1633,15 @@ server_lookup:
} else { } else {
Key *skey; Key *skey;
ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len, ret = _kdc_find_etype(context, server,
&skey, &etype); b->etype.val, b->etype.len, &skey);
if(ret) { if(ret) {
kdc_log(context, config, 0, kdc_log(context, config, 0,
"Server (%s) has no support for etypes", spn); "Server (%s) has no support for etypes", spn);
goto out; goto out;
} }
ekey = &skey->key; ekey = &skey->key;
etype = skey->key.keytype;
kvno = server->entry.kvno; kvno = server->entry.kvno;
} }