diff options
Diffstat (limited to 'src/kdc')
| -rw-r--r-- | src/kdc/do_as_req.c | 44 | ||||
| -rw-r--r-- | src/kdc/do_tgs_req.c | 24 | ||||
| -rw-r--r-- | src/kdc/extern.c | 1 | ||||
| -rw-r--r-- | src/kdc/extern.h | 6 | ||||
| -rw-r--r-- | src/kdc/kdc_preauth.c | 88 | ||||
| -rw-r--r-- | src/kdc/kdc_util.c | 22 | ||||
| -rw-r--r-- | src/kdc/main.c | 23 |
7 files changed, 194 insertions, 14 deletions
diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c index 9571fb212..8db39ac4f 100644 --- a/src/kdc/do_as_req.c +++ b/src/kdc/do_as_req.c @@ -104,6 +104,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, const char *status; krb5_key_data *server_key, *client_key; krb5_keyblock server_keyblock, client_keyblock; + krb5_keyblock *mkey_ptr; krb5_enctype useenctype; krb5_boolean update_client = 0; krb5_data e_data; @@ -115,6 +116,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, void *pa_context = NULL; int did_log = 0; const char *emsg = 0; + krb5_keylist_node *tmp_mkey_list; #if APPLE_PKINIT asReqDebug("process_as_req top realm %s name %s\n", @@ -425,9 +427,28 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, goto errout; } + if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist, &server, + &mkey_ptr))) { + /* try refreshing master key list */ + /* XXX it would nice if we had the mkvno here for optimization */ + if (krb5_db_fetch_mkey_list(kdc_context, master_princ, + &master_keyblock, 0, &tmp_mkey_list) == 0) { + krb5_dbe_free_key_list(kdc_context, master_keylist); + master_keylist = tmp_mkey_list; + if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist, + &server, &mkey_ptr))) { + status = "FINDING_MASTER_KEY"; + goto errout; + } + } else { + status = "FINDING_MASTER_KEY"; + goto errout; + } + } + /* convert server.key into a real key (it may be encrypted in the database) */ - if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, &master_keyblock, + if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, mkey_ptr, /* server_keyblock is later used to generate auth data signatures */ server_key, &server_keyblock, NULL))) { @@ -456,8 +477,27 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, goto errout; } + if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist, &client, + &mkey_ptr))) { + /* try refreshing master key list */ + /* XXX it would nice if we had the mkvno here for optimization */ + if (krb5_db_fetch_mkey_list(kdc_context, master_princ, + &master_keyblock, 0, &tmp_mkey_list) == 0) { + krb5_dbe_free_key_list(kdc_context, master_keylist); + master_keylist = tmp_mkey_list; + if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist, + &client, &mkey_ptr))) { + status = "FINDING_MASTER_KEY"; + goto errout; + } + } else { + status = "FINDING_MASTER_KEY"; + goto errout; + } + } + /* convert client.key_data into a real key */ - if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, &master_keyblock, + if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, mkey_ptr, client_key, &client_keyblock, NULL))) { status = "DECRYPT_CLIENT_KEY"; diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c index 084300256..a6ce704bd 100644 --- a/src/kdc/do_tgs_req.c +++ b/src/kdc/do_tgs_req.c @@ -105,6 +105,7 @@ process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from, krb5_keyblock session_key; krb5_timestamp until, rtime; krb5_keyblock encrypting_key; + krb5_keyblock *mkey_ptr; krb5_key_data *server_key; char *cname = 0, *sname = 0, *altcname = 0; krb5_last_req_entry *nolrarray[2], nolrentry; @@ -572,10 +573,31 @@ tgt_again: status = "FINDING_SERVER_KEY"; goto cleanup; } + + if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist, &server, + &mkey_ptr))) { + krb5_keylist_node *tmp_mkey_list; + /* try refreshing master key list */ + /* XXX it would nice if we had the mkvno here for optimization */ + if (krb5_db_fetch_mkey_list(kdc_context, master_princ, + &master_keyblock, 0, &tmp_mkey_list) == 0) { + krb5_dbe_free_key_list(kdc_context, master_keylist); + master_keylist = tmp_mkey_list; + if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist, + &server, &mkey_ptr))) { + status = "FINDING_MASTER_KEY"; + goto cleanup; + } + } else { + status = "FINDING_MASTER_KEY"; + goto cleanup; + } + } + /* convert server.key into a real key (it may be encrypted * in the database) */ if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, - &master_keyblock, + mkey_ptr, server_key, &encrypting_key, NULL))) { status = "DECRYPT_SERVER_KEY"; diff --git a/src/kdc/extern.c b/src/kdc/extern.c index 2a2c1ae22..7ebc7bb3a 100644 --- a/src/kdc/extern.c +++ b/src/kdc/extern.c @@ -27,6 +27,7 @@ */ #include "k5-int.h" +#include "kdb.h" #include "extern.h" /* real declarations of KDC's externs */ diff --git a/src/kdc/extern.h b/src/kdc/extern.h index 20cc4bc04..88e8b0dde 100644 --- a/src/kdc/extern.h +++ b/src/kdc/extern.h @@ -53,7 +53,12 @@ typedef struct __kdc_realm_data { char * realm_stash; /* Stash file name for realm */ char * realm_mpname; /* Master principal name for realm */ krb5_principal realm_mprinc; /* Master principal for realm */ + /* + * Note realm_mkey is mkey read from stash or keyboard and may not be the + * latest. The mkey_list will have all the mkeys in use. + */ krb5_keyblock realm_mkey; /* Master key for this realm */ + krb5_keylist_node * mkey_list; /* list of mkeys in use for this realm */ /* * TGS per-realm data. */ @@ -86,6 +91,7 @@ kdc_realm_t *find_realm_data (char *, krb5_ui_4); #define max_life_for_realm kdc_active_realm->realm_maxlife #define max_renewable_life_for_realm kdc_active_realm->realm_maxrlife #define master_keyblock kdc_active_realm->realm_mkey +#define master_keylist kdc_active_realm->mkey_list #define master_princ kdc_active_realm->realm_mprinc #define tgs_server kdc_active_realm->realm_tgsprinc #define reject_bad_transit kdc_active_realm->realm_reject_bad_transit diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index 6ec156440..7aacca402 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -665,8 +665,9 @@ get_entry_data(krb5_context context, int i, k; krb5_data *ret; krb5_deltat *delta; - krb5_keyblock *keys; + krb5_keyblock *keys, *mkey_ptr; krb5_key_data *entry_key; + krb5_error_code error; switch (type) { case krb5plugin_preauth_entry_request_certificate: @@ -700,13 +701,32 @@ get_entry_data(krb5_context context, ret->data = (char *) keys; ret->length = sizeof(krb5_keyblock) * (request->nktypes + 1); memset(ret->data, 0, ret->length); + if ((error = krb5_dbe_find_mkey(context, master_keylist, entry, + &mkey_ptr))) { + krb5_keylist_node *tmp_mkey_list; + /* try refreshing the mkey list in case it's been updated */ + if (krb5_db_fetch_mkey_list(context, master_princ, + &master_keyblock, 0, + &tmp_mkey_list) == 0) { + krb5_dbe_free_key_list(context, master_keylist); + master_keylist = tmp_mkey_list; + if ((error = krb5_dbe_find_mkey(context, master_keylist, entry, + &mkey_ptr))) { + free(ret); + return (error); + } + } else { + free(ret); + return (error); + } + } k = 0; for (i = 0; i < request->nktypes; i++) { entry_key = NULL; if (krb5_dbe_find_enctype(context, entry, request->ktype[i], -1, 0, &entry_key) != 0) continue; - if (krb5_dbekd_decrypt_key_data(context, &master_keyblock, + if (krb5_dbekd_decrypt_key_data(context, mkey_ptr, entry_key, &keys[k], NULL) != 0) { if (keys[k].contents != NULL) krb5_free_keyblock_contents(context, &keys[k]); @@ -1337,7 +1357,7 @@ verify_enc_timestamp(krb5_context context, krb5_db_entry *client, krb5_data scratch; krb5_data enc_ts_data; krb5_enc_data *enc_data = 0; - krb5_keyblock key; + krb5_keyblock key, *mkey_ptr; krb5_key_data * client_key; krb5_int32 start; krb5_timestamp timenow; @@ -1355,6 +1375,24 @@ verify_enc_timestamp(krb5_context context, krb5_db_entry *client, if ((enc_ts_data.data = (char *) malloc(enc_ts_data.length)) == NULL) goto cleanup; + if ((retval = krb5_dbe_find_mkey(context, master_keylist, client, + &mkey_ptr))) { + krb5_keylist_node *tmp_mkey_list; + /* try refreshing the mkey list in case it's been updated */ + if (krb5_db_fetch_mkey_list(context, master_princ, + &master_keyblock, 0, + &tmp_mkey_list) == 0) { + krb5_dbe_free_key_list(context, master_keylist); + master_keylist = tmp_mkey_list; + if ((retval = krb5_dbe_find_mkey(context, master_keylist, client, + &mkey_ptr))) { + goto cleanup; + } + } else { + goto cleanup; + } + } + start = 0; decrypt_err = 0; while (1) { @@ -1363,7 +1401,7 @@ verify_enc_timestamp(krb5_context context, krb5_db_entry *client, -1, 0, &client_key))) goto cleanup; - if ((retval = krb5_dbekd_decrypt_key_data(context, &master_keyblock, + if ((retval = krb5_dbekd_decrypt_key_data(context, mkey_ptr, client_key, &key, NULL))) goto cleanup; @@ -1946,7 +1984,7 @@ get_sam_edata(krb5_context context, krb5_kdc_req *request, krb5_sam_challenge sc; krb5_predicted_sam_response psr; krb5_data * scratch; - krb5_keyblock encrypting_key; + krb5_keyblock encrypting_key, *mkey_ptr; char response[9]; char inputblock[8]; krb5_data predict_response; @@ -2010,6 +2048,24 @@ get_sam_edata(krb5_context context, krb5_kdc_req *request, if (sc.sam_type) { /* so use assoc to get the key out! */ { + if ((retval = krb5_dbe_find_mkey(context, master_keylist, &assoc, + &mkey_ptr))) { + krb5_keylist_node *tmp_mkey_list; + /* try refreshing the mkey list in case it's been updated */ + if (krb5_db_fetch_mkey_list(context, master_princ, + &master_keyblock, 0, + &tmp_mkey_list) == 0) { + krb5_dbe_free_key_list(context, master_keylist); + master_keylist = tmp_mkey_list; + if ((retval = krb5_dbe_find_mkey(context, master_keylist, &assoc, + &mkey_ptr))) { + return (retval); + } + } else { + return (retval); + } + } + /* here's what do_tgs_req does */ retval = krb5_dbe_find_enctype(kdc_context, &assoc, ENCTYPE_DES_CBC_RAW, @@ -2026,7 +2082,7 @@ get_sam_edata(krb5_context context, krb5_kdc_req *request, } /* convert server.key into a real key */ retval = krb5_dbekd_decrypt_key_data(kdc_context, - &master_keyblock, + mkey_ptr, assoc_key, &encrypting_key, NULL); if (retval) { @@ -2513,7 +2569,7 @@ static krb5_error_code verify_pkinit_request( unsigned cert_hash_len; unsigned key_dex; unsigned cert_match = 0; - krb5_keyblock decrypted_key; + krb5_keyblock decrypted_key, *mkey_ptr; /* the data we get from the AS-REQ */ krb5_timestamp client_ctime = 0; @@ -2657,6 +2713,22 @@ static krb5_error_code verify_pkinit_request( goto cleanup; } cert_hash_len = strlen(cert_hash); + if ((krtn = krb5_dbe_find_mkey(context, master_keylist, &entry, &mkey_ptr))) { + krb5_keylist_node *tmp_mkey_list; + /* try refreshing the mkey list in case it's been updated */ + if (krb5_db_fetch_mkey_list(context, master_princ, + &master_keyblock, 0, + &tmp_mkey_list) == 0) { + krb5_dbe_free_key_list(context, master_keylist); + master_keylist = tmp_mkey_list; + if ((krtn = krb5_dbe_find_mkey(context, master_keylist, &entry, + &mkey_ptr))) { + goto cleanup; + } + } else { + goto cleanup; + } + } for(key_dex=0; key_dex<client->n_key_data; key_dex++) { krb5_key_data *key_data = &client->key_data[key_dex]; kdcPkinitDebug("--- key %u type[0] %u length[0] %u type[1] %u length[1] %u\n", @@ -2671,7 +2743,7 @@ static krb5_error_code verify_pkinit_request( * Unfortunately this key is stored encrypted even though it's * not sensitive... */ - krtn = krb5_dbekd_decrypt_key_data(context, &master_keyblock, + krtn = krb5_dbekd_decrypt_key_data(context, mkey_ptr, key_data, &decrypted_key, NULL); if(krtn) { kdcPkinitDebug("verify_pkinit_request: error decrypting cert hash block\n"); diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c index 34a8ed0c3..28b4a37ca 100644 --- a/src/kdc/kdc_util.c +++ b/src/kdc/kdc_util.c @@ -415,6 +415,7 @@ kdc_get_server_key(krb5_ticket *ticket, unsigned int flags, krb5_error_code retval; krb5_boolean more, similar; krb5_key_data * server_key; + krb5_keyblock * mkey_ptr; *nprincs = 1; @@ -445,6 +446,25 @@ kdc_get_server_key(krb5_ticket *ticket, unsigned int flags, retval = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; goto errout; } + + if ((retval = krb5_dbe_find_mkey(kdc_context, master_keylist, server, + &mkey_ptr))) { + krb5_keylist_node *tmp_mkey_list; + /* try refreshing master key list */ + /* XXX it would nice if we had the mkvno here for optimization */ + if (krb5_db_fetch_mkey_list(kdc_context, master_princ, + &master_keyblock, 0, &tmp_mkey_list) == 0) { + krb5_dbe_free_key_list(kdc_context, master_keylist); + master_keylist = tmp_mkey_list; + if ((retval = krb5_dbe_find_mkey(kdc_context, master_keylist, + server, &mkey_ptr))) { + goto errout; + } + } else { + goto errout; + } + } + retval = krb5_dbe_find_enctype(kdc_context, server, match_enctype ? ticket->enc_part.enctype : -1, -1, (krb5_int32)ticket->enc_part.kvno, @@ -456,7 +476,7 @@ kdc_get_server_key(krb5_ticket *ticket, unsigned int flags, goto errout; } if ((*key = (krb5_keyblock *)malloc(sizeof **key))) { - retval = krb5_dbekd_decrypt_key_data(kdc_context, &master_keyblock, + retval = krb5_dbekd_decrypt_key_data(kdc_context, mkey_ptr, server_key, *key, NULL); } else diff --git a/src/kdc/main.c b/src/kdc/main.c index b9334680b..bb4d7584d 100644 --- a/src/kdc/main.c +++ b/src/kdc/main.c @@ -154,9 +154,12 @@ finish_realm(kdc_realm_t *rdp) if (rdp->realm_mprinc) krb5_free_principal(rdp->realm_context, rdp->realm_mprinc); if (rdp->realm_mkey.length && rdp->realm_mkey.contents) { + /* XXX shouldn't memset be zap for safety? */ memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length); free(rdp->realm_mkey.contents); } + if (rdp->mkey_list) + krb5_dbe_free_key_list(rdp->realm_context, rdp->mkey_list); krb5_db_fini(rdp->realm_context); if (rdp->realm_tgsprinc) krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc); @@ -242,6 +245,7 @@ init_realm(char *progname, kdc_realm_t *rdp, char *realm, krb5_boolean manual; krb5_realm_params *rparams; int kdb_open_flags; + krb5_kvno mkvno = IGNORE_VNO; memset((char *) rdp, 0, sizeof(kdc_realm_t)); if (!realm) { @@ -374,18 +378,25 @@ init_realm(char *progname, kdc_realm_t *rdp, char *realm, } /* - * Get the master key. + * Get the master key (note, may not be the most current mkey). */ if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc, rdp->realm_mkey.enctype, manual, FALSE, rdp->realm_stash, - NULL, NULL, &rdp->realm_mkey))) { + &mkvno, NULL, &rdp->realm_mkey))) { com_err(progname, kret, "while fetching master key %s for realm %s", rdp->realm_mpname, realm); goto whoops; } +#if 0 /************** Begin IFDEF'ed OUT *******************************/ + /* + * Commenting krb5_db_verify_master_key out because it requires the most + * current mkey which may not be the case here. The call to + * krb5_db_fetch_mkey_list() will end up verifying that the mkey is viable + * anyway. + */ /* Verify the master key */ if ((kret = krb5_db_verify_master_key(rdp->realm_context, rdp->realm_mprinc, @@ -395,6 +406,14 @@ init_realm(char *progname, kdc_realm_t *rdp, char *realm, "while verifying master key for realm %s", realm); goto whoops; } +#endif /**************** END IFDEF'ed OUT *******************************/ + + if ((kret = krb5_db_fetch_mkey_list(rdp->realm_context, rdp->realm_mprinc, + &rdp->realm_mkey, mkvno, &rdp->mkey_list))) { + com_err(progname, kret, + "while fetching master keys list for realm %s", realm); + goto whoops; + } if ((kret = krb5_db_set_mkey(rdp->realm_context, &rdp->realm_mkey))) { com_err(progname, kret, |
