xref: /freebsd/crypto/heimdal/lib/hdb/mkey.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
15e9cd1aeSAssar Westerlund /*
2*ae771770SStanislav Sedov  * 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 
395e9cd1aeSAssar Westerlund 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);
514137ff4cSJacques Vidrine 	if (mkey->crypto)
525e9cd1aeSAssar Westerlund 	    krb5_crypto_destroy(context, mkey->crypto);
535e9cd1aeSAssar Westerlund 	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;
654137ff4cSJacques Vidrine 
665e9cd1aeSAssar Westerlund     *mkey = calloc(1, sizeof(**mkey));
674137ff4cSJacques Vidrine     if(*mkey == NULL) {
68*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
695e9cd1aeSAssar Westerlund 	return ENOMEM;
704137ff4cSJacques Vidrine     }
715e9cd1aeSAssar Westerlund     (*mkey)->keytab.vno = kvno;
725e9cd1aeSAssar Westerlund     ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal);
734137ff4cSJacques Vidrine     if(ret)
744137ff4cSJacques Vidrine 	goto fail;
755e9cd1aeSAssar Westerlund     ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock);
764137ff4cSJacques Vidrine     if(ret)
774137ff4cSJacques Vidrine 	goto fail;
785e9cd1aeSAssar Westerlund     if(etype != 0)
795e9cd1aeSAssar Westerlund 	(*mkey)->keytab.keyblock.keytype = etype;
805e9cd1aeSAssar Westerlund     (*mkey)->keytab.timestamp = time(NULL);
815e9cd1aeSAssar Westerlund     ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto);
824137ff4cSJacques Vidrine     if(ret)
834137ff4cSJacques Vidrine 	goto fail;
844137ff4cSJacques Vidrine     return 0;
854137ff4cSJacques Vidrine  fail:
864137ff4cSJacques Vidrine     hdb_free_master_key(context, *mkey);
875e9cd1aeSAssar Westerlund     *mkey = NULL;
885e9cd1aeSAssar Westerlund     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));
130c19800e8SDoug Rabson 	if(p == NULL) {
131c19800e8SDoug Rabson 	    krb5_kt_end_seq_get(context, id, &cursor);
132c19800e8SDoug Rabson 	    ret = ENOMEM;
133c19800e8SDoug Rabson 	    goto out;
134c19800e8SDoug Rabson 	}
1355e9cd1aeSAssar Westerlund 	p->keytab = entry;
1365e9cd1aeSAssar Westerlund 	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,
149*ae771770SStanislav Sedov 		int byteorder, hdb_master_key *mkey)
1505e9cd1aeSAssar Westerlund {
1515e9cd1aeSAssar Westerlund     int fd;
1525e9cd1aeSAssar Westerlund     krb5_error_code ret;
1535e9cd1aeSAssar Westerlund     krb5_storage *sp;
154c19800e8SDoug Rabson     int16_t enctype;
1555e9cd1aeSAssar Westerlund     krb5_keyblock key;
1565e9cd1aeSAssar Westerlund 
1575e9cd1aeSAssar Westerlund     fd = open(filename, O_RDONLY | O_BINARY);
1584137ff4cSJacques Vidrine     if(fd < 0) {
1594137ff4cSJacques Vidrine 	int save_errno = errno;
160*ae771770SStanislav Sedov 	krb5_set_error_message(context, save_errno, "failed to open %s: %s",
161*ae771770SStanislav Sedov 			       filename, strerror(save_errno));
1624137ff4cSJacques Vidrine 	return save_errno;
1634137ff4cSJacques Vidrine     }
1645e9cd1aeSAssar Westerlund     sp = krb5_storage_from_fd(fd);
1655e9cd1aeSAssar Westerlund     if(sp == NULL) {
1665e9cd1aeSAssar Westerlund 	close(fd);
1675e9cd1aeSAssar Westerlund 	return errno;
1685e9cd1aeSAssar Westerlund     }
169*ae771770SStanislav Sedov     krb5_storage_set_flags(sp, byteorder);
1705e9cd1aeSAssar Westerlund     /* could possibly use ret_keyblock here, but do it with more
1715e9cd1aeSAssar Westerlund        checks for now */
172*ae771770SStanislav Sedov     {
1735e9cd1aeSAssar Westerlund 	ret = krb5_ret_int16(sp, &enctype);
174*ae771770SStanislav Sedov 	if (ret)
1755e9cd1aeSAssar Westerlund 	    goto out;
176*ae771770SStanislav Sedov 	ret = krb5_enctype_valid(context, enctype);
177*ae771770SStanislav Sedov 	if (ret)
178*ae771770SStanislav Sedov 	   goto out;
1795e9cd1aeSAssar Westerlund 	key.keytype = enctype;
1805e9cd1aeSAssar Westerlund 	ret = krb5_ret_data(sp, &key.keyvalue);
1815e9cd1aeSAssar Westerlund 	if(ret)
1825e9cd1aeSAssar Westerlund 	    goto out;
183*ae771770SStanislav Sedov     }
184*ae771770SStanislav Sedov     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;
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;
207*ae771770SStanislav Sedov 	krb5_set_error_message(context, save_errno, "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;
216*ae771770SStanislav Sedov 	krb5_set_error_message(context, save_errno, "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. */
231*ae771770SStanislav Sedov     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);
2514137ff4cSJacques Vidrine     if(fd < 0) {
2524137ff4cSJacques Vidrine 	int save_errno = errno;
253*ae771770SStanislav Sedov 	krb5_set_error_message(context, save_errno, "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;
262*ae771770SStanislav Sedov 	krb5_set_error_message(context, save_errno, "error reading %s: %s",
2634137ff4cSJacques Vidrine 			       filename, strerror(save_errno));
2644137ff4cSJacques Vidrine 	return save_errno;
2654137ff4cSJacques Vidrine     }
2664137ff4cSJacques Vidrine     if(len != 8) {
267*ae771770SStanislav Sedov 	krb5_set_error_message(context, HEIM_ERR_EOF,
268*ae771770SStanislav Sedov 			       "bad contents of %s", filename);
2694137ff4cSJacques Vidrine 	return HEIM_ERR_EOF; /* XXX file might be too large */
2704137ff4cSJacques Vidrine     }
2715e9cd1aeSAssar Westerlund 
2725e9cd1aeSAssar Westerlund     memset(&key, 0, sizeof(key));
2735e9cd1aeSAssar Westerlund     key.keytype = ETYPE_DES_PCBC_NONE;
2745e9cd1aeSAssar Westerlund     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");
3004137ff4cSJacques Vidrine     if(f == NULL) {
3014137ff4cSJacques Vidrine 	int save_errno = errno;
302*ae771770SStanislav Sedov 	krb5_set_error_message(context, save_errno, "failed to open %s: %s",
3034137ff4cSJacques Vidrine 			       filename, strerror(save_errno));
3044137ff4cSJacques Vidrine 	return save_errno;
3054137ff4cSJacques Vidrine     }
3065e9cd1aeSAssar Westerlund 
3075e9cd1aeSAssar Westerlund     if(fread(buf, 1, 2, f) != 2) {
3085e9cd1aeSAssar Westerlund 	fclose(f);
309*ae771770SStanislav Sedov 	krb5_set_error_message(context, HEIM_ERR_EOF, "end of file reading %s", filename);
3105e9cd1aeSAssar Westerlund 	return HEIM_ERR_EOF;
3115e9cd1aeSAssar Westerlund     }
3125e9cd1aeSAssar Westerlund 
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 {
329*ae771770SStanislav Sedov       /*
330*ae771770SStanislav Sedov        * Check both LittleEndian and BigEndian since they key file
331*ae771770SStanislav Sedov        * might be moved from a machine with diffrent byte order, or
332*ae771770SStanislav Sedov        * its running on MacOS X that always uses BE master keys.
333*ae771770SStanislav Sedov        */
334*ae771770SStanislav Sedov       ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_LE, mkey);
335*ae771770SStanislav Sedov       if (ret)
336*ae771770SStanislav Sedov           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 
3625e9cd1aeSAssar Westerlund     return ret;
3635e9cd1aeSAssar Westerlund }
3645e9cd1aeSAssar Westerlund 
365c19800e8SDoug Rabson hdb_master_key
_hdb_find_master_key(uint32_t * mkvno,hdb_master_key mkey)366c19800e8SDoug Rabson _hdb_find_master_key(uint32_t *mkvno, hdb_master_key mkey)
3675e9cd1aeSAssar Westerlund {
3685e9cd1aeSAssar Westerlund     hdb_master_key ret = NULL;
3695e9cd1aeSAssar Westerlund     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;
375*ae771770SStanislav Sedov 	} else if((uint32_t)mkey->keytab.vno == *mkvno)
3765e9cd1aeSAssar Westerlund 	    return mkey;
3775e9cd1aeSAssar Westerlund 	mkey = mkey->next;
3785e9cd1aeSAssar Westerlund     }
3795e9cd1aeSAssar Westerlund     return ret;
3805e9cd1aeSAssar Westerlund }
3815e9cd1aeSAssar Westerlund 
382c19800e8SDoug Rabson int
_hdb_mkey_version(hdb_master_key mkey)383c19800e8SDoug Rabson _hdb_mkey_version(hdb_master_key mkey)
3845e9cd1aeSAssar Westerlund {
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)407c19800e8SDoug Rabson hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
408c19800e8SDoug Rabson {
409c19800e8SDoug Rabson 
4105e9cd1aeSAssar Westerlund     krb5_error_code ret;
4115e9cd1aeSAssar Westerlund     krb5_data res;
412bbd80c28SJacques Vidrine     size_t keysize;
4135e9cd1aeSAssar Westerlund 
4145e9cd1aeSAssar Westerlund     hdb_master_key key;
4155e9cd1aeSAssar Westerlund 
4165e9cd1aeSAssar Westerlund     if(k->mkvno == NULL)
417c19800e8SDoug Rabson 	return 0;
4185e9cd1aeSAssar Westerlund 
419c19800e8SDoug Rabson     key = _hdb_find_master_key(k->mkvno, mkey);
4205e9cd1aeSAssar Westerlund 
4215e9cd1aeSAssar Westerlund     if (key == NULL)
4225e9cd1aeSAssar Westerlund 	return HDB_ERR_NO_MKEY;
4235e9cd1aeSAssar Westerlund 
424c19800e8SDoug Rabson     ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY,
4255e9cd1aeSAssar Westerlund 			    k->key.keyvalue.data,
4265e9cd1aeSAssar Westerlund 			    k->key.keyvalue.length,
4275e9cd1aeSAssar Westerlund 			    &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,
432c19800e8SDoug Rabson 				k->key.keyvalue.length,
433c19800e8SDoug Rabson 				&res);
434c19800e8SDoug Rabson     }
4355e9cd1aeSAssar Westerlund     if (ret)
4365e9cd1aeSAssar Westerlund 	return ret;
4375e9cd1aeSAssar Westerlund 
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);
446bbd80c28SJacques Vidrine 	return KRB5_BAD_KEYSIZE;
447bbd80c28SJacques Vidrine     }
448bbd80c28SJacques Vidrine 
4495e9cd1aeSAssar Westerlund     memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
4505e9cd1aeSAssar Westerlund     free(k->key.keyvalue.data);
4515e9cd1aeSAssar Westerlund     k->key.keyvalue = res;
452bbd80c28SJacques Vidrine     k->key.keyvalue.length = keysize;
4535e9cd1aeSAssar Westerlund     free(k->mkvno);
4545e9cd1aeSAssar Westerlund     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 {
462*ae771770SStanislav Sedov     size_t i;
463c19800e8SDoug Rabson 
464c19800e8SDoug Rabson     for(i = 0; i < ent->keys.len; i++){
465c19800e8SDoug Rabson 	krb5_error_code ret;
466c19800e8SDoug Rabson 
467c19800e8SDoug Rabson 	ret = hdb_unseal_key_mkey(context, &ent->keys.val[i], mkey);
468c19800e8SDoug Rabson 	if (ret)
469c19800e8SDoug Rabson 	    return ret;
4705e9cd1aeSAssar Westerlund     }
4715e9cd1aeSAssar Westerlund     return 0;
4725e9cd1aeSAssar Westerlund }
4735e9cd1aeSAssar Westerlund 
4745e9cd1aeSAssar Westerlund 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)
4765e9cd1aeSAssar Westerlund {
477c19800e8SDoug Rabson     if (db->hdb_master_key_set == 0)
4785e9cd1aeSAssar Westerlund 	return 0;
479c19800e8SDoug Rabson     return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key);
4805e9cd1aeSAssar Westerlund }
4815e9cd1aeSAssar Westerlund 
4825e9cd1aeSAssar Westerlund 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)
4845e9cd1aeSAssar Westerlund {
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 
490c19800e8SDoug Rabson krb5_error_code
hdb_seal_key_mkey(krb5_context context,Key * k,hdb_master_key mkey)491c19800e8SDoug Rabson hdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
492c19800e8SDoug Rabson {
4935e9cd1aeSAssar Westerlund     krb5_error_code ret;
4945e9cd1aeSAssar Westerlund     krb5_data res;
4955e9cd1aeSAssar Westerlund     hdb_master_key key;
4965e9cd1aeSAssar Westerlund 
4975e9cd1aeSAssar Westerlund     if(k->mkvno != NULL)
498c19800e8SDoug Rabson 	return 0;
4995e9cd1aeSAssar Westerlund 
500c19800e8SDoug Rabson     key = _hdb_find_master_key(k->mkvno, mkey);
5015e9cd1aeSAssar Westerlund 
5025e9cd1aeSAssar Westerlund     if (key == NULL)
5035e9cd1aeSAssar Westerlund 	return HDB_ERR_NO_MKEY;
5045e9cd1aeSAssar Westerlund 
505c19800e8SDoug Rabson     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);
5135e9cd1aeSAssar Westerlund     free(k->key.keyvalue.data);
5145e9cd1aeSAssar Westerlund     k->key.keyvalue = res;
5155e9cd1aeSAssar Westerlund 
516c19800e8SDoug Rabson     if (k->mkvno == NULL) {
5175e9cd1aeSAssar Westerlund 	k->mkvno = malloc(sizeof(*k->mkvno));
5185e9cd1aeSAssar Westerlund 	if (k->mkvno == NULL)
5195e9cd1aeSAssar Westerlund 	    return ENOMEM;
520c19800e8SDoug Rabson     }
5215e9cd1aeSAssar Westerlund     *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 {
529*ae771770SStanislav Sedov     size_t i;
530c19800e8SDoug Rabson     for(i = 0; i < ent->keys.len; i++){
531c19800e8SDoug Rabson 	krb5_error_code ret;
532c19800e8SDoug Rabson 
533c19800e8SDoug Rabson 	ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey);
534c19800e8SDoug Rabson 	if (ret)
535c19800e8SDoug Rabson 	    return ret;
5365e9cd1aeSAssar Westerlund     }
5375e9cd1aeSAssar Westerlund     return 0;
5385e9cd1aeSAssar Westerlund }
5395e9cd1aeSAssar Westerlund 
5405e9cd1aeSAssar Westerlund 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)
5445e9cd1aeSAssar Westerlund 	return 0;
5455e9cd1aeSAssar Westerlund 
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)
553c19800e8SDoug Rabson 	return 0;
554c19800e8SDoug Rabson 
555c19800e8SDoug Rabson     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 
5665e9cd1aeSAssar Westerlund     ret = hdb_process_master_key(context, 0, key, 0, &mkey);
5675e9cd1aeSAssar Westerlund     if (ret)
5685e9cd1aeSAssar Westerlund 	return ret;
569c19800e8SDoug Rabson     db->hdb_master_key = mkey;
5705e9cd1aeSAssar Westerlund #if 0 /* XXX - why? */
5715e9cd1aeSAssar Westerlund     des_set_random_generator_seed(key.keyvalue.data);
5725e9cd1aeSAssar Westerlund #endif
573c19800e8SDoug Rabson     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);
5865e9cd1aeSAssar Westerlund     if (ret) {
5875e9cd1aeSAssar Westerlund 	if (ret != ENOENT)
5885e9cd1aeSAssar Westerlund 	    return ret;
589*ae771770SStanislav Sedov 	krb5_clear_error_message(context);
5905e9cd1aeSAssar Westerlund 	return 0;
5915e9cd1aeSAssar Westerlund     }
592c19800e8SDoug Rabson     db->hdb_master_key = key;
593c19800e8SDoug Rabson     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)5985e9cd1aeSAssar Westerlund hdb_clear_master_key (krb5_context context,
5995e9cd1aeSAssar Westerlund 		      HDB *db)
6005e9cd1aeSAssar Westerlund {
601c19800e8SDoug Rabson     if (db->hdb_master_key_set) {
602c19800e8SDoug Rabson 	hdb_free_master_key(context, db->hdb_master_key);
603c19800e8SDoug Rabson 	db->hdb_master_key_set = 0;
6045e9cd1aeSAssar Westerlund     }
6055e9cd1aeSAssar Westerlund     return 0;
6065e9cd1aeSAssar Westerlund }
607