set_keys.c revision 72445
155682Smarkm/* 272445Sassar * Copyright (c) 1997 - 2000 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "kadm5_locl.h" 3555682Smarkm 3672445SassarRCSID("$Id: set_keys.c,v 1.23 2000/11/15 23:13:30 assar Exp $"); 3755682Smarkm 3855682Smarkm/* 3972445Sassar * the known and used DES enctypes 4055682Smarkm */ 4155682Smarkm 4272445Sassarstatic krb5_enctype des_types[] = { ETYPE_DES_CBC_CRC, 4372445Sassar ETYPE_DES_CBC_MD4, 4472445Sassar ETYPE_DES_CBC_MD5 }; 4572445Sassarstatic unsigned n_des_types = sizeof(des_types) / sizeof(des_types[0]); 4672445Sassar 4772445Sassarstatic krb5_error_code 4872445Sassarmake_keys(krb5_context context, krb5_principal principal, const char *password, 4972445Sassar Key **keys_ret, size_t *num_keys_ret) 5055682Smarkm{ 5172445Sassar krb5_enctype all_etypes[] = { ETYPE_DES3_CBC_SHA1, 5272445Sassar ETYPE_DES_CBC_MD5, 5372445Sassar ETYPE_DES_CBC_MD4, 5472445Sassar ETYPE_DES_CBC_CRC }; 5555682Smarkm 5655682Smarkm 5772445Sassar krb5_enctype e; 5855682Smarkm 5972445Sassar krb5_error_code ret = 0; 6072445Sassar char **ktypes, **kp; 6172445Sassar 6272445Sassar Key *keys = NULL, *tmp; 6372445Sassar int num_keys = 0; 6472445Sassar Key key; 6572445Sassar 6655682Smarkm int i; 6772445Sassar char *v4_ktypes[] = {"des3:pw-salt", "v4", NULL}; 6855682Smarkm 6972445Sassar ktypes = krb5_config_get_strings(context, NULL, "kadmin", 7072445Sassar "default_keys", NULL); 7155682Smarkm 7272445Sassar /* for each entry in `default_keys' try to parse it as a sequence 7372445Sassar of etype:salttype:salt, syntax of this if something like: 7472445Sassar [(des|des3|etype):](pw|afs3)[:string], if etype is omitted it 7572445Sassar means everything, and if string is omitted is means the default 7672445Sassar string (for that principal). Additional special values: 7772445Sassar v5 == pw-salt, and 7872445Sassar v4 == pw-salt: 7972445Sassar */ 8055682Smarkm 8172445Sassar if (ktypes == NULL 8272445Sassar && krb5_config_get_bool (context, NULL, "kadmin", 8372445Sassar "use_v4_salt", NULL)) 8472445Sassar ktypes = v4_ktypes; 8555682Smarkm 8672445Sassar for(kp = ktypes; kp && *kp; kp++) { 8772445Sassar krb5_enctype *etypes; 8872445Sassar int num_etypes; 8972445Sassar krb5_salt salt; 9072445Sassar krb5_boolean salt_set; 9155682Smarkm 9272445Sassar const char *p; 9372445Sassar char buf[3][256]; 9472445Sassar int num_buf = 0; 9555682Smarkm 9672445Sassar p = *kp; 9772445Sassar if(strcmp(p, "v5") == 0) 9872445Sassar p = "pw-salt"; 9972445Sassar else if(strcmp(p, "v4") == 0) 10072445Sassar p = "des:pw-salt:"; 10172445Sassar 10272445Sassar /* split p in a list of :-separated strings */ 10372445Sassar for(num_buf = 0; num_buf < 3; num_buf++) 10472445Sassar if(strsep_copy(&p, ":", buf[num_buf], sizeof(buf[num_buf])) == -1) 10572445Sassar break; 10655682Smarkm 10772445Sassar etypes = NULL; 10872445Sassar num_etypes = 0; 10972445Sassar memset(&salt, 0, sizeof(salt)); 11072445Sassar salt_set = FALSE; 11155682Smarkm 11272445Sassar for(i = 0; i < num_buf; i++) { 11372445Sassar if(etypes == NULL) { 11472445Sassar /* this might be a etype specifier */ 11572445Sassar /* XXX there should be a string_to_etypes handling 11672445Sassar special cases like `des' and `all' */ 11772445Sassar if(strcmp(buf[i], "des") == 0) { 11872445Sassar etypes = all_etypes + 1; 11972445Sassar num_etypes = 3; 12072445Sassar continue; 12172445Sassar } else if(strcmp(buf[i], "des3") == 0) { 12272445Sassar e = ETYPE_DES3_CBC_SHA1; 12372445Sassar etypes = &e; 12472445Sassar num_etypes = 1; 12572445Sassar continue; 12672445Sassar } else { 12772445Sassar ret = krb5_string_to_enctype(context, buf[i], &e); 12872445Sassar if(ret == 0) { 12972445Sassar etypes = &e; 13072445Sassar num_etypes = 1; 13172445Sassar continue; 13272445Sassar } 13372445Sassar } 13472445Sassar } 13572445Sassar if(salt.salttype == 0) { 13672445Sassar /* interpret string as a salt specifier, if no etype 13772445Sassar is set, this sets default values */ 13872445Sassar /* XXX should perhaps use string_to_salttype, but that 13972445Sassar interface sucks */ 14072445Sassar if(strcmp(buf[i], "pw-salt") == 0) { 14172445Sassar if(etypes == NULL) { 14272445Sassar etypes = all_etypes; 14372445Sassar num_etypes = 4; 14472445Sassar } 14572445Sassar salt.salttype = KRB5_PW_SALT; 14672445Sassar } else if(strcmp(buf[i], "afs3-salt") == 0) { 14772445Sassar if(etypes == NULL) { 14872445Sassar etypes = all_etypes + 1; 14972445Sassar num_etypes = 3; 15072445Sassar } 15172445Sassar salt.salttype = KRB5_AFS3_SALT; 15272445Sassar } 15372445Sassar } else { 15472445Sassar /* if there is a final string, use it as the string to 15572445Sassar salt with, this is mostly useful with null salt for 15672445Sassar v4 compat, and a cell name for afs compat */ 15772445Sassar salt.saltvalue.data = buf[i]; 15872445Sassar salt.saltvalue.length = strlen(buf[i]); 15972445Sassar salt_set = TRUE; 16072445Sassar } 16172445Sassar } 16255682Smarkm 16372445Sassar if(etypes == NULL || salt.salttype == 0) { 16472445Sassar krb5_warnx(context, "bad value for default_keys `%s'", *kp); 16572445Sassar continue; 16672445Sassar } 16755682Smarkm 16872445Sassar if(!salt_set && salt.salttype == KRB5_PW_SALT) 16972445Sassar /* make up default salt */ 17072445Sassar ret = krb5_get_pw_salt(context, principal, &salt); 17172445Sassar memset(&key, 0, sizeof(key)); 17272445Sassar for(i = 0; i < num_etypes; i++) { 17372445Sassar ret = krb5_string_to_key_salt (context, 17472445Sassar etypes[i], 17572445Sassar password, 17672445Sassar salt, 17772445Sassar &key.key); 17872445Sassar 17972445Sassar if(ret) 18072445Sassar goto out; 18172445Sassar 18272445Sassar if (salt.salttype != KRB5_PW_SALT || salt_set) { 18372445Sassar key.salt = malloc (sizeof(*key.salt)); 18472445Sassar if (key.salt == NULL) { 18572445Sassar free_Key(&key); 18672445Sassar ret = ENOMEM; 18772445Sassar goto out; 18872445Sassar } 18972445Sassar key.salt->type = salt.salttype; 19072445Sassar krb5_data_zero (&key.salt->salt); 19172445Sassar 19272445Sassar /* is the salt has not been set explicitly, it will be 19372445Sassar the default salt, so there's no need to explicitly 19472445Sassar copy it */ 19572445Sassar if (salt_set) { 19672445Sassar ret = krb5_data_copy(&key.salt->salt, 19772445Sassar salt.saltvalue.data, 19872445Sassar salt.saltvalue.length); 19972445Sassar if (ret) { 20072445Sassar free_Key(&key); 20172445Sassar goto out; 20272445Sassar } 20372445Sassar } 20472445Sassar } 20572445Sassar tmp = realloc(keys, (num_keys + 1) * sizeof(*keys)); 20672445Sassar if(tmp == NULL) { 20772445Sassar free_Key(&key); 20872445Sassar ret = ENOMEM; 20972445Sassar goto out; 21072445Sassar } 21172445Sassar keys = tmp; 21272445Sassar keys[num_keys++] = key; 21372445Sassar } 21455682Smarkm } 21555682Smarkm 21672445Sassar if(num_keys == 0) { 21772445Sassar /* if we didn't manage to find a single valid key, create a 21872445Sassar default set */ 21972445Sassar /* XXX only do this is there is no `default_keys'? */ 22072445Sassar krb5_salt v5_salt; 22172445Sassar tmp = realloc(keys, (num_keys + 4) * sizeof(*keys)); 22272445Sassar if(tmp == NULL) { 22372445Sassar ret = ENOMEM; 22455682Smarkm goto out; 22572445Sassar } 22672445Sassar keys = tmp; 22772445Sassar ret = krb5_get_pw_salt(context, principal, &v5_salt); 22872445Sassar if(ret) 22972445Sassar goto out; 23072445Sassar for(i = 0; i < 4; i++) { 23172445Sassar memset(&key, 0, sizeof(key)); 23272445Sassar ret = krb5_string_to_key_salt(context, all_etypes[i], password, 23372445Sassar v5_salt, &key.key); 23472445Sassar if(ret) { 23572445Sassar krb5_free_salt(context, v5_salt); 23655682Smarkm goto out; 23755682Smarkm } 23872445Sassar keys[num_keys++] = key; 23955682Smarkm } 24072445Sassar krb5_free_salt(context, v5_salt); 24155682Smarkm } 24255682Smarkm 24372445Sassar out: 24472445Sassar if(ret == 0) { 24572445Sassar *keys_ret = keys; 24672445Sassar *num_keys_ret = num_keys; 24772445Sassar } else { 24872445Sassar for(i = 0; i < num_keys; i++) { 24972445Sassar free_Key(&keys[i]); 25072445Sassar } 25172445Sassar free(keys); 25272445Sassar } 25372445Sassar return ret; 25472445Sassar} 25555682Smarkm 25672445Sassar/* 25772445Sassar * Set the keys of `ent' to the string-to-key of `password' 25872445Sassar */ 25972445Sassar 26072445Sassarkadm5_ret_t 26172445Sassar_kadm5_set_keys(kadm5_server_context *context, 26272445Sassar hdb_entry *ent, 26372445Sassar const char *password) 26472445Sassar{ 26572445Sassar kadm5_ret_t ret; 26672445Sassar Key *keys; 26772445Sassar size_t num_keys; 26872445Sassar 26972445Sassar ret = make_keys(context->context, ent->principal, password, 27072445Sassar &keys, &num_keys); 27172445Sassar 27272445Sassar if(ret) 27372445Sassar return ret; 27472445Sassar 27572445Sassar _kadm5_free_keys (context, ent->keys.len, ent->keys.val); 27655682Smarkm ent->keys.val = keys; 27772445Sassar ent->keys.len = num_keys; 27855682Smarkm ent->kvno++; 27972445Sassar return 0; 28055682Smarkm} 28155682Smarkm 28255682Smarkm/* 28355682Smarkm * Set the keys of `ent' to (`n_key_data', `key_data') 28455682Smarkm */ 28555682Smarkm 28655682Smarkmkadm5_ret_t 28772445Sassar_kadm5_set_keys2(kadm5_server_context *context, 28872445Sassar hdb_entry *ent, 28955682Smarkm int16_t n_key_data, 29055682Smarkm krb5_key_data *key_data) 29155682Smarkm{ 29255682Smarkm krb5_error_code ret; 29355682Smarkm int i; 29472445Sassar unsigned len; 29572445Sassar Key *keys; 29655682Smarkm 29772445Sassar len = n_key_data; 29872445Sassar keys = malloc (len * sizeof(*keys)); 29972445Sassar if (keys == NULL) 30055682Smarkm return ENOMEM; 30172445Sassar 30272445Sassar _kadm5_init_keys (keys, len); 30372445Sassar 30455682Smarkm for(i = 0; i < n_key_data; i++) { 30572445Sassar keys[i].mkvno = NULL; 30672445Sassar keys[i].key.keytype = key_data[i].key_data_type[0]; 30772445Sassar ret = krb5_data_copy(&keys[i].key.keyvalue, 30855682Smarkm key_data[i].key_data_contents[0], 30955682Smarkm key_data[i].key_data_length[0]); 31055682Smarkm if(ret) 31172445Sassar goto out; 31255682Smarkm if(key_data[i].key_data_ver == 2) { 31355682Smarkm Salt *salt; 31472445Sassar 31555682Smarkm salt = malloc(sizeof(*salt)); 31672445Sassar if(salt == NULL) { 31772445Sassar ret = ENOMEM; 31872445Sassar goto out; 31972445Sassar } 32072445Sassar keys[i].salt = salt; 32155682Smarkm salt->type = key_data[i].key_data_type[1]; 32255682Smarkm krb5_data_copy(&salt->salt, 32355682Smarkm key_data[i].key_data_contents[1], 32455682Smarkm key_data[i].key_data_length[1]); 32555682Smarkm } else 32672445Sassar keys[i].salt = NULL; 32755682Smarkm } 32872445Sassar _kadm5_free_keys (context, ent->keys.len, ent->keys.val); 32972445Sassar ent->keys.len = len; 33072445Sassar ent->keys.val = keys; 33155682Smarkm ent->kvno++; 33255682Smarkm return 0; 33372445Sassar out: 33472445Sassar _kadm5_free_keys (context, len, keys); 33572445Sassar return ret; 33655682Smarkm} 33755682Smarkm 33855682Smarkm/* 33972445Sassar * Set the keys of `ent' to `n_keys, keys' 34072445Sassar */ 34172445Sassar 34272445Sassarkadm5_ret_t 34372445Sassar_kadm5_set_keys3(kadm5_server_context *context, 34472445Sassar hdb_entry *ent, 34572445Sassar int n_keys, 34672445Sassar krb5_keyblock *keyblocks) 34772445Sassar{ 34872445Sassar krb5_error_code ret; 34972445Sassar int i; 35072445Sassar unsigned len; 35172445Sassar Key *keys; 35272445Sassar 35372445Sassar len = n_keys; 35472445Sassar keys = malloc (len * sizeof(*keys)); 35572445Sassar if (keys == NULL) 35672445Sassar return ENOMEM; 35772445Sassar 35872445Sassar _kadm5_init_keys (keys, len); 35972445Sassar 36072445Sassar for(i = 0; i < n_keys; i++) { 36172445Sassar keys[i].mkvno = NULL; 36272445Sassar ret = krb5_copy_keyblock_contents (context->context, 36372445Sassar &keyblocks[i], 36472445Sassar &keys[i].key); 36572445Sassar if(ret) 36672445Sassar goto out; 36772445Sassar keys[i].salt = NULL; 36872445Sassar } 36972445Sassar _kadm5_free_keys (context, ent->keys.len, ent->keys.val); 37072445Sassar ent->keys.len = len; 37172445Sassar ent->keys.val = keys; 37272445Sassar ent->kvno++; 37372445Sassar return 0; 37472445Sassar out: 37572445Sassar _kadm5_free_keys (context, len, keys); 37672445Sassar return ret; 37772445Sassar} 37872445Sassar 37972445Sassar/* 38055682Smarkm * Set the keys of `ent' to random keys and return them in `n_keys' 38155682Smarkm * and `new_keys'. 38255682Smarkm */ 38355682Smarkm 38455682Smarkmkadm5_ret_t 38555682Smarkm_kadm5_set_keys_randomly (kadm5_server_context *context, 38655682Smarkm hdb_entry *ent, 38755682Smarkm krb5_keyblock **new_keys, 38855682Smarkm int *n_keys) 38955682Smarkm{ 39055682Smarkm kadm5_ret_t ret = 0; 39155682Smarkm int i; 39255682Smarkm unsigned len; 39355682Smarkm krb5_keyblock *keys; 39455682Smarkm Key *hkeys; 39555682Smarkm 39655682Smarkm len = n_des_types + 1; 39755682Smarkm keys = malloc (len * sizeof(*keys)); 39855682Smarkm if (keys == NULL) 39955682Smarkm return ENOMEM; 40055682Smarkm 40155682Smarkm for (i = 0; i < len; ++i) { 40255682Smarkm keys[i].keyvalue.length = 0; 40355682Smarkm keys[i].keyvalue.data = NULL; 40455682Smarkm } 40555682Smarkm 40655682Smarkm hkeys = malloc (len * sizeof(*hkeys)); 40755682Smarkm if (hkeys == NULL) { 40855682Smarkm free (keys); 40955682Smarkm return ENOMEM; 41055682Smarkm } 41155682Smarkm 41272445Sassar _kadm5_init_keys (hkeys, len); 41355682Smarkm 41455682Smarkm ret = krb5_generate_random_keyblock (context->context, 41555682Smarkm des_types[0], 41655682Smarkm &keys[0]); 41755682Smarkm if (ret) 41855682Smarkm goto out; 41955682Smarkm 42055682Smarkm ret = krb5_copy_keyblock_contents (context->context, 42155682Smarkm &keys[0], 42255682Smarkm &hkeys[0].key); 42355682Smarkm if (ret) 42455682Smarkm goto out; 42555682Smarkm 42655682Smarkm for (i = 1; i < n_des_types; ++i) { 42755682Smarkm ret = krb5_copy_keyblock_contents (context->context, 42855682Smarkm &keys[0], 42955682Smarkm &keys[i]); 43055682Smarkm if (ret) 43155682Smarkm goto out; 43255682Smarkm keys[i].keytype = des_types[i]; 43355682Smarkm ret = krb5_copy_keyblock_contents (context->context, 43455682Smarkm &keys[0], 43555682Smarkm &hkeys[i].key); 43655682Smarkm if (ret) 43755682Smarkm goto out; 43855682Smarkm hkeys[i].key.keytype = des_types[i]; 43955682Smarkm } 44055682Smarkm 44155682Smarkm ret = krb5_generate_random_keyblock (context->context, 44255682Smarkm ETYPE_DES3_CBC_SHA1, 44355682Smarkm &keys[n_des_types]); 44455682Smarkm if (ret) 44555682Smarkm goto out; 44655682Smarkm 44755682Smarkm ret = krb5_copy_keyblock_contents (context->context, 44855682Smarkm &keys[n_des_types], 44955682Smarkm &hkeys[n_des_types].key); 45055682Smarkm if (ret) 45155682Smarkm goto out; 45255682Smarkm 45372445Sassar _kadm5_free_keys (context, ent->keys.len, ent->keys.val); 45455682Smarkm ent->keys.len = len; 45555682Smarkm ent->keys.val = hkeys; 45655682Smarkm ent->kvno++; 45755682Smarkm *new_keys = keys; 45855682Smarkm *n_keys = len; 45955682Smarkm return ret; 46055682Smarkmout: 46155682Smarkm for (i = 0; i < len; ++i) 46255682Smarkm krb5_free_keyblock_contents (context->context, &keys[i]); 46355682Smarkm free (keys); 46472445Sassar _kadm5_free_keys (context, len, hkeys); 46555682Smarkm return ret; 46655682Smarkm} 467