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