aboutsummaryrefslogtreecommitdiff
path: root/src/lib/kadm5/srv
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/lib/kadm5/srv
parent77b1e1108ca32617fe43825748c68c575e77f010 (diff)
downloadkrb5-e246f7e7b2cddfca9eb744f24e50dd034247a74b.zip
krb5-e246f7e7b2cddfca9eb744f24e50dd034247a74b.tar.gz
krb5-e246f7e7b2cddfca9eb744f24e50dd034247a74b.tar.bz2
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/lib/kadm5/srv')
-rw-r--r--src/lib/kadm5/srv/libkadm5srv.exports1
-rw-r--r--src/lib/kadm5/srv/server_kdb.c43
-rw-r--r--src/lib/kadm5/srv/svr_iters.c1
-rw-r--r--src/lib/kadm5/srv/svr_principal.c153
4 files changed, 172 insertions, 26 deletions
diff --git a/src/lib/kadm5/srv/libkadm5srv.exports b/src/lib/kadm5/srv/libkadm5srv.exports
index a025776..545d43b 100644
--- a/src/lib/kadm5/srv/libkadm5srv.exports
+++ b/src/lib/kadm5/srv/libkadm5srv.exports
@@ -87,6 +87,7 @@ krb5_string_to_keysalts
krb5_match_config_pattern
master_db
master_keyblock
+master_keylist
master_princ
osa_free_princ_ent
ovsec_kadm_chpass_principal
diff --git a/src/lib/kadm5/srv/server_kdb.c b/src/lib/kadm5/srv/server_kdb.c
index 836cd00..47f00c0 100644
--- a/src/lib/kadm5/srv/server_kdb.c
+++ b/src/lib/kadm5/srv/server_kdb.c
@@ -4,6 +4,11 @@
* $Header$
*/
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
#if !defined(lint) && !defined(__CODECENTER__)
static char *rcsid = "$Header$";
#endif
@@ -15,7 +20,9 @@ static char *rcsid = "$Header$";
#include "server_internal.h"
krb5_principal master_princ;
-krb5_keyblock master_keyblock;
+krb5_keyblock master_keyblock; /* local mkey */
+krb5_keylist_node *master_keylist = NULL;
+krb5_actkvno_node *active_mkey_list = NULL;
krb5_db_entry master_db;
krb5_principal hist_princ;
@@ -32,6 +39,7 @@ krb5_error_code kdb_init_master(kadm5_server_handle_t handle,
int ret = 0;
char *realm;
krb5_boolean from_kbd = FALSE;
+ krb5_kvno mkvno = IGNORE_VNO;
if (from_keyboard)
from_kbd = TRUE;
@@ -50,22 +58,45 @@ krb5_error_code kdb_init_master(kadm5_server_handle_t handle,
master_keyblock.enctype = handle->params.enctype;
+ /*
+ * Fetch the local mkey, may not be the latest but that's okay because we
+ * really want the list of all mkeys and those can be retrieved with any
+ * valid mkey.
+ */
ret = krb5_db_fetch_mkey(handle->context, master_princ,
master_keyblock.enctype, from_kbd,
FALSE /* only prompt once */,
handle->params.stash_file,
- NULL /* don't care about kvno */,
+ &mkvno /* get the kvno of the returned mkey */,
NULL /* I'm not sure about this,
but it's what the kdc does --marc */,
&master_keyblock);
if (ret)
goto done;
+#if 0 /************** Begin IFDEF'ed OUT *******************************/
+ /*
+ * krb5_db_fetch_mkey_list will verify mkey so don't call
+ * krb5_db_verify_master_key()
+ */
if ((ret = krb5_db_verify_master_key(handle->context, master_princ,
IGNORE_VNO, &master_keyblock))) {
krb5_db_fini(handle->context);
return ret;
}
+#endif /**************** END IFDEF'ed OUT *******************************/
+
+ if ((ret = krb5_db_fetch_mkey_list(handle->context, master_princ,
+ &master_keyblock, mkvno, &master_keylist))) {
+ krb5_db_fini(handle->context);
+ return (ret);
+ }
+
+ if ((ret = krb5_dbe_fetch_act_key_list(handle->context, master_princ,
+ &active_mkey_list))) {
+ krb5_db_fini(handle->context);
+ return (ret);
+ }
done:
if (r == NULL)
@@ -106,6 +137,7 @@ krb5_error_code kdb_init_hist(kadm5_server_handle_t handle, char *r)
char *realm, *hist_name;
krb5_key_data *key_data;
krb5_key_salt_tuple ks[1];
+ krb5_keyblock *tmp_mkey;
if (r == NULL) {
if ((ret = krb5_get_default_realm(handle->context, &realm)))
@@ -177,7 +209,12 @@ krb5_error_code kdb_init_hist(kadm5_server_handle_t handle, char *r)
if (ret)
goto done;
- ret = krb5_dbekd_decrypt_key_data(handle->context, &master_keyblock,
+ ret = krb5_dbe_find_mkey(handle->context, master_keylist, &hist_db,
+ &tmp_mkey);
+ if (ret)
+ goto done;
+
+ ret = krb5_dbekd_decrypt_key_data(handle->context, tmp_mkey,
key_data, &hist_key, NULL);
if (ret)
goto done;
diff --git a/src/lib/kadm5/srv/svr_iters.c b/src/lib/kadm5/srv/svr_iters.c
index cd3fb41..757d3ab 100644
--- a/src/lib/kadm5/srv/svr_iters.c
+++ b/src/lib/kadm5/srv/svr_iters.c
@@ -46,6 +46,7 @@ struct iter_data {
#endif
};
+/* XXX Duplicated in kdb5_util! */
/*
* Function: glob_to_regexp
*
diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c
index 2bdc1f5..2071437 100644
--- a/src/lib/kadm5/srv/svr_principal.c
+++ b/src/lib/kadm5/srv/svr_principal.c
@@ -32,13 +32,15 @@ static char *rcsid = "$Header$";
extern krb5_principal master_princ;
extern krb5_principal hist_princ;
-extern krb5_keyblock master_keyblock;
+extern krb5_keyblock master_keyblock;
+extern krb5_keylist_node *master_keylist;
+extern krb5_actkvno_node *active_mkey_list;
extern krb5_keyblock hist_key;
extern krb5_db_entry master_db;
extern krb5_db_entry hist_db;
extern krb5_kvno hist_kvno;
-static int decrypt_key_data(krb5_context context,
+static int decrypt_key_data(krb5_context context, krb5_keyblock *mkey,
int n_key_data, krb5_key_data *key_data,
krb5_keyblock **keyblocks, int *n_keys);
@@ -205,6 +207,8 @@ kadm5_create_principal_3(void *server_handle,
krb5_tl_data *tl_data_orig, *tl_data_tail;
unsigned int ret;
kadm5_server_handle_t handle = server_handle;
+ krb5_keyblock *act_mkey;
+ krb5_kvno act_kvno;
CHECK_HANDLE(server_handle);
@@ -347,7 +351,16 @@ kadm5_create_principal_3(void *server_handle,
/* initialize the keys */
- if ((ret = krb5_dbe_cpw(handle->context, &master_keyblock,
+ ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
+ active_mkey_list, &act_kvno, &act_mkey);
+ if (ret) {
+ krb5_db_free_principal(handle->context, &kdb, 1);
+ if (mask & KADM5_POLICY)
+ (void) kadm5_free_policy_ent(handle->lhandle, &polent);
+ return (ret);
+ }
+
+ if ((ret = krb5_dbe_cpw(handle->context, act_mkey,
n_ks_tuple?ks_tuple:handle->params.keysalts,
n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
password,
@@ -359,6 +372,16 @@ kadm5_create_principal_3(void *server_handle,
return(ret);
}
+ /* Record the master key VNO used to encrypt this entry's keys */
+ ret = krb5_dbe_update_mkvno(handle->context, &kdb, act_kvno);
+ if (ret)
+ {
+ krb5_db_free_principal(handle->context, &kdb, 1);
+ if (mask & KADM5_POLICY)
+ (void) kadm5_free_policy_ent(handle->lhandle, &polent);
+ return ret;
+ }
+
/* populate the admin-server-specific fields. In the OV server,
this used to be in a separate database. Since there's already
marshalling code for the admin fields, to keep things simple,
@@ -806,12 +829,24 @@ kadm5_get_principal(void *server_handle, krb5_principal principal,
if (kdb.key_data[i].key_data_kvno > entry->kvno)
entry->kvno = kdb.key_data[i].key_data_kvno;
+ ret = krb5_dbe_lookup_mkvno(handle->context, &kdb, &entry->mkvno);
+ if (ret)
+ goto done;
+
+ /*
+ * It's my understanding that KADM5_API_VERSION_1 is for OpenVision admin
+ * system compatiblity and is not required to maintain at this point so I'm
+ * commenting out this code.
+ * -- Will Fiveash
+ */
+#if 0 /************** Begin IFDEF'ed OUT *******************************/
if (handle->api_version == KADM5_API_VERSION_2)
entry->mkvno = 0;
else {
/* XXX I'll be damned if I know how to deal with this one --marc */
entry->mkvno = 1;
}
+#endif /**************** END IFDEF'ed OUT *******************************/
/*
* The new fields that only exist in version 2 start here
@@ -936,6 +971,7 @@ done:
*/
static kadm5_ret_t
check_pw_reuse(krb5_context context,
+ krb5_keyblock *mkey,
krb5_keyblock *hist_keyblock,
int n_new_key_data, krb5_key_data *new_key_data,
unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
@@ -946,7 +982,7 @@ check_pw_reuse(krb5_context context,
for (x = 0; x < n_new_key_data; x++) {
ret = krb5_dbekd_decrypt_key_data(context,
- &master_keyblock,
+ mkey,
&(new_key_data[x]),
&newkey, NULL);
if (ret)
@@ -999,7 +1035,7 @@ check_pw_reuse(krb5_context context,
* set to n_key_data.
*/
static
-int create_history_entry(krb5_context context, int n_key_data,
+int create_history_entry(krb5_context context, krb5_keyblock *mkey, int n_key_data,
krb5_key_data *key_data, osa_pw_hist_ent *hist)
{
int i, ret;
@@ -1013,7 +1049,7 @@ int create_history_entry(krb5_context context, int n_key_data,
for (i = 0; i < n_key_data; i++) {
ret = krb5_dbekd_decrypt_key_data(context,
- &master_keyblock,
+ mkey,
&key_data[i],
&key, &salt);
if (ret)
@@ -1302,6 +1338,8 @@ kadm5_chpass_principal_3(void *server_handle,
int have_pol = 0;
kadm5_server_handle_t handle = server_handle;
osa_pw_hist_ent hist;
+ krb5_keyblock *act_mkey;
+ krb5_kvno act_kvno;
CHECK_HANDLE(server_handle);
@@ -1335,7 +1373,12 @@ kadm5_chpass_principal_3(void *server_handle,
KADM5_POLICY, &pol, principal)))
goto done;
- ret = krb5_dbe_cpw(handle->context, &master_keyblock,
+ ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
+ active_mkey_list, &act_kvno, &act_mkey);
+ if (ret)
+ goto done;
+
+ ret = krb5_dbe_cpw(handle->context, act_mkey,
n_ks_tuple?ks_tuple:handle->params.keysalts,
n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
password, 0 /* increment kvno */,
@@ -1343,6 +1386,10 @@ kadm5_chpass_principal_3(void *server_handle,
if (ret)
goto done;
+ ret = krb5_dbe_update_mkvno(handle->context, &kdb, act_kvno);
+ if (ret)
+ goto done;
+
kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
ret = krb5_timeofday(handle->context, &now);
@@ -1372,12 +1419,13 @@ kadm5_chpass_principal_3(void *server_handle,
#endif
ret = create_history_entry(handle->context,
+ act_mkey,
kdb_save.n_key_data,
kdb_save.key_data, &hist);
if (ret)
goto done;
- ret = check_pw_reuse(handle->context, &hist_key,
+ ret = check_pw_reuse(handle->context, act_mkey, &hist_key,
kdb.n_key_data, kdb.key_data,
1, &hist);
if (ret)
@@ -1389,7 +1437,7 @@ kadm5_chpass_principal_3(void *server_handle,
goto done;
}
- ret = check_pw_reuse(handle->context, &hist_key,
+ ret = check_pw_reuse(handle->context, act_mkey, &hist_key,
kdb.n_key_data, kdb.key_data,
adb.old_key_len, adb.old_keys);
if (ret)
@@ -1489,6 +1537,7 @@ kadm5_randkey_principal_3(void *server_handle,
krb5_key_data *key_data;
int ret, last_pwd, have_pol = 0;
kadm5_server_handle_t handle = server_handle;
+ krb5_keyblock *act_mkey;
if (keyblocks)
*keyblocks = NULL;
@@ -1507,7 +1556,12 @@ kadm5_randkey_principal_3(void *server_handle,
if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
return(ret);
- ret = krb5_dbe_crk(handle->context, &master_keyblock,
+ ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
+ active_mkey_list, NULL, &act_mkey);
+ if (ret)
+ goto done;
+
+ ret = krb5_dbe_crk(handle->context, act_mkey,
n_ks_tuple?ks_tuple:handle->params.keysalts,
n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
keepold,
@@ -1552,7 +1606,7 @@ kadm5_randkey_principal_3(void *server_handle,
goto done;
}
- ret = check_pw_reuse(handle->context, &hist_key,
+ ret = check_pw_reuse(handle->context, act_mkey, &hist_key,
kdb.n_key_data, kdb.key_data,
adb.old_key_len, adb.old_keys);
if (ret)
@@ -1579,12 +1633,12 @@ kadm5_randkey_principal_3(void *server_handle,
if (ret)
goto done;
- ret = decrypt_key_data(handle->context, 1, key_data,
+ ret = decrypt_key_data(handle->context, act_mkey, 1, key_data,
keyblocks, NULL);
if (ret)
goto done;
} else {
- ret = decrypt_key_data(handle->context,
+ ret = decrypt_key_data(handle->context, act_mkey,
kdb.n_key_data, kdb.key_data,
keyblocks, n_keys);
if (ret)
@@ -1630,6 +1684,7 @@ kadm5_setv4key_principal(void *server_handle,
#endif
kadm5_server_handle_t handle = server_handle;
krb5_key_data tmp_key_data;
+ krb5_keyblock *act_mkey;
memset( &tmp_key_data, 0, sizeof(tmp_key_data));
@@ -1667,8 +1722,13 @@ kadm5_setv4key_principal(void *server_handle,
keysalt.data.length = 0;
keysalt.data.data = NULL;
+ ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
+ active_mkey_list, NULL, &act_mkey);
+ if (ret)
+ goto done;
+
/* use tmp_key_data as temporary location and reallocate later */
- ret = krb5_dbekd_encrypt_key_data(handle->context, &master_keyblock,
+ ret = krb5_dbekd_encrypt_key_data(handle->context, act_mkey,
keyblock, &keysalt, kvno + 1,
&tmp_key_data);
if (ret) {
@@ -1809,6 +1869,7 @@ kadm5_setkey_principal_3(void *server_handle,
krb5_keysalt keysalt;
krb5_key_data tmp_key_data;
krb5_key_data *tptr;
+ krb5_keyblock *act_mkey;
CHECK_HANDLE(server_handle);
@@ -1880,15 +1941,20 @@ kadm5_setkey_principal_3(void *server_handle,
}
memset (&tmp_key_data, 0, sizeof(tmp_key_data));
+ ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
+ active_mkey_list, NULL, &act_mkey);
+ if (ret)
+ goto done;
+
ret = krb5_dbekd_encrypt_key_data(handle->context,
- &master_keyblock,
+ act_mkey,
&keyblocks[i],
n_ks_tuple ? &keysalt : NULL,
kvno + 1,
&tmp_key_data);
- if (ret) {
+ if (ret)
goto done;
- }
+
tptr = &kdb.key_data[i];
tptr->key_data_ver = tmp_key_data.key_data_ver;
tptr->key_data_kvno = tmp_key_data.key_data_kvno;
@@ -2013,6 +2079,7 @@ kadm5_get_principal_keys(void *server_handle /* IN */,
krb5_key_data *key_data;
kadm5_ret_t ret;
kadm5_server_handle_t handle = server_handle;
+ krb5_keyblock *mkey_ptr;
if (keyblocks)
*keyblocks = NULL;
@@ -2026,6 +2093,25 @@ kadm5_get_principal_keys(void *server_handle /* IN */,
return(ret);
if (keyblocks) {
+ if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &kdb,
+ &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(handle->context, master_princ,
+ &master_keyblock, 0,
+ &tmp_mkey_list) == 0) {
+ krb5_dbe_free_key_list(handle->context, master_keylist);
+ master_keylist = tmp_mkey_list;
+ if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist,
+ &kdb, &mkey_ptr))) {
+ goto done;
+ }
+ } else {
+ goto done;
+ }
+ }
+
if (handle->api_version == KADM5_API_VERSION_1) {
/* Version 1 clients will expect to see a DES_CRC enctype. */
if ((ret = krb5_dbe_find_enctype(handle->context, &kdb,
@@ -2033,11 +2119,11 @@ kadm5_get_principal_keys(void *server_handle /* IN */,
-1, -1, &key_data)))
goto done;
- if ((ret = decrypt_key_data(handle->context, 1, key_data,
+ if ((ret = decrypt_key_data(handle->context, mkey_ptr, 1, key_data,
keyblocks, NULL)))
goto done;
} else {
- ret = decrypt_key_data(handle->context,
+ ret = decrypt_key_data(handle->context, mkey_ptr,
kdb.n_key_data, kdb.key_data,
keyblocks, n_keys);
if (ret)
@@ -2056,10 +2142,10 @@ done:
/*
* Allocate an array of n_key_data krb5_keyblocks, fill in each
* element with the results of decrypting the nth key in key_data with
- * master_keyblock, and if n_keys is not NULL fill it in with the
+ * mkey, and if n_keys is not NULL fill it in with the
* number of keys decrypted.
*/
-static int decrypt_key_data(krb5_context context,
+static int decrypt_key_data(krb5_context context, krb5_keyblock *mkey,
int n_key_data, krb5_key_data *key_data,
krb5_keyblock **keyblocks, int *n_keys)
{
@@ -2072,7 +2158,7 @@ static int decrypt_key_data(krb5_context context,
memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock));
for (i = 0; i < n_key_data; i++) {
- ret = krb5_dbekd_decrypt_key_data(context, &master_keyblock,
+ ret = krb5_dbekd_decrypt_key_data(context, mkey,
&key_data[i],
&keys[i], NULL);
if (ret) {
@@ -2135,6 +2221,7 @@ kadm5_ret_t kadm5_decrypt_key(void *server_handle,
kadm5_server_handle_t handle = server_handle;
krb5_db_entry dbent;
krb5_key_data *key_data;
+ krb5_keyblock *mkey_ptr;
int ret;
CHECK_HANDLE(server_handle);
@@ -2149,8 +2236,28 @@ kadm5_ret_t kadm5_decrypt_key(void *server_handle,
stype, kvno, &key_data)))
return ret;
+ /* find_mkey only uses this field */
+ dbent.tl_data = entry->tl_data;
+ if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &dbent,
+ &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(handle->context, master_princ,
+ &master_keyblock, 0, &tmp_mkey_list) == 0) {
+ krb5_dbe_free_key_list(handle->context, master_keylist);
+ master_keylist = tmp_mkey_list;
+ if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist,
+ &dbent, &mkey_ptr))) {
+ return ret;
+ }
+ } else {
+ return ret;
+ }
+ }
+
if ((ret = krb5_dbekd_decrypt_key_data(handle->context,
- &master_keyblock, key_data,
+ mkey_ptr, key_data,
keyblock, keysalt)))
return ret;