Home | History | Annotate | Line # | Download | only in hdb
      1  1.3    pettai /*	$NetBSD: keys.c,v 1.6 2023/06/19 21:41:43 christos Exp $	*/
      2  1.1     elric 
      3  1.1     elric /*
      4  1.4  christos  * Copyright (c) 1997 - 2011 Kungliga Tekniska Hgskolan
      5  1.1     elric  * (Royal Institute of Technology, Stockholm, Sweden).
      6  1.1     elric  * All rights reserved.
      7  1.1     elric  *
      8  1.1     elric  * Redistribution and use in source and binary forms, with or without
      9  1.1     elric  * modification, are permitted provided that the following conditions
     10  1.1     elric  * are met:
     11  1.1     elric  *
     12  1.1     elric  * 1. Redistributions of source code must retain the above copyright
     13  1.1     elric  *    notice, this list of conditions and the following disclaimer.
     14  1.1     elric  *
     15  1.1     elric  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1     elric  *    notice, this list of conditions and the following disclaimer in the
     17  1.1     elric  *    documentation and/or other materials provided with the distribution.
     18  1.1     elric  *
     19  1.1     elric  * 3. Neither the name of the Institute nor the names of its contributors
     20  1.1     elric  *    may be used to endorse or promote products derived from this software
     21  1.1     elric  *    without specific prior written permission.
     22  1.1     elric  *
     23  1.1     elric  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  1.1     elric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  1.1     elric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  1.1     elric  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  1.1     elric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  1.1     elric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  1.1     elric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  1.1     elric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  1.1     elric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  1.1     elric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  1.1     elric  * SUCH DAMAGE.
     34  1.1     elric  */
     35  1.1     elric 
     36  1.1     elric #include "hdb_locl.h"
     37  1.1     elric 
     38  1.4  christos struct hx509_certs_data;
     39  1.4  christos struct krb5_pk_identity;
     40  1.4  christos struct krb5_pk_cert;
     41  1.4  christos struct ContentInfo;
     42  1.4  christos struct AlgorithmIdentifier;
     43  1.4  christos struct _krb5_krb_auth_data;
     44  1.4  christos typedef struct krb5_pk_init_ctx_data *krb5_pk_init_ctx;
     45  1.4  christos struct krb5_dh_moduli;
     46  1.4  christos struct _krb5_key_data;
     47  1.4  christos struct _krb5_encryption_type;
     48  1.4  christos struct _krb5_key_type;
     49  1.4  christos #include <krb5/pkinit_asn1.h>
     50  1.4  christos #include <krb5/krb5-private.h>
     51  1.4  christos #include <krb5/base64.h>
     52  1.4  christos 
     53  1.1     elric /*
     54  1.1     elric  * free all the memory used by (len, keys)
     55  1.1     elric  */
     56  1.1     elric 
     57  1.1     elric void
     58  1.4  christos hdb_free_keys(krb5_context context, int len, Key *keys)
     59  1.1     elric {
     60  1.4  christos     size_t i;
     61  1.1     elric 
     62  1.1     elric     for (i = 0; i < len; i++) {
     63  1.1     elric 	free(keys[i].mkvno);
     64  1.1     elric 	keys[i].mkvno = NULL;
     65  1.1     elric 	if (keys[i].salt != NULL) {
     66  1.1     elric 	    free_Salt(keys[i].salt);
     67  1.1     elric 	    free(keys[i].salt);
     68  1.1     elric 	    keys[i].salt = NULL;
     69  1.1     elric 	}
     70  1.1     elric 	krb5_free_keyblock_contents(context, &keys[i].key);
     71  1.1     elric     }
     72  1.1     elric     free (keys);
     73  1.1     elric }
     74  1.1     elric 
     75  1.1     elric /*
     76  1.1     elric  * for each entry in `default_keys' try to parse it as a sequence
     77  1.1     elric  * of etype:salttype:salt, syntax of this if something like:
     78  1.1     elric  * [(des|des3|etype):](pw-salt|afs3)[:string], if etype is omitted it
     79  1.1     elric  *      means all etypes, and if string is omitted is means the default
     80  1.1     elric  * string (for that principal). Additional special values:
     81  1.1     elric  *	v5 == pw-salt, and
     82  1.1     elric  *	v4 == des:pw-salt:
     83  1.1     elric  *	afs or afs3 == des:afs3-salt
     84  1.1     elric  */
     85  1.1     elric 
     86  1.1     elric static const krb5_enctype des_etypes[] = {
     87  1.4  christos     KRB5_ENCTYPE_DES_CBC_MD5,
     88  1.4  christos     KRB5_ENCTYPE_DES_CBC_MD4,
     89  1.4  christos     KRB5_ENCTYPE_DES_CBC_CRC
     90  1.1     elric };
     91  1.1     elric 
     92  1.1     elric static const krb5_enctype all_etypes[] = {
     93  1.4  christos     KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
     94  1.4  christos     KRB5_ENCTYPE_DES3_CBC_SHA1,
     95  1.4  christos     KRB5_ENCTYPE_ARCFOUR_HMAC_MD5
     96  1.1     elric };
     97  1.1     elric 
     98  1.1     elric static krb5_error_code
     99  1.1     elric parse_key_set(krb5_context context, const char *key,
    100  1.1     elric 	      krb5_enctype **ret_enctypes, size_t *ret_num_enctypes,
    101  1.1     elric 	      krb5_salt *salt, krb5_principal principal)
    102  1.1     elric {
    103  1.1     elric     const char *p;
    104  1.1     elric     char buf[3][256];
    105  1.1     elric     int num_buf = 0;
    106  1.1     elric     int i, num_enctypes = 0;
    107  1.1     elric     krb5_enctype e;
    108  1.1     elric     const krb5_enctype *enctypes = NULL;
    109  1.1     elric     krb5_error_code ret;
    110  1.1     elric 
    111  1.1     elric     p = key;
    112  1.1     elric 
    113  1.1     elric     *ret_enctypes = NULL;
    114  1.1     elric     *ret_num_enctypes = 0;
    115  1.1     elric 
    116  1.1     elric     /* split p in a list of :-separated strings */
    117  1.1     elric     for(num_buf = 0; num_buf < 3; num_buf++)
    118  1.1     elric 	if(strsep_copy(&p, ":", buf[num_buf], sizeof(buf[num_buf])) == -1)
    119  1.1     elric 	    break;
    120  1.1     elric 
    121  1.1     elric     salt->saltvalue.data = NULL;
    122  1.1     elric     salt->saltvalue.length = 0;
    123  1.1     elric 
    124  1.1     elric     for(i = 0; i < num_buf; i++) {
    125  1.1     elric 	if(enctypes == NULL && num_buf > 1) {
    126  1.1     elric 	    /* this might be a etype specifier */
    127  1.1     elric 	    /* XXX there should be a string_to_etypes handling
    128  1.1     elric 	       special cases like `des' and `all' */
    129  1.1     elric 	    if(strcmp(buf[i], "des") == 0) {
    130  1.1     elric 		enctypes = des_etypes;
    131  1.1     elric 		num_enctypes = sizeof(des_etypes)/sizeof(des_etypes[0]);
    132  1.1     elric 	    } else if(strcmp(buf[i], "des3") == 0) {
    133  1.4  christos 		e = KRB5_ENCTYPE_DES3_CBC_SHA1;
    134  1.1     elric 		enctypes = &e;
    135  1.1     elric 		num_enctypes = 1;
    136  1.1     elric 	    } else {
    137  1.1     elric 		ret = krb5_string_to_enctype(context, buf[i], &e);
    138  1.1     elric 		if (ret == 0) {
    139  1.1     elric 		    enctypes = &e;
    140  1.1     elric 		    num_enctypes = 1;
    141  1.1     elric 		} else
    142  1.1     elric 		    return ret;
    143  1.1     elric 	    }
    144  1.1     elric 	    continue;
    145  1.1     elric 	}
    146  1.1     elric 	if(salt->salttype == 0) {
    147  1.1     elric 	    /* interpret string as a salt specifier, if no etype
    148  1.1     elric 	       is set, this sets default values */
    149  1.1     elric 	    /* XXX should perhaps use string_to_salttype, but that
    150  1.1     elric 	       interface sucks */
    151  1.1     elric 	    if(strcmp(buf[i], "pw-salt") == 0) {
    152  1.1     elric 		if(enctypes == NULL) {
    153  1.1     elric 		    enctypes = all_etypes;
    154  1.1     elric 		    num_enctypes = sizeof(all_etypes)/sizeof(all_etypes[0]);
    155  1.1     elric 		}
    156  1.1     elric 		salt->salttype = KRB5_PW_SALT;
    157  1.1     elric 	    } else if(strcmp(buf[i], "afs3-salt") == 0) {
    158  1.1     elric 		if(enctypes == NULL) {
    159  1.1     elric 		    enctypes = des_etypes;
    160  1.1     elric 		    num_enctypes = sizeof(des_etypes)/sizeof(des_etypes[0]);
    161  1.1     elric 		}
    162  1.1     elric 		salt->salttype = KRB5_AFS3_SALT;
    163  1.1     elric 	    }
    164  1.1     elric 	    continue;
    165  1.1     elric 	}
    166  1.1     elric 
    167  1.4  christos         if (salt->saltvalue.data != NULL)
    168  1.4  christos             free(salt->saltvalue.data);
    169  1.4  christos         /* if there is a final string, use it as the string to
    170  1.4  christos            salt with, this is mostly useful with null salt for
    171  1.4  christos            v4 compat, and a cell name for afs compat */
    172  1.4  christos         salt->saltvalue.data = strdup(buf[i]);
    173  1.4  christos         if (salt->saltvalue.data == NULL)
    174  1.4  christos             return krb5_enomem(context);
    175  1.4  christos         salt->saltvalue.length = strlen(buf[i]);
    176  1.1     elric     }
    177  1.1     elric 
    178  1.1     elric     if(enctypes == NULL || salt->salttype == 0) {
    179  1.4  christos 	krb5_free_salt(context, *salt);
    180  1.1     elric 	krb5_set_error_message(context, EINVAL, "bad value for default_keys `%s'", key);
    181  1.1     elric 	return EINVAL;
    182  1.1     elric     }
    183  1.1     elric 
    184  1.1     elric     /* if no salt was specified make up default salt */
    185  1.1     elric     if(salt->saltvalue.data == NULL) {
    186  1.4  christos 	if(salt->salttype == KRB5_PW_SALT) {
    187  1.1     elric 	    ret = krb5_get_pw_salt(context, principal, salt);
    188  1.4  christos 	    if (ret)
    189  1.4  christos 		return ret;
    190  1.4  christos 	} else if(salt->salttype == KRB5_AFS3_SALT) {
    191  1.1     elric 	    krb5_const_realm realm = krb5_principal_get_realm(context, principal);
    192  1.1     elric 	    salt->saltvalue.data = strdup(realm);
    193  1.1     elric 	    if(salt->saltvalue.data == NULL) {
    194  1.1     elric 		krb5_set_error_message(context, ENOMEM,
    195  1.1     elric 				       "out of memory while "
    196  1.1     elric 				       "parsing salt specifiers");
    197  1.1     elric 		return ENOMEM;
    198  1.1     elric 	    }
    199  1.1     elric 	    strlwr(salt->saltvalue.data);
    200  1.1     elric 	    salt->saltvalue.length = strlen(realm);
    201  1.1     elric 	}
    202  1.1     elric     }
    203  1.1     elric 
    204  1.1     elric     *ret_enctypes = malloc(sizeof(enctypes[0]) * num_enctypes);
    205  1.1     elric     if (*ret_enctypes == NULL) {
    206  1.1     elric 	krb5_free_salt(context, *salt);
    207  1.1     elric 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
    208  1.1     elric 	return ENOMEM;
    209  1.1     elric     }
    210  1.1     elric     memcpy(*ret_enctypes, enctypes, sizeof(enctypes[0]) * num_enctypes);
    211  1.1     elric     *ret_num_enctypes = num_enctypes;
    212  1.1     elric 
    213  1.1     elric     return 0;
    214  1.1     elric }
    215  1.1     elric 
    216  1.4  christos /**
    217  1.4  christos  * This function prunes an HDB entry's keys that are too old to have been used
    218  1.4  christos  * to mint still valid tickets (based on the entry's maximum ticket lifetime).
    219  1.4  christos  *
    220  1.4  christos  * @param context   Context
    221  1.4  christos  * @param entry	    HDB entry
    222  1.4  christos  */
    223  1.4  christos krb5_error_code
    224  1.4  christos hdb_prune_keys(krb5_context context, hdb_entry *entry)
    225  1.4  christos {
    226  1.4  christos     HDB_extension *ext;
    227  1.4  christos     HDB_Ext_KeySet *keys;
    228  1.4  christos     size_t nelem;
    229  1.4  christos 
    230  1.4  christos     ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
    231  1.4  christos     if (ext == NULL)
    232  1.4  christos 	return 0;
    233  1.4  christos     keys = &ext->data.u.hist_keys;
    234  1.4  christos     nelem = keys->len;
    235  1.4  christos 
    236  1.4  christos     /* Optionally drop key history for keys older than now - max_life */
    237  1.4  christos     if (entry->max_life != NULL && nelem > 0
    238  1.4  christos 	&& krb5_config_get_bool_default(context, NULL, FALSE,
    239  1.4  christos 					"kadmin", "prune-key-history", NULL)) {
    240  1.4  christos 	hdb_keyset *elem;
    241  1.4  christos 	time_t ceiling = time(NULL) - *entry->max_life;
    242  1.4  christos 	time_t keep_time = 0;
    243  1.4  christos 	size_t i;
    244  1.4  christos 
    245  1.4  christos 	/*
    246  1.4  christos 	 * Compute most recent key timestamp that predates the current time
    247  1.4  christos 	 * by at least the entry's maximum ticket lifetime.
    248  1.4  christos 	 */
    249  1.4  christos 	for (i = 0; i < nelem; ++i) {
    250  1.4  christos 	    elem = &keys->val[i];
    251  1.4  christos 	    if (elem->set_time && *elem->set_time < ceiling
    252  1.4  christos 		&& (keep_time == 0 || *elem->set_time > keep_time))
    253  1.4  christos 		keep_time = *elem->set_time;
    254  1.4  christos 	}
    255  1.4  christos 
    256  1.4  christos 	/* Drop obsolete entries */
    257  1.4  christos 	if (keep_time) {
    258  1.4  christos 	    for (i = 0; i < nelem; /* see below */) {
    259  1.4  christos 		elem = &keys->val[i];
    260  1.4  christos 		if (elem->set_time && *elem->set_time < keep_time) {
    261  1.4  christos 		    remove_HDB_Ext_KeySet(keys, i);
    262  1.4  christos 		    /*
    263  1.4  christos 		     * Removing the i'th element shifts the tail down, continue
    264  1.4  christos 		     * at same index with reduced upper bound.
    265  1.4  christos 		     */
    266  1.4  christos 		    --nelem;
    267  1.4  christos 		    continue;
    268  1.4  christos 		}
    269  1.4  christos 		++i;
    270  1.4  christos 	    }
    271  1.4  christos 	}
    272  1.4  christos     }
    273  1.4  christos 
    274  1.4  christos     return 0;
    275  1.4  christos }
    276  1.4  christos 
    277  1.4  christos /**
    278  1.4  christos  * This function adds an HDB entry's current keyset to the entry's key
    279  1.4  christos  * history.  The current keyset is left alone; the caller is responsible
    280  1.4  christos  * for freeing it.
    281  1.4  christos  *
    282  1.4  christos  * @param context   Context
    283  1.4  christos  * @param entry	    HDB entry
    284  1.4  christos  */
    285  1.4  christos krb5_error_code
    286  1.4  christos hdb_add_current_keys_to_history(krb5_context context, hdb_entry *entry)
    287  1.4  christos {
    288  1.4  christos     krb5_boolean replace = FALSE;
    289  1.4  christos     krb5_error_code ret;
    290  1.4  christos     HDB_extension *ext;
    291  1.4  christos     HDB_Ext_KeySet *keys;
    292  1.4  christos     hdb_keyset newkeyset;
    293  1.4  christos     time_t newtime;
    294  1.4  christos 
    295  1.4  christos     if (entry->keys.len == 0)
    296  1.4  christos 	return 0; /* nothing to do */
    297  1.4  christos 
    298  1.4  christos     ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
    299  1.4  christos     if (ext == NULL) {
    300  1.4  christos 	replace = TRUE;
    301  1.4  christos 	ext = calloc(1, sizeof (*ext));
    302  1.4  christos 	if (ext == NULL)
    303  1.4  christos 	    return krb5_enomem(context);
    304  1.4  christos 
    305  1.4  christos 	ext->data.element = choice_HDB_extension_data_hist_keys;
    306  1.4  christos     }
    307  1.4  christos     keys = &ext->data.u.hist_keys;
    308  1.4  christos 
    309  1.4  christos     ext->mandatory = FALSE;
    310  1.4  christos 
    311  1.4  christos     /*
    312  1.4  christos      * Copy in newest old keyset
    313  1.4  christos      */
    314  1.4  christos     ret = hdb_entry_get_pw_change_time(entry, &newtime);
    315  1.4  christos     if (ret)
    316  1.4  christos 	goto out;
    317  1.4  christos 
    318  1.4  christos     memset(&newkeyset, 0, sizeof(newkeyset));
    319  1.4  christos     newkeyset.keys = entry->keys;
    320  1.4  christos     newkeyset.kvno = entry->kvno;
    321  1.4  christos     newkeyset.set_time = &newtime;
    322  1.4  christos 
    323  1.4  christos     ret = add_HDB_Ext_KeySet(keys, &newkeyset);
    324  1.4  christos     if (ret)
    325  1.4  christos 	goto out;
    326  1.4  christos 
    327  1.4  christos     if (replace) {
    328  1.4  christos 	/* hdb_replace_extension() deep-copies ext; what a waste */
    329  1.4  christos 	ret = hdb_replace_extension(context, entry, ext);
    330  1.4  christos 	if (ret)
    331  1.4  christos 	    goto out;
    332  1.4  christos     }
    333  1.4  christos 
    334  1.4  christos     ret = hdb_prune_keys(context, entry);
    335  1.4  christos     if (ret)
    336  1.4  christos 	goto out;
    337  1.4  christos 
    338  1.4  christos  out:
    339  1.4  christos     if (replace && ext) {
    340  1.4  christos 	free_HDB_extension(ext);
    341  1.4  christos 	free(ext);
    342  1.4  christos     }
    343  1.4  christos     return ret;
    344  1.4  christos }
    345  1.4  christos 
    346  1.4  christos /**
    347  1.4  christos  * This function adds a key to an HDB entry's key history.
    348  1.4  christos  *
    349  1.4  christos  * @param context   Context
    350  1.4  christos  * @param entry	    HDB entry
    351  1.4  christos  * @param kvno	    Key version number of the key to add to the history
    352  1.4  christos  * @param key	    The Key to add
    353  1.4  christos  */
    354  1.4  christos krb5_error_code
    355  1.4  christos hdb_add_history_key(krb5_context context, hdb_entry *entry, krb5_kvno kvno, Key *key)
    356  1.4  christos {
    357  1.4  christos     size_t i;
    358  1.4  christos     hdb_keyset keyset;
    359  1.4  christos     HDB_Ext_KeySet *hist_keys;
    360  1.4  christos     HDB_extension ext;
    361  1.4  christos     HDB_extension *extp;
    362  1.4  christos     krb5_error_code ret;
    363  1.4  christos 
    364  1.4  christos     memset(&keyset, 0, sizeof (keyset));
    365  1.4  christos     memset(&ext, 0, sizeof (ext));
    366  1.4  christos 
    367  1.4  christos     extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
    368  1.4  christos     if (extp == NULL) {
    369  1.4  christos 	ext.data.element = choice_HDB_extension_data_hist_keys;
    370  1.4  christos 	extp = &ext;
    371  1.4  christos     }
    372  1.4  christos 
    373  1.4  christos     extp->mandatory = FALSE;
    374  1.4  christos     hist_keys = &extp->data.u.hist_keys;
    375  1.4  christos 
    376  1.4  christos     for (i = 0; i < hist_keys->len; i++) {
    377  1.4  christos 	if (hist_keys->val[i].kvno == kvno) {
    378  1.4  christos 	    ret = add_Keys(&hist_keys->val[i].keys, key);
    379  1.4  christos 	    goto out;
    380  1.4  christos 	}
    381  1.4  christos     }
    382  1.4  christos 
    383  1.4  christos     keyset.kvno = kvno;
    384  1.4  christos     ret = add_Keys(&keyset.keys, key);
    385  1.4  christos     if (ret)
    386  1.4  christos 	goto out;
    387  1.4  christos     ret = add_HDB_Ext_KeySet(hist_keys, &keyset);
    388  1.4  christos     if (ret)
    389  1.4  christos 	goto out;
    390  1.4  christos     if (extp == &ext) {
    391  1.4  christos 	ret = hdb_replace_extension(context, entry, &ext);
    392  1.4  christos 	if (ret)
    393  1.4  christos 	    goto out;
    394  1.4  christos     }
    395  1.4  christos 
    396  1.4  christos out:
    397  1.4  christos     free_hdb_keyset(&keyset);
    398  1.4  christos     free_HDB_extension(&ext);
    399  1.4  christos     return ret;
    400  1.4  christos }
    401  1.4  christos 
    402  1.4  christos 
    403  1.4  christos /**
    404  1.4  christos  * This function changes an hdb_entry's kvno, swapping the current key
    405  1.4  christos  * set with a historical keyset.  If no historical keys are found then
    406  1.4  christos  * an error is returned (the caller can still set entry->kvno directly).
    407  1.4  christos  *
    408  1.4  christos  * @param context	krb5_context
    409  1.4  christos  * @param new_kvno	New kvno for the entry
    410  1.4  christos  * @param entry		hdb_entry to modify
    411  1.4  christos  */
    412  1.4  christos krb5_error_code
    413  1.4  christos hdb_change_kvno(krb5_context context, krb5_kvno new_kvno, hdb_entry *entry)
    414  1.4  christos {
    415  1.4  christos     HDB_extension ext;
    416  1.4  christos     HDB_extension *extp;
    417  1.4  christos     hdb_keyset keyset;
    418  1.4  christos     HDB_Ext_KeySet *hist_keys;
    419  1.4  christos     size_t i;
    420  1.4  christos     int found = 0;
    421  1.4  christos     krb5_error_code ret;
    422  1.4  christos 
    423  1.4  christos     if (entry->kvno == new_kvno)
    424  1.4  christos 	return 0;
    425  1.4  christos 
    426  1.4  christos     extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
    427  1.4  christos     if (extp == NULL) {
    428  1.4  christos 	memset(&ext, 0, sizeof (ext));
    429  1.4  christos 	ext.data.element = choice_HDB_extension_data_hist_keys;
    430  1.4  christos 	extp = &ext;
    431  1.4  christos     }
    432  1.4  christos 
    433  1.4  christos     memset(&keyset, 0, sizeof (keyset));
    434  1.4  christos     hist_keys = &extp->data.u.hist_keys;
    435  1.4  christos     for (i = 0; i < hist_keys->len; i++) {
    436  1.4  christos 	if (hist_keys->val[i].kvno == new_kvno) {
    437  1.4  christos 	    found = 1;
    438  1.4  christos 	    ret = copy_hdb_keyset(&hist_keys->val[i], &keyset);
    439  1.4  christos 	    if (ret)
    440  1.4  christos 		goto out;
    441  1.4  christos 	    ret = remove_HDB_Ext_KeySet(hist_keys, i);
    442  1.4  christos 	    if (ret)
    443  1.4  christos 		goto out;
    444  1.4  christos 	    break;
    445  1.4  christos 	}
    446  1.4  christos     }
    447  1.4  christos 
    448  1.4  christos     if (!found)
    449  1.4  christos 	return HDB_ERR_KVNO_NOT_FOUND;
    450  1.4  christos 
    451  1.4  christos     ret = hdb_add_current_keys_to_history(context, entry);
    452  1.4  christos     if (ret)
    453  1.4  christos 	goto out;
    454  1.4  christos 
    455  1.4  christos     /* Note: we do nothing with keyset.set_time */
    456  1.4  christos     entry->kvno = new_kvno;
    457  1.4  christos     entry->keys = keyset.keys; /* shortcut */
    458  1.4  christos     memset(&keyset.keys, 0, sizeof (keyset.keys));
    459  1.4  christos 
    460  1.4  christos out:
    461  1.4  christos     free_hdb_keyset(&keyset);
    462  1.4  christos     return ret;
    463  1.4  christos }
    464  1.4  christos 
    465  1.4  christos 
    466  1.1     elric static krb5_error_code
    467  1.1     elric add_enctype_to_key_set(Key **key_set, size_t *nkeyset,
    468  1.1     elric 		       krb5_enctype enctype, krb5_salt *salt)
    469  1.1     elric {
    470  1.1     elric     krb5_error_code ret;
    471  1.1     elric     Key key, *tmp;
    472  1.1     elric 
    473  1.1     elric     memset(&key, 0, sizeof(key));
    474  1.1     elric 
    475  1.1     elric     tmp = realloc(*key_set, (*nkeyset + 1) * sizeof((*key_set)[0]));
    476  1.1     elric     if (tmp == NULL)
    477  1.1     elric 	return ENOMEM;
    478  1.1     elric 
    479  1.1     elric     *key_set = tmp;
    480  1.1     elric 
    481  1.1     elric     key.key.keytype = enctype;
    482  1.1     elric     key.key.keyvalue.length = 0;
    483  1.1     elric     key.key.keyvalue.data = NULL;
    484  1.1     elric 
    485  1.1     elric     if (salt) {
    486  1.1     elric 	key.salt = calloc(1, sizeof(*key.salt));
    487  1.1     elric 	if (key.salt == NULL) {
    488  1.1     elric 	    free_Key(&key);
    489  1.1     elric 	    return ENOMEM;
    490  1.1     elric 	}
    491  1.2    pettai 
    492  1.1     elric 	key.salt->type = salt->salttype;
    493  1.1     elric 	krb5_data_zero (&key.salt->salt);
    494  1.2    pettai 
    495  1.1     elric 	ret = krb5_data_copy(&key.salt->salt,
    496  1.1     elric 			     salt->saltvalue.data,
    497  1.1     elric 			     salt->saltvalue.length);
    498  1.1     elric 	if (ret) {
    499  1.1     elric 	    free_Key(&key);
    500  1.1     elric 	    return ret;
    501  1.1     elric 	}
    502  1.1     elric     } else
    503  1.1     elric 	key.salt = NULL;
    504  1.1     elric 
    505  1.1     elric     (*key_set)[*nkeyset] = key;
    506  1.1     elric 
    507  1.1     elric     *nkeyset += 1;
    508  1.1     elric 
    509  1.1     elric     return 0;
    510  1.1     elric }
    511  1.1     elric 
    512  1.1     elric 
    513  1.4  christos static
    514  1.4  christos krb5_error_code
    515  1.4  christos ks_tuple2str(krb5_context context, int n_ks_tuple,
    516  1.4  christos 	     krb5_key_salt_tuple *ks_tuple, char ***ks_tuple_strs)
    517  1.4  christos {
    518  1.4  christos 	size_t i;
    519  1.4  christos 	char **ksnames;
    520  1.4  christos 	krb5_error_code rc = KRB5_PROG_ETYPE_NOSUPP;
    521  1.4  christos 
    522  1.4  christos 	*ks_tuple_strs = NULL;
    523  1.4  christos 	if (n_ks_tuple < 1)
    524  1.4  christos 		return 0;
    525  1.4  christos 
    526  1.4  christos 	if ((ksnames = calloc(n_ks_tuple + 1, sizeof (*ksnames))) == NULL)
    527  1.4  christos 		return (errno);
    528  1.4  christos 
    529  1.4  christos 	for (i = 0; i < n_ks_tuple; i++) {
    530  1.4  christos             char *ename, *sname;
    531  1.4  christos 
    532  1.4  christos 	    if (krb5_enctype_to_string(context, ks_tuple[i].ks_enctype, &ename))
    533  1.4  christos 		goto out;
    534  1.4  christos 	    if (krb5_salttype_to_string(context, ks_tuple[i].ks_enctype,
    535  1.4  christos 					ks_tuple[i].ks_salttype, &sname)) {
    536  1.4  christos                 free(ename);
    537  1.4  christos 		goto out;
    538  1.4  christos             }
    539  1.4  christos 
    540  1.4  christos 	    if (asprintf(&ksnames[i], "%s:%s", ename, sname) == -1) {
    541  1.4  christos 		    rc = errno;
    542  1.4  christos 		    free(ename);
    543  1.4  christos 		    free(sname);
    544  1.4  christos 		    goto out;
    545  1.4  christos 	    }
    546  1.4  christos 	    free(ename);
    547  1.4  christos 	    free(sname);
    548  1.4  christos 	}
    549  1.4  christos 
    550  1.4  christos 	ksnames[i] = NULL;
    551  1.4  christos 	*ks_tuple_strs = ksnames;
    552  1.4  christos 	return 0;
    553  1.4  christos 
    554  1.4  christos out:
    555  1.4  christos 	for (i = 0; i < n_ks_tuple; i++)
    556  1.4  christos 		free(ksnames[i]);
    557  1.4  christos 	free(ksnames);
    558  1.4  christos 	return (rc);
    559  1.4  christos }
    560  1.4  christos 
    561  1.4  christos /*
    562  1.4  christos  *
    563  1.4  christos  */
    564  1.4  christos 
    565  1.4  christos static char **
    566  1.4  christos glob_rules_keys(krb5_context context, krb5_const_principal principal)
    567  1.4  christos {
    568  1.4  christos     const krb5_config_binding *list;
    569  1.4  christos     krb5_principal pattern;
    570  1.4  christos     krb5_error_code ret;
    571  1.4  christos 
    572  1.4  christos     list = krb5_config_get_list(context, NULL, "kadmin",
    573  1.4  christos 				"default_key_rules", NULL);
    574  1.4  christos     if (list == NULL)
    575  1.4  christos 	return NULL;
    576  1.4  christos 
    577  1.4  christos     while (list) {
    578  1.4  christos 	if (list->type == krb5_config_string) {
    579  1.4  christos 	    ret = krb5_parse_name(context, list->name, &pattern);
    580  1.4  christos 	    if (ret == 0) {
    581  1.4  christos 		ret = krb5_principal_match(context, principal, pattern);
    582  1.4  christos 		krb5_free_principal(context, pattern);
    583  1.4  christos 		if (ret) {
    584  1.4  christos 		    return krb5_config_get_strings(context, list,
    585  1.4  christos 						   list->name, NULL);
    586  1.4  christos 		}
    587  1.4  christos 	    }
    588  1.4  christos 	}
    589  1.4  christos 	list = list->next;
    590  1.4  christos     }
    591  1.4  christos     return NULL;
    592  1.4  christos }
    593  1.4  christos 
    594  1.4  christos /*
    595  1.4  christos  * NIST guidance in Section 5.1 of [SP800-132] requires that a portion
    596  1.4  christos  * of the salt of at least 128 bits shall be randomly generated.
    597  1.4  christos  */
    598  1.4  christos static krb5_error_code
    599  1.4  christos add_random_to_salt(krb5_context context, krb5_salt *in, krb5_salt *out)
    600  1.4  christos {
    601  1.4  christos     krb5_error_code ret;
    602  1.4  christos     char *p;
    603  1.4  christos     unsigned char random[16];
    604  1.4  christos     char *s;
    605  1.4  christos     int slen;
    606  1.4  christos 
    607  1.4  christos     krb5_generate_random_block(random, sizeof(random));
    608  1.4  christos 
    609  1.4  christos     slen = rk_base64_encode(random, sizeof(random), &s);
    610  1.4  christos     if (slen < 0)
    611  1.4  christos 	return ENOMEM;
    612  1.4  christos 
    613  1.4  christos     ret = krb5_data_alloc(&out->saltvalue, slen + in->saltvalue.length);
    614  1.4  christos     if (ret) {
    615  1.4  christos 	free(s);
    616  1.4  christos 	return ret;
    617  1.4  christos     }
    618  1.4  christos 
    619  1.4  christos     p = out->saltvalue.data;
    620  1.4  christos     memcpy(p, s, slen);
    621  1.4  christos     memcpy(&p[slen], in->saltvalue.data, in->saltvalue.length);
    622  1.4  christos 
    623  1.4  christos     out->salttype = in->salttype;
    624  1.4  christos     free(s);
    625  1.4  christos 
    626  1.4  christos     return 0;
    627  1.4  christos }
    628  1.4  christos 
    629  1.1     elric /*
    630  1.1     elric  * Generate the `key_set' from the [kadmin]default_keys statement. If
    631  1.1     elric  * `no_salt' is set, salt is not important (and will not be set) since
    632  1.1     elric  * it's random keys that is going to be created.
    633  1.1     elric  */
    634  1.1     elric 
    635  1.1     elric krb5_error_code
    636  1.1     elric hdb_generate_key_set(krb5_context context, krb5_principal principal,
    637  1.4  christos 		     krb5_key_salt_tuple *ks_tuple, int n_ks_tuple,
    638  1.1     elric 		     Key **ret_key_set, size_t *nkeyset, int no_salt)
    639  1.1     elric {
    640  1.4  christos     char **ktypes = NULL;
    641  1.4  christos     char **kp;
    642  1.1     elric     krb5_error_code ret;
    643  1.1     elric     Key *k, *key_set;
    644  1.2    pettai     size_t i, j;
    645  1.4  christos     char **ks_tuple_strs;
    646  1.4  christos     char **config_ktypes = NULL;
    647  1.2    pettai     static const char *default_keytypes[] = {
    648  1.1     elric 	"aes256-cts-hmac-sha1-96:pw-salt",
    649  1.1     elric 	"des3-cbc-sha1:pw-salt",
    650  1.1     elric 	"arcfour-hmac-md5:pw-salt",
    651  1.1     elric 	NULL
    652  1.1     elric     };
    653  1.1     elric 
    654  1.4  christos     if ((ret = ks_tuple2str(context, n_ks_tuple, ks_tuple, &ks_tuple_strs)))
    655  1.4  christos 	    return ret;
    656  1.4  christos 
    657  1.4  christos     ktypes = ks_tuple_strs;
    658  1.4  christos     if (ktypes == NULL) {
    659  1.4  christos 	ktypes = glob_rules_keys(context, principal);
    660  1.4  christos     }
    661  1.4  christos     if (ktypes == NULL) {
    662  1.4  christos 	config_ktypes = krb5_config_get_strings(context, NULL, "kadmin",
    663  1.4  christos 						"default_keys", NULL);
    664  1.4  christos 	ktypes = config_ktypes;
    665  1.4  christos     }
    666  1.1     elric     if (ktypes == NULL)
    667  1.2    pettai 	ktypes = (char **)(intptr_t)default_keytypes;
    668  1.1     elric 
    669  1.1     elric     *ret_key_set = key_set = NULL;
    670  1.1     elric     *nkeyset = 0;
    671  1.1     elric 
    672  1.1     elric     for(kp = ktypes; kp && *kp; kp++) {
    673  1.1     elric 	const char *p;
    674  1.1     elric 	krb5_salt salt;
    675  1.1     elric 	krb5_enctype *enctypes;
    676  1.1     elric 	size_t num_enctypes;
    677  1.1     elric 
    678  1.1     elric 	p = *kp;
    679  1.1     elric 	/* check alias */
    680  1.1     elric 	if(strcmp(p, "v5") == 0)
    681  1.1     elric 	    p = "pw-salt";
    682  1.1     elric 	else if(strcmp(p, "v4") == 0)
    683  1.1     elric 	    p = "des:pw-salt:";
    684  1.1     elric 	else if(strcmp(p, "afs") == 0 || strcmp(p, "afs3") == 0)
    685  1.1     elric 	    p = "des:afs3-salt";
    686  1.1     elric 	else if (strcmp(p, "arcfour-hmac-md5") == 0)
    687  1.1     elric 	    p = "arcfour-hmac-md5:pw-salt";
    688  1.2    pettai 
    689  1.1     elric 	memset(&salt, 0, sizeof(salt));
    690  1.1     elric 
    691  1.1     elric 	ret = parse_key_set(context, p,
    692  1.1     elric 			    &enctypes, &num_enctypes, &salt, principal);
    693  1.1     elric 	if (ret) {
    694  1.1     elric 	    krb5_warn(context, ret, "bad value for default_keys `%s'", *kp);
    695  1.1     elric 	    ret = 0;
    696  1.4  christos             krb5_free_salt(context, salt);
    697  1.1     elric 	    continue;
    698  1.1     elric 	}
    699  1.1     elric 
    700  1.1     elric 	for (i = 0; i < num_enctypes; i++) {
    701  1.4  christos 	    krb5_salt *saltp = no_salt ? NULL : &salt;
    702  1.4  christos 	    krb5_salt rsalt;
    703  1.4  christos 
    704  1.1     elric 	    /* find duplicates */
    705  1.1     elric 	    for (j = 0; j < *nkeyset; j++) {
    706  1.1     elric 
    707  1.1     elric 		k = &key_set[j];
    708  1.1     elric 
    709  1.1     elric 		if (k->key.keytype == enctypes[i]) {
    710  1.1     elric 		    if (no_salt)
    711  1.1     elric 			break;
    712  1.1     elric 		    if (k->salt == NULL && salt.salttype == KRB5_PW_SALT)
    713  1.1     elric 			break;
    714  1.1     elric 		    if (k->salt->type == salt.salttype &&
    715  1.1     elric 			k->salt->salt.length == salt.saltvalue.length &&
    716  1.1     elric 			memcmp(k->salt->salt.data, salt.saltvalue.data,
    717  1.1     elric 			       salt.saltvalue.length) == 0)
    718  1.1     elric 			break;
    719  1.1     elric 		}
    720  1.1     elric 	    }
    721  1.1     elric 	    /* not a duplicate, lets add it */
    722  1.4  christos 	    if (j < *nkeyset)
    723  1.4  christos 		continue;
    724  1.4  christos 
    725  1.4  christos 	    memset(&rsalt, 0, sizeof(rsalt));
    726  1.4  christos 
    727  1.4  christos 	    /* prepend salt with randomness if required */
    728  1.4  christos 	    if (!no_salt &&
    729  1.4  christos 		_krb5_enctype_requires_random_salt(context, enctypes[i])) {
    730  1.4  christos 		saltp = &rsalt;
    731  1.4  christos 		ret = add_random_to_salt(context, &salt, &rsalt);
    732  1.4  christos 	    }
    733  1.4  christos 
    734  1.4  christos 	    if (ret == 0)
    735  1.1     elric 		ret = add_enctype_to_key_set(&key_set, nkeyset, enctypes[i],
    736  1.4  christos 					     saltp);
    737  1.4  christos 	    krb5_free_salt(context, rsalt);
    738  1.4  christos 
    739  1.4  christos 	    if (ret) {
    740  1.4  christos 		free(enctypes);
    741  1.4  christos 		krb5_free_salt(context, salt);
    742  1.4  christos 		goto out;
    743  1.1     elric 	    }
    744  1.1     elric 	}
    745  1.1     elric 	free(enctypes);
    746  1.1     elric 	krb5_free_salt(context, salt);
    747  1.1     elric     }
    748  1.1     elric 
    749  1.1     elric     *ret_key_set = key_set;
    750  1.1     elric 
    751  1.1     elric  out:
    752  1.4  christos     if (config_ktypes != NULL)
    753  1.4  christos 	krb5_config_free_strings(config_ktypes);
    754  1.4  christos 
    755  1.4  christos     for(kp = ks_tuple_strs; kp && *kp; kp++)
    756  1.4  christos 	free(*kp);
    757  1.4  christos     free(ks_tuple_strs);
    758  1.1     elric 
    759  1.1     elric     if (ret) {
    760  1.1     elric 	krb5_warn(context, ret,
    761  1.1     elric 		  "failed to parse the [kadmin]default_keys values");
    762  1.1     elric 
    763  1.1     elric 	for (i = 0; i < *nkeyset; i++)
    764  1.1     elric 	    free_Key(&key_set[i]);
    765  1.1     elric 	free(key_set);
    766  1.1     elric     } else if (*nkeyset == 0) {
    767  1.1     elric 	krb5_warnx(context,
    768  1.1     elric 		   "failed to parse any of the [kadmin]default_keys values");
    769  1.1     elric 	ret = EINVAL; /* XXX */
    770  1.1     elric     }
    771  1.1     elric 
    772  1.1     elric     return ret;
    773  1.1     elric }
    774  1.1     elric 
    775  1.1     elric 
    776  1.1     elric krb5_error_code
    777  1.5  christos hdb_generate_key_set_password_with_ks_tuple(krb5_context context,
    778  1.5  christos 					    krb5_principal principal,
    779  1.5  christos 					    const char *password,
    780  1.5  christos 					    krb5_key_salt_tuple *ks_tuple,
    781  1.5  christos 					    int n_ks_tuple,
    782  1.5  christos 					    Key **keys, size_t *num_keys)
    783  1.1     elric {
    784  1.1     elric     krb5_error_code ret;
    785  1.2    pettai     size_t i;
    786  1.1     elric 
    787  1.4  christos     ret = hdb_generate_key_set(context, principal, ks_tuple, n_ks_tuple,
    788  1.1     elric 				keys, num_keys, 0);
    789  1.1     elric     if (ret)
    790  1.1     elric 	return ret;
    791  1.1     elric 
    792  1.1     elric     for (i = 0; i < (*num_keys); i++) {
    793  1.1     elric 	krb5_salt salt;
    794  1.4  christos 	Key *key = &(*keys)[i];
    795  1.1     elric 
    796  1.4  christos 	salt.salttype = key->salt->type;
    797  1.4  christos 	salt.saltvalue.length = key->salt->salt.length;
    798  1.4  christos 	salt.saltvalue.data = key->salt->salt.data;
    799  1.1     elric 
    800  1.1     elric 	ret = krb5_string_to_key_salt (context,
    801  1.4  christos 				       key->key.keytype,
    802  1.1     elric 				       password,
    803  1.1     elric 				       salt,
    804  1.4  christos 				       &key->key);
    805  1.1     elric 	if(ret)
    806  1.1     elric 	    break;
    807  1.1     elric     }
    808  1.1     elric 
    809  1.1     elric     if(ret) {
    810  1.1     elric 	hdb_free_keys (context, *num_keys, *keys);
    811  1.1     elric 	return ret;
    812  1.1     elric     }
    813  1.1     elric     return ret;
    814  1.1     elric }
    815  1.5  christos 
    816  1.5  christos 
    817  1.5  christos krb5_error_code
    818  1.5  christos hdb_generate_key_set_password(krb5_context context,
    819  1.5  christos 			      krb5_principal principal,
    820  1.5  christos 			      const char *password,
    821  1.5  christos 			      Key **keys, size_t *num_keys)
    822  1.5  christos {
    823  1.5  christos 
    824  1.5  christos     return hdb_generate_key_set_password_with_ks_tuple(context, principal,
    825  1.5  christos 						       password, NULL, 0,
    826  1.5  christos 						       keys, num_keys);
    827  1.5  christos }
    828