Initial commit for second approach for multiple kvno. NOT TESTED!

This commit is contained in:
Nicolas Williams
2011-03-25 16:00:49 -05:00
committed by Nicolas Williams
parent ed91d4c9e3
commit fca53990e4
12 changed files with 227 additions and 32 deletions

View File

@@ -29,6 +29,7 @@ gen_files_hdb = \
asn1_HDB_Ext_Lan_Manager_OWF.x \
asn1_HDB_Ext_Password.x \
asn1_HDB_Ext_Aliases.x \
asn1_HDB_Ext_KeySet.x \
asn1_HDB_extension.x \
asn1_HDB_extensions.x \
asn1_hdb_entry.x \

View File

@@ -105,7 +105,6 @@ _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
krb5_principal enterprise_principal = NULL;
krb5_data key, value;
krb5_error_code ret;
int code;
if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
if (principal->name.name_string.len != 1) {
@@ -125,43 +124,72 @@ _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
hdb_principal2key(context, principal, &key);
if (enterprise_principal)
krb5_free_principal(context, enterprise_principal);
code = db->hdb__get(context, db, key, &value);
ret = db->hdb__get(context, db, key, &value);
krb5_data_free(&key);
if(code)
return code;
code = hdb_value2entry(context, &value, &entry->entry);
if (code == ASN1_BAD_ID && (flags & HDB_F_CANON) == 0) {
if(ret)
return ret;
ret = hdb_value2entry(context, &value, &entry->entry);
if (ret == ASN1_BAD_ID && (flags & HDB_F_CANON) == 0) {
krb5_data_free(&value);
return HDB_ERR_NOENTRY;
} else if (code == ASN1_BAD_ID) {
} else if (ret == ASN1_BAD_ID) {
hdb_entry_alias alias;
code = hdb_value2entry_alias(context, &value, &alias);
if (code) {
ret = hdb_value2entry_alias(context, &value, &alias);
if (ret) {
krb5_data_free(&value);
return code;
return ret;
}
hdb_principal2key(context, alias.principal, &key);
krb5_data_free(&value);
free_hdb_entry_alias(&alias);
code = db->hdb__get(context, db, key, &value);
ret = db->hdb__get(context, db, key, &value);
krb5_data_free(&key);
if (code)
return code;
code = hdb_value2entry(context, &value, &entry->entry);
if (code) {
if (ret)
return ret;
ret = hdb_value2entry(context, &value, &entry->entry);
if (ret) {
krb5_data_free(&value);
return code;
return ret;
}
}
krb5_data_free(&value);
if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
code = hdb_unseal_keys (context, db, &entry->entry);
if (code)
if ((flags & HDB_F_KVNO_SPECIFIED) == 0 &&
(flags & HDB_F_CURRENT_KVNO) == 0) {
/*
* Decrypt all the old keys too, since we don't know which
* the caller will need.
*/
ret = hdb_unseal_keys_kvno(context, db, 0, &entry->entry);
if (ret) {
hdb_free_entry(context, entry);
return ret;
}
return code;
} else if ((flags & HDB_F_KVNO_SPECIFIED) != 0 &&
kvno != entry->entry.kvno &&
kvno < entry->entry.kvno &&
kvno > 0) {
/* Decrypt the keys we were asked for, if not the current ones */
ret = hdb_unseal_keys_kvno(context, db, kvno, &entry->entry);
if (ret) {
hdb_free_entry(context, entry);
return ret;
}
}
/* Always decrypt the current keys too */
ret = hdb_unseal_keys(context, db, &entry->entry);
if (ret) {
hdb_free_entry(context, entry);
return ret;
}
}
return ret;
}
static krb5_error_code

View File

@@ -87,6 +87,14 @@ HDB-Ext-Aliases ::= SEQUENCE {
aliases[1] SEQUENCE OF Principal -- all names, inc primary
}
hdb_keyset ::= SEQUENCE {
kvno[0] INTEGER (0..4294967295),
replace-time[1] KerberosTime, -- time this key was replaced
keys[2] SEQUENCE OF Key
}
HDB-Ext-KeySet ::= SEQUENCE OF hdb_keyset
HDB-extension ::= SEQUENCE {
mandatory[0] BOOLEAN, -- kdc MUST understand this extension,
@@ -102,6 +110,7 @@ HDB-extension ::= SEQUENCE {
aliases[6] HDB-Ext-Aliases,
last-pw-change[7] KerberosTime,
pkinit-cert[8] HDB-Ext-PKINIT-cert,
hist-keys[9] HDB-Ext-KeySet,
...
},
...
@@ -109,11 +118,6 @@ HDB-extension ::= SEQUENCE {
HDB-extensions ::= SEQUENCE OF HDB-extension
hdb_keyset ::= SEQUENCE {
kvno[1] INTEGER (0..4294967295),
keys[0] SEQUENCE OF Key
}
hdb_entry ::= SEQUENCE {
principal[0] Principal OPTIONAL, -- this is optional only
-- for compatibility with libkrb5

View File

@@ -168,13 +168,14 @@ hdb_unlock(int fd)
void
hdb_free_entry(krb5_context context, hdb_entry_ex *ent)
{
size_t i;
Key *k;
int i;
if (ent->free_entry)
(*ent->free_entry)(context, ent);
for(i = 0; i < ent->entry.keys.len; ++i) {
Key *k = &ent->entry.keys.val[i];
for(i = 0; i < ent->entry.keys.len; i++) {
k = &ent->entry.keys.val[i];
memset (k->key.keyvalue.data, 0, k->key.keyvalue.length);
}

View File

@@ -57,6 +57,7 @@ enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK };
#define HDB_F_CANON 32 /* want canonicalition */
#define HDB_F_ADMIN_DATA 64 /* want data that kdc don't use */
#define HDB_F_KVNO_SPECIFIED 128 /* we want a particular KVNO */
#define HDB_F_CURRENT_KVNO 256 /* we want the current KVNO */
/* hdb_capability_flags */
#define HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL 1

View File

@@ -39,7 +39,7 @@
*/
void
hdb_free_keys (krb5_context context, int len, Key *keys)
hdb_free_keys(krb5_context context, int len, Key *keys)
{
int i;
@@ -56,6 +56,19 @@ hdb_free_keys (krb5_context context, int len, Key *keys)
free (keys);
}
void
hdb_free_keysets(krb5_context context, int len, hdb_keyset *keysets)
{
int i;
for (i = 0; i < len; i++) {
hdb_free_keys(context, keysets[i].keys.len, keysets[i].keys.val);
keysets[i].keys.val = NULL;
keysets[i].keys.len = 0;
}
free (keysets);
}
/*
* for each entry in `default_keys' try to parse it as a sequence
* of etype:salttype:salt, syntax of this if something like:
@@ -196,6 +209,60 @@ parse_key_set(krb5_context context, const char *key,
return 0;
}
krb5_error_code
hdb_add_current_keys_to_history(krb5_context context, hdb_entry *entry)
{
krb5_error_code ret;
HDB_extension *ext;
HDB_Ext_KeySet *hist_keys;
hdb_keyset *tmp_keysets;
int add = 0;
ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
if (ext != NULL) {
hist_keys = &ext->data.u.hist_keys;
tmp_keysets = realloc(hist_keys->val,
sizeof (*hist_keys->val) * (hist_keys->len + 1));
if (tmp_keysets == NULL)
return ENOMEM;
hist_keys->val = tmp_keysets;
memmove(&hist_keys->val[1], hist_keys->val,
sizeof (*hist_keys->val) * hist_keys->len++);
} else {
add = 1;
ext = calloc(1, sizeof (*ext));
if (ext == NULL)
return ENOMEM;
ext->data.element = choice_HDB_extension_data_hist_keys;
hist_keys = &ext->data.u.hist_keys;
hist_keys->val = calloc(1, sizeof (*hist_keys->val));
if (hist_keys->val == NULL) {
free(hist_keys);
return ENOMEM;
}
hist_keys->len = 1;
}
hist_keys->val[0].keys.val = entry->keys.val;
hist_keys->val[0].keys.len = entry->keys.len;
hist_keys->val[0].kvno = entry->kvno;
hist_keys->val[0].replace_time = time(NULL);
if (add) {
ret = hdb_replace_extension(context, entry, ext);
if (ret) {
free_HDB_extension(ext);
return ret;
}
}
/* hdb_replace_extension() copies ext, so we have to free it */
free_HDB_extension(ext);
return 0;
}
static krb5_error_code
add_enctype_to_key_set(Key **key_set, size_t *nkeyset,
krb5_enctype enctype, krb5_salt *salt)

View File

@@ -32,6 +32,7 @@
*/
#include "hdb_locl.h"
#include <assert.h>
#ifndef O_BINARY
#define O_BINARY 0
#endif
@@ -479,6 +480,85 @@ hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent)
return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key);
}
krb5_error_code
hdb_unseal_keys_kvno(krb5_context context, HDB *db, krb5_kvno kvno,
hdb_entry *ent)
{
krb5_error_code ret = KRB5KRB_AP_ERR_NOKEY; /* XXX need a better code? */
HDB_extension *tmp;
HDB_Ext_KeySet *hist_keys;
hdb_keyset *tmp_keys;
Key *tmp_val;
unsigned int tmp_len;
krb5_kvno tmp_kvno;
int i, k;
assert(kvno == 0 || kvno < ent->kvno);
tmp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
if (tmp == NULL)
return ret;
tmp_len = ent->keys.len;
tmp_val = ent->keys.val;
tmp_kvno = ent->kvno;
hist_keys = &tmp->data.u.hist_keys;
for (i = hist_keys->len - 1; i >= 0; i++) {
if (kvno != 0 && hist_keys->val[i].kvno != kvno)
continue;
for (k = 0; k < hist_keys->val[i].keys.len; k++) {
ret = hdb_unseal_key_mkey(context,
&hist_keys->val[i].keys.val[k],
db->hdb_master_key);
if (ret)
return (ret);
}
if (kvno == 0)
continue;
/*
* NOTE: What follows is a bit of an ugly hack.
*
* This is the keyset we're being asked for, so we add the
* current keyset to the history, leave the one we were asked
* for in the history, and pretend the one we were asked for is
* also the current keyset.
*
* This is a bit of a defensive hack in case an entry fetched
* this way ever gets modified then stored: if the keyset is not
* changed we can detect this and put things back, else we won't
* drop any keysets from history by accident.
*
* Note too that we only ever get called with a non-zero kvno
* either in the KDC or in cases where we aren't changing the
* HDB entry anyways, which is why this is just a defensive
* hack. We also don't fetch specific kvnos in the dump case,
* so there's no danger that we'll dump this entry and load it
* again, repeatedly causing the history to grow boundelessly.
*/
tmp_keys = realloc(hist_keys->val,
sizeof (*hist_keys->val) * (hist_keys->len + 1));
if (tmp_keys == NULL)
return ENOMEM;
memmove(&tmp_keys[1], tmp_keys,
sizeof (*hist_keys->val) * hist_keys->len++);
tmp_keys[0].keys.len = ent->keys.len;
tmp_keys[0].keys.val = ent->keys.val;
tmp_keys[0].kvno = ent->kvno;
tmp_keys[0].replace_time = time(NULL);
i++;
ent->keys.len = hist_keys->val[i].keys.len;
ent->keys.val = hist_keys->val[i].keys.val;
ent->kvno = kvno;
}
return (ret);
}
krb5_error_code
hdb_unseal_key(krb5_context context, HDB *db, Key *k)
{

View File

@@ -62,11 +62,12 @@ append_string(krb5_context context, krb5_storage *sp, const char *fmt, ...)
{
krb5_error_code ret;
char *s;
int rc;
va_list ap;
va_start(ap, fmt);
vasprintf(&s, fmt, ap);
rc = vasprintf(&s, fmt, ap);
va_end(ap);
if(s == NULL) {
if(rc < 0) {
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
@@ -127,7 +128,7 @@ static krb5_error_code
entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent)
{
char *p;
size_t i;
int i;
krb5_error_code ret;
/* --- principal */
@@ -234,7 +235,6 @@ entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent)
} else
append_string(context, sp, "-");
return 0;
}

View File

@@ -88,6 +88,7 @@ main(int argc, char **argv)
memset(&keyset, 0, sizeof(keyset));
keyset.kvno = kvno_integer;
keyset.replace_time = time(NULL);
ret = hdb_generate_key_set_password(context, principal, password_str,
&keyset.keys.val, &len);

View File

@@ -4,6 +4,7 @@ HEIMDAL_HDB_1.0 {
global:
encode_hdb_keyset;
hdb_add_master_key;
hdb_add_current_keys_to_history;
hdb_check_db_format;
hdb_clear_extension;
hdb_clear_master_key;

View File

@@ -58,6 +58,10 @@ change(void *server_handle,
if(ret)
goto out;
ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
if (ret)
goto out;
if (context->db->hdb_capability_flags & HDB_CAP_F_HANDLE_PASSWORDS) {
ret = context->db->hdb_password(context->context, context->db,
&ent, password, cond);
@@ -170,6 +174,9 @@ kadm5_s_chpass_principal_with_key(void *server_handle,
HDB_F_GET_ANY|HDB_F_ADMIN_DATA, &ent);
if(ret == HDB_ERR_NOENTRY)
goto out;
ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
if (ret)
goto out2;
ret = _kadm5_set_keys2(context, &ent.entry, n_key_data, key_data);
if(ret)
goto out2;

View File

@@ -59,6 +59,10 @@ kadm5_s_randkey_principal(void *server_handle,
if(ret)
goto out;
ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
if (ret)
goto out2;
ret = _kadm5_set_keys_randomly (context,
&ent.entry,
new_keys,