xref: /freebsd/crypto/heimdal/lib/hdb/mkey.c (revision bbd80c28)
15e9cd1aeSAssar Westerlund /*
28373020dSJacques Vidrine  * Copyright (c) 2000 - 2002 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 
39bbd80c28SJacques Vidrine RCSID("$Id: mkey.c,v 1.15 2003/03/28 02:01:33 lha 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);
534137ff4cSJacques Vidrine 	if (mkey->crypto)
545e9cd1aeSAssar Westerlund 	    krb5_crypto_destroy(context, mkey->crypto);
555e9cd1aeSAssar Westerlund 	ptr = mkey;
565e9cd1aeSAssar Westerlund 	mkey = mkey->next;
575e9cd1aeSAssar Westerlund 	free(ptr);
585e9cd1aeSAssar Westerlund     }
595e9cd1aeSAssar Westerlund }
605e9cd1aeSAssar Westerlund 
615e9cd1aeSAssar Westerlund krb5_error_code
625e9cd1aeSAssar Westerlund hdb_process_master_key(krb5_context context,
635e9cd1aeSAssar Westerlund 		       int kvno, krb5_keyblock *key, krb5_enctype etype,
645e9cd1aeSAssar Westerlund 		       hdb_master_key *mkey)
655e9cd1aeSAssar Westerlund {
665e9cd1aeSAssar Westerlund     krb5_error_code ret;
674137ff4cSJacques Vidrine 
685e9cd1aeSAssar Westerlund     *mkey = calloc(1, sizeof(**mkey));
694137ff4cSJacques Vidrine     if(*mkey == NULL) {
704137ff4cSJacques Vidrine 	krb5_set_error_string(context, "malloc: out of memory");
715e9cd1aeSAssar Westerlund 	return ENOMEM;
724137ff4cSJacques Vidrine     }
735e9cd1aeSAssar Westerlund     (*mkey)->keytab.vno = kvno;
745e9cd1aeSAssar Westerlund     ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal);
754137ff4cSJacques Vidrine     if(ret)
764137ff4cSJacques Vidrine 	goto fail;
775e9cd1aeSAssar Westerlund     ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock);
784137ff4cSJacques Vidrine     if(ret)
794137ff4cSJacques Vidrine 	goto fail;
805e9cd1aeSAssar Westerlund     if(etype != 0)
815e9cd1aeSAssar Westerlund 	(*mkey)->keytab.keyblock.keytype = etype;
825e9cd1aeSAssar Westerlund     (*mkey)->keytab.timestamp = time(NULL);
835e9cd1aeSAssar Westerlund     ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto);
844137ff4cSJacques Vidrine     if(ret)
854137ff4cSJacques Vidrine 	goto fail;
864137ff4cSJacques Vidrine     return 0;
874137ff4cSJacques Vidrine  fail:
884137ff4cSJacques Vidrine     hdb_free_master_key(context, *mkey);
895e9cd1aeSAssar Westerlund     *mkey = NULL;
905e9cd1aeSAssar Westerlund     return ret;
915e9cd1aeSAssar Westerlund }
925e9cd1aeSAssar Westerlund 
935e9cd1aeSAssar Westerlund krb5_error_code
945e9cd1aeSAssar Westerlund hdb_add_master_key(krb5_context context, krb5_keyblock *key,
955e9cd1aeSAssar Westerlund 		   hdb_master_key *inout)
965e9cd1aeSAssar Westerlund {
975e9cd1aeSAssar Westerlund     int vno = 0;
985e9cd1aeSAssar Westerlund     hdb_master_key p;
995e9cd1aeSAssar Westerlund     krb5_error_code ret;
1005e9cd1aeSAssar Westerlund 
1015e9cd1aeSAssar Westerlund     for(p = *inout; p; p = p->next)
1025e9cd1aeSAssar Westerlund 	vno = max(vno, p->keytab.vno);
1035e9cd1aeSAssar Westerlund     vno++;
1045e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, vno, key, 0, &p);
1055e9cd1aeSAssar Westerlund     if(ret)
1065e9cd1aeSAssar Westerlund 	return ret;
1075e9cd1aeSAssar Westerlund     p->next = *inout;
1085e9cd1aeSAssar Westerlund     *inout = p;
1095e9cd1aeSAssar Westerlund     return 0;
1105e9cd1aeSAssar Westerlund }
1115e9cd1aeSAssar Westerlund 
1125e9cd1aeSAssar Westerlund static krb5_error_code
1135e9cd1aeSAssar Westerlund read_master_keytab(krb5_context context, const char *filename,
1145e9cd1aeSAssar Westerlund 		   hdb_master_key *mkey)
1155e9cd1aeSAssar Westerlund {
1165e9cd1aeSAssar Westerlund     krb5_error_code ret;
1175e9cd1aeSAssar Westerlund     krb5_keytab id;
1185e9cd1aeSAssar Westerlund     krb5_kt_cursor cursor;
1195e9cd1aeSAssar Westerlund     krb5_keytab_entry entry;
1205e9cd1aeSAssar Westerlund     hdb_master_key p;
1215e9cd1aeSAssar Westerlund 
1225e9cd1aeSAssar Westerlund     ret = krb5_kt_resolve(context, filename, &id);
1235e9cd1aeSAssar Westerlund     if(ret)
1245e9cd1aeSAssar Westerlund 	return ret;
1255e9cd1aeSAssar Westerlund 
1265e9cd1aeSAssar Westerlund     ret = krb5_kt_start_seq_get(context, id, &cursor);
1275e9cd1aeSAssar Westerlund     if(ret)
1285e9cd1aeSAssar Westerlund 	goto out;
1295e9cd1aeSAssar Westerlund     *mkey = NULL;
1305e9cd1aeSAssar Westerlund     while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) {
1315e9cd1aeSAssar Westerlund 	p = calloc(1, sizeof(*p));
1325e9cd1aeSAssar Westerlund 	p->keytab = entry;
1335e9cd1aeSAssar Westerlund 	ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto);
1345e9cd1aeSAssar Westerlund 	p->next = *mkey;
1355e9cd1aeSAssar Westerlund 	*mkey = p;
1365e9cd1aeSAssar Westerlund     }
1375e9cd1aeSAssar Westerlund     krb5_kt_end_seq_get(context, id, &cursor);
1385e9cd1aeSAssar Westerlund   out:
1395e9cd1aeSAssar Westerlund     krb5_kt_close(context, id);
1405e9cd1aeSAssar Westerlund     return ret;
1415e9cd1aeSAssar Westerlund }
1425e9cd1aeSAssar Westerlund 
1435e9cd1aeSAssar Westerlund /* read a MIT master keyfile */
1445e9cd1aeSAssar Westerlund static krb5_error_code
1455e9cd1aeSAssar Westerlund read_master_mit(krb5_context context, const char *filename,
1465e9cd1aeSAssar Westerlund 		hdb_master_key *mkey)
1475e9cd1aeSAssar Westerlund {
1485e9cd1aeSAssar Westerlund     int fd;
1495e9cd1aeSAssar Westerlund     krb5_error_code ret;
1505e9cd1aeSAssar Westerlund     krb5_storage *sp;
1515e9cd1aeSAssar Westerlund     u_int16_t enctype;
1525e9cd1aeSAssar Westerlund     krb5_keyblock key;
1535e9cd1aeSAssar Westerlund 
1545e9cd1aeSAssar Westerlund     fd = open(filename, O_RDONLY | O_BINARY);
1554137ff4cSJacques Vidrine     if(fd < 0) {
1564137ff4cSJacques Vidrine 	int save_errno = errno;
1574137ff4cSJacques Vidrine 	krb5_set_error_string(context, "failed to open %s: %s", filename,
1584137ff4cSJacques Vidrine 			      strerror(save_errno));
1594137ff4cSJacques Vidrine 	return save_errno;
1604137ff4cSJacques Vidrine     }
1615e9cd1aeSAssar Westerlund     sp = krb5_storage_from_fd(fd);
1625e9cd1aeSAssar Westerlund     if(sp == NULL) {
1635e9cd1aeSAssar Westerlund 	close(fd);
1645e9cd1aeSAssar Westerlund 	return errno;
1655e9cd1aeSAssar Westerlund     }
1665e9cd1aeSAssar Westerlund     krb5_storage_set_flags(sp, KRB5_STORAGE_HOST_BYTEORDER);
1675e9cd1aeSAssar Westerlund #if 0
1685e9cd1aeSAssar Westerlund     /* could possibly use ret_keyblock here, but do it with more
1695e9cd1aeSAssar Westerlund        checks for now */
1705e9cd1aeSAssar Westerlund     ret = krb5_ret_keyblock(sp, &key);
1715e9cd1aeSAssar Westerlund #else
1725e9cd1aeSAssar Westerlund     ret = krb5_ret_int16(sp, &enctype);
1735e9cd1aeSAssar Westerlund     if((htons(enctype) & 0xff00) == 0x3000) {
1744137ff4cSJacques Vidrine 	krb5_set_error_string(context, "unknown keytype in %s: %#x, expected %#x",
1754137ff4cSJacques Vidrine 			      filename, htons(enctype), 0x3000);
1765e9cd1aeSAssar Westerlund 	ret = HEIM_ERR_BAD_MKEY;
1775e9cd1aeSAssar Westerlund 	goto out;
1785e9cd1aeSAssar Westerlund     }
1795e9cd1aeSAssar Westerlund     key.keytype = enctype;
1805e9cd1aeSAssar Westerlund     ret = krb5_ret_data(sp, &key.keyvalue);
1815e9cd1aeSAssar Westerlund     if(ret)
1825e9cd1aeSAssar Westerlund 	goto out;
1835e9cd1aeSAssar Westerlund #endif
1845e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, 0, &key, 0, mkey);
1855e9cd1aeSAssar Westerlund     krb5_free_keyblock_contents(context, &key);
1865e9cd1aeSAssar Westerlund   out:
1875e9cd1aeSAssar Westerlund     krb5_storage_free(sp);
1885e9cd1aeSAssar Westerlund     close(fd);
1895e9cd1aeSAssar Westerlund     return ret;
1905e9cd1aeSAssar Westerlund }
1915e9cd1aeSAssar Westerlund 
1925e9cd1aeSAssar Westerlund /* read an old master key file */
1935e9cd1aeSAssar Westerlund static krb5_error_code
1945e9cd1aeSAssar Westerlund read_master_encryptionkey(krb5_context context, const char *filename,
1955e9cd1aeSAssar Westerlund 			  hdb_master_key *mkey)
1965e9cd1aeSAssar Westerlund {
1975e9cd1aeSAssar Westerlund     int fd;
1985e9cd1aeSAssar Westerlund     krb5_keyblock key;
1995e9cd1aeSAssar Westerlund     krb5_error_code ret;
2005e9cd1aeSAssar Westerlund     unsigned char buf[256];
2015e9cd1aeSAssar Westerlund     ssize_t len;
2028373020dSJacques Vidrine     size_t ret_len;
2035e9cd1aeSAssar Westerlund 
2045e9cd1aeSAssar Westerlund     fd = open(filename, O_RDONLY | O_BINARY);
2054137ff4cSJacques Vidrine     if(fd < 0) {
2064137ff4cSJacques Vidrine 	int save_errno = errno;
2074137ff4cSJacques Vidrine 	krb5_set_error_string(context, "failed to open %s: %s",
2084137ff4cSJacques Vidrine 			      filename, strerror(save_errno));
2094137ff4cSJacques Vidrine 	return save_errno;
2104137ff4cSJacques Vidrine     }
2115e9cd1aeSAssar Westerlund 
2125e9cd1aeSAssar Westerlund     len = read(fd, buf, sizeof(buf));
2135e9cd1aeSAssar Westerlund     close(fd);
2144137ff4cSJacques Vidrine     if(len < 0) {
2154137ff4cSJacques Vidrine 	int save_errno = errno;
2164137ff4cSJacques Vidrine 	krb5_set_error_string(context, "error reading %s: %s",
2174137ff4cSJacques Vidrine 			      filename, strerror(save_errno));
2184137ff4cSJacques Vidrine 	return save_errno;
2194137ff4cSJacques Vidrine     }
2205e9cd1aeSAssar Westerlund 
2218373020dSJacques Vidrine     ret = decode_EncryptionKey(buf, len, &key, &ret_len);
2225e9cd1aeSAssar Westerlund     memset(buf, 0, sizeof(buf));
2235e9cd1aeSAssar Westerlund     if(ret)
2245e9cd1aeSAssar Westerlund 	return ret;
2255e9cd1aeSAssar Westerlund 
2265e9cd1aeSAssar Westerlund     /* Originally, the keytype was just that, and later it got changed
2275e9cd1aeSAssar Westerlund        to des-cbc-md5, but we always used des in cfb64 mode. This
2285e9cd1aeSAssar Westerlund        should cover all cases, but will break if someone has hacked
2295e9cd1aeSAssar Westerlund        this code to really use des-cbc-md5 -- but then that's not my
2305e9cd1aeSAssar Westerlund        problem. */
2315e9cd1aeSAssar Westerlund     if(key.keytype == KEYTYPE_DES || key.keytype == ETYPE_DES_CBC_MD5)
2325e9cd1aeSAssar Westerlund 	key.keytype = ETYPE_DES_CFB64_NONE;
2335e9cd1aeSAssar Westerlund 
2345e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, 0, &key, 0, mkey);
2355e9cd1aeSAssar Westerlund     krb5_free_keyblock_contents(context, &key);
2365e9cd1aeSAssar Westerlund     return ret;
2375e9cd1aeSAssar Westerlund }
2385e9cd1aeSAssar Westerlund 
2395e9cd1aeSAssar Westerlund /* read a krb4 /.k style file */
2405e9cd1aeSAssar Westerlund static krb5_error_code
2415e9cd1aeSAssar Westerlund read_master_krb4(krb5_context context, const char *filename,
2425e9cd1aeSAssar Westerlund 		 hdb_master_key *mkey)
2435e9cd1aeSAssar Westerlund {
2445e9cd1aeSAssar Westerlund     int fd;
2455e9cd1aeSAssar Westerlund     krb5_keyblock key;
2465e9cd1aeSAssar Westerlund     krb5_error_code ret;
2475e9cd1aeSAssar Westerlund     unsigned char buf[256];
2485e9cd1aeSAssar Westerlund     ssize_t len;
2495e9cd1aeSAssar Westerlund 
2505e9cd1aeSAssar Westerlund     fd = open(filename, O_RDONLY | O_BINARY);
2514137ff4cSJacques Vidrine     if(fd < 0) {
2524137ff4cSJacques Vidrine 	int save_errno = errno;
2534137ff4cSJacques Vidrine 	krb5_set_error_string(context, "failed to open %s: %s",
2544137ff4cSJacques Vidrine 			      filename, strerror(save_errno));
2554137ff4cSJacques Vidrine 	return save_errno;
2564137ff4cSJacques Vidrine     }
2575e9cd1aeSAssar Westerlund 
2585e9cd1aeSAssar Westerlund     len = read(fd, buf, sizeof(buf));
2595e9cd1aeSAssar Westerlund     close(fd);
2604137ff4cSJacques Vidrine     if(len < 0) {
2614137ff4cSJacques Vidrine 	int save_errno = errno;
2624137ff4cSJacques Vidrine 	krb5_set_error_string(context, "error reading %s: %s",
2634137ff4cSJacques Vidrine 			      filename, strerror(save_errno));
2644137ff4cSJacques Vidrine 	return save_errno;
2654137ff4cSJacques Vidrine     }
2664137ff4cSJacques Vidrine     if(len != 8) {
2674137ff4cSJacques Vidrine 	krb5_set_error_string(context, "bad contents of %s", filename);
2684137ff4cSJacques Vidrine 	return HEIM_ERR_EOF; /* XXX file might be too large */
2694137ff4cSJacques Vidrine     }
2705e9cd1aeSAssar Westerlund 
2715e9cd1aeSAssar Westerlund     memset(&key, 0, sizeof(key));
2725e9cd1aeSAssar Westerlund     key.keytype = ETYPE_DES_PCBC_NONE;
2735e9cd1aeSAssar Westerlund     ret = krb5_data_copy(&key.keyvalue, buf, len);
2745e9cd1aeSAssar Westerlund     memset(buf, 0, sizeof(buf));
2755e9cd1aeSAssar Westerlund     if(ret)
2765e9cd1aeSAssar Westerlund 	return ret;
2775e9cd1aeSAssar Westerlund 
2785e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, 0, &key, 0, mkey);
2795e9cd1aeSAssar Westerlund     krb5_free_keyblock_contents(context, &key);
2805e9cd1aeSAssar Westerlund     return ret;
2815e9cd1aeSAssar Westerlund }
2825e9cd1aeSAssar Westerlund 
2835e9cd1aeSAssar Westerlund krb5_error_code
2845e9cd1aeSAssar Westerlund hdb_read_master_key(krb5_context context, const char *filename,
2855e9cd1aeSAssar Westerlund 		    hdb_master_key *mkey)
2865e9cd1aeSAssar Westerlund {
2875e9cd1aeSAssar Westerlund     FILE *f;
2885e9cd1aeSAssar Westerlund     unsigned char buf[16];
2895e9cd1aeSAssar Westerlund     krb5_error_code ret;
2905e9cd1aeSAssar Westerlund 
2915e9cd1aeSAssar Westerlund     off_t len;
2925e9cd1aeSAssar Westerlund 
2935e9cd1aeSAssar Westerlund     *mkey = NULL;
2945e9cd1aeSAssar Westerlund 
2955e9cd1aeSAssar Westerlund     if(filename == NULL)
2965e9cd1aeSAssar Westerlund 	filename = HDB_DB_DIR "/m-key";
2975e9cd1aeSAssar Westerlund 
2985e9cd1aeSAssar Westerlund     f = fopen(filename, "r");
2994137ff4cSJacques Vidrine     if(f == NULL) {
3004137ff4cSJacques Vidrine 	int save_errno = errno;
3014137ff4cSJacques Vidrine 	krb5_set_error_string(context, "failed to open %s: %s",
3024137ff4cSJacques Vidrine 			      filename, strerror(save_errno));
3034137ff4cSJacques Vidrine 	return save_errno;
3044137ff4cSJacques Vidrine     }
3055e9cd1aeSAssar Westerlund 
3065e9cd1aeSAssar Westerlund     if(fread(buf, 1, 2, f) != 2) {
3074137ff4cSJacques Vidrine 	krb5_set_error_string(context, "end of file reading %s", filename);
3085e9cd1aeSAssar Westerlund 	fclose(f);
3095e9cd1aeSAssar Westerlund 	return HEIM_ERR_EOF;
3105e9cd1aeSAssar Westerlund     }
3115e9cd1aeSAssar Westerlund 
3125e9cd1aeSAssar Westerlund     fseek(f, 0, SEEK_END);
3135e9cd1aeSAssar Westerlund     len = ftell(f);
3145e9cd1aeSAssar Westerlund 
3155e9cd1aeSAssar Westerlund     if(fclose(f) != 0)
3165e9cd1aeSAssar Westerlund 	return errno;
3175e9cd1aeSAssar Westerlund 
3185e9cd1aeSAssar Westerlund     if(len < 0)
3195e9cd1aeSAssar Westerlund 	return errno;
3205e9cd1aeSAssar Westerlund 
3215e9cd1aeSAssar Westerlund     if(len == 8) {
3225e9cd1aeSAssar Westerlund 	ret = read_master_krb4(context, filename, mkey);
3235e9cd1aeSAssar Westerlund     } else if(buf[0] == 0x30 && len <= 127 && buf[1] == len - 2) {
3245e9cd1aeSAssar Westerlund 	ret = read_master_encryptionkey(context, filename, mkey);
3255e9cd1aeSAssar Westerlund     } else if(buf[0] == 5 && buf[1] >= 1 && buf[1] <= 2) {
3265e9cd1aeSAssar Westerlund 	ret = read_master_keytab(context, filename, mkey);
3275e9cd1aeSAssar Westerlund     } else {
3285e9cd1aeSAssar Westerlund 	ret = read_master_mit(context, filename, mkey);
3295e9cd1aeSAssar Westerlund     }
3305e9cd1aeSAssar Westerlund     return ret;
3315e9cd1aeSAssar Westerlund }
3325e9cd1aeSAssar Westerlund 
3335e9cd1aeSAssar Westerlund krb5_error_code
3345e9cd1aeSAssar Westerlund hdb_write_master_key(krb5_context context, const char *filename,
3355e9cd1aeSAssar Westerlund 		     hdb_master_key mkey)
3365e9cd1aeSAssar Westerlund {
3375e9cd1aeSAssar Westerlund     krb5_error_code ret;
3385e9cd1aeSAssar Westerlund     hdb_master_key p;
3395e9cd1aeSAssar Westerlund     krb5_keytab kt;
3405e9cd1aeSAssar Westerlund 
3415e9cd1aeSAssar Westerlund     if(filename == NULL)
3425e9cd1aeSAssar Westerlund 	filename = HDB_DB_DIR "/m-key";
3435e9cd1aeSAssar Westerlund 
3445e9cd1aeSAssar Westerlund     ret = krb5_kt_resolve(context, filename, &kt);
3455e9cd1aeSAssar Westerlund     if(ret)
3465e9cd1aeSAssar Westerlund 	return ret;
3475e9cd1aeSAssar Westerlund 
3485e9cd1aeSAssar Westerlund     for(p = mkey; p; p = p->next) {
3495e9cd1aeSAssar Westerlund 	ret = krb5_kt_add_entry(context, kt, &p->keytab);
3505e9cd1aeSAssar Westerlund     }
3515e9cd1aeSAssar Westerlund 
3525e9cd1aeSAssar Westerlund     krb5_kt_close(context, kt);
3535e9cd1aeSAssar Westerlund 
3545e9cd1aeSAssar Westerlund     return ret;
3555e9cd1aeSAssar Westerlund }
3565e9cd1aeSAssar Westerlund 
3575e9cd1aeSAssar Westerlund static hdb_master_key
3585e9cd1aeSAssar Westerlund find_master_key(Key *key, hdb_master_key mkey)
3595e9cd1aeSAssar Westerlund {
3605e9cd1aeSAssar Westerlund     hdb_master_key ret = NULL;
3615e9cd1aeSAssar Westerlund     while(mkey) {
3625e9cd1aeSAssar Westerlund 	if(ret == NULL && mkey->keytab.vno == 0)
3635e9cd1aeSAssar Westerlund 	    ret = mkey;
3645e9cd1aeSAssar Westerlund 	if(key->mkvno == NULL) {
3655e9cd1aeSAssar Westerlund 	    if(ret == NULL || mkey->keytab.vno > ret->keytab.vno)
3665e9cd1aeSAssar Westerlund 		ret = mkey;
3675e9cd1aeSAssar Westerlund 	} else if(mkey->keytab.vno == *key->mkvno)
3685e9cd1aeSAssar Westerlund 	    return mkey;
3695e9cd1aeSAssar Westerlund 	mkey = mkey->next;
3705e9cd1aeSAssar Westerlund     }
3715e9cd1aeSAssar Westerlund     return ret;
3725e9cd1aeSAssar Westerlund }
3735e9cd1aeSAssar Westerlund 
3745e9cd1aeSAssar Westerlund krb5_error_code
3755e9cd1aeSAssar Westerlund hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
3765e9cd1aeSAssar Westerlund {
3775e9cd1aeSAssar Westerlund     int i;
3785e9cd1aeSAssar Westerlund     krb5_error_code ret;
3795e9cd1aeSAssar Westerlund     krb5_data res;
380bbd80c28SJacques Vidrine     size_t keysize;
3815e9cd1aeSAssar Westerlund     Key *k;
3825e9cd1aeSAssar Westerlund 
3835e9cd1aeSAssar Westerlund     for(i = 0; i < ent->keys.len; i++){
3845e9cd1aeSAssar Westerlund 	hdb_master_key key;
3855e9cd1aeSAssar Westerlund 
3865e9cd1aeSAssar Westerlund 	k = &ent->keys.val[i];
3875e9cd1aeSAssar Westerlund 	if(k->mkvno == NULL)
3885e9cd1aeSAssar Westerlund 	    continue;
3895e9cd1aeSAssar Westerlund 
3905e9cd1aeSAssar Westerlund 	key = find_master_key(&ent->keys.val[i], mkey);
3915e9cd1aeSAssar Westerlund 
3925e9cd1aeSAssar Westerlund 	if (key == NULL)
3935e9cd1aeSAssar Westerlund 	    return HDB_ERR_NO_MKEY;
3945e9cd1aeSAssar Westerlund 
3955e9cd1aeSAssar Westerlund 	ret = krb5_decrypt(context, key->crypto, HDB_KU_MKEY,
3965e9cd1aeSAssar Westerlund 			   k->key.keyvalue.data,
3975e9cd1aeSAssar Westerlund 			   k->key.keyvalue.length,
3985e9cd1aeSAssar Westerlund 			   &res);
3995e9cd1aeSAssar Westerlund 	if (ret)
4005e9cd1aeSAssar Westerlund 	    return ret;
4015e9cd1aeSAssar Westerlund 
402bbd80c28SJacques Vidrine 	/* fixup keylength if the key got padded when encrypting it */
403bbd80c28SJacques Vidrine 	ret = krb5_enctype_keysize(context, k->key.keytype, &keysize);
404bbd80c28SJacques Vidrine 	if (ret) {
405bbd80c28SJacques Vidrine 	    krb5_data_free(&res);
406bbd80c28SJacques Vidrine 	    return ret;
407bbd80c28SJacques Vidrine 	}
408bbd80c28SJacques Vidrine 	if (keysize > res.length) {
409bbd80c28SJacques Vidrine 	    krb5_data_free(&res);
410bbd80c28SJacques Vidrine 	    return KRB5_BAD_KEYSIZE;
411bbd80c28SJacques Vidrine 	}
412bbd80c28SJacques Vidrine 
4135e9cd1aeSAssar Westerlund 	memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
4145e9cd1aeSAssar Westerlund 	free(k->key.keyvalue.data);
4155e9cd1aeSAssar Westerlund 	k->key.keyvalue = res;
416bbd80c28SJacques Vidrine 	k->key.keyvalue.length = keysize;
4175e9cd1aeSAssar Westerlund 	free(k->mkvno);
4185e9cd1aeSAssar Westerlund 	k->mkvno = NULL;
4195e9cd1aeSAssar Westerlund     }
4205e9cd1aeSAssar Westerlund     return 0;
4215e9cd1aeSAssar Westerlund }
4225e9cd1aeSAssar Westerlund 
4235e9cd1aeSAssar Westerlund krb5_error_code
4245e9cd1aeSAssar Westerlund hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent)
4255e9cd1aeSAssar Westerlund {
4265e9cd1aeSAssar Westerlund     if (db->master_key_set == 0)
4275e9cd1aeSAssar Westerlund 	return 0;
4285e9cd1aeSAssar Westerlund     return hdb_unseal_keys_mkey(context, ent, db->master_key);
4295e9cd1aeSAssar Westerlund }
4305e9cd1aeSAssar Westerlund 
4315e9cd1aeSAssar Westerlund krb5_error_code
4325e9cd1aeSAssar Westerlund hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
4335e9cd1aeSAssar Westerlund {
4345e9cd1aeSAssar Westerlund     int i;
4355e9cd1aeSAssar Westerlund     krb5_error_code ret;
4365e9cd1aeSAssar Westerlund     krb5_data res;
4375e9cd1aeSAssar Westerlund     for(i = 0; i < ent->keys.len; i++){
4385e9cd1aeSAssar Westerlund 	Key *k = &ent->keys.val[i];
4395e9cd1aeSAssar Westerlund 	hdb_master_key key;
4405e9cd1aeSAssar Westerlund 
4415e9cd1aeSAssar Westerlund 	if(k->mkvno != NULL)
4425e9cd1aeSAssar Westerlund 	    continue;
4435e9cd1aeSAssar Westerlund 
4445e9cd1aeSAssar Westerlund 	key = find_master_key(k, mkey);
4455e9cd1aeSAssar Westerlund 
4465e9cd1aeSAssar Westerlund 	if (key == NULL)
4475e9cd1aeSAssar Westerlund 	    return HDB_ERR_NO_MKEY;
4485e9cd1aeSAssar Westerlund 
4495e9cd1aeSAssar Westerlund 	ret = krb5_encrypt(context, key->crypto, HDB_KU_MKEY,
4505e9cd1aeSAssar Westerlund 			   k->key.keyvalue.data,
4515e9cd1aeSAssar Westerlund 			   k->key.keyvalue.length,
4525e9cd1aeSAssar Westerlund 			   &res);
4535e9cd1aeSAssar Westerlund 	if (ret)
4545e9cd1aeSAssar Westerlund 	    return ret;
4555e9cd1aeSAssar Westerlund 
4565e9cd1aeSAssar Westerlund 	memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
4575e9cd1aeSAssar Westerlund 	free(k->key.keyvalue.data);
4585e9cd1aeSAssar Westerlund 	k->key.keyvalue = res;
4595e9cd1aeSAssar Westerlund 
4605e9cd1aeSAssar Westerlund 	k->mkvno = malloc(sizeof(*k->mkvno));
4615e9cd1aeSAssar Westerlund 	if (k->mkvno == NULL)
4625e9cd1aeSAssar Westerlund 	    return ENOMEM;
4635e9cd1aeSAssar Westerlund 	*k->mkvno = key->keytab.vno;
4645e9cd1aeSAssar Westerlund     }
4655e9cd1aeSAssar Westerlund     return 0;
4665e9cd1aeSAssar Westerlund }
4675e9cd1aeSAssar Westerlund 
4685e9cd1aeSAssar Westerlund krb5_error_code
4695e9cd1aeSAssar Westerlund hdb_seal_keys(krb5_context context, HDB *db, hdb_entry *ent)
4705e9cd1aeSAssar Westerlund {
4715e9cd1aeSAssar Westerlund     if (db->master_key_set == 0)
4725e9cd1aeSAssar Westerlund 	return 0;
4735e9cd1aeSAssar Westerlund 
4745e9cd1aeSAssar Westerlund     return hdb_seal_keys_mkey(context, ent, db->master_key);
4755e9cd1aeSAssar Westerlund }
4765e9cd1aeSAssar Westerlund 
4775e9cd1aeSAssar Westerlund krb5_error_code
4785e9cd1aeSAssar Westerlund hdb_set_master_key (krb5_context context,
4795e9cd1aeSAssar Westerlund 		    HDB *db,
4805e9cd1aeSAssar Westerlund 		    krb5_keyblock *key)
4815e9cd1aeSAssar Westerlund {
4825e9cd1aeSAssar Westerlund     krb5_error_code ret;
4835e9cd1aeSAssar Westerlund     hdb_master_key mkey;
4845e9cd1aeSAssar Westerlund 
4855e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, 0, key, 0, &mkey);
4865e9cd1aeSAssar Westerlund     if (ret)
4875e9cd1aeSAssar Westerlund 	return ret;
4885e9cd1aeSAssar Westerlund     db->master_key = mkey;
4895e9cd1aeSAssar Westerlund #if 0 /* XXX - why? */
4905e9cd1aeSAssar Westerlund     des_set_random_generator_seed(key.keyvalue.data);
4915e9cd1aeSAssar Westerlund #endif
4925e9cd1aeSAssar Westerlund     db->master_key_set = 1;
4935e9cd1aeSAssar Westerlund     return 0;
4945e9cd1aeSAssar Westerlund }
4955e9cd1aeSAssar Westerlund 
4965e9cd1aeSAssar Westerlund krb5_error_code
4975e9cd1aeSAssar Westerlund hdb_set_master_keyfile (krb5_context context,
4985e9cd1aeSAssar Westerlund 			HDB *db,
4995e9cd1aeSAssar Westerlund 			const char *keyfile)
5005e9cd1aeSAssar Westerlund {
5015e9cd1aeSAssar Westerlund     hdb_master_key key;
5025e9cd1aeSAssar Westerlund     krb5_error_code ret;
5035e9cd1aeSAssar Westerlund 
5045e9cd1aeSAssar Westerlund     ret = hdb_read_master_key(context, keyfile, &key);
5055e9cd1aeSAssar Westerlund     if (ret) {
5065e9cd1aeSAssar Westerlund 	if (ret != ENOENT)
5075e9cd1aeSAssar Westerlund 	    return ret;
5084137ff4cSJacques Vidrine 	krb5_clear_error_string(context);
5095e9cd1aeSAssar Westerlund 	return 0;
5105e9cd1aeSAssar Westerlund     }
5115e9cd1aeSAssar Westerlund     db->master_key = key;
5125e9cd1aeSAssar Westerlund     db->master_key_set = 1;
5135e9cd1aeSAssar Westerlund     return ret;
5145e9cd1aeSAssar Westerlund }
5155e9cd1aeSAssar Westerlund 
5165e9cd1aeSAssar Westerlund krb5_error_code
5175e9cd1aeSAssar Westerlund hdb_clear_master_key (krb5_context context,
5185e9cd1aeSAssar Westerlund 		      HDB *db)
5195e9cd1aeSAssar Westerlund {
5205e9cd1aeSAssar Westerlund     if (db->master_key_set) {
5215e9cd1aeSAssar Westerlund 	hdb_free_master_key(context, db->master_key);
5225e9cd1aeSAssar Westerlund 	db->master_key_set = 0;
5235e9cd1aeSAssar Westerlund     }
5245e9cd1aeSAssar Westerlund     return 0;
5255e9cd1aeSAssar Westerlund }
526