LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hdb - mkey.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 15 416 3.6 %
Date: 2024-04-21 15:09:00 Functions: 2 26 7.7 %

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

Generated by: LCOV version 1.14