📄 mkey.c
字号:
/* * Copyright (c) 2000 - 2004 Kungliga Tekniska H鰃skolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "hdb_locl.h"#ifndef O_BINARY#define O_BINARY 0#endifRCSID("$Id: mkey.c 21745 2007-07-31 16:11:25Z lha $");struct hdb_master_key_data { krb5_keytab_entry keytab; krb5_crypto crypto; struct hdb_master_key_data *next;};voidhdb_free_master_key(krb5_context context, hdb_master_key mkey){ struct hdb_master_key_data *ptr; while(mkey) { krb5_kt_free_entry(context, &mkey->keytab); if (mkey->crypto) krb5_crypto_destroy(context, mkey->crypto); ptr = mkey; mkey = mkey->next; free(ptr); }}krb5_error_codehdb_process_master_key(krb5_context context, int kvno, krb5_keyblock *key, krb5_enctype etype, hdb_master_key *mkey){ krb5_error_code ret; *mkey = calloc(1, sizeof(**mkey)); if(*mkey == NULL) { krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } (*mkey)->keytab.vno = kvno; ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal); if(ret) goto fail; ret = krb5_copy_keyblock_contents(context, key, &(*mkey)->keytab.keyblock); if(ret) goto fail; if(etype != 0) (*mkey)->keytab.keyblock.keytype = etype; (*mkey)->keytab.timestamp = time(NULL); ret = krb5_crypto_init(context, key, etype, &(*mkey)->crypto); if(ret) goto fail; return 0; fail: hdb_free_master_key(context, *mkey); *mkey = NULL; return ret;}krb5_error_codehdb_add_master_key(krb5_context context, krb5_keyblock *key, hdb_master_key *inout){ int vno = 0; hdb_master_key p; krb5_error_code ret; for(p = *inout; p; p = p->next) vno = max(vno, p->keytab.vno); vno++; ret = hdb_process_master_key(context, vno, key, 0, &p); if(ret) return ret; p->next = *inout; *inout = p; return 0;}static krb5_error_coderead_master_keytab(krb5_context context, const char *filename, hdb_master_key *mkey){ krb5_error_code ret; krb5_keytab id; krb5_kt_cursor cursor; krb5_keytab_entry entry; hdb_master_key p; ret = krb5_kt_resolve(context, filename, &id); if(ret) return ret; ret = krb5_kt_start_seq_get(context, id, &cursor); if(ret) goto out; *mkey = NULL; while(krb5_kt_next_entry(context, id, &entry, &cursor) == 0) { p = calloc(1, sizeof(*p)); if(p == NULL) { krb5_kt_end_seq_get(context, id, &cursor); ret = ENOMEM; goto out; } p->keytab = entry; ret = krb5_crypto_init(context, &p->keytab.keyblock, 0, &p->crypto); p->next = *mkey; *mkey = p; } krb5_kt_end_seq_get(context, id, &cursor); out: krb5_kt_close(context, id); return ret;}/* read a MIT master keyfile */static krb5_error_coderead_master_mit(krb5_context context, const char *filename, hdb_master_key *mkey){ int fd; krb5_error_code ret; krb5_storage *sp; int16_t enctype; krb5_keyblock key; fd = open(filename, O_RDONLY | O_BINARY); if(fd < 0) { int save_errno = errno; krb5_set_error_string(context, "failed to open %s: %s", filename, strerror(save_errno)); return save_errno; } sp = krb5_storage_from_fd(fd); if(sp == NULL) { close(fd); return errno; } krb5_storage_set_flags(sp, KRB5_STORAGE_HOST_BYTEORDER);#if 0 /* could possibly use ret_keyblock here, but do it with more checks for now */ ret = krb5_ret_keyblock(sp, &key);#else ret = krb5_ret_int16(sp, &enctype); if((htons(enctype) & 0xff00) == 0x3000) { krb5_set_error_string(context, "unknown keytype in %s: %#x, expected %#x", filename, htons(enctype), 0x3000); ret = HEIM_ERR_BAD_MKEY; goto out; } key.keytype = enctype; ret = krb5_ret_data(sp, &key.keyvalue); if(ret) goto out;#endif ret = hdb_process_master_key(context, 0, &key, 0, mkey); krb5_free_keyblock_contents(context, &key); out: krb5_storage_free(sp); close(fd); return ret;}/* read an old master key file */static krb5_error_coderead_master_encryptionkey(krb5_context context, const char *filename, hdb_master_key *mkey){ int fd; krb5_keyblock key; krb5_error_code ret; unsigned char buf[256]; ssize_t len; size_t ret_len; fd = open(filename, O_RDONLY | O_BINARY); if(fd < 0) { int save_errno = errno; krb5_set_error_string(context, "failed to open %s: %s", filename, strerror(save_errno)); return save_errno; } len = read(fd, buf, sizeof(buf)); close(fd); if(len < 0) { int save_errno = errno; krb5_set_error_string(context, "error reading %s: %s", filename, strerror(save_errno)); return save_errno; } ret = decode_EncryptionKey(buf, len, &key, &ret_len); memset(buf, 0, sizeof(buf)); if(ret) return ret; /* Originally, the keytype was just that, and later it got changed to des-cbc-md5, but we always used des in cfb64 mode. This should cover all cases, but will break if someone has hacked this code to really use des-cbc-md5 -- but then that's not my problem. */ if(key.keytype == KEYTYPE_DES || key.keytype == ETYPE_DES_CBC_MD5) key.keytype = ETYPE_DES_CFB64_NONE; ret = hdb_process_master_key(context, 0, &key, 0, mkey); krb5_free_keyblock_contents(context, &key); return ret;}/* read a krb4 /.k style file */static krb5_error_coderead_master_krb4(krb5_context context, const char *filename, hdb_master_key *mkey){ int fd; krb5_keyblock key; krb5_error_code ret; unsigned char buf[256]; ssize_t len; fd = open(filename, O_RDONLY | O_BINARY); if(fd < 0) { int save_errno = errno; krb5_set_error_string(context, "failed to open %s: %s", filename, strerror(save_errno)); return save_errno; } len = read(fd, buf, sizeof(buf)); close(fd); if(len < 0) { int save_errno = errno; krb5_set_error_string(context, "error reading %s: %s", filename, strerror(save_errno)); return save_errno; } if(len != 8) { krb5_set_error_string(context, "bad contents of %s", filename); return HEIM_ERR_EOF; /* XXX file might be too large */ } memset(&key, 0, sizeof(key)); key.keytype = ETYPE_DES_PCBC_NONE; ret = krb5_data_copy(&key.keyvalue, buf, len); memset(buf, 0, sizeof(buf)); if(ret) return ret; ret = hdb_process_master_key(context, 0, &key, 0, mkey); krb5_free_keyblock_contents(context, &key); return ret;}krb5_error_codehdb_read_master_key(krb5_context context, const char *filename, hdb_master_key *mkey){ FILE *f; unsigned char buf[16]; krb5_error_code ret; off_t len; *mkey = NULL; if(filename == NULL) filename = HDB_DB_DIR "/m-key"; f = fopen(filename, "r"); if(f == NULL) { int save_errno = errno; krb5_set_error_string(context, "failed to open %s: %s", filename, strerror(save_errno)); return save_errno; } if(fread(buf, 1, 2, f) != 2) { krb5_set_error_string(context, "end of file reading %s", filename); fclose(f); return HEIM_ERR_EOF; } fseek(f, 0, SEEK_END); len = ftell(f); if(fclose(f) != 0) return errno; if(len < 0) return errno; if(len == 8) { ret = read_master_krb4(context, filename, mkey); } else if(buf[0] == 0x30 && len <= 127 && buf[1] == len - 2) { ret = read_master_encryptionkey(context, filename, mkey); } else if(buf[0] == 5 && buf[1] >= 1 && buf[1] <= 2) { ret = read_master_keytab(context, filename, mkey); } else { ret = read_master_mit(context, filename, mkey); } return ret;}krb5_error_codehdb_write_master_key(krb5_context context, const char *filename, hdb_master_key mkey){ krb5_error_code ret; hdb_master_key p; krb5_keytab kt; if(filename == NULL) filename = HDB_DB_DIR "/m-key"; ret = krb5_kt_resolve(context, filename, &kt); if(ret) return ret; for(p = mkey; p; p = p->next) { ret = krb5_kt_add_entry(context, kt, &p->keytab); } krb5_kt_close(context, kt); return ret;}hdb_master_key_hdb_find_master_key(uint32_t *mkvno, hdb_master_key mkey){ hdb_master_key ret = NULL; while(mkey) { if(ret == NULL && mkey->keytab.vno == 0) ret = mkey; if(mkvno == NULL) { if(ret == NULL || mkey->keytab.vno > ret->keytab.vno) ret = mkey; } else if(mkey->keytab.vno == *mkvno) return mkey; mkey = mkey->next; } return ret;}int_hdb_mkey_version(hdb_master_key mkey){ return mkey->keytab.vno;}int_hdb_mkey_decrypt(krb5_context context, hdb_master_key key, krb5_key_usage usage, void *ptr, size_t size, krb5_data *res){ return krb5_decrypt(context, key->crypto, usage, ptr, size, res);}int_hdb_mkey_encrypt(krb5_context context, hdb_master_key key, krb5_key_usage usage, const void *ptr, size_t size, krb5_data *res){ return krb5_encrypt(context, key->crypto, usage, ptr, size, res);}krb5_error_codehdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) { krb5_error_code ret; krb5_data res; size_t keysize; hdb_master_key key; if(k->mkvno == NULL) return 0; key = _hdb_find_master_key(k->mkvno, mkey); if (key == NULL) return HDB_ERR_NO_MKEY; ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY, k->key.keyvalue.data, k->key.keyvalue.length, &res); if(ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) { /* try to decrypt with MIT key usage */ ret = _hdb_mkey_decrypt(context, key, 0, k->key.keyvalue.data, k->key.keyvalue.length, &res); } if (ret) return ret; /* fixup keylength if the key got padded when encrypting it */ ret = krb5_enctype_keysize(context, k->key.keytype, &keysize); if (ret) { krb5_data_free(&res); return ret; } if (keysize > res.length) { krb5_data_free(&res); return KRB5_BAD_KEYSIZE; } memset(k->key.keyvalue.data, 0, k->key.keyvalue.length); free(k->key.keyvalue.data); k->key.keyvalue = res; k->key.keyvalue.length = keysize; free(k->mkvno); k->mkvno = NULL; return 0;}krb5_error_codehdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey){ int i; for(i = 0; i < ent->keys.len; i++){ krb5_error_code ret; ret = hdb_unseal_key_mkey(context, &ent->keys.val[i], mkey); if (ret) return ret; } return 0;}krb5_error_codehdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent){ if (db->hdb_master_key_set == 0) return 0; return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key);}krb5_error_codehdb_unseal_key(krb5_context context, HDB *db, Key *k){ if (db->hdb_master_key_set == 0) return 0; return hdb_unseal_key_mkey(context, k, db->hdb_master_key);}krb5_error_codehdb_seal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey){ krb5_error_code ret; krb5_data res; hdb_master_key key; if(k->mkvno != NULL) return 0; key = _hdb_find_master_key(k->mkvno, mkey); if (key == NULL) return HDB_ERR_NO_MKEY; ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY, k->key.keyvalue.data, k->key.keyvalue.length, &res); if (ret) return ret; memset(k->key.keyvalue.data, 0, k->key.keyvalue.length); free(k->key.keyvalue.data); k->key.keyvalue = res; if (k->mkvno == NULL) { k->mkvno = malloc(sizeof(*k->mkvno)); if (k->mkvno == NULL) return ENOMEM; } *k->mkvno = key->keytab.vno; return 0;}krb5_error_codehdb_seal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey){ int i; for(i = 0; i < ent->keys.len; i++){ krb5_error_code ret; ret = hdb_seal_key_mkey(context, &ent->keys.val[i], mkey); if (ret) return ret; } return 0;}krb5_error_codehdb_seal_keys(krb5_context context, HDB *db, hdb_entry *ent){ if (db->hdb_master_key_set == 0) return 0; return hdb_seal_keys_mkey(context, ent, db->hdb_master_key);}krb5_error_codehdb_seal_key(krb5_context context, HDB *db, Key *k){ if (db->hdb_master_key_set == 0) return 0; return hdb_seal_key_mkey(context, k, db->hdb_master_key);}krb5_error_codehdb_set_master_key (krb5_context context, HDB *db, krb5_keyblock *key){ krb5_error_code ret; hdb_master_key mkey; ret = hdb_process_master_key(context, 0, key, 0, &mkey); if (ret) return ret; db->hdb_master_key = mkey;#if 0 /* XXX - why? */ des_set_random_generator_seed(key.keyvalue.data);#endif db->hdb_master_key_set = 1; return 0;}krb5_error_codehdb_set_master_keyfile (krb5_context context, HDB *db, const char *keyfile){ hdb_master_key key; krb5_error_code ret; ret = hdb_read_master_key(context, keyfile, &key); if (ret) { if (ret != ENOENT) return ret; krb5_clear_error_string(context); return 0; } db->hdb_master_key = key; db->hdb_master_key_set = 1; return ret;}krb5_error_codehdb_clear_master_key (krb5_context context, HDB *db){ if (db->hdb_master_key_set) { hdb_free_master_key(context, db->hdb_master_key); db->hdb_master_key_set = 0; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -