Home | History | Annotate | Line # | Download | only in hdb
      1  1.1     elric /*	$NetBSD: mkey.c,v 1.3 2019/12/15 22:50:49 christos Exp $	*/
      2  1.1     elric 
      3  1.1     elric /*
      4  1.1     elric  * Copyright (c) 2000 - 2004 Kungliga Tekniska Hgskolan
      5  1.1     elric  * (Royal Institute of Technology, Stockholm, Sweden).
      6  1.1     elric  * All rights reserved.
      7  1.1     elric  *
      8  1.1     elric  * Redistribution and use in source and binary forms, with or without
      9  1.1     elric  * modification, are permitted provided that the following conditions
     10  1.1     elric  * are met:
     11  1.1     elric  *
     12  1.1     elric  * 1. Redistributions of source code must retain the above copyright
     13  1.1     elric  *    notice, this list of conditions and the following disclaimer.
     14  1.1     elric  *
     15  1.1     elric  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1     elric  *    notice, this list of conditions and the following disclaimer in the
     17  1.1     elric  *    documentation and/or other materials provided with the distribution.
     18  1.1     elric  *
     19  1.1     elric  * 3. Neither the name of the Institute nor the names of its contributors
     20  1.1     elric  *    may be used to endorse or promote products derived from this software
     21  1.1     elric  *    without specific prior written permission.
     22  1.1     elric  *
     23  1.1     elric  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  1.1     elric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  1.1     elric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  1.1     elric  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  1.1     elric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  1.1     elric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  1.1     elric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  1.1     elric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  1.1     elric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  1.1     elric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  1.1     elric  * SUCH DAMAGE.
     34  1.1     elric  */
     35  1.1     elric 
     36  1.1     elric #include "hdb_locl.h"
     37  1.1     elric #ifndef O_BINARY
     38  1.1     elric #define O_BINARY 0
     39  1.1     elric #endif
     40  1.1     elric 
     41  1.1     elric struct hdb_master_key_data {
     42  1.1     elric     krb5_keytab_entry keytab;
     43  1.1     elric     krb5_crypto crypto;
     44  1.1     elric     struct hdb_master_key_data *next;
     45  1.2  christos     unsigned int key_usage;
     46  1.1     elric };
     47  1.1     elric 
     48  1.1     elric void
     49  1.1     elric hdb_free_master_key(krb5_context context, hdb_master_key mkey)
     50  1.1     elric {
     51  1.1     elric     struct hdb_master_key_data *ptr;
     52  1.1     elric     while(mkey) {
     53  1.1     elric 	krb5_kt_free_entry(context, &mkey->keytab);
     54  1.1     elric 	if (mkey->crypto)
     55  1.1     elric 	    krb5_crypto_destroy(context, mkey->crypto);
     56  1.1     elric 	ptr = mkey;
     57  1.1     elric 	mkey = mkey->next;
     58  1.1     elric 	free(ptr);
     59  1.1     elric     }
     60  1.1     elric }
     61  1.1     elric 
     62  1.1     elric krb5_error_code
     63  1.1     elric hdb_process_master_key(krb5_context context,
     64  1.1     elric 		       int kvno, krb5_keyblock *key, krb5_enctype etype,
     65  1.1     elric 		       hdb_master_key *mkey)
     66  1.1     elric {
     67  1.1     elric     krb5_error_code ret;
     68  1.1     elric 
     69  1.1     elric     *mkey = calloc(1, sizeof(**mkey));
     70  1.1     elric     if(*mkey == NULL) {
     71  1.1     elric 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
     72  1.1     elric 	return ENOMEM;
     73  1.1     elric     }
     74  1.2  christos     (*mkey)->key_usage = HDB_KU_MKEY;
     75  1.1     elric     (*mkey)->keytab.vno = kvno;
     76  1.1     elric     ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal);
     77  1.1     elric     if(ret)
     78  1.1     elric 	goto fail;
     79  1.1     elric     ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock);
     80  1.1     elric     if(ret)
     81  1.1     elric 	goto fail;
     82  1.1     elric     if(etype != 0)
     83  1.1     elric 	(*mkey)->keytab.keyblock.keytype = etype;
     84  1.1     elric     (*mkey)->keytab.timestamp = time(NULL);
     85  1.1     elric     ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto);
     86  1.1     elric     if(ret)
     87  1.1     elric 	goto fail;
     88  1.1     elric     return 0;
     89  1.1     elric  fail:
     90  1.1     elric     hdb_free_master_key(context, *mkey);
     91  1.1     elric     *mkey = NULL;
     92  1.1     elric     return ret;
     93  1.1     elric }
     94  1.1     elric 
     95  1.1     elric krb5_error_code
     96  1.1     elric hdb_add_master_key(krb5_context context, krb5_keyblock *key,
     97  1.1     elric 		   hdb_master_key *inout)
     98  1.1     elric {
     99  1.1     elric     int vno = 0;
    100  1.1     elric     hdb_master_key p;
    101  1.1     elric     krb5_error_code ret;
    102  1.1     elric 
    103  1.1     elric     for(p = *inout; p; p = p->next)
    104  1.1     elric 	vno = max(vno, p->keytab.vno);
    105  1.1     elric     vno++;
    106  1.1     elric     ret = hdb_process_master_key(context, vno, key, 0, &p);
    107  1.1     elric     if(ret)
    108  1.1     elric 	return ret;
    109  1.1     elric     p->next = *inout;
    110  1.1     elric     *inout = p;
    111  1.1     elric     return 0;
    112  1.1     elric }
    113  1.1     elric 
    114  1.1     elric static krb5_error_code
    115  1.1     elric read_master_keytab(krb5_context context, const char *filename,
    116  1.1     elric 		   hdb_master_key *mkey)
    117  1.1     elric {
    118  1.1     elric     krb5_error_code ret;
    119  1.1     elric     krb5_keytab id;
    120  1.1     elric     krb5_kt_cursor cursor;
    121  1.1     elric     krb5_keytab_entry entry;
    122  1.1     elric     hdb_master_key p;
    123  1.1     elric 
    124  1.2  christos     *mkey = NULL;
    125  1.1     elric     ret = krb5_kt_resolve(context, filename, &id);
    126  1.1     elric     if(ret)
    127  1.1     elric 	return ret;
    128  1.1     elric 
    129  1.1     elric     ret = krb5_kt_start_seq_get(context, id, &cursor);
    130  1.1     elric     if(ret)
    131  1.1     elric 	goto out;
    132  1.1     elric     while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) {
    133  1.1     elric 	p = calloc(1, sizeof(*p));
    134  1.2  christos 	if (p == NULL) {
    135  1.1     elric 	    ret = ENOMEM;
    136  1.2  christos 	    break;
    137  1.1     elric 	}
    138  1.1     elric 	p->keytab = entry;
    139  1.1     elric 	p->next = *mkey;
    140  1.1     elric 	*mkey = p;
    141  1.2  christos 	ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto);
    142  1.2  christos 	if (ret)
    143  1.2  christos 	    break;
    144  1.1     elric     }
    145  1.1     elric     krb5_kt_end_seq_get(context, id, &cursor);
    146  1.1     elric   out:
    147  1.1     elric     krb5_kt_close(context, id);
    148  1.2  christos     if (ret) {
    149  1.2  christos 	hdb_free_master_key(context, *mkey);
    150  1.2  christos 	*mkey = NULL;
    151  1.2  christos     }
    152  1.1     elric     return ret;
    153  1.1     elric }
    154  1.1     elric 
    155  1.1     elric /* read a MIT master keyfile */
    156  1.1     elric static krb5_error_code
    157  1.1     elric read_master_mit(krb5_context context, const char *filename,
    158  1.1     elric 		int byteorder, hdb_master_key *mkey)
    159  1.1     elric {
    160  1.1     elric     int fd;
    161  1.1     elric     krb5_error_code ret;
    162  1.1     elric     krb5_storage *sp;
    163  1.1     elric     int16_t enctype;
    164  1.1     elric     krb5_keyblock key;
    165  1.2  christos 
    166  1.1     elric     fd = open(filename, O_RDONLY | O_BINARY);
    167  1.1     elric     if(fd < 0) {
    168  1.1     elric 	int save_errno = errno;
    169  1.1     elric 	krb5_set_error_message(context, save_errno, "failed to open %s: %s",
    170  1.1     elric 			       filename, strerror(save_errno));
    171  1.1     elric 	return save_errno;
    172  1.1     elric     }
    173  1.1     elric     sp = krb5_storage_from_fd(fd);
    174  1.1     elric     if(sp == NULL) {
    175  1.1     elric 	close(fd);
    176  1.1     elric 	return errno;
    177  1.1     elric     }
    178  1.1     elric     krb5_storage_set_flags(sp, byteorder);
    179  1.1     elric     /* could possibly use ret_keyblock here, but do it with more
    180  1.1     elric        checks for now */
    181  1.1     elric     {
    182  1.1     elric 	ret = krb5_ret_int16(sp, &enctype);
    183  1.1     elric 	if (ret)
    184  1.1     elric 	    goto out;
    185  1.1     elric 	ret = krb5_enctype_valid(context, enctype);
    186  1.1     elric 	if (ret)
    187  1.1     elric 	   goto out;
    188  1.1     elric 	key.keytype = enctype;
    189  1.1     elric 	ret = krb5_ret_data(sp, &key.keyvalue);
    190  1.1     elric 	if(ret)
    191  1.1     elric 	    goto out;
    192  1.1     elric     }
    193  1.1     elric     ret = hdb_process_master_key(context, 1, &key, 0, mkey);
    194  1.1     elric     krb5_free_keyblock_contents(context, &key);
    195  1.1     elric   out:
    196  1.1     elric     krb5_storage_free(sp);
    197  1.1     elric     close(fd);
    198  1.1     elric     return ret;
    199  1.1     elric }
    200  1.1     elric 
    201  1.1     elric /* read an old master key file */
    202  1.1     elric static krb5_error_code
    203  1.1     elric read_master_encryptionkey(krb5_context context, const char *filename,
    204  1.1     elric 			  hdb_master_key *mkey)
    205  1.1     elric {
    206  1.1     elric     int fd;
    207  1.1     elric     krb5_keyblock key;
    208  1.1     elric     krb5_error_code ret;
    209  1.1     elric     unsigned char buf[256];
    210  1.1     elric     ssize_t len;
    211  1.1     elric     size_t ret_len;
    212  1.2  christos 
    213  1.1     elric     fd = open(filename, O_RDONLY | O_BINARY);
    214  1.1     elric     if(fd < 0) {
    215  1.1     elric 	int save_errno = errno;
    216  1.1     elric 	krb5_set_error_message(context, save_errno, "failed to open %s: %s",
    217  1.1     elric 			      filename, strerror(save_errno));
    218  1.1     elric 	return save_errno;
    219  1.1     elric     }
    220  1.1     elric 
    221  1.1     elric     len = read(fd, buf, sizeof(buf));
    222  1.1     elric     close(fd);
    223  1.1     elric     if(len < 0) {
    224  1.1     elric 	int save_errno = errno;
    225  1.1     elric 	krb5_set_error_message(context, save_errno, "error reading %s: %s",
    226  1.1     elric 			      filename, strerror(save_errno));
    227  1.1     elric 	return save_errno;
    228  1.1     elric     }
    229  1.1     elric 
    230  1.1     elric     ret = decode_EncryptionKey(buf, len, &key, &ret_len);
    231  1.3  christos     memset_s(buf, sizeof(buf), 0, sizeof(buf));
    232  1.1     elric     if(ret)
    233  1.1     elric 	return ret;
    234  1.1     elric 
    235  1.1     elric     /* Originally, the keytype was just that, and later it got changed
    236  1.1     elric        to des-cbc-md5, but we always used des in cfb64 mode. This
    237  1.1     elric        should cover all cases, but will break if someone has hacked
    238  1.1     elric        this code to really use des-cbc-md5 -- but then that's not my
    239  1.1     elric        problem. */
    240  1.2  christos     if(key.keytype == ETYPE_DES_CBC_CRC || key.keytype == ETYPE_DES_CBC_MD5)
    241  1.1     elric 	key.keytype = ETYPE_DES_CFB64_NONE;
    242  1.1     elric 
    243  1.1     elric     ret = hdb_process_master_key(context, 0, &key, 0, mkey);
    244  1.1     elric     krb5_free_keyblock_contents(context, &key);
    245  1.1     elric     return ret;
    246  1.1     elric }
    247  1.1     elric 
    248  1.1     elric /* read a krb4 /.k style file */
    249  1.1     elric static krb5_error_code
    250  1.1     elric read_master_krb4(krb5_context context, const char *filename,
    251  1.1     elric 		 hdb_master_key *mkey)
    252  1.1     elric {
    253  1.1     elric     int fd;
    254  1.1     elric     krb5_keyblock key;
    255  1.1     elric     krb5_error_code ret;
    256  1.1     elric     unsigned char buf[256];
    257  1.1     elric     ssize_t len;
    258  1.2  christos 
    259  1.1     elric     fd = open(filename, O_RDONLY | O_BINARY);
    260  1.1     elric     if(fd < 0) {
    261  1.1     elric 	int save_errno = errno;
    262  1.1     elric 	krb5_set_error_message(context, save_errno, "failed to open %s: %s",
    263  1.1     elric 			       filename, strerror(save_errno));
    264  1.1     elric 	return save_errno;
    265  1.1     elric     }
    266  1.1     elric 
    267  1.1     elric     len = read(fd, buf, sizeof(buf));
    268  1.1     elric     close(fd);
    269  1.1     elric     if(len < 0) {
    270  1.1     elric 	int save_errno = errno;
    271  1.1     elric 	krb5_set_error_message(context, save_errno, "error reading %s: %s",
    272  1.1     elric 			       filename, strerror(save_errno));
    273  1.1     elric 	return save_errno;
    274  1.1     elric     }
    275  1.1     elric     if(len != 8) {
    276  1.1     elric 	krb5_set_error_message(context, HEIM_ERR_EOF,
    277  1.1     elric 			       "bad contents of %s", filename);
    278  1.1     elric 	return HEIM_ERR_EOF; /* XXX file might be too large */
    279  1.1     elric     }
    280  1.1     elric 
    281  1.1     elric     memset(&key, 0, sizeof(key));
    282  1.1     elric     key.keytype = ETYPE_DES_PCBC_NONE;
    283  1.1     elric     ret = krb5_data_copy(&key.keyvalue, buf, len);
    284  1.3  christos     memset_s(buf, sizeof(buf), 0, sizeof(buf));
    285  1.1     elric     if(ret)
    286  1.1     elric 	return ret;
    287  1.1     elric 
    288  1.1     elric     ret = hdb_process_master_key(context, 0, &key, 0, mkey);
    289  1.1     elric     krb5_free_keyblock_contents(context, &key);
    290  1.1     elric     return ret;
    291  1.1     elric }
    292  1.1     elric 
    293  1.1     elric krb5_error_code
    294  1.1     elric hdb_read_master_key(krb5_context context, const char *filename,
    295  1.1     elric 		    hdb_master_key *mkey)
    296  1.1     elric {
    297  1.1     elric     FILE *f;
    298  1.1     elric     unsigned char buf[16];
    299  1.1     elric     krb5_error_code ret;
    300  1.1     elric 
    301  1.1     elric     off_t len;
    302  1.1     elric 
    303  1.1     elric     *mkey = NULL;
    304  1.1     elric 
    305  1.1     elric     if(filename == NULL)
    306  1.1     elric 	filename = HDB_DB_DIR "/m-key";
    307  1.1     elric 
    308  1.1     elric     f = fopen(filename, "r");
    309  1.1     elric     if(f == NULL) {
    310  1.1     elric 	int save_errno = errno;
    311  1.1     elric 	krb5_set_error_message(context, save_errno, "failed to open %s: %s",
    312  1.1     elric 			       filename, strerror(save_errno));
    313  1.1     elric 	return save_errno;
    314  1.1     elric     }
    315  1.1     elric 
    316  1.1     elric     if(fread(buf, 1, 2, f) != 2) {
    317  1.1     elric 	fclose(f);
    318  1.1     elric 	krb5_set_error_message(context, HEIM_ERR_EOF, "end of file reading %s", filename);
    319  1.1     elric 	return HEIM_ERR_EOF;
    320  1.1     elric     }
    321  1.1     elric 
    322  1.1     elric     fseek(f, 0, SEEK_END);
    323  1.1     elric     len = ftell(f);
    324  1.1     elric 
    325  1.1     elric     if(fclose(f) != 0)
    326  1.1     elric 	return errno;
    327  1.1     elric 
    328  1.1     elric     if(len < 0)
    329  1.1     elric 	return errno;
    330  1.1     elric 
    331  1.1     elric     if(len == 8) {
    332  1.1     elric 	ret = read_master_krb4(context, filename, mkey);
    333  1.1     elric     } else if(buf[0] == 0x30 && len <= 127 && buf[1] == len - 2) {
    334  1.1     elric 	ret = read_master_encryptionkey(context, filename, mkey);
    335  1.1     elric     } else if(buf[0] == 5 && buf[1] >= 1 && buf[1] <= 2) {
    336  1.1     elric 	ret = read_master_keytab(context, filename, mkey);
    337  1.1     elric     } else {
    338  1.1     elric       /*
    339  1.1     elric        * Check both LittleEndian and BigEndian since they key file
    340  1.1     elric        * might be moved from a machine with diffrent byte order, or
    341  1.1     elric        * its running on MacOS X that always uses BE master keys.
    342  1.1     elric        */
    343  1.1     elric       ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_LE, mkey);
    344  1.1     elric       if (ret)
    345  1.1     elric           ret = read_master_mit(context, filename, KRB5_STORAGE_BYTEORDER_BE, mkey);
    346  1.1     elric     }
    347  1.1     elric     return ret;
    348  1.1     elric }
    349  1.1     elric 
    350  1.1     elric krb5_error_code
    351  1.1     elric hdb_write_master_key(krb5_context context, const char *filename,
    352  1.1     elric 		     hdb_master_key mkey)
    353  1.1     elric {
    354  1.1     elric     krb5_error_code ret;
    355  1.1     elric     hdb_master_key p;
    356  1.1     elric     krb5_keytab kt;
    357  1.1     elric 
    358  1.1     elric     if(filename == NULL)
    359  1.1     elric 	filename = HDB_DB_DIR "/m-key";
    360  1.1     elric 
    361  1.1     elric     ret = krb5_kt_resolve(context, filename, &kt);
    362  1.1     elric     if(ret)
    363  1.1     elric 	return ret;
    364  1.1     elric 
    365  1.1     elric     for(p = mkey; p; p = p->next) {
    366  1.1     elric 	ret = krb5_kt_add_entry(context, kt, &p->keytab);
    367  1.1     elric     }
    368  1.1     elric 
    369  1.1     elric     krb5_kt_close(context, kt);
    370  1.1     elric 
    371  1.1     elric     return ret;
    372  1.1     elric }
    373  1.1     elric 
    374  1.2  christos krb5_error_code
    375  1.2  christos _hdb_set_master_key_usage(krb5_context context, HDB *db, unsigned int key_usage)
    376  1.2  christos {
    377  1.2  christos     if (db->hdb_master_key_set == 0)
    378  1.2  christos 	return HDB_ERR_NO_MKEY;
    379  1.2  christos     db->hdb_master_key->key_usage = key_usage;
    380  1.2  christos     return 0;
    381  1.2  christos }
    382  1.2  christos 
    383  1.1     elric hdb_master_key
    384  1.2  christos _hdb_find_master_key(unsigned int *mkvno, hdb_master_key mkey)
    385  1.1     elric {
    386  1.1     elric     hdb_master_key ret = NULL;
    387  1.1     elric     while(mkey) {
    388  1.1     elric 	if(ret == NULL && mkey->keytab.vno == 0)
    389  1.1     elric 	    ret = mkey;
    390  1.1     elric 	if(mkvno == NULL) {
    391  1.1     elric 	    if(ret == NULL || mkey->keytab.vno > ret->keytab.vno)
    392  1.1     elric 		ret = mkey;
    393  1.2  christos 	} else if((uint32_t)mkey->keytab.vno == *mkvno)
    394  1.1     elric 	    return mkey;
    395  1.1     elric 	mkey = mkey->next;
    396  1.1     elric     }
    397  1.1     elric     return ret;
    398  1.1     elric }
    399  1.1     elric 
    400  1.1     elric int
    401  1.1     elric _hdb_mkey_version(hdb_master_key mkey)
    402  1.1     elric {
    403  1.1     elric     return mkey->keytab.vno;
    404  1.1     elric }
    405  1.1     elric 
    406  1.1     elric int
    407  1.1     elric _hdb_mkey_decrypt(krb5_context context, hdb_master_key key,
    408  1.1     elric 		  krb5_key_usage usage,
    409  1.1     elric 		  void *ptr, size_t size, krb5_data *res)
    410  1.1     elric {
    411  1.1     elric     return krb5_decrypt(context, key->crypto, usage,
    412  1.1     elric 			ptr, size, res);
    413  1.1     elric }
    414  1.1     elric 
    415  1.1     elric int
    416  1.1     elric _hdb_mkey_encrypt(krb5_context context, hdb_master_key key,
    417  1.1     elric 		  krb5_key_usage usage,
    418  1.1     elric 		  const void *ptr, size_t size, krb5_data *res)
    419  1.1     elric {
    420  1.1     elric     return krb5_encrypt(context, key->crypto, usage,
    421  1.1     elric 			ptr, size, res);
    422  1.1     elric }
    423  1.1     elric 
    424  1.1     elric krb5_error_code
    425  1.1     elric hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
    426  1.1     elric {
    427  1.2  christos 
    428  1.1     elric     krb5_error_code ret;
    429  1.1     elric     krb5_data res;
    430  1.1     elric     size_t keysize;
    431  1.1     elric 
    432  1.1     elric     hdb_master_key key;
    433  1.1     elric 
    434  1.1     elric     if(k->mkvno == NULL)
    435  1.1     elric 	return 0;
    436  1.2  christos 
    437  1.1     elric     key = _hdb_find_master_key(k->mkvno, mkey);
    438  1.1     elric 
    439  1.1     elric     if (key == NULL)
    440  1.1     elric 	return HDB_ERR_NO_MKEY;
    441  1.1     elric 
    442  1.1     elric     ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY,
    443  1.1     elric 			    k->key.keyvalue.data,
    444  1.1     elric 			    k->key.keyvalue.length,
    445  1.1     elric 			    &res);
    446  1.1     elric     if(ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
    447  1.1     elric 	/* try to decrypt with MIT key usage */
    448  1.1     elric 	ret = _hdb_mkey_decrypt(context, key, 0,
    449  1.1     elric 				k->key.keyvalue.data,
    450  1.1     elric 				k->key.keyvalue.length,
    451  1.1     elric 				&res);
    452  1.1     elric     }
    453  1.1     elric     if (ret)
    454  1.1     elric 	return ret;
    455  1.1     elric 
    456  1.1     elric     /* fixup keylength if the key got padded when encrypting it */
    457  1.1     elric     ret = krb5_enctype_keysize(context, k->key.keytype, &keysize);
    458  1.1     elric     if (ret) {
    459  1.1     elric 	krb5_data_free(&res);
    460  1.1     elric 	return ret;
    461  1.1     elric     }
    462  1.1     elric     if (keysize > res.length) {
    463  1.1     elric 	krb5_data_free(&res);
    464  1.1     elric 	return KRB5_BAD_KEYSIZE;
    465  1.1     elric     }
    466  1.1     elric 
    467  1.1     elric     memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
    468  1.1     elric     free(k->key.keyvalue.data);
    469  1.1     elric     k->key.keyvalue = res;
    470  1.1     elric     k->key.keyvalue.length = keysize;
    471  1.1     elric     free(k->mkvno);
    472  1.1     elric     k->mkvno = NULL;
    473  1.1     elric 
    474  1.1     elric     return 0;
    475  1.1     elric }
    476  1.1     elric 
    477  1.1     elric krb5_error_code
    478  1.1     elric hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
    479  1.1     elric {
    480  1.2  christos     size_t i;
    481  1.1     elric 
    482  1.1     elric     for(i = 0; i < ent->keys.len; i++){
    483  1.1     elric 	krb5_error_code ret;
    484  1.1     elric 
    485  1.1     elric 	ret = hdb_unseal_key_mkey(context, &ent->keys.val[i], mkey);
    486  1.1     elric 	if (ret)
    487  1.1     elric 	    return ret;
    488  1.1     elric     }
    489  1.1     elric     return 0;
    490  1.1     elric }
    491  1.1     elric 
    492  1.1     elric krb5_error_code
    493  1.1     elric hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent)
    494  1.1     elric {
    495  1.1     elric     if (db->hdb_master_key_set == 0)
    496  1.1     elric 	return 0;
    497  1.1     elric     return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key);
    498  1.1     elric }
    499  1.1     elric 
    500  1.2  christos /*
    501  1.2  christos  * Unseal the keys for the given kvno (or all of them) of entry.
    502  1.2  christos  *
    503  1.2  christos  * If kvno == 0 -> unseal all.
    504  1.2  christos  * if kvno != 0 -> unseal the requested kvno and make sure it's the one listed
    505  1.2  christos  *                 as the current keyset for the entry (swapping it with a
    506  1.2  christos  *                 historical keyset if need be).
    507  1.2  christos  */
    508  1.2  christos krb5_error_code
    509  1.2  christos hdb_unseal_keys_kvno(krb5_context context, HDB *db, krb5_kvno kvno,
    510  1.2  christos 		     unsigned flags, hdb_entry *ent)
    511  1.2  christos {
    512  1.2  christos     krb5_error_code ret = HDB_ERR_NOENTRY;
    513  1.2  christos     HDB_extension *ext;
    514  1.2  christos     HDB_Ext_KeySet *hist_keys;
    515  1.2  christos     Key *tmp_val;
    516  1.2  christos     time_t tmp_set_time;
    517  1.2  christos     unsigned int tmp_len;
    518  1.2  christos     unsigned int kvno_diff = 0;
    519  1.2  christos     krb5_kvno tmp_kvno;
    520  1.2  christos     size_t i, k;
    521  1.2  christos     int exclude_dead = 0;
    522  1.2  christos     KerberosTime now = 0;
    523  1.2  christos 
    524  1.2  christos     if (kvno == 0)
    525  1.2  christos 	ret = 0;
    526  1.2  christos 
    527  1.2  christos     if ((flags & HDB_F_LIVE_CLNT_KVNOS) || (flags & HDB_F_LIVE_SVC_KVNOS)) {
    528  1.2  christos 	exclude_dead = 1;
    529  1.2  christos 	now = time(NULL);
    530  1.2  christos 	if (HDB_F_LIVE_CLNT_KVNOS)
    531  1.2  christos 	    kvno_diff = hdb_entry_get_kvno_diff_clnt(ent);
    532  1.2  christos 	else
    533  1.2  christos 	    kvno_diff = hdb_entry_get_kvno_diff_svc(ent);
    534  1.2  christos     }
    535  1.2  christos 
    536  1.2  christos     ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
    537  1.2  christos     if (ext == NULL || (&ext->data.u.hist_keys)->len == 0)
    538  1.2  christos 	return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key);
    539  1.2  christos 
    540  1.2  christos     /* For swapping; see below */
    541  1.2  christos     tmp_len = ent->keys.len;
    542  1.2  christos     tmp_val = ent->keys.val;
    543  1.2  christos     tmp_kvno = ent->kvno;
    544  1.2  christos     (void) hdb_entry_get_pw_change_time(ent, &tmp_set_time);
    545  1.2  christos 
    546  1.2  christos     hist_keys = &ext->data.u.hist_keys;
    547  1.2  christos 
    548  1.2  christos     for (i = 0; i < hist_keys->len; i++) {
    549  1.2  christos 	if (kvno != 0 && hist_keys->val[i].kvno != kvno)
    550  1.2  christos 	    continue;
    551  1.2  christos 
    552  1.2  christos 	if (exclude_dead &&
    553  1.2  christos 	    ((ent->max_life != NULL &&
    554  1.2  christos 	      hist_keys->val[i].set_time != NULL &&
    555  1.2  christos 	      (*hist_keys->val[i].set_time) < (now - (*ent->max_life))) ||
    556  1.2  christos 	    (hist_keys->val[i].kvno < kvno &&
    557  1.2  christos 	     (kvno - hist_keys->val[i].kvno) > kvno_diff)))
    558  1.2  christos 	    /*
    559  1.2  christos 	     * The KDC may want to to check for this keyset's set_time
    560  1.2  christos 	     * is within the TGS principal's max_life, say.  But we stop
    561  1.2  christos 	     * here.
    562  1.2  christos 	     */
    563  1.2  christos 	    continue;
    564  1.2  christos 
    565  1.2  christos 	/* Either the keys we want, or all the keys */
    566  1.2  christos 	for (k = 0; k < hist_keys->val[i].keys.len; k++) {
    567  1.2  christos 	    ret = hdb_unseal_key_mkey(context,
    568  1.2  christos 				      &hist_keys->val[i].keys.val[k],
    569  1.2  christos 				      db->hdb_master_key);
    570  1.2  christos 	    /*
    571  1.2  christos 	     * If kvno == 0 we might not want to bail here!  E.g., if we
    572  1.2  christos 	     * no longer have the right master key, so just ignore this.
    573  1.2  christos 	     *
    574  1.2  christos 	     * We could filter out keys that we can't decrypt here
    575  1.2  christos 	     * because of HDB_ERR_NO_MKEY.  However, it seems safest to
    576  1.2  christos 	     * filter them out only where necessary, say, in kadm5.
    577  1.2  christos 	     */
    578  1.2  christos 	    if (ret && kvno != 0)
    579  1.2  christos 		return ret;
    580  1.2  christos 	    if (ret && ret != HDB_ERR_NO_MKEY)
    581  1.2  christos 		return (ret);
    582  1.2  christos 	}
    583  1.2  christos 
    584  1.2  christos 	if (kvno == 0)
    585  1.2  christos 	    continue;
    586  1.2  christos 
    587  1.2  christos 	/*
    588  1.2  christos 	 * What follows is a bit of a hack.
    589  1.2  christos 	 *
    590  1.2  christos 	 * This is the keyset we're being asked for, but it's not the
    591  1.2  christos 	 * current keyset.  So we add the current keyset to the history,
    592  1.2  christos 	 * leave the one we were asked for in the history, and pretend
    593  1.2  christos 	 * the one we were asked for is also the current keyset.
    594  1.2  christos 	 *
    595  1.2  christos 	 * This is a bit of a defensive hack in case an entry fetched
    596  1.2  christos 	 * this way ever gets modified then stored: if the keyset is not
    597  1.2  christos 	 * changed we can detect this and put things back, else we won't
    598  1.2  christos 	 * drop any keysets from history by accident.
    599  1.2  christos 	 *
    600  1.2  christos 	 * Note too that we only ever get called with a non-zero kvno
    601  1.2  christos 	 * either in the KDC or in cases where we aren't changing the
    602  1.2  christos 	 * HDB entry anyways, which is why this is just a defensive
    603  1.2  christos 	 * hack.  We also don't fetch specific kvnos in the dump case,
    604  1.2  christos 	 * so there's no danger that we'll dump this entry and load it
    605  1.2  christos 	 * again, repeatedly causing the history to grow boundelessly.
    606  1.2  christos 	 */
    607  1.2  christos 
    608  1.2  christos 	/* Swap key sets */
    609  1.2  christos 	ent->kvno = hist_keys->val[i].kvno;
    610  1.2  christos 	ent->keys.val = hist_keys->val[i].keys.val;
    611  1.2  christos 	ent->keys.len = hist_keys->val[i].keys.len;
    612  1.2  christos 	if (hist_keys->val[i].set_time != NULL)
    613  1.2  christos 	    /* Sloppy, but the callers we expect won't care */
    614  1.2  christos 	    (void) hdb_entry_set_pw_change_time(context, ent,
    615  1.2  christos 						*hist_keys->val[i].set_time);
    616  1.2  christos 	hist_keys->val[i].kvno = tmp_kvno;
    617  1.2  christos 	hist_keys->val[i].keys.val = tmp_val;
    618  1.2  christos 	hist_keys->val[i].keys.len = tmp_len;
    619  1.2  christos 	if (hist_keys->val[i].set_time != NULL)
    620  1.2  christos 	    /* Sloppy, but the callers we expect won't care */
    621  1.2  christos 	    *hist_keys->val[i].set_time = tmp_set_time;
    622  1.2  christos 
    623  1.2  christos 	return 0;
    624  1.2  christos     }
    625  1.2  christos 
    626  1.2  christos     return (ret);
    627  1.2  christos }
    628  1.2  christos 
    629  1.1     elric krb5_error_code
    630  1.1     elric hdb_unseal_key(krb5_context context, HDB *db, Key *k)
    631  1.1     elric {
    632  1.1     elric     if (db->hdb_master_key_set == 0)
    633  1.1     elric 	return 0;
    634  1.1     elric     return hdb_unseal_key_mkey(context, k, db->hdb_master_key);
    635  1.1     elric }
    636  1.1     elric 
    637  1.1     elric krb5_error_code
    638  1.1     elric hdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey)
    639  1.1     elric {
    640  1.1     elric     krb5_error_code ret;
    641  1.1     elric     krb5_data res;
    642  1.1     elric     hdb_master_key key;
    643  1.1     elric 
    644  1.1     elric     if(k->mkvno != NULL)
    645  1.1     elric 	return 0;
    646  1.1     elric 
    647  1.1     elric     key = _hdb_find_master_key(k->mkvno, mkey);
    648  1.1     elric 
    649  1.1     elric     if (key == NULL)
    650  1.1     elric 	return HDB_ERR_NO_MKEY;
    651  1.1     elric 
    652  1.1     elric     ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY,
    653  1.1     elric 			    k->key.keyvalue.data,
    654  1.1     elric 			    k->key.keyvalue.length,
    655  1.1     elric 			    &res);
    656  1.1     elric     if (ret)
    657  1.1     elric 	return ret;
    658  1.1     elric 
    659  1.1     elric     memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
    660  1.1     elric     free(k->key.keyvalue.data);
    661  1.1     elric     k->key.keyvalue = res;
    662  1.1     elric 
    663  1.1     elric     if (k->mkvno == NULL) {
    664  1.1     elric 	k->mkvno = malloc(sizeof(*k->mkvno));
    665  1.1     elric 	if (k->mkvno == NULL)
    666  1.1     elric 	    return ENOMEM;
    667  1.1     elric     }
    668  1.1     elric     *k->mkvno = key->keytab.vno;
    669  1.2  christos 
    670  1.1     elric     return 0;
    671  1.1     elric }
    672  1.1     elric 
    673  1.1     elric krb5_error_code
    674  1.1     elric hdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
    675  1.1     elric {
    676  1.2  christos     HDB_extension *ext;
    677  1.2  christos     HDB_Ext_KeySet *hist_keys;
    678  1.2  christos     size_t i, k;
    679  1.2  christos     krb5_error_code ret;
    680  1.2  christos 
    681  1.1     elric     for(i = 0; i < ent->keys.len; i++){
    682  1.1     elric 	ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey);
    683  1.1     elric 	if (ret)
    684  1.1     elric 	    return ret;
    685  1.1     elric     }
    686  1.2  christos 
    687  1.2  christos     ext = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
    688  1.2  christos     if (ext == NULL)
    689  1.2  christos 	return 0;
    690  1.2  christos     hist_keys = &ext->data.u.hist_keys;
    691  1.2  christos 
    692  1.2  christos     for (i = 0; i < hist_keys->len; i++) {
    693  1.2  christos 	for (k = 0; k < hist_keys->val[i].keys.len; k++) {
    694  1.2  christos 	    ret = hdb_seal_key_mkey(context, &hist_keys->val[i].keys.val[k],
    695  1.2  christos 				    mkey);
    696  1.2  christos 	    if (ret)
    697  1.2  christos 		return ret;
    698  1.2  christos 	}
    699  1.2  christos     }
    700  1.2  christos 
    701  1.1     elric     return 0;
    702  1.1     elric }
    703  1.1     elric 
    704  1.1     elric krb5_error_code
    705  1.1     elric hdb_seal_keys(krb5_context context, HDB *db, hdb_entry *ent)
    706  1.1     elric {
    707  1.1     elric     if (db->hdb_master_key_set == 0)
    708  1.1     elric 	return 0;
    709  1.1     elric 
    710  1.1     elric     return hdb_seal_keys_mkey(context, ent, db->hdb_master_key);
    711  1.1     elric }
    712  1.1     elric 
    713  1.1     elric krb5_error_code
    714  1.1     elric hdb_seal_key(krb5_context context, HDB *db, Key *k)
    715  1.1     elric {
    716  1.1     elric     if (db->hdb_master_key_set == 0)
    717  1.1     elric 	return 0;
    718  1.1     elric 
    719  1.1     elric     return hdb_seal_key_mkey(context, k, db->hdb_master_key);
    720  1.1     elric }
    721  1.1     elric 
    722  1.1     elric krb5_error_code
    723  1.2  christos hdb_set_master_key(krb5_context context,
    724  1.2  christos 		   HDB *db,
    725  1.2  christos 		   krb5_keyblock *key)
    726  1.1     elric {
    727  1.1     elric     krb5_error_code ret;
    728  1.1     elric     hdb_master_key mkey;
    729  1.1     elric 
    730  1.1     elric     ret = hdb_process_master_key(context, 0, key, 0, &mkey);
    731  1.1     elric     if (ret)
    732  1.1     elric 	return ret;
    733  1.1     elric     db->hdb_master_key = mkey;
    734  1.1     elric #if 0 /* XXX - why? */
    735  1.1     elric     des_set_random_generator_seed(key.keyvalue.data);
    736  1.1     elric #endif
    737  1.1     elric     db->hdb_master_key_set = 1;
    738  1.2  christos     db->hdb_master_key->key_usage = HDB_KU_MKEY;
    739  1.1     elric     return 0;
    740  1.1     elric }
    741  1.1     elric 
    742  1.1     elric krb5_error_code
    743  1.1     elric hdb_set_master_keyfile (krb5_context context,
    744  1.1     elric 			HDB *db,
    745  1.1     elric 			const char *keyfile)
    746  1.1     elric {
    747  1.1     elric     hdb_master_key key;
    748  1.1     elric     krb5_error_code ret;
    749  1.1     elric 
    750  1.1     elric     ret = hdb_read_master_key(context, keyfile, &key);
    751  1.1     elric     if (ret) {
    752  1.1     elric 	if (ret != ENOENT)
    753  1.1     elric 	    return ret;
    754  1.1     elric 	krb5_clear_error_message(context);
    755  1.1     elric 	return 0;
    756  1.1     elric     }
    757  1.1     elric     db->hdb_master_key = key;
    758  1.1     elric     db->hdb_master_key_set = 1;
    759  1.1     elric     return ret;
    760  1.1     elric }
    761  1.1     elric 
    762  1.1     elric krb5_error_code
    763  1.1     elric hdb_clear_master_key (krb5_context context,
    764  1.1     elric 		      HDB *db)
    765  1.1     elric {
    766  1.1     elric     if (db->hdb_master_key_set) {
    767  1.1     elric 	hdb_free_master_key(context, db->hdb_master_key);
    768  1.1     elric 	db->hdb_master_key_set = 0;
    769  1.1     elric     }
    770  1.1     elric     return 0;
    771  1.1     elric }
    772