Initial patch for dealing with AD x-realm key rollover

AD issues x-realm TGTs with kvno 0.  On key x-realm trust key change
    we need to be able to try current and previous keys for trust, else
    we will have some failures.
This commit is contained in:
Nicolas Williams
2011-11-11 02:06:48 -06:00
parent b26fc106de
commit c9609cdb37
9 changed files with 105 additions and 47 deletions

View File

@@ -118,7 +118,7 @@ ntlm_service(void *ctx, const heim_idata *req,
if (ret)
goto failed;
ret = hdb_enctype2key(context, &user->entry,
ret = hdb_enctype2key(context, &user->entry, NULL,
ETYPE_ARCFOUR_HMAC_MD5, &key);
if (ret) {
krb5_set_error_message(context, ret, "NTLM missing arcfour key");

View File

@@ -883,7 +883,7 @@ _kdc_do_digest(krb5_context context,
goto failed;
}
ret = hdb_enctype2key(context, &user->entry,
ret = hdb_enctype2key(context, &user->entry, NULL,
ETYPE_ARCFOUR_HMAC_MD5, &key);
if (ret) {
krb5_set_error_message(context, ret,
@@ -1209,7 +1209,7 @@ _kdc_do_digest(krb5_context context,
goto out;
}
ret = hdb_enctype2key(context, &user->entry,
ret = hdb_enctype2key(context, &user->entry, NULL,
ETYPE_ARCFOUR_HMAC_MD5, &key);
if (ret) {
krb5_set_error_message(context, ret, "NTLM missing arcfour key");

View File

@@ -61,7 +61,7 @@ get_fastuser_crypto(kdc_request_t r, krb5_enctype enctype, krb5_crypto *crypto)
ret = _kdc_get_preferred_key(r->context, r->config, fast_user,
"fast-cookie", &enctype, &cookie_key);
else
ret = hdb_enctype2key(r->context, &fast_user->entry,
ret = hdb_enctype2key(r->context, &fast_user->entry, NULL,
enctype, &cookie_key);
if (ret)
goto out;
@@ -438,7 +438,7 @@ _kdc_fast_unwrap_request(kdc_request_t r)
goto out;
}
ret = hdb_enctype2key(r->context, &armor_user->entry,
ret = hdb_enctype2key(r->context, &armor_user->entry, NULL,
ap_req.ticket.enc_part.etype,
&armor_key);
if (ret) {

View File

@@ -173,7 +173,7 @@ _kdc_find_etype(krb5_context context, krb5_boolean use_strongest_session_key,
if (clientbest == (krb5_enctype)ETYPE_NULL)
clientbest = p[i];
/* check target princ support */
ret = hdb_enctype2key(context, &princ->entry, p[i], &key);
ret = hdb_enctype2key(context, &princ->entry, NULL, p[i], &key);
if (ret)
continue;
if (is_preauth && !is_default_salt_p(&def_salt, key))
@@ -206,7 +206,8 @@ _kdc_find_etype(krb5_context context, krb5_boolean use_strongest_session_key,
!_kdc_is_weak_exception(princ->entry.principal, etypes[i]))
continue;
while (hdb_next_enctype2key(context, &princ->entry, etypes[i], &key) == 0) {
while (hdb_next_enctype2key(context, &princ->entry, NULL,
etypes[i], &key) == 0) {
if (key->key.keyvalue.length == 0) {
ret = KRB5KDC_ERR_NULL_KEY;
continue;
@@ -552,7 +553,7 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa)
goto out;
}
ret = hdb_enctype2key(r->context, &r->client->entry,
ret = hdb_enctype2key(r->context, &r->client->entry, NULL,
enc_data.etype, &pa_key);
if(ret){
char *estr;
@@ -608,7 +609,7 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa)
krb5_free_error_message(r->context, msg);
free(str);
if(hdb_next_enctype2key(r->context, &r->client->entry,
if(hdb_next_enctype2key(r->context, &r->client->entry, NULL,
enc_data.etype, &pa_key) == 0)
goto try_next_key;

View File

@@ -139,7 +139,7 @@ _kdc_add_KRB5SignedPath(krb5_context context,
{
Key *key;
ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
ret = hdb_enctype2key(context, &krbtgt->entry, NULL, enctype, &key);
if (ret == 0)
ret = krb5_crypto_init(context, &key->key, 0, &crypto);
if (ret) {
@@ -226,7 +226,8 @@ check_KRB5SignedPath(krb5_context context,
{
Key *key;
ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use correct kvno! */
sp.etype, &key);
if (ret == 0)
ret = krb5_crypto_init(context, &key->key, 0, &crypto);
if (ret) {
@@ -1156,6 +1157,10 @@ tgs_parse_request(krb5_context context,
krb5_flags ap_req_options;
krb5_flags verify_ap_req_flags;
krb5_crypto crypto;
krb5uint32 krbtgt_kvno; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
krb5uint32 krbtgt_kvno_try;
int kvno_search_tries = 4; /* number of kvnos to try when tkt_vno == 0 */
const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
Key *tkey;
krb5_keyblock *subkey = NULL;
unsigned usage;
@@ -1186,20 +1191,52 @@ tgs_parse_request(krb5_context context,
ap_req.ticket.sname,
ap_req.ticket.realm);
ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, ap_req.ticket.enc_part.kvno, NULL, krbtgt);
krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
krbtgt_kvno_try = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT,
&krbtgt_kvno, NULL, krbtgt);
if(ret == HDB_ERR_NOT_FOUND_HERE) {
if (ret == HDB_ERR_NOT_FOUND_HERE) {
/* XXX Factor out this unparsing of the same princ all over */
char *p;
ret = krb5_unparse_name(context, princ, &p);
if (ret != 0)
p = failed;
krb5_free_principal(context, princ);
kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p);
kdc_log(context, config, 5,
"Ticket-granting ticket account %s does not have secrets at "
"this KDC, need to proxy", p);
if (ret == 0)
free(p);
ret = HDB_ERR_NOT_FOUND_HERE;
goto out;
} else if(ret){
} else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
char *p;
ret = krb5_unparse_name(context, princ, &p);
if (ret != 0)
p = failed;
krb5_free_principal(context, princ);
kdc_log(context, config, 5,
"Ticket-granting ticket account %s does not have keys for "
"kvno %d at this KDC", p, krbtgt_kvno);
if (ret == 0)
free(p);
ret = HDB_ERR_KVNO_NOT_FOUND;
goto out;
} else if (ret == HDB_ERR_NO_MKEY) {
char *p;
ret = krb5_unparse_name(context, princ, &p);
if (ret != 0)
p = failed;
krb5_free_principal(context, princ);
kdc_log(context, config, 5,
"Missing master key for decrypting keys for ticket-granting "
"ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
if (ret == 0)
free(p);
ret = HDB_ERR_KVNO_NOT_FOUND;
goto out;
} else if (ret) {
const char *msg = krb5_get_error_message(context, ret);
char *p;
ret = krb5_unparse_name(context, princ, &p);
@@ -1215,30 +1252,17 @@ tgs_parse_request(krb5_context context,
goto out;
}
if(ap_req.ticket.enc_part.kvno &&
*ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
char *p;
ret = krb5_unparse_name (context, princ, &p);
krb5_free_principal(context, princ);
if (ret != 0)
p = failed;
kdc_log(context, config, 0,
"Ticket kvno = %d, DB kvno = %d (%s)",
*ap_req.ticket.enc_part.kvno,
(*krbtgt)->entry.kvno,
p);
if (ret == 0)
free (p);
ret = KRB5KRB_AP_ERR_BADKEYVER;
goto out;
}
*krbtgt_etype = ap_req.ticket.enc_part.etype;
ret = hdb_enctype2key(context, &(*krbtgt)->entry,
next_kvno:
krbtgt_keys = hdb_kvno2keys(context, &(*krbtgt)->entry, krbtgt_kvno_try);
ret = hdb_enctype2key(context, &(*krbtgt)->entry, krbtgt_keys,
ap_req.ticket.enc_part.etype, &tkey);
if(ret){
if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
kvno_search_tries--;
krbtgt_kvno_try--;
goto next_kvno;
} else if (ret) {
char *str = NULL, *p = NULL;
krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
@@ -1267,6 +1291,11 @@ tgs_parse_request(krb5_context context,
&ap_req_options,
ticket,
KRB5_KU_TGS_REQ_AUTH);
if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
kvno_search_tries--;
krbtgt_kvno_try--;
goto next_kvno;
}
krb5_free_principal(context, princ);
if(ret) {
@@ -1554,7 +1583,7 @@ tgs_build_reply(krb5_context context,
ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
goto out;
}
ret = hdb_enctype2key(context, &uu->entry,
ret = hdb_enctype2key(context, &uu->entry, NULL,
t->enc_part.etype, &uukey);
if(ret){
_kdc_free_ent(context, uu);
@@ -1734,7 +1763,7 @@ server_lookup:
* Validate authoriation data
*/
ret = hdb_enctype2key(context, &krbtgt->entry,
ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use the right kvno! */
krbtgt_etype, &tkey_check);
if(ret) {
kdc_log(context, config, 0,
@@ -1814,7 +1843,7 @@ server_lookup:
"Failed to find key for krbtgt PAC signature");
goto out;
}
ret = hdb_enctype2key(context, &krbtgt_out->entry,
ret = hdb_enctype2key(context, &krbtgt_out->entry, NULL,
tkey_sign->key.keytype, &tkey_sign);
if(ret) {
kdc_log(context, config, 0,
@@ -2065,6 +2094,8 @@ server_lookup:
t = &b->additional_tickets->val[0];
ret = hdb_enctype2key(context, &client->entry,
hdb_kvno2keys(context, &client->entry,
t->enc_part.kvno ? * t->enc_part.kvno : 0),
t->enc_part.etype, &clientkey);
if(ret){
ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */

View File

@@ -143,7 +143,7 @@ _kdc_get_preferred_key(krb5_context context,
for (i = 0; p[i] != (krb5_enctype)ETYPE_NULL; i++) {
if (krb5_enctype_valid(context, p[i]) != 0)
continue;
ret = hdb_enctype2key(context, &h->entry, p[i], key);
ret = hdb_enctype2key(context, &h->entry, NULL, p[i], key);
if (ret != 0)
continue;
if (enctype != NULL)
@@ -157,8 +157,8 @@ _kdc_get_preferred_key(krb5_context context,
if (krb5_enctype_valid(context, h->entry.keys.val[i].key.keytype)
!= 0)
continue;
ret = hdb_enctype2key(context, &h->entry,
h->entry.keys.val[i].key.keytype, key);
ret = hdb_enctype2key(context, &h->entry, NULL,
h->entry.keys.val[i].key.keytype, key);
if (ret != 0)
continue;
if (enctype != NULL)

View File

@@ -92,19 +92,42 @@ static struct hdb_method dbmetod =
{ HDB_INTERFACE_VERSION, "", hdb_ndbm_create };
#endif
const Keys *
hdb_kvno2keys(krb5_context context,
const hdb_entry *e,
krb5_kvno kvno)
{
HDB_Ext_KeySet *hist_keys;
HDB_extension *extp;
size_t i;
if (kvno == 0)
return &e->keys;
extp = hdb_find_extension(e, choice_HDB_extension_data_hist_keys);
if (extp == NULL)
return 0;
hist_keys = &extp->data.u.hist_keys;
for (i = 0; i < hist_keys->len; i++) {
if (hist_keys->val[i].kvno == kvno)
return &hist_keys->val[i].keys;
}
return NULL;
}
krb5_error_code
hdb_next_enctype2key(krb5_context context,
const hdb_entry *e,
const Keys *keyset,
krb5_enctype enctype,
Key **key)
{
const Keys *keys = keyset ? keyset : &e->keys;
Key *k;
for (k = *key ? (*key) + 1 : e->keys.val;
k < e->keys.val + e->keys.len;
k++)
{
for (k = *key ? (*key) + 1 : keys->val; k < keys->val + keys->len; k++) {
if(k->key.keytype == enctype){
*key = k;
return 0;
@@ -119,11 +142,12 @@ hdb_next_enctype2key(krb5_context context,
krb5_error_code
hdb_enctype2key(krb5_context context,
hdb_entry *e,
const Keys *keyset,
krb5_enctype enctype,
Key **key)
{
*key = NULL;
return hdb_next_enctype2key(context, e, enctype, key);
return hdb_next_enctype2key(context, e, keyset, enctype, key);
}
void

View File

@@ -45,6 +45,7 @@ EXPORTS
hdb_init_db
hdb_interface_version DATA
hdb_key2principal
hdb_kvno2keys
hdb_list_builtin
hdb_lock
hdb_next_enctype2key

View File

@@ -47,6 +47,7 @@ HEIMDAL_HDB_1.0 {
hdb_get_dbinfo;
hdb_init_db;
hdb_key2principal;
hdb_kvno2keys;
hdb_list_builtin;
hdb_lock;
hdb_next_enctype2key;