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