xref: /freebsd/crypto/heimdal/lib/hdb/mkey.c (revision c19800e8)
15e9cd1aeSAssar Westerlund /*
2c19800e8SDoug Rabson  * Copyright (c) 2000 - 2004 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 
39c19800e8SDoug Rabson struct hdb_master_key_data {
405e9cd1aeSAssar Westerlund     krb5_keytab_entry keytab;
415e9cd1aeSAssar Westerlund     krb5_crypto crypto;
425e9cd1aeSAssar Westerlund     struct hdb_master_key_data *next;
435e9cd1aeSAssar Westerlund };
445e9cd1aeSAssar Westerlund 
455e9cd1aeSAssar Westerlund void
hdb_free_master_key(krb5_context context,hdb_master_key mkey)465e9cd1aeSAssar Westerlund hdb_free_master_key(krb5_context context, hdb_master_key mkey)
475e9cd1aeSAssar Westerlund {
485e9cd1aeSAssar Westerlund     struct hdb_master_key_data *ptr;
495e9cd1aeSAssar Westerlund     while(mkey) {
505e9cd1aeSAssar Westerlund 	krb5_kt_free_entry(context, &mkey->keytab);
515e9cd1aeSAssar Westerlund 	if (mkey->crypto)
525e9cd1aeSAssar Westerlund 	    krb5_crypto_destroy(context, mkey->crypto);
534137ff4cSJacques Vidrine 	ptr = mkey;
545e9cd1aeSAssar Westerlund 	mkey = mkey->next;
555e9cd1aeSAssar Westerlund 	free(ptr);
565e9cd1aeSAssar Westerlund     }
575e9cd1aeSAssar Westerlund }
585e9cd1aeSAssar Westerlund 
595e9cd1aeSAssar Westerlund krb5_error_code
hdb_process_master_key(krb5_context context,int kvno,krb5_keyblock * key,krb5_enctype etype,hdb_master_key * mkey)605e9cd1aeSAssar Westerlund hdb_process_master_key(krb5_context context,
615e9cd1aeSAssar Westerlund 		       int kvno, krb5_keyblock *key, krb5_enctype etype,
625e9cd1aeSAssar Westerlund 		       hdb_master_key *mkey)
635e9cd1aeSAssar Westerlund {
645e9cd1aeSAssar Westerlund     krb5_error_code ret;
655e9cd1aeSAssar Westerlund 
665e9cd1aeSAssar Westerlund     *mkey = calloc(1, sizeof(**mkey));
674137ff4cSJacques Vidrine     if(*mkey == NULL) {
685e9cd1aeSAssar Westerlund 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
694137ff4cSJacques Vidrine 	return ENOMEM;
704137ff4cSJacques Vidrine     }
715e9cd1aeSAssar Westerlund     (*mkey)->keytab.vno = kvno;
724137ff4cSJacques Vidrine     ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal);
735e9cd1aeSAssar Westerlund     if(ret)
745e9cd1aeSAssar Westerlund 	goto fail;
754137ff4cSJacques Vidrine     ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock);
764137ff4cSJacques Vidrine     if(ret)
775e9cd1aeSAssar Westerlund 	goto fail;
784137ff4cSJacques Vidrine     if(etype != 0)
794137ff4cSJacques Vidrine 	(*mkey)->keytab.keyblock.keytype = etype;
805e9cd1aeSAssar Westerlund     (*mkey)->keytab.timestamp = time(NULL);
815e9cd1aeSAssar Westerlund     ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto);
825e9cd1aeSAssar Westerlund     if(ret)
835e9cd1aeSAssar Westerlund 	goto fail;
844137ff4cSJacques Vidrine     return 0;
854137ff4cSJacques Vidrine  fail:
864137ff4cSJacques Vidrine     hdb_free_master_key(context, *mkey);
874137ff4cSJacques Vidrine     *mkey = NULL;
884137ff4cSJacques Vidrine     return ret;
895e9cd1aeSAssar Westerlund }
905e9cd1aeSAssar Westerlund 
915e9cd1aeSAssar Westerlund krb5_error_code
hdb_add_master_key(krb5_context context,krb5_keyblock * key,hdb_master_key * inout)925e9cd1aeSAssar Westerlund hdb_add_master_key(krb5_context context, krb5_keyblock *key,
935e9cd1aeSAssar Westerlund 		   hdb_master_key *inout)
945e9cd1aeSAssar Westerlund {
955e9cd1aeSAssar Westerlund     int vno = 0;
965e9cd1aeSAssar Westerlund     hdb_master_key p;
975e9cd1aeSAssar Westerlund     krb5_error_code ret;
985e9cd1aeSAssar Westerlund 
995e9cd1aeSAssar Westerlund     for(p = *inout; p; p = p->next)
1005e9cd1aeSAssar Westerlund 	vno = max(vno, p->keytab.vno);
1015e9cd1aeSAssar Westerlund     vno++;
1025e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, vno, key, 0, &p);
1035e9cd1aeSAssar Westerlund     if(ret)
1045e9cd1aeSAssar Westerlund 	return ret;
1055e9cd1aeSAssar Westerlund     p->next = *inout;
1065e9cd1aeSAssar Westerlund     *inout = p;
1075e9cd1aeSAssar Westerlund     return 0;
1085e9cd1aeSAssar Westerlund }
1095e9cd1aeSAssar Westerlund 
1105e9cd1aeSAssar Westerlund static krb5_error_code
read_master_keytab(krb5_context context,const char * filename,hdb_master_key * mkey)1115e9cd1aeSAssar Westerlund read_master_keytab(krb5_context context, const char *filename,
1125e9cd1aeSAssar Westerlund 		   hdb_master_key *mkey)
1135e9cd1aeSAssar Westerlund {
1145e9cd1aeSAssar Westerlund     krb5_error_code ret;
1155e9cd1aeSAssar Westerlund     krb5_keytab id;
1165e9cd1aeSAssar Westerlund     krb5_kt_cursor cursor;
1175e9cd1aeSAssar Westerlund     krb5_keytab_entry entry;
1185e9cd1aeSAssar Westerlund     hdb_master_key p;
1195e9cd1aeSAssar Westerlund 
1205e9cd1aeSAssar Westerlund     ret = krb5_kt_resolve(context, filename, &id);
1215e9cd1aeSAssar Westerlund     if(ret)
1225e9cd1aeSAssar Westerlund 	return ret;
1235e9cd1aeSAssar Westerlund 
1245e9cd1aeSAssar Westerlund     ret = krb5_kt_start_seq_get(context, id, &cursor);
1255e9cd1aeSAssar Westerlund     if(ret)
1265e9cd1aeSAssar Westerlund 	goto out;
1275e9cd1aeSAssar Westerlund     *mkey = NULL;
1285e9cd1aeSAssar Westerlund     while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) {
1295e9cd1aeSAssar Westerlund 	p = calloc(1, sizeof(*p));
1305e9cd1aeSAssar Westerlund 	if(p == NULL) {
1315e9cd1aeSAssar Westerlund 	    krb5_kt_end_seq_get(context, id, &cursor);
132c19800e8SDoug Rabson 	    ret = ENOMEM;
133c19800e8SDoug Rabson 	    goto out;
134c19800e8SDoug Rabson 	}
135c19800e8SDoug Rabson 	p->keytab = entry;
136c19800e8SDoug Rabson 	ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto);
1375e9cd1aeSAssar Westerlund 	p->next = *mkey;
1385e9cd1aeSAssar Westerlund 	*mkey = p;
1395e9cd1aeSAssar Westerlund     }
1405e9cd1aeSAssar Westerlund     krb5_kt_end_seq_get(context, id, &cursor);
1415e9cd1aeSAssar Westerlund   out:
1425e9cd1aeSAssar Westerlund     krb5_kt_close(context, id);
1435e9cd1aeSAssar Westerlund     return ret;
1445e9cd1aeSAssar Westerlund }
1455e9cd1aeSAssar Westerlund 
1465e9cd1aeSAssar Westerlund /* read a MIT master keyfile */
1475e9cd1aeSAssar Westerlund static krb5_error_code
read_master_mit(krb5_context context,const char * filename,int byteorder,hdb_master_key * mkey)1485e9cd1aeSAssar Westerlund read_master_mit(krb5_context context, const char *filename,
1495e9cd1aeSAssar Westerlund 		int byteorder, hdb_master_key *mkey)
1505e9cd1aeSAssar Westerlund {
1515e9cd1aeSAssar Westerlund     int fd;
1525e9cd1aeSAssar Westerlund     krb5_error_code ret;
1535e9cd1aeSAssar Westerlund     krb5_storage *sp;
1545e9cd1aeSAssar Westerlund     int16_t enctype;
1555e9cd1aeSAssar Westerlund     krb5_keyblock key;
156c19800e8SDoug Rabson 
1575e9cd1aeSAssar Westerlund     fd = open(filename, O_RDONLY | O_BINARY);
1585e9cd1aeSAssar Westerlund     if(fd < 0) {
1595e9cd1aeSAssar Westerlund 	int save_errno = errno;
1604137ff4cSJacques Vidrine 	krb5_set_error_message(context, save_errno, "failed to open %s: %s",
1614137ff4cSJacques Vidrine 			       filename, strerror(save_errno));
1624137ff4cSJacques Vidrine 	return save_errno;
1634137ff4cSJacques Vidrine     }
1644137ff4cSJacques Vidrine     sp = krb5_storage_from_fd(fd);
1654137ff4cSJacques Vidrine     if(sp == NULL) {
1665e9cd1aeSAssar Westerlund 	close(fd);
1675e9cd1aeSAssar Westerlund 	return errno;
1685e9cd1aeSAssar Westerlund     }
1695e9cd1aeSAssar Westerlund     krb5_storage_set_flags(sp, byteorder);
1705e9cd1aeSAssar Westerlund     /* could possibly use ret_keyblock here, but do it with more
1715e9cd1aeSAssar Westerlund        checks for now */
1725e9cd1aeSAssar Westerlund     {
1735e9cd1aeSAssar Westerlund 	ret = krb5_ret_int16(sp, &enctype);
1745e9cd1aeSAssar Westerlund 	if (ret)
1755e9cd1aeSAssar Westerlund 	    goto out;
1765e9cd1aeSAssar Westerlund 	ret = krb5_enctype_valid(context, enctype);
1775e9cd1aeSAssar Westerlund 	if (ret)
1785e9cd1aeSAssar Westerlund 	   goto out;
1794137ff4cSJacques Vidrine 	key.keytype = enctype;
1804137ff4cSJacques Vidrine 	ret = krb5_ret_data(sp, &key.keyvalue);
1815e9cd1aeSAssar Westerlund 	if(ret)
1825e9cd1aeSAssar Westerlund 	    goto out;
1835e9cd1aeSAssar Westerlund     }
1845e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, 1, &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
read_master_encryptionkey(krb5_context context,const char * filename,hdb_master_key * mkey)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;
2025e9cd1aeSAssar Westerlund     size_t ret_len;
2035e9cd1aeSAssar Westerlund 
2045e9cd1aeSAssar Westerlund     fd = open(filename, O_RDONLY | O_BINARY);
2055e9cd1aeSAssar Westerlund     if(fd < 0) {
2065e9cd1aeSAssar Westerlund 	int save_errno = errno;
2078373020dSJacques Vidrine 	krb5_set_error_message(context, save_errno, "failed to open %s: %s",
2085e9cd1aeSAssar Westerlund 			      filename, strerror(save_errno));
2095e9cd1aeSAssar Westerlund 	return save_errno;
2104137ff4cSJacques Vidrine     }
2114137ff4cSJacques Vidrine 
2124137ff4cSJacques Vidrine     len = read(fd, buf, sizeof(buf));
2134137ff4cSJacques Vidrine     close(fd);
2144137ff4cSJacques Vidrine     if(len < 0) {
2154137ff4cSJacques Vidrine 	int save_errno = errno;
2165e9cd1aeSAssar Westerlund 	krb5_set_error_message(context, save_errno, "error reading %s: %s",
2175e9cd1aeSAssar Westerlund 			      filename, strerror(save_errno));
2185e9cd1aeSAssar Westerlund 	return save_errno;
2194137ff4cSJacques Vidrine     }
2204137ff4cSJacques Vidrine 
2214137ff4cSJacques Vidrine     ret = decode_EncryptionKey(buf, len, &key, &ret_len);
2224137ff4cSJacques Vidrine     memset(buf, 0, sizeof(buf));
2234137ff4cSJacques Vidrine     if(ret)
2244137ff4cSJacques Vidrine 	return ret;
2255e9cd1aeSAssar Westerlund 
2268373020dSJacques Vidrine     /* 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 == ETYPE_DES_CBC_CRC || 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
read_master_krb4(krb5_context context,const char * filename,hdb_master_key * mkey)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);
2515e9cd1aeSAssar Westerlund     if(fd < 0) {
2525e9cd1aeSAssar Westerlund 	int save_errno = errno;
2535e9cd1aeSAssar Westerlund 	krb5_set_error_message(context, save_errno, "failed to open %s: %s",
2545e9cd1aeSAssar Westerlund 			       filename, strerror(save_errno));
2555e9cd1aeSAssar Westerlund 	return save_errno;
2564137ff4cSJacques Vidrine     }
2574137ff4cSJacques Vidrine 
2584137ff4cSJacques Vidrine     len = read(fd, buf, sizeof(buf));
2594137ff4cSJacques Vidrine     close(fd);
2604137ff4cSJacques Vidrine     if(len < 0) {
2614137ff4cSJacques Vidrine 	int save_errno = errno;
2625e9cd1aeSAssar Westerlund 	krb5_set_error_message(context, save_errno, "error reading %s: %s",
2635e9cd1aeSAssar Westerlund 			       filename, strerror(save_errno));
2645e9cd1aeSAssar Westerlund 	return save_errno;
2654137ff4cSJacques Vidrine     }
2664137ff4cSJacques Vidrine     if(len != 8) {
2674137ff4cSJacques Vidrine 	krb5_set_error_message(context, HEIM_ERR_EOF,
2684137ff4cSJacques Vidrine 			       "bad contents of %s", filename);
2694137ff4cSJacques Vidrine 	return HEIM_ERR_EOF; /* XXX file might be too large */
2704137ff4cSJacques Vidrine     }
2714137ff4cSJacques Vidrine 
2724137ff4cSJacques Vidrine     memset(&key, 0, sizeof(key));
2734137ff4cSJacques Vidrine     key.keytype = ETYPE_DES_PCBC_NONE;
2744137ff4cSJacques Vidrine     ret = krb5_data_copy(&key.keyvalue, buf, len);
2755e9cd1aeSAssar Westerlund     memset(buf, 0, sizeof(buf));
2765e9cd1aeSAssar Westerlund     if(ret)
2775e9cd1aeSAssar Westerlund 	return ret;
2785e9cd1aeSAssar Westerlund 
2795e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, 0, &key, 0, mkey);
2805e9cd1aeSAssar Westerlund     krb5_free_keyblock_contents(context, &key);
2815e9cd1aeSAssar Westerlund     return ret;
2825e9cd1aeSAssar Westerlund }
2835e9cd1aeSAssar Westerlund 
2845e9cd1aeSAssar Westerlund krb5_error_code
hdb_read_master_key(krb5_context context,const char * filename,hdb_master_key * mkey)2855e9cd1aeSAssar Westerlund hdb_read_master_key(krb5_context context, const char *filename,
2865e9cd1aeSAssar Westerlund 		    hdb_master_key *mkey)
2875e9cd1aeSAssar Westerlund {
2885e9cd1aeSAssar Westerlund     FILE *f;
2895e9cd1aeSAssar Westerlund     unsigned char buf[16];
2905e9cd1aeSAssar Westerlund     krb5_error_code ret;
2915e9cd1aeSAssar Westerlund 
2925e9cd1aeSAssar Westerlund     off_t len;
2935e9cd1aeSAssar Westerlund 
2945e9cd1aeSAssar Westerlund     *mkey = NULL;
2955e9cd1aeSAssar Westerlund 
2965e9cd1aeSAssar Westerlund     if(filename == NULL)
2975e9cd1aeSAssar Westerlund 	filename = HDB_DB_DIR "/m-key";
2985e9cd1aeSAssar Westerlund 
2995e9cd1aeSAssar Westerlund     f = fopen(filename, "r");
3005e9cd1aeSAssar Westerlund     if(f == NULL) {
3015e9cd1aeSAssar Westerlund 	int save_errno = errno;
3025e9cd1aeSAssar Westerlund 	krb5_set_error_message(context, save_errno, "failed to open %s: %s",
3035e9cd1aeSAssar Westerlund 			       filename, strerror(save_errno));
3044137ff4cSJacques Vidrine 	return save_errno;
3054137ff4cSJacques Vidrine     }
3064137ff4cSJacques Vidrine 
3074137ff4cSJacques Vidrine     if(fread(buf, 1, 2, f) != 2) {
3084137ff4cSJacques Vidrine 	fclose(f);
3094137ff4cSJacques Vidrine 	krb5_set_error_message(context, HEIM_ERR_EOF, "end of file reading %s", filename);
3105e9cd1aeSAssar Westerlund 	return HEIM_ERR_EOF;
3115e9cd1aeSAssar Westerlund     }
3124137ff4cSJacques Vidrine 
3135e9cd1aeSAssar Westerlund     fseek(f, 0, SEEK_END);
3145e9cd1aeSAssar Westerlund     len = ftell(f);
3155e9cd1aeSAssar Westerlund 
3165e9cd1aeSAssar Westerlund     if(fclose(f) != 0)
3175e9cd1aeSAssar Westerlund 	return errno;
3185e9cd1aeSAssar Westerlund 
3195e9cd1aeSAssar Westerlund     if(len < 0)
3205e9cd1aeSAssar Westerlund 	return errno;
3215e9cd1aeSAssar Westerlund 
3225e9cd1aeSAssar Westerlund     if(len == 8) {
3235e9cd1aeSAssar Westerlund 	ret = read_master_krb4(context, filename, mkey);
3245e9cd1aeSAssar Westerlund     } else if(buf[0] == 0x30 && len <= 127 && buf[1] == len - 2) {
3255e9cd1aeSAssar Westerlund 	ret = read_master_encryptionkey(context, filename, mkey);
3265e9cd1aeSAssar Westerlund     } else if(buf[0] == 5 && buf[1] >= 1 && buf[1] <= 2) {
3275e9cd1aeSAssar Westerlund 	ret = read_master_keytab(context, filename, mkey);
3285e9cd1aeSAssar Westerlund     } else {
3295e9cd1aeSAssar Westerlund       /*
3305e9cd1aeSAssar Westerlund        * Check both LittleEndian and BigEndian since they key file
3315e9cd1aeSAssar Westerlund        * might be moved from a machine with diffrent byte order, or
3325e9cd1aeSAssar Westerlund        * its running on MacOS X that always uses BE master keys.
3335e9cd1aeSAssar Westerlund        */
3345e9cd1aeSAssar Westerlund       ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_LE, mkey);
3355e9cd1aeSAssar Westerlund       if (ret)
3365e9cd1aeSAssar Westerlund           ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_BE, mkey);
3375e9cd1aeSAssar Westerlund     }
3385e9cd1aeSAssar Westerlund     return ret;
3395e9cd1aeSAssar Westerlund }
3405e9cd1aeSAssar Westerlund 
3415e9cd1aeSAssar Westerlund krb5_error_code
hdb_write_master_key(krb5_context context,const char * filename,hdb_master_key mkey)3425e9cd1aeSAssar Westerlund hdb_write_master_key(krb5_context context, const char *filename,
3435e9cd1aeSAssar Westerlund 		     hdb_master_key mkey)
3445e9cd1aeSAssar Westerlund {
3455e9cd1aeSAssar Westerlund     krb5_error_code ret;
3465e9cd1aeSAssar Westerlund     hdb_master_key p;
3475e9cd1aeSAssar Westerlund     krb5_keytab kt;
3485e9cd1aeSAssar Westerlund 
3495e9cd1aeSAssar Westerlund     if(filename == NULL)
3505e9cd1aeSAssar Westerlund 	filename = HDB_DB_DIR "/m-key";
3515e9cd1aeSAssar Westerlund 
3525e9cd1aeSAssar Westerlund     ret = krb5_kt_resolve(context, filename, &kt);
3535e9cd1aeSAssar Westerlund     if(ret)
3545e9cd1aeSAssar Westerlund 	return ret;
3555e9cd1aeSAssar Westerlund 
3565e9cd1aeSAssar Westerlund     for(p = mkey; p; p = p->next) {
3575e9cd1aeSAssar Westerlund 	ret = krb5_kt_add_entry(context, kt, &p->keytab);
3585e9cd1aeSAssar Westerlund     }
3595e9cd1aeSAssar Westerlund 
3605e9cd1aeSAssar Westerlund     krb5_kt_close(context, kt);
3615e9cd1aeSAssar Westerlund 
362c19800e8SDoug Rabson     return ret;
363c19800e8SDoug Rabson }
3645e9cd1aeSAssar Westerlund 
3655e9cd1aeSAssar Westerlund hdb_master_key
_hdb_find_master_key(uint32_t * mkvno,hdb_master_key mkey)3665e9cd1aeSAssar Westerlund _hdb_find_master_key(uint32_t *mkvno, hdb_master_key mkey)
3675e9cd1aeSAssar Westerlund {
3685e9cd1aeSAssar Westerlund     hdb_master_key ret = NULL;
369c19800e8SDoug Rabson     while(mkey) {
3705e9cd1aeSAssar Westerlund 	if(ret == NULL && mkey->keytab.vno == 0)
3715e9cd1aeSAssar Westerlund 	    ret = mkey;
372c19800e8SDoug Rabson 	if(mkvno == NULL) {
3735e9cd1aeSAssar Westerlund 	    if(ret == NULL || mkey->keytab.vno > ret->keytab.vno)
3745e9cd1aeSAssar Westerlund 		ret = mkey;
3755e9cd1aeSAssar Westerlund 	} else if((uint32_t)mkey->keytab.vno == *mkvno)
3765e9cd1aeSAssar Westerlund 	    return mkey;
3775e9cd1aeSAssar Westerlund 	mkey = mkey->next;
3785e9cd1aeSAssar Westerlund     }
379c19800e8SDoug Rabson     return ret;
380c19800e8SDoug Rabson }
3815e9cd1aeSAssar Westerlund 
382c19800e8SDoug Rabson int
_hdb_mkey_version(hdb_master_key mkey)383c19800e8SDoug Rabson _hdb_mkey_version(hdb_master_key mkey)
384c19800e8SDoug Rabson {
385c19800e8SDoug Rabson     return mkey->keytab.vno;
386c19800e8SDoug Rabson }
387c19800e8SDoug Rabson 
388c19800e8SDoug Rabson int
_hdb_mkey_decrypt(krb5_context context,hdb_master_key key,krb5_key_usage usage,void * ptr,size_t size,krb5_data * res)389c19800e8SDoug Rabson _hdb_mkey_decrypt(krb5_context context, hdb_master_key key,
390c19800e8SDoug Rabson 		  krb5_key_usage usage,
391c19800e8SDoug Rabson 		  void *ptr, size_t size, krb5_data *res)
392c19800e8SDoug Rabson {
393c19800e8SDoug Rabson     return krb5_decrypt(context, key->crypto, usage,
394c19800e8SDoug Rabson 			ptr, size, res);
395c19800e8SDoug Rabson }
396c19800e8SDoug Rabson 
397c19800e8SDoug Rabson int
_hdb_mkey_encrypt(krb5_context context,hdb_master_key key,krb5_key_usage usage,const void * ptr,size_t size,krb5_data * res)398c19800e8SDoug Rabson _hdb_mkey_encrypt(krb5_context context, hdb_master_key key,
399c19800e8SDoug Rabson 		  krb5_key_usage usage,
400c19800e8SDoug Rabson 		  const void *ptr, size_t size, krb5_data *res)
401c19800e8SDoug Rabson {
402c19800e8SDoug Rabson     return krb5_encrypt(context, key->crypto, usage,
403c19800e8SDoug Rabson 			ptr, size, res);
404c19800e8SDoug Rabson }
405c19800e8SDoug Rabson 
406c19800e8SDoug Rabson krb5_error_code
hdb_unseal_key_mkey(krb5_context context,Key * k,hdb_master_key mkey)4075e9cd1aeSAssar Westerlund hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
4085e9cd1aeSAssar Westerlund {
409bbd80c28SJacques Vidrine 
4105e9cd1aeSAssar Westerlund     krb5_error_code ret;
4115e9cd1aeSAssar Westerlund     krb5_data res;
4125e9cd1aeSAssar Westerlund     size_t keysize;
4135e9cd1aeSAssar Westerlund 
414c19800e8SDoug Rabson     hdb_master_key key;
4155e9cd1aeSAssar Westerlund 
416c19800e8SDoug Rabson     if(k->mkvno == NULL)
4175e9cd1aeSAssar Westerlund 	return 0;
4185e9cd1aeSAssar Westerlund 
4195e9cd1aeSAssar Westerlund     key = _hdb_find_master_key(k->mkvno, mkey);
4205e9cd1aeSAssar Westerlund 
421c19800e8SDoug Rabson     if (key == NULL)
4225e9cd1aeSAssar Westerlund 	return HDB_ERR_NO_MKEY;
4235e9cd1aeSAssar Westerlund 
4245e9cd1aeSAssar Westerlund     ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY,
425c19800e8SDoug Rabson 			    k->key.keyvalue.data,
426c19800e8SDoug Rabson 			    k->key.keyvalue.length,
427c19800e8SDoug Rabson 			    &res);
428c19800e8SDoug Rabson     if(ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
429c19800e8SDoug Rabson 	/* try to decrypt with MIT key usage */
430c19800e8SDoug Rabson 	ret = _hdb_mkey_decrypt(context, key, 0,
431c19800e8SDoug Rabson 				k->key.keyvalue.data,
4325e9cd1aeSAssar Westerlund 				k->key.keyvalue.length,
4335e9cd1aeSAssar Westerlund 				&res);
4345e9cd1aeSAssar Westerlund     }
435bbd80c28SJacques Vidrine     if (ret)
436bbd80c28SJacques Vidrine 	return ret;
437bbd80c28SJacques Vidrine 
438bbd80c28SJacques Vidrine     /* fixup keylength if the key got padded when encrypting it */
439bbd80c28SJacques Vidrine     ret = krb5_enctype_keysize(context, k->key.keytype, &keysize);
440bbd80c28SJacques Vidrine     if (ret) {
441bbd80c28SJacques Vidrine 	krb5_data_free(&res);
442bbd80c28SJacques Vidrine 	return ret;
443bbd80c28SJacques Vidrine     }
444bbd80c28SJacques Vidrine     if (keysize > res.length) {
445bbd80c28SJacques Vidrine 	krb5_data_free(&res);
4465e9cd1aeSAssar Westerlund 	return KRB5_BAD_KEYSIZE;
4475e9cd1aeSAssar Westerlund     }
4485e9cd1aeSAssar Westerlund 
449bbd80c28SJacques Vidrine     memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
4505e9cd1aeSAssar Westerlund     free(k->key.keyvalue.data);
4515e9cd1aeSAssar Westerlund     k->key.keyvalue = res;
452c19800e8SDoug Rabson     k->key.keyvalue.length = keysize;
453c19800e8SDoug Rabson     free(k->mkvno);
454c19800e8SDoug Rabson     k->mkvno = NULL;
455c19800e8SDoug Rabson 
456c19800e8SDoug Rabson     return 0;
457c19800e8SDoug Rabson }
458c19800e8SDoug Rabson 
459c19800e8SDoug Rabson krb5_error_code
hdb_unseal_keys_mkey(krb5_context context,hdb_entry * ent,hdb_master_key mkey)460c19800e8SDoug Rabson hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
461c19800e8SDoug Rabson {
462c19800e8SDoug Rabson     size_t i;
463c19800e8SDoug Rabson 
464c19800e8SDoug Rabson     for(i = 0; i < ent->keys.len; i++){
465c19800e8SDoug Rabson 	krb5_error_code ret;
466c19800e8SDoug Rabson 
4675e9cd1aeSAssar Westerlund 	ret = hdb_unseal_key_mkey(context, &ent->keys.val[i], mkey);
4685e9cd1aeSAssar Westerlund 	if (ret)
4695e9cd1aeSAssar Westerlund 	    return ret;
4705e9cd1aeSAssar Westerlund     }
4715e9cd1aeSAssar Westerlund     return 0;
4725e9cd1aeSAssar Westerlund }
4735e9cd1aeSAssar Westerlund 
474c19800e8SDoug Rabson krb5_error_code
hdb_unseal_keys(krb5_context context,HDB * db,hdb_entry * ent)4755e9cd1aeSAssar Westerlund hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent)
476c19800e8SDoug Rabson {
4775e9cd1aeSAssar Westerlund     if (db->hdb_master_key_set == 0)
4785e9cd1aeSAssar Westerlund 	return 0;
4795e9cd1aeSAssar Westerlund     return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key);
480c19800e8SDoug Rabson }
4815e9cd1aeSAssar Westerlund 
482c19800e8SDoug Rabson krb5_error_code
hdb_unseal_key(krb5_context context,HDB * db,Key * k)483c19800e8SDoug Rabson hdb_unseal_key(krb5_context context, HDB *db, Key *k)
484c19800e8SDoug Rabson {
485c19800e8SDoug Rabson     if (db->hdb_master_key_set == 0)
486c19800e8SDoug Rabson 	return 0;
487c19800e8SDoug Rabson     return hdb_unseal_key_mkey(context, k, db->hdb_master_key);
488c19800e8SDoug Rabson }
489c19800e8SDoug Rabson 
4905e9cd1aeSAssar Westerlund krb5_error_code
hdb_seal_key_mkey(krb5_context context,Key * k,hdb_master_key mkey)4915e9cd1aeSAssar Westerlund hdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
4925e9cd1aeSAssar Westerlund {
4935e9cd1aeSAssar Westerlund     krb5_error_code ret;
4945e9cd1aeSAssar Westerlund     krb5_data res;
495c19800e8SDoug Rabson     hdb_master_key key;
4965e9cd1aeSAssar Westerlund 
497c19800e8SDoug Rabson     if(k->mkvno != NULL)
4985e9cd1aeSAssar Westerlund 	return 0;
4995e9cd1aeSAssar Westerlund 
5005e9cd1aeSAssar Westerlund     key = _hdb_find_master_key(k->mkvno, mkey);
5015e9cd1aeSAssar Westerlund 
502c19800e8SDoug Rabson     if (key == NULL)
5035e9cd1aeSAssar Westerlund 	return HDB_ERR_NO_MKEY;
5045e9cd1aeSAssar Westerlund 
5055e9cd1aeSAssar Westerlund     ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY,
5065e9cd1aeSAssar Westerlund 			    k->key.keyvalue.data,
5075e9cd1aeSAssar Westerlund 			    k->key.keyvalue.length,
5085e9cd1aeSAssar Westerlund 			    &res);
5095e9cd1aeSAssar Westerlund     if (ret)
5105e9cd1aeSAssar Westerlund 	return ret;
5115e9cd1aeSAssar Westerlund 
5125e9cd1aeSAssar Westerlund     memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
513c19800e8SDoug Rabson     free(k->key.keyvalue.data);
5145e9cd1aeSAssar Westerlund     k->key.keyvalue = res;
5155e9cd1aeSAssar Westerlund 
5165e9cd1aeSAssar Westerlund     if (k->mkvno == NULL) {
517c19800e8SDoug Rabson 	k->mkvno = malloc(sizeof(*k->mkvno));
5185e9cd1aeSAssar Westerlund 	if (k->mkvno == NULL)
519c19800e8SDoug Rabson 	    return ENOMEM;
520c19800e8SDoug Rabson     }
521c19800e8SDoug Rabson     *k->mkvno = key->keytab.vno;
522c19800e8SDoug Rabson 
523c19800e8SDoug Rabson     return 0;
524c19800e8SDoug Rabson }
525c19800e8SDoug Rabson 
526c19800e8SDoug Rabson krb5_error_code
hdb_seal_keys_mkey(krb5_context context,hdb_entry * ent,hdb_master_key mkey)527c19800e8SDoug Rabson hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
528c19800e8SDoug Rabson {
529c19800e8SDoug Rabson     size_t i;
530c19800e8SDoug Rabson     for(i = 0; i < ent->keys.len; i++){
531c19800e8SDoug Rabson 	krb5_error_code ret;
532c19800e8SDoug Rabson 
5335e9cd1aeSAssar Westerlund 	ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey);
5345e9cd1aeSAssar Westerlund 	if (ret)
5355e9cd1aeSAssar Westerlund 	    return ret;
5365e9cd1aeSAssar Westerlund     }
5375e9cd1aeSAssar Westerlund     return 0;
5385e9cd1aeSAssar Westerlund }
5395e9cd1aeSAssar Westerlund 
540c19800e8SDoug Rabson krb5_error_code
hdb_seal_keys(krb5_context context,HDB * db,hdb_entry * ent)5415e9cd1aeSAssar Westerlund hdb_seal_keys(krb5_context context, HDB *db, hdb_entry *ent)
5425e9cd1aeSAssar Westerlund {
543c19800e8SDoug Rabson     if (db->hdb_master_key_set == 0)
544c19800e8SDoug Rabson 	return 0;
545c19800e8SDoug Rabson 
546c19800e8SDoug Rabson     return hdb_seal_keys_mkey(context, ent, db->hdb_master_key);
547c19800e8SDoug Rabson }
548c19800e8SDoug Rabson 
549c19800e8SDoug Rabson krb5_error_code
hdb_seal_key(krb5_context context,HDB * db,Key * k)550c19800e8SDoug Rabson hdb_seal_key(krb5_context context, HDB *db, Key *k)
551c19800e8SDoug Rabson {
552c19800e8SDoug Rabson     if (db->hdb_master_key_set == 0)
5535e9cd1aeSAssar Westerlund 	return 0;
5545e9cd1aeSAssar Westerlund 
5555e9cd1aeSAssar Westerlund     return hdb_seal_key_mkey(context, k, db->hdb_master_key);
5565e9cd1aeSAssar Westerlund }
5575e9cd1aeSAssar Westerlund 
5585e9cd1aeSAssar Westerlund krb5_error_code
hdb_set_master_key(krb5_context context,HDB * db,krb5_keyblock * key)5595e9cd1aeSAssar Westerlund hdb_set_master_key (krb5_context context,
5605e9cd1aeSAssar Westerlund 		    HDB *db,
5615e9cd1aeSAssar Westerlund 		    krb5_keyblock *key)
5625e9cd1aeSAssar Westerlund {
5635e9cd1aeSAssar Westerlund     krb5_error_code ret;
5645e9cd1aeSAssar Westerlund     hdb_master_key mkey;
5655e9cd1aeSAssar Westerlund 
566c19800e8SDoug Rabson     ret = hdb_process_master_key(context, 0, key, 0, &mkey);
5675e9cd1aeSAssar Westerlund     if (ret)
5685e9cd1aeSAssar Westerlund 	return ret;
5695e9cd1aeSAssar Westerlund     db->hdb_master_key = mkey;
570c19800e8SDoug Rabson #if 0 /* XXX - why? */
5715e9cd1aeSAssar Westerlund     des_set_random_generator_seed(key.keyvalue.data);
5725e9cd1aeSAssar Westerlund #endif
5735e9cd1aeSAssar Westerlund     db->hdb_master_key_set = 1;
5745e9cd1aeSAssar Westerlund     return 0;
5755e9cd1aeSAssar Westerlund }
5765e9cd1aeSAssar Westerlund 
5775e9cd1aeSAssar Westerlund krb5_error_code
hdb_set_master_keyfile(krb5_context context,HDB * db,const char * keyfile)5785e9cd1aeSAssar Westerlund hdb_set_master_keyfile (krb5_context context,
5795e9cd1aeSAssar Westerlund 			HDB *db,
5805e9cd1aeSAssar Westerlund 			const char *keyfile)
5815e9cd1aeSAssar Westerlund {
5825e9cd1aeSAssar Westerlund     hdb_master_key key;
5835e9cd1aeSAssar Westerlund     krb5_error_code ret;
5845e9cd1aeSAssar Westerlund 
5855e9cd1aeSAssar Westerlund     ret = hdb_read_master_key(context, keyfile, &key);
5864137ff4cSJacques Vidrine     if (ret) {
5875e9cd1aeSAssar Westerlund 	if (ret != ENOENT)
5885e9cd1aeSAssar Westerlund 	    return ret;
589c19800e8SDoug Rabson 	krb5_clear_error_message(context);
590c19800e8SDoug Rabson 	return 0;
5915e9cd1aeSAssar Westerlund     }
5925e9cd1aeSAssar Westerlund     db->hdb_master_key = key;
5935e9cd1aeSAssar Westerlund     db->hdb_master_key_set = 1;
5945e9cd1aeSAssar Westerlund     return ret;
5955e9cd1aeSAssar Westerlund }
5965e9cd1aeSAssar Westerlund 
5975e9cd1aeSAssar Westerlund krb5_error_code
hdb_clear_master_key(krb5_context context,HDB * db)598c19800e8SDoug Rabson hdb_clear_master_key (krb5_context context,
599c19800e8SDoug Rabson 		      HDB *db)
600c19800e8SDoug Rabson {
6015e9cd1aeSAssar Westerlund     if (db->hdb_master_key_set) {
6025e9cd1aeSAssar Westerlund 	hdb_free_master_key(context, db->hdb_master_key);
6035e9cd1aeSAssar Westerlund 	db->hdb_master_key_set = 0;
604     }
605     return 0;
606 }
607