xref: /freebsd/crypto/heimdal/lib/hdb/mkey.c (revision 5e9cd1ae3e10592ed70e7575551cba1bbab04d84)
15e9cd1aeSAssar Westerlund /*
25e9cd1aeSAssar Westerlund  * Copyright (c) 2000 - 2001 Kungliga Tekniska H�gskolan
35e9cd1aeSAssar Westerlund  * (Royal Institute of Technology, Stockholm, Sweden).
45e9cd1aeSAssar Westerlund  * All rights reserved.
55e9cd1aeSAssar Westerlund  *
65e9cd1aeSAssar Westerlund  * Redistribution and use in source and binary forms, with or without
75e9cd1aeSAssar Westerlund  * modification, are permitted provided that the following conditions
85e9cd1aeSAssar Westerlund  * are met:
95e9cd1aeSAssar Westerlund  *
105e9cd1aeSAssar Westerlund  * 1. Redistributions of source code must retain the above copyright
115e9cd1aeSAssar Westerlund  *    notice, this list of conditions and the following disclaimer.
125e9cd1aeSAssar Westerlund  *
135e9cd1aeSAssar Westerlund  * 2. Redistributions in binary form must reproduce the above copyright
145e9cd1aeSAssar Westerlund  *    notice, this list of conditions and the following disclaimer in the
155e9cd1aeSAssar Westerlund  *    documentation and/or other materials provided with the distribution.
165e9cd1aeSAssar Westerlund  *
175e9cd1aeSAssar Westerlund  * 3. Neither the name of the Institute nor the names of its contributors
185e9cd1aeSAssar Westerlund  *    may be used to endorse or promote products derived from this software
195e9cd1aeSAssar Westerlund  *    without specific prior written permission.
205e9cd1aeSAssar Westerlund  *
215e9cd1aeSAssar Westerlund  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
225e9cd1aeSAssar Westerlund  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
235e9cd1aeSAssar Westerlund  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
245e9cd1aeSAssar Westerlund  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
255e9cd1aeSAssar Westerlund  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
265e9cd1aeSAssar Westerlund  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
275e9cd1aeSAssar Westerlund  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
285e9cd1aeSAssar Westerlund  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
295e9cd1aeSAssar Westerlund  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
305e9cd1aeSAssar Westerlund  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
315e9cd1aeSAssar Westerlund  * SUCH DAMAGE.
325e9cd1aeSAssar Westerlund  */
335e9cd1aeSAssar Westerlund 
345e9cd1aeSAssar Westerlund #include "hdb_locl.h"
355e9cd1aeSAssar Westerlund #ifndef O_BINARY
365e9cd1aeSAssar Westerlund #define O_BINARY 0
375e9cd1aeSAssar Westerlund #endif
385e9cd1aeSAssar Westerlund 
395e9cd1aeSAssar Westerlund RCSID("$Id: mkey.c,v 1.8 2001/01/30 01:20:57 assar Exp $");
405e9cd1aeSAssar Westerlund 
415e9cd1aeSAssar Westerlund struct hdb_master_key_data {
425e9cd1aeSAssar Westerlund     krb5_keytab_entry keytab;
435e9cd1aeSAssar Westerlund     krb5_crypto crypto;
445e9cd1aeSAssar Westerlund     struct hdb_master_key_data *next;
455e9cd1aeSAssar Westerlund };
465e9cd1aeSAssar Westerlund 
475e9cd1aeSAssar Westerlund void
485e9cd1aeSAssar Westerlund hdb_free_master_key(krb5_context context, hdb_master_key mkey)
495e9cd1aeSAssar Westerlund {
505e9cd1aeSAssar Westerlund     struct hdb_master_key_data *ptr;
515e9cd1aeSAssar Westerlund     while(mkey) {
525e9cd1aeSAssar Westerlund 	krb5_kt_free_entry(context, &mkey->keytab);
535e9cd1aeSAssar Westerlund 	krb5_crypto_destroy(context, mkey->crypto);
545e9cd1aeSAssar Westerlund 	ptr = mkey;
555e9cd1aeSAssar Westerlund 	mkey = mkey->next;
565e9cd1aeSAssar Westerlund 	free(ptr);
575e9cd1aeSAssar Westerlund     }
585e9cd1aeSAssar Westerlund }
595e9cd1aeSAssar Westerlund 
605e9cd1aeSAssar Westerlund krb5_error_code
615e9cd1aeSAssar Westerlund hdb_process_master_key(krb5_context context,
625e9cd1aeSAssar Westerlund 		       int kvno, krb5_keyblock *key, krb5_enctype etype,
635e9cd1aeSAssar Westerlund 		       hdb_master_key *mkey)
645e9cd1aeSAssar Westerlund {
655e9cd1aeSAssar Westerlund     krb5_error_code ret;
665e9cd1aeSAssar Westerlund     *mkey = calloc(1, sizeof(**mkey));
675e9cd1aeSAssar Westerlund     if(*mkey == NULL)
685e9cd1aeSAssar Westerlund 	return ENOMEM;
695e9cd1aeSAssar Westerlund     (*mkey)->keytab.vno = kvno;
705e9cd1aeSAssar Westerlund     ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal);
715e9cd1aeSAssar Westerlund     ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock);
725e9cd1aeSAssar Westerlund     if(ret) {
735e9cd1aeSAssar Westerlund 	free(*mkey);
745e9cd1aeSAssar Westerlund 	*mkey = NULL;
755e9cd1aeSAssar Westerlund 	return ret;
765e9cd1aeSAssar Westerlund     }
775e9cd1aeSAssar Westerlund     if(etype != 0)
785e9cd1aeSAssar Westerlund 	(*mkey)->keytab.keyblock.keytype = etype;
795e9cd1aeSAssar Westerlund     (*mkey)->keytab.timestamp = time(NULL);
805e9cd1aeSAssar Westerlund     ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto);
815e9cd1aeSAssar Westerlund     if(ret) {
825e9cd1aeSAssar Westerlund 	krb5_free_keyblock_contents(context, &(*mkey)->keytab.keyblock);
835e9cd1aeSAssar Westerlund 	free(*mkey);
845e9cd1aeSAssar Westerlund 	*mkey = NULL;
855e9cd1aeSAssar Westerlund     }
865e9cd1aeSAssar Westerlund     return ret;
875e9cd1aeSAssar Westerlund }
885e9cd1aeSAssar Westerlund 
895e9cd1aeSAssar Westerlund krb5_error_code
905e9cd1aeSAssar Westerlund hdb_add_master_key(krb5_context context, krb5_keyblock *key,
915e9cd1aeSAssar Westerlund 		   hdb_master_key *inout)
925e9cd1aeSAssar Westerlund {
935e9cd1aeSAssar Westerlund     int vno = 0;
945e9cd1aeSAssar Westerlund     hdb_master_key p;
955e9cd1aeSAssar Westerlund     krb5_error_code ret;
965e9cd1aeSAssar Westerlund 
975e9cd1aeSAssar Westerlund     for(p = *inout; p; p = p->next)
985e9cd1aeSAssar Westerlund 	vno = max(vno, p->keytab.vno);
995e9cd1aeSAssar Westerlund     vno++;
1005e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, vno, key, 0, &p);
1015e9cd1aeSAssar Westerlund     if(ret)
1025e9cd1aeSAssar Westerlund 	return ret;
1035e9cd1aeSAssar Westerlund     p->next = *inout;
1045e9cd1aeSAssar Westerlund     *inout = p;
1055e9cd1aeSAssar Westerlund     return 0;
1065e9cd1aeSAssar Westerlund }
1075e9cd1aeSAssar Westerlund 
1085e9cd1aeSAssar Westerlund static krb5_error_code
1095e9cd1aeSAssar Westerlund read_master_keytab(krb5_context context, const char *filename,
1105e9cd1aeSAssar Westerlund 		   hdb_master_key *mkey)
1115e9cd1aeSAssar Westerlund {
1125e9cd1aeSAssar Westerlund     krb5_error_code ret;
1135e9cd1aeSAssar Westerlund     krb5_keytab id;
1145e9cd1aeSAssar Westerlund     krb5_kt_cursor cursor;
1155e9cd1aeSAssar Westerlund     krb5_keytab_entry entry;
1165e9cd1aeSAssar Westerlund     hdb_master_key p;
1175e9cd1aeSAssar Westerlund 
1185e9cd1aeSAssar Westerlund     ret = krb5_kt_resolve(context, filename, &id);
1195e9cd1aeSAssar Westerlund     if(ret)
1205e9cd1aeSAssar Westerlund 	return ret;
1215e9cd1aeSAssar Westerlund 
1225e9cd1aeSAssar Westerlund     ret = krb5_kt_start_seq_get(context, id, &cursor);
1235e9cd1aeSAssar Westerlund     if(ret)
1245e9cd1aeSAssar Westerlund 	goto out;
1255e9cd1aeSAssar Westerlund     *mkey = NULL;
1265e9cd1aeSAssar Westerlund     while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) {
1275e9cd1aeSAssar Westerlund 	p = calloc(1, sizeof(*p));
1285e9cd1aeSAssar Westerlund 	p->keytab = entry;
1295e9cd1aeSAssar Westerlund 	ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto);
1305e9cd1aeSAssar Westerlund 	p->next = *mkey;
1315e9cd1aeSAssar Westerlund 	*mkey = p;
1325e9cd1aeSAssar Westerlund     }
1335e9cd1aeSAssar Westerlund     krb5_kt_end_seq_get(context, id, &cursor);
1345e9cd1aeSAssar Westerlund   out:
1355e9cd1aeSAssar Westerlund     krb5_kt_close(context, id);
1365e9cd1aeSAssar Westerlund     return ret;
1375e9cd1aeSAssar Westerlund }
1385e9cd1aeSAssar Westerlund 
1395e9cd1aeSAssar Westerlund /* read a MIT master keyfile */
1405e9cd1aeSAssar Westerlund static krb5_error_code
1415e9cd1aeSAssar Westerlund read_master_mit(krb5_context context, const char *filename,
1425e9cd1aeSAssar Westerlund 		hdb_master_key *mkey)
1435e9cd1aeSAssar Westerlund {
1445e9cd1aeSAssar Westerlund     int fd;
1455e9cd1aeSAssar Westerlund     krb5_error_code ret;
1465e9cd1aeSAssar Westerlund     krb5_storage *sp;
1475e9cd1aeSAssar Westerlund     u_int16_t enctype;
1485e9cd1aeSAssar Westerlund     krb5_keyblock key;
1495e9cd1aeSAssar Westerlund 
1505e9cd1aeSAssar Westerlund     fd = open(filename, O_RDONLY | O_BINARY);
1515e9cd1aeSAssar Westerlund     if(fd < 0)
1525e9cd1aeSAssar Westerlund 	return errno;
1535e9cd1aeSAssar Westerlund     sp = krb5_storage_from_fd(fd);
1545e9cd1aeSAssar Westerlund     if(sp == NULL) {
1555e9cd1aeSAssar Westerlund 	close(fd);
1565e9cd1aeSAssar Westerlund 	return errno;
1575e9cd1aeSAssar Westerlund     }
1585e9cd1aeSAssar Westerlund     krb5_storage_set_flags(sp, KRB5_STORAGE_HOST_BYTEORDER);
1595e9cd1aeSAssar Westerlund #if 0
1605e9cd1aeSAssar Westerlund     /* could possibly use ret_keyblock here, but do it with more
1615e9cd1aeSAssar Westerlund        checks for now */
1625e9cd1aeSAssar Westerlund     ret = krb5_ret_keyblock(sp, &key);
1635e9cd1aeSAssar Westerlund #else
1645e9cd1aeSAssar Westerlund     ret = krb5_ret_int16(sp, &enctype);
1655e9cd1aeSAssar Westerlund     if((htons(enctype) & 0xff00) == 0x3000) {
1665e9cd1aeSAssar Westerlund 	ret = HEIM_ERR_BAD_MKEY;
1675e9cd1aeSAssar Westerlund 	goto out;
1685e9cd1aeSAssar Westerlund     }
1695e9cd1aeSAssar Westerlund     key.keytype = enctype;
1705e9cd1aeSAssar Westerlund     ret = krb5_ret_data(sp, &key.keyvalue);
1715e9cd1aeSAssar Westerlund     if(ret)
1725e9cd1aeSAssar Westerlund 	goto out;
1735e9cd1aeSAssar Westerlund #endif
1745e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, 0, &key, 0, mkey);
1755e9cd1aeSAssar Westerlund     krb5_free_keyblock_contents(context, &key);
1765e9cd1aeSAssar Westerlund   out:
1775e9cd1aeSAssar Westerlund     krb5_storage_free(sp);
1785e9cd1aeSAssar Westerlund     close(fd);
1795e9cd1aeSAssar Westerlund     return ret;
1805e9cd1aeSAssar Westerlund }
1815e9cd1aeSAssar Westerlund 
1825e9cd1aeSAssar Westerlund /* read an old master key file */
1835e9cd1aeSAssar Westerlund static krb5_error_code
1845e9cd1aeSAssar Westerlund read_master_encryptionkey(krb5_context context, const char *filename,
1855e9cd1aeSAssar Westerlund 			  hdb_master_key *mkey)
1865e9cd1aeSAssar Westerlund {
1875e9cd1aeSAssar Westerlund     int fd;
1885e9cd1aeSAssar Westerlund     krb5_keyblock key;
1895e9cd1aeSAssar Westerlund     krb5_error_code ret;
1905e9cd1aeSAssar Westerlund     unsigned char buf[256];
1915e9cd1aeSAssar Westerlund     ssize_t len;
1925e9cd1aeSAssar Westerlund 
1935e9cd1aeSAssar Westerlund     fd = open(filename, O_RDONLY | O_BINARY);
1945e9cd1aeSAssar Westerlund     if(fd < 0)
1955e9cd1aeSAssar Westerlund 	return errno;
1965e9cd1aeSAssar Westerlund 
1975e9cd1aeSAssar Westerlund     len = read(fd, buf, sizeof(buf));
1985e9cd1aeSAssar Westerlund     close(fd);
1995e9cd1aeSAssar Westerlund     if(len < 0)
2005e9cd1aeSAssar Westerlund 	return errno;
2015e9cd1aeSAssar Westerlund 
2025e9cd1aeSAssar Westerlund     ret = decode_EncryptionKey(buf, len, &key, &len);
2035e9cd1aeSAssar Westerlund     memset(buf, 0, sizeof(buf));
2045e9cd1aeSAssar Westerlund     if(ret)
2055e9cd1aeSAssar Westerlund 	return ret;
2065e9cd1aeSAssar Westerlund 
2075e9cd1aeSAssar Westerlund     /* Originally, the keytype was just that, and later it got changed
2085e9cd1aeSAssar Westerlund        to des-cbc-md5, but we always used des in cfb64 mode. This
2095e9cd1aeSAssar Westerlund        should cover all cases, but will break if someone has hacked
2105e9cd1aeSAssar Westerlund        this code to really use des-cbc-md5 -- but then that's not my
2115e9cd1aeSAssar Westerlund        problem. */
2125e9cd1aeSAssar Westerlund     if(key.keytype == KEYTYPE_DES || key.keytype == ETYPE_DES_CBC_MD5)
2135e9cd1aeSAssar Westerlund 	key.keytype = ETYPE_DES_CFB64_NONE;
2145e9cd1aeSAssar Westerlund 
2155e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, 0, &key, 0, mkey);
2165e9cd1aeSAssar Westerlund     krb5_free_keyblock_contents(context, &key);
2175e9cd1aeSAssar Westerlund     return ret;
2185e9cd1aeSAssar Westerlund }
2195e9cd1aeSAssar Westerlund 
2205e9cd1aeSAssar Westerlund /* read a krb4 /.k style file */
2215e9cd1aeSAssar Westerlund static krb5_error_code
2225e9cd1aeSAssar Westerlund read_master_krb4(krb5_context context, const char *filename,
2235e9cd1aeSAssar Westerlund 		 hdb_master_key *mkey)
2245e9cd1aeSAssar Westerlund {
2255e9cd1aeSAssar Westerlund     int fd;
2265e9cd1aeSAssar Westerlund     krb5_keyblock key;
2275e9cd1aeSAssar Westerlund     krb5_error_code ret;
2285e9cd1aeSAssar Westerlund     unsigned char buf[256];
2295e9cd1aeSAssar Westerlund     ssize_t len;
2305e9cd1aeSAssar Westerlund 
2315e9cd1aeSAssar Westerlund     fd = open(filename, O_RDONLY | O_BINARY);
2325e9cd1aeSAssar Westerlund     if(fd < 0)
2335e9cd1aeSAssar Westerlund 	return errno;
2345e9cd1aeSAssar Westerlund 
2355e9cd1aeSAssar Westerlund     len = read(fd, buf, sizeof(buf));
2365e9cd1aeSAssar Westerlund     close(fd);
2375e9cd1aeSAssar Westerlund     if(len < 0)
2385e9cd1aeSAssar Westerlund 	return errno;
2395e9cd1aeSAssar Westerlund 
2405e9cd1aeSAssar Westerlund     memset(&key, 0, sizeof(key));
2415e9cd1aeSAssar Westerlund     key.keytype = ETYPE_DES_PCBC_NONE;
2425e9cd1aeSAssar Westerlund     ret = krb5_data_copy(&key.keyvalue, buf, len);
2435e9cd1aeSAssar Westerlund     memset(buf, 0, sizeof(buf));
2445e9cd1aeSAssar Westerlund     if(ret)
2455e9cd1aeSAssar Westerlund 	return ret;
2465e9cd1aeSAssar Westerlund 
2475e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, 0, &key, 0, mkey);
2485e9cd1aeSAssar Westerlund     krb5_free_keyblock_contents(context, &key);
2495e9cd1aeSAssar Westerlund     return ret;
2505e9cd1aeSAssar Westerlund }
2515e9cd1aeSAssar Westerlund 
2525e9cd1aeSAssar Westerlund krb5_error_code
2535e9cd1aeSAssar Westerlund hdb_read_master_key(krb5_context context, const char *filename,
2545e9cd1aeSAssar Westerlund 		    hdb_master_key *mkey)
2555e9cd1aeSAssar Westerlund {
2565e9cd1aeSAssar Westerlund     FILE *f;
2575e9cd1aeSAssar Westerlund     unsigned char buf[16];
2585e9cd1aeSAssar Westerlund     krb5_error_code ret;
2595e9cd1aeSAssar Westerlund 
2605e9cd1aeSAssar Westerlund     off_t len;
2615e9cd1aeSAssar Westerlund 
2625e9cd1aeSAssar Westerlund     *mkey = NULL;
2635e9cd1aeSAssar Westerlund 
2645e9cd1aeSAssar Westerlund     if(filename == NULL)
2655e9cd1aeSAssar Westerlund 	filename = HDB_DB_DIR "/m-key";
2665e9cd1aeSAssar Westerlund 
2675e9cd1aeSAssar Westerlund     f = fopen(filename, "r");
2685e9cd1aeSAssar Westerlund     if(f == NULL)
2695e9cd1aeSAssar Westerlund 	return errno;
2705e9cd1aeSAssar Westerlund 
2715e9cd1aeSAssar Westerlund     if(fread(buf, 1, 2, f) != 2) {
2725e9cd1aeSAssar Westerlund 	fclose(f);
2735e9cd1aeSAssar Westerlund 	return HEIM_ERR_EOF;
2745e9cd1aeSAssar Westerlund     }
2755e9cd1aeSAssar Westerlund 
2765e9cd1aeSAssar Westerlund     fseek(f, 0, SEEK_END);
2775e9cd1aeSAssar Westerlund     len = ftell(f);
2785e9cd1aeSAssar Westerlund 
2795e9cd1aeSAssar Westerlund     if(fclose(f) != 0)
2805e9cd1aeSAssar Westerlund 	return errno;
2815e9cd1aeSAssar Westerlund 
2825e9cd1aeSAssar Westerlund     if(len < 0)
2835e9cd1aeSAssar Westerlund 	return errno;
2845e9cd1aeSAssar Westerlund 
2855e9cd1aeSAssar Westerlund     if(len == 8) {
2865e9cd1aeSAssar Westerlund 	ret = read_master_krb4(context, filename, mkey);
2875e9cd1aeSAssar Westerlund     } else if(buf[0] == 0x30 && len <= 127 && buf[1] == len - 2) {
2885e9cd1aeSAssar Westerlund 	ret = read_master_encryptionkey(context, filename, mkey);
2895e9cd1aeSAssar Westerlund     } else if(buf[0] == 5 && buf[1] >= 1 && buf[1] <= 2) {
2905e9cd1aeSAssar Westerlund 	ret = read_master_keytab(context, filename, mkey);
2915e9cd1aeSAssar Westerlund     } else {
2925e9cd1aeSAssar Westerlund 	ret = read_master_mit(context, filename, mkey);
2935e9cd1aeSAssar Westerlund     }
2945e9cd1aeSAssar Westerlund     return ret;
2955e9cd1aeSAssar Westerlund }
2965e9cd1aeSAssar Westerlund 
2975e9cd1aeSAssar Westerlund krb5_error_code
2985e9cd1aeSAssar Westerlund hdb_write_master_key(krb5_context context, const char *filename,
2995e9cd1aeSAssar Westerlund 		     hdb_master_key mkey)
3005e9cd1aeSAssar Westerlund {
3015e9cd1aeSAssar Westerlund     krb5_error_code ret;
3025e9cd1aeSAssar Westerlund     hdb_master_key p;
3035e9cd1aeSAssar Westerlund     krb5_keytab kt;
3045e9cd1aeSAssar Westerlund 
3055e9cd1aeSAssar Westerlund     if(filename == NULL)
3065e9cd1aeSAssar Westerlund 	filename = HDB_DB_DIR "/m-key";
3075e9cd1aeSAssar Westerlund 
3085e9cd1aeSAssar Westerlund     ret = krb5_kt_resolve(context, filename, &kt);
3095e9cd1aeSAssar Westerlund     if(ret)
3105e9cd1aeSAssar Westerlund 	return ret;
3115e9cd1aeSAssar Westerlund 
3125e9cd1aeSAssar Westerlund     for(p = mkey; p; p = p->next) {
3135e9cd1aeSAssar Westerlund 	ret = krb5_kt_add_entry(context, kt, &p->keytab);
3145e9cd1aeSAssar Westerlund     }
3155e9cd1aeSAssar Westerlund 
3165e9cd1aeSAssar Westerlund     krb5_kt_close(context, kt);
3175e9cd1aeSAssar Westerlund 
3185e9cd1aeSAssar Westerlund     return ret;
3195e9cd1aeSAssar Westerlund }
3205e9cd1aeSAssar Westerlund 
3215e9cd1aeSAssar Westerlund static hdb_master_key
3225e9cd1aeSAssar Westerlund find_master_key(Key *key, hdb_master_key mkey)
3235e9cd1aeSAssar Westerlund {
3245e9cd1aeSAssar Westerlund     hdb_master_key ret = NULL;
3255e9cd1aeSAssar Westerlund     while(mkey) {
3265e9cd1aeSAssar Westerlund 	if(ret == NULL && mkey->keytab.vno == 0)
3275e9cd1aeSAssar Westerlund 	    ret = mkey;
3285e9cd1aeSAssar Westerlund 	if(key->mkvno == NULL) {
3295e9cd1aeSAssar Westerlund 	    if(ret == NULL || mkey->keytab.vno > ret->keytab.vno)
3305e9cd1aeSAssar Westerlund 		ret = mkey;
3315e9cd1aeSAssar Westerlund 	} else if(mkey->keytab.vno == *key->mkvno)
3325e9cd1aeSAssar Westerlund 	    return mkey;
3335e9cd1aeSAssar Westerlund 	mkey = mkey->next;
3345e9cd1aeSAssar Westerlund     }
3355e9cd1aeSAssar Westerlund     return ret;
3365e9cd1aeSAssar Westerlund }
3375e9cd1aeSAssar Westerlund 
3385e9cd1aeSAssar Westerlund krb5_error_code
3395e9cd1aeSAssar Westerlund hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
3405e9cd1aeSAssar Westerlund {
3415e9cd1aeSAssar Westerlund     int i;
3425e9cd1aeSAssar Westerlund     krb5_error_code ret;
3435e9cd1aeSAssar Westerlund     krb5_data res;
3445e9cd1aeSAssar Westerlund     Key *k;
3455e9cd1aeSAssar Westerlund 
3465e9cd1aeSAssar Westerlund     for(i = 0; i < ent->keys.len; i++){
3475e9cd1aeSAssar Westerlund 	hdb_master_key key;
3485e9cd1aeSAssar Westerlund 
3495e9cd1aeSAssar Westerlund 	k = &ent->keys.val[i];
3505e9cd1aeSAssar Westerlund 	if(k->mkvno == NULL)
3515e9cd1aeSAssar Westerlund 	    continue;
3525e9cd1aeSAssar Westerlund 
3535e9cd1aeSAssar Westerlund 	key = find_master_key(&ent->keys.val[i], mkey);
3545e9cd1aeSAssar Westerlund 
3555e9cd1aeSAssar Westerlund 	if (key == NULL)
3565e9cd1aeSAssar Westerlund 	    return HDB_ERR_NO_MKEY;
3575e9cd1aeSAssar Westerlund 
3585e9cd1aeSAssar Westerlund 	ret = krb5_decrypt(context, key->crypto, HDB_KU_MKEY,
3595e9cd1aeSAssar Westerlund 			   k->key.keyvalue.data,
3605e9cd1aeSAssar Westerlund 			   k->key.keyvalue.length,
3615e9cd1aeSAssar Westerlund 			   &res);
3625e9cd1aeSAssar Westerlund 	if (ret)
3635e9cd1aeSAssar Westerlund 	    return ret;
3645e9cd1aeSAssar Westerlund 
3655e9cd1aeSAssar Westerlund 	memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
3665e9cd1aeSAssar Westerlund 	free(k->key.keyvalue.data);
3675e9cd1aeSAssar Westerlund 	k->key.keyvalue = res;
3685e9cd1aeSAssar Westerlund 	free(k->mkvno);
3695e9cd1aeSAssar Westerlund 	k->mkvno = NULL;
3705e9cd1aeSAssar Westerlund     }
3715e9cd1aeSAssar Westerlund     return 0;
3725e9cd1aeSAssar Westerlund }
3735e9cd1aeSAssar Westerlund 
3745e9cd1aeSAssar Westerlund krb5_error_code
3755e9cd1aeSAssar Westerlund hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent)
3765e9cd1aeSAssar Westerlund {
3775e9cd1aeSAssar Westerlund     if (db->master_key_set == 0)
3785e9cd1aeSAssar Westerlund 	return 0;
3795e9cd1aeSAssar Westerlund     return hdb_unseal_keys_mkey(context, ent, db->master_key);
3805e9cd1aeSAssar Westerlund }
3815e9cd1aeSAssar Westerlund 
3825e9cd1aeSAssar Westerlund krb5_error_code
3835e9cd1aeSAssar Westerlund hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
3845e9cd1aeSAssar Westerlund {
3855e9cd1aeSAssar Westerlund     int i;
3865e9cd1aeSAssar Westerlund     krb5_error_code ret;
3875e9cd1aeSAssar Westerlund     krb5_data res;
3885e9cd1aeSAssar Westerlund     for(i = 0; i < ent->keys.len; i++){
3895e9cd1aeSAssar Westerlund 	Key *k = &ent->keys.val[i];
3905e9cd1aeSAssar Westerlund 	hdb_master_key key;
3915e9cd1aeSAssar Westerlund 
3925e9cd1aeSAssar Westerlund 	if(k->mkvno != NULL)
3935e9cd1aeSAssar Westerlund 	    continue;
3945e9cd1aeSAssar Westerlund 
3955e9cd1aeSAssar Westerlund 	key = find_master_key(k, mkey);
3965e9cd1aeSAssar Westerlund 
3975e9cd1aeSAssar Westerlund 	if (key == NULL)
3985e9cd1aeSAssar Westerlund 	    return HDB_ERR_NO_MKEY;
3995e9cd1aeSAssar Westerlund 
4005e9cd1aeSAssar Westerlund 	ret = krb5_encrypt(context, key->crypto, HDB_KU_MKEY,
4015e9cd1aeSAssar Westerlund 			   k->key.keyvalue.data,
4025e9cd1aeSAssar Westerlund 			   k->key.keyvalue.length,
4035e9cd1aeSAssar Westerlund 			   &res);
4045e9cd1aeSAssar Westerlund 	if (ret)
4055e9cd1aeSAssar Westerlund 	    return ret;
4065e9cd1aeSAssar Westerlund 
4075e9cd1aeSAssar Westerlund 	memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
4085e9cd1aeSAssar Westerlund 	free(k->key.keyvalue.data);
4095e9cd1aeSAssar Westerlund 	k->key.keyvalue = res;
4105e9cd1aeSAssar Westerlund 
4115e9cd1aeSAssar Westerlund 	k->mkvno = malloc(sizeof(*k->mkvno));
4125e9cd1aeSAssar Westerlund 	if (k->mkvno == NULL)
4135e9cd1aeSAssar Westerlund 	    return ENOMEM;
4145e9cd1aeSAssar Westerlund 	*k->mkvno = key->keytab.vno;
4155e9cd1aeSAssar Westerlund     }
4165e9cd1aeSAssar Westerlund     return 0;
4175e9cd1aeSAssar Westerlund }
4185e9cd1aeSAssar Westerlund 
4195e9cd1aeSAssar Westerlund krb5_error_code
4205e9cd1aeSAssar Westerlund hdb_seal_keys(krb5_context context, HDB *db, hdb_entry *ent)
4215e9cd1aeSAssar Westerlund {
4225e9cd1aeSAssar Westerlund     if (db->master_key_set == 0)
4235e9cd1aeSAssar Westerlund 	return 0;
4245e9cd1aeSAssar Westerlund 
4255e9cd1aeSAssar Westerlund     return hdb_seal_keys_mkey(context, ent, db->master_key);
4265e9cd1aeSAssar Westerlund }
4275e9cd1aeSAssar Westerlund 
4285e9cd1aeSAssar Westerlund krb5_error_code
4295e9cd1aeSAssar Westerlund hdb_set_master_key (krb5_context context,
4305e9cd1aeSAssar Westerlund 		    HDB *db,
4315e9cd1aeSAssar Westerlund 		    krb5_keyblock *key)
4325e9cd1aeSAssar Westerlund {
4335e9cd1aeSAssar Westerlund     krb5_error_code ret;
4345e9cd1aeSAssar Westerlund     hdb_master_key mkey;
4355e9cd1aeSAssar Westerlund 
4365e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, 0, key, 0, &mkey);
4375e9cd1aeSAssar Westerlund     if (ret)
4385e9cd1aeSAssar Westerlund 	return ret;
4395e9cd1aeSAssar Westerlund     db->master_key = mkey;
4405e9cd1aeSAssar Westerlund #if 0 /* XXX - why? */
4415e9cd1aeSAssar Westerlund     des_set_random_generator_seed(key.keyvalue.data);
4425e9cd1aeSAssar Westerlund #endif
4435e9cd1aeSAssar Westerlund     db->master_key_set = 1;
4445e9cd1aeSAssar Westerlund     return 0;
4455e9cd1aeSAssar Westerlund }
4465e9cd1aeSAssar Westerlund 
4475e9cd1aeSAssar Westerlund krb5_error_code
4485e9cd1aeSAssar Westerlund hdb_set_master_keyfile (krb5_context context,
4495e9cd1aeSAssar Westerlund 			HDB *db,
4505e9cd1aeSAssar Westerlund 			const char *keyfile)
4515e9cd1aeSAssar Westerlund {
4525e9cd1aeSAssar Westerlund     hdb_master_key key;
4535e9cd1aeSAssar Westerlund     krb5_error_code ret;
4545e9cd1aeSAssar Westerlund 
4555e9cd1aeSAssar Westerlund     ret = hdb_read_master_key(context, keyfile, &key);
4565e9cd1aeSAssar Westerlund     if (ret) {
4575e9cd1aeSAssar Westerlund 	if (ret != ENOENT)
4585e9cd1aeSAssar Westerlund 	    return ret;
4595e9cd1aeSAssar Westerlund 	return 0;
4605e9cd1aeSAssar Westerlund     }
4615e9cd1aeSAssar Westerlund     db->master_key = key;
4625e9cd1aeSAssar Westerlund     db->master_key_set = 1;
4635e9cd1aeSAssar Westerlund     return ret;
4645e9cd1aeSAssar Westerlund }
4655e9cd1aeSAssar Westerlund 
4665e9cd1aeSAssar Westerlund krb5_error_code
4675e9cd1aeSAssar Westerlund hdb_clear_master_key (krb5_context context,
4685e9cd1aeSAssar Westerlund 		      HDB *db)
4695e9cd1aeSAssar Westerlund {
4705e9cd1aeSAssar Westerlund     if (db->master_key_set) {
4715e9cd1aeSAssar Westerlund 	hdb_free_master_key(context, db->master_key);
4725e9cd1aeSAssar Westerlund 	db->master_key_set = 0;
4735e9cd1aeSAssar Westerlund     }
4745e9cd1aeSAssar Westerlund     return 0;
4755e9cd1aeSAssar Westerlund }
476