summaryrefslogtreecommitdiffstats
path: root/src/kdc
diff options
context:
space:
mode:
authorWill Fiveash <will.fiveash@oracle.com>2009-01-30 23:55:14 +0000
committerWill Fiveash <will.fiveash@oracle.com>2009-01-30 23:55:14 +0000
commite246f7e7b2cddfca9eb744f24e50dd034247a74b (patch)
tree97ec348048dab2eec4206fa99df1e18adab77cf1 /src/kdc
parent77b1e1108ca32617fe43825748c68c575e77f010 (diff)
downloadkrb5-e246f7e7b2cddfca9eb744f24e50dd034247a74b.tar.gz
krb5-e246f7e7b2cddfca9eb744f24e50dd034247a74b.tar.xz
krb5-e246f7e7b2cddfca9eb744f24e50dd034247a74b.zip
Master Key Migration Project
Commit for the Master Key Migration Project. http://k5wiki.kerberos.org/wiki/Projects/Master_Key_Migration This commit provides the ability to add a new master key (with an enctype differing from the current master key) to the master key principal and stash file and then migrate the encryption of existing principals long term keys to use the new master key. In addition deletion of master keys is provided. ticket: 6354 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@21844 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/kdc')
-rw-r--r--src/kdc/do_as_req.c44
-rw-r--r--src/kdc/do_tgs_req.c24
-rw-r--r--src/kdc/extern.c1
-rw-r--r--src/kdc/extern.h6
-rw-r--r--src/kdc/kdc_preauth.c88
-rw-r--r--src/kdc/kdc_util.c22
-rw-r--r--src/kdc/main.c23
7 files changed, 194 insertions, 14 deletions
diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
index 9571fb2122..8db39ac4f2 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 0843002569..a6ce704bd7 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 2a2c1ae22e..7ebc7bb3a6 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 20cc4bc049..88e8b0ddef 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 6ec156440f..7aacca402e 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 34a8ed0c3f..28b4a37ca0 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 b9334680b4..bb4d7584d7 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,