1233294Sstas
2178825Sdfr/*
3233294Sstas * Copyright (c) 1997 - 2001, 2003 - 2004 Kungliga Tekniska H��gskolan
4233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
5233294Sstas * All rights reserved.
6178825Sdfr *
7233294Sstas * Redistribution and use in source and binary forms, with or without
8233294Sstas * modification, are permitted provided that the following conditions
9233294Sstas * are met:
10178825Sdfr *
11233294Sstas * 1. Redistributions of source code must retain the above copyright
12233294Sstas *    notice, this list of conditions and the following disclaimer.
13178825Sdfr *
14233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
15233294Sstas *    notice, this list of conditions and the following disclaimer in the
16233294Sstas *    documentation and/or other materials provided with the distribution.
17178825Sdfr *
18233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
19233294Sstas *    may be used to endorse or promote products derived from this software
20233294Sstas *    without specific prior written permission.
21178825Sdfr *
22233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32233294Sstas * SUCH DAMAGE.
33178825Sdfr */
34178825Sdfr
35178825Sdfr#include "hdb_locl.h"
36178825Sdfr
37178825Sdfr/*
38178825Sdfr * free all the memory used by (len, keys)
39178825Sdfr */
40178825Sdfr
41178825Sdfrvoid
42178825Sdfrhdb_free_keys (krb5_context context, int len, Key *keys)
43178825Sdfr{
44178825Sdfr    int i;
45178825Sdfr
46178825Sdfr    for (i = 0; i < len; i++) {
47178825Sdfr	free(keys[i].mkvno);
48178825Sdfr	keys[i].mkvno = NULL;
49178825Sdfr	if (keys[i].salt != NULL) {
50178825Sdfr	    free_Salt(keys[i].salt);
51178825Sdfr	    free(keys[i].salt);
52178825Sdfr	    keys[i].salt = NULL;
53178825Sdfr	}
54178825Sdfr	krb5_free_keyblock_contents(context, &keys[i].key);
55178825Sdfr    }
56178825Sdfr    free (keys);
57178825Sdfr}
58178825Sdfr
59233294Sstas/*
60178825Sdfr * for each entry in `default_keys' try to parse it as a sequence
61178825Sdfr * of etype:salttype:salt, syntax of this if something like:
62178825Sdfr * [(des|des3|etype):](pw-salt|afs3)[:string], if etype is omitted it
63178825Sdfr *      means all etypes, and if string is omitted is means the default
64178825Sdfr * string (for that principal). Additional special values:
65178825Sdfr *	v5 == pw-salt, and
66178825Sdfr *	v4 == des:pw-salt:
67178825Sdfr *	afs or afs3 == des:afs3-salt
68178825Sdfr */
69178825Sdfr
70233294Sstasstatic const krb5_enctype des_etypes[] = {
71178825Sdfr    ETYPE_DES_CBC_MD5,
72178825Sdfr    ETYPE_DES_CBC_MD4,
73233294Sstas    ETYPE_DES_CBC_CRC
74233294Sstas};
75233294Sstas
76233294Sstasstatic const krb5_enctype all_etypes[] = {
77178825Sdfr    ETYPE_AES256_CTS_HMAC_SHA1_96,
78178825Sdfr    ETYPE_ARCFOUR_HMAC_MD5,
79178825Sdfr    ETYPE_DES3_CBC_SHA1
80178825Sdfr};
81178825Sdfr
82178825Sdfrstatic krb5_error_code
83233294Sstasparse_key_set(krb5_context context, const char *key,
84233294Sstas	      krb5_enctype **ret_enctypes, size_t *ret_num_enctypes,
85178825Sdfr	      krb5_salt *salt, krb5_principal principal)
86178825Sdfr{
87178825Sdfr    const char *p;
88178825Sdfr    char buf[3][256];
89178825Sdfr    int num_buf = 0;
90178825Sdfr    int i, num_enctypes = 0;
91178825Sdfr    krb5_enctype e;
92178825Sdfr    const krb5_enctype *enctypes = NULL;
93178825Sdfr    krb5_error_code ret;
94233294Sstas
95178825Sdfr    p = key;
96178825Sdfr
97178825Sdfr    *ret_enctypes = NULL;
98178825Sdfr    *ret_num_enctypes = 0;
99178825Sdfr
100178825Sdfr    /* split p in a list of :-separated strings */
101178825Sdfr    for(num_buf = 0; num_buf < 3; num_buf++)
102178825Sdfr	if(strsep_copy(&p, ":", buf[num_buf], sizeof(buf[num_buf])) == -1)
103178825Sdfr	    break;
104178825Sdfr
105178825Sdfr    salt->saltvalue.data = NULL;
106178825Sdfr    salt->saltvalue.length = 0;
107178825Sdfr
108178825Sdfr    for(i = 0; i < num_buf; i++) {
109178825Sdfr	if(enctypes == NULL && num_buf > 1) {
110178825Sdfr	    /* this might be a etype specifier */
111178825Sdfr	    /* XXX there should be a string_to_etypes handling
112178825Sdfr	       special cases like `des' and `all' */
113178825Sdfr	    if(strcmp(buf[i], "des") == 0) {
114233294Sstas		enctypes = des_etypes;
115233294Sstas		num_enctypes = sizeof(des_etypes)/sizeof(des_etypes[0]);
116178825Sdfr	    } else if(strcmp(buf[i], "des3") == 0) {
117178825Sdfr		e = ETYPE_DES3_CBC_SHA1;
118178825Sdfr		enctypes = &e;
119178825Sdfr		num_enctypes = 1;
120178825Sdfr	    } else {
121178825Sdfr		ret = krb5_string_to_enctype(context, buf[i], &e);
122178825Sdfr		if (ret == 0) {
123178825Sdfr		    enctypes = &e;
124178825Sdfr		    num_enctypes = 1;
125178825Sdfr		} else
126178825Sdfr		    return ret;
127178825Sdfr	    }
128178825Sdfr	    continue;
129178825Sdfr	}
130178825Sdfr	if(salt->salttype == 0) {
131178825Sdfr	    /* interpret string as a salt specifier, if no etype
132178825Sdfr	       is set, this sets default values */
133178825Sdfr	    /* XXX should perhaps use string_to_salttype, but that
134178825Sdfr	       interface sucks */
135178825Sdfr	    if(strcmp(buf[i], "pw-salt") == 0) {
136178825Sdfr		if(enctypes == NULL) {
137178825Sdfr		    enctypes = all_etypes;
138178825Sdfr		    num_enctypes = sizeof(all_etypes)/sizeof(all_etypes[0]);
139178825Sdfr		}
140178825Sdfr		salt->salttype = KRB5_PW_SALT;
141178825Sdfr	    } else if(strcmp(buf[i], "afs3-salt") == 0) {
142178825Sdfr		if(enctypes == NULL) {
143233294Sstas		    enctypes = des_etypes;
144233294Sstas		    num_enctypes = sizeof(des_etypes)/sizeof(des_etypes[0]);
145178825Sdfr		}
146178825Sdfr		salt->salttype = KRB5_AFS3_SALT;
147178825Sdfr	    }
148178825Sdfr	    continue;
149178825Sdfr	}
150178825Sdfr
151178825Sdfr	{
152178825Sdfr	    /* if there is a final string, use it as the string to
153178825Sdfr	       salt with, this is mostly useful with null salt for
154178825Sdfr	       v4 compat, and a cell name for afs compat */
155178825Sdfr	    salt->saltvalue.data = strdup(buf[i]);
156178825Sdfr	    if (salt->saltvalue.data == NULL) {
157233294Sstas		krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
158178825Sdfr		return ENOMEM;
159178825Sdfr	    }
160178825Sdfr	    salt->saltvalue.length = strlen(buf[i]);
161178825Sdfr	}
162178825Sdfr    }
163233294Sstas
164178825Sdfr    if(enctypes == NULL || salt->salttype == 0) {
165233294Sstas	krb5_set_error_message(context, EINVAL, "bad value for default_keys `%s'", key);
166178825Sdfr	return EINVAL;
167178825Sdfr    }
168233294Sstas
169178825Sdfr    /* if no salt was specified make up default salt */
170178825Sdfr    if(salt->saltvalue.data == NULL) {
171178825Sdfr	if(salt->salttype == KRB5_PW_SALT)
172178825Sdfr	    ret = krb5_get_pw_salt(context, principal, salt);
173178825Sdfr	else if(salt->salttype == KRB5_AFS3_SALT) {
174233294Sstas	    krb5_const_realm realm = krb5_principal_get_realm(context, principal);
175233294Sstas	    salt->saltvalue.data = strdup(realm);
176178825Sdfr	    if(salt->saltvalue.data == NULL) {
177233294Sstas		krb5_set_error_message(context, ENOMEM,
178233294Sstas				       "out of memory while "
179233294Sstas				       "parsing salt specifiers");
180178825Sdfr		return ENOMEM;
181178825Sdfr	    }
182178825Sdfr	    strlwr(salt->saltvalue.data);
183233294Sstas	    salt->saltvalue.length = strlen(realm);
184178825Sdfr	}
185178825Sdfr    }
186178825Sdfr
187178825Sdfr    *ret_enctypes = malloc(sizeof(enctypes[0]) * num_enctypes);
188178825Sdfr    if (*ret_enctypes == NULL) {
189178825Sdfr	krb5_free_salt(context, *salt);
190233294Sstas	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
191178825Sdfr	return ENOMEM;
192178825Sdfr    }
193178825Sdfr    memcpy(*ret_enctypes, enctypes, sizeof(enctypes[0]) * num_enctypes);
194178825Sdfr    *ret_num_enctypes = num_enctypes;
195178825Sdfr
196178825Sdfr    return 0;
197178825Sdfr}
198178825Sdfr
199178825Sdfrstatic krb5_error_code
200233294Sstasadd_enctype_to_key_set(Key **key_set, size_t *nkeyset,
201178825Sdfr		       krb5_enctype enctype, krb5_salt *salt)
202178825Sdfr{
203178825Sdfr    krb5_error_code ret;
204178825Sdfr    Key key, *tmp;
205178825Sdfr
206178825Sdfr    memset(&key, 0, sizeof(key));
207178825Sdfr
208178825Sdfr    tmp = realloc(*key_set, (*nkeyset + 1) * sizeof((*key_set)[0]));
209178825Sdfr    if (tmp == NULL)
210178825Sdfr	return ENOMEM;
211233294Sstas
212178825Sdfr    *key_set = tmp;
213178825Sdfr
214178825Sdfr    key.key.keytype = enctype;
215178825Sdfr    key.key.keyvalue.length = 0;
216178825Sdfr    key.key.keyvalue.data = NULL;
217233294Sstas
218178825Sdfr    if (salt) {
219233294Sstas	key.salt = calloc(1, sizeof(*key.salt));
220178825Sdfr	if (key.salt == NULL) {
221178825Sdfr	    free_Key(&key);
222178825Sdfr	    return ENOMEM;
223178825Sdfr	}
224233294Sstas
225178825Sdfr	key.salt->type = salt->salttype;
226178825Sdfr	krb5_data_zero (&key.salt->salt);
227233294Sstas
228233294Sstas	ret = krb5_data_copy(&key.salt->salt,
229233294Sstas			     salt->saltvalue.data,
230178825Sdfr			     salt->saltvalue.length);
231178825Sdfr	if (ret) {
232178825Sdfr	    free_Key(&key);
233178825Sdfr	    return ret;
234178825Sdfr	}
235178825Sdfr    } else
236178825Sdfr	key.salt = NULL;
237233294Sstas
238178825Sdfr    (*key_set)[*nkeyset] = key;
239233294Sstas
240178825Sdfr    *nkeyset += 1;
241178825Sdfr
242178825Sdfr    return 0;
243178825Sdfr}
244178825Sdfr
245178825Sdfr
246178825Sdfr/*
247178825Sdfr * Generate the `key_set' from the [kadmin]default_keys statement. If
248178825Sdfr * `no_salt' is set, salt is not important (and will not be set) since
249178825Sdfr * it's random keys that is going to be created.
250178825Sdfr */
251178825Sdfr
252178825Sdfrkrb5_error_code
253178825Sdfrhdb_generate_key_set(krb5_context context, krb5_principal principal,
254178825Sdfr		     Key **ret_key_set, size_t *nkeyset, int no_salt)
255178825Sdfr{
256178825Sdfr    char **ktypes, **kp;
257178825Sdfr    krb5_error_code ret;
258178825Sdfr    Key *k, *key_set;
259233294Sstas    size_t i, j;
260233294Sstas    static const char *default_keytypes[] = {
261178825Sdfr	"aes256-cts-hmac-sha1-96:pw-salt",
262178825Sdfr	"des3-cbc-sha1:pw-salt",
263178825Sdfr	"arcfour-hmac-md5:pw-salt",
264178825Sdfr	NULL
265178825Sdfr    };
266233294Sstas
267178825Sdfr    ktypes = krb5_config_get_strings(context, NULL, "kadmin",
268178825Sdfr				     "default_keys", NULL);
269178825Sdfr    if (ktypes == NULL)
270233294Sstas	ktypes = (char **)(intptr_t)default_keytypes;
271178825Sdfr
272178825Sdfr    *ret_key_set = key_set = NULL;
273178825Sdfr    *nkeyset = 0;
274178825Sdfr
275178825Sdfr    ret = 0;
276233294Sstas
277178825Sdfr    for(kp = ktypes; kp && *kp; kp++) {
278178825Sdfr	const char *p;
279178825Sdfr	krb5_salt salt;
280178825Sdfr	krb5_enctype *enctypes;
281178825Sdfr	size_t num_enctypes;
282178825Sdfr
283178825Sdfr	p = *kp;
284178825Sdfr	/* check alias */
285178825Sdfr	if(strcmp(p, "v5") == 0)
286178825Sdfr	    p = "pw-salt";
287178825Sdfr	else if(strcmp(p, "v4") == 0)
288178825Sdfr	    p = "des:pw-salt:";
289178825Sdfr	else if(strcmp(p, "afs") == 0 || strcmp(p, "afs3") == 0)
290178825Sdfr	    p = "des:afs3-salt";
291178825Sdfr	else if (strcmp(p, "arcfour-hmac-md5") == 0)
292178825Sdfr	    p = "arcfour-hmac-md5:pw-salt";
293233294Sstas
294178825Sdfr	memset(&salt, 0, sizeof(salt));
295178825Sdfr
296178825Sdfr	ret = parse_key_set(context, p,
297178825Sdfr			    &enctypes, &num_enctypes, &salt, principal);
298178825Sdfr	if (ret) {
299178825Sdfr	    krb5_warn(context, ret, "bad value for default_keys `%s'", *kp);
300178825Sdfr	    ret = 0;
301178825Sdfr	    continue;
302178825Sdfr	}
303178825Sdfr
304178825Sdfr	for (i = 0; i < num_enctypes; i++) {
305178825Sdfr	    /* find duplicates */
306178825Sdfr	    for (j = 0; j < *nkeyset; j++) {
307178825Sdfr
308178825Sdfr		k = &key_set[j];
309178825Sdfr
310178825Sdfr		if (k->key.keytype == enctypes[i]) {
311178825Sdfr		    if (no_salt)
312178825Sdfr			break;
313178825Sdfr		    if (k->salt == NULL && salt.salttype == KRB5_PW_SALT)
314178825Sdfr			break;
315178825Sdfr		    if (k->salt->type == salt.salttype &&
316178825Sdfr			k->salt->salt.length == salt.saltvalue.length &&
317233294Sstas			memcmp(k->salt->salt.data, salt.saltvalue.data,
318178825Sdfr			       salt.saltvalue.length) == 0)
319178825Sdfr			break;
320178825Sdfr		}
321178825Sdfr	    }
322178825Sdfr	    /* not a duplicate, lets add it */
323178825Sdfr	    if (j == *nkeyset) {
324233294Sstas		ret = add_enctype_to_key_set(&key_set, nkeyset, enctypes[i],
325178825Sdfr					     no_salt ? NULL : &salt);
326178825Sdfr		if (ret) {
327178825Sdfr		    free(enctypes);
328178825Sdfr		    krb5_free_salt(context, salt);
329178825Sdfr		    goto out;
330178825Sdfr		}
331178825Sdfr	    }
332178825Sdfr	}
333178825Sdfr	free(enctypes);
334178825Sdfr	krb5_free_salt(context, salt);
335178825Sdfr    }
336233294Sstas
337178825Sdfr    *ret_key_set = key_set;
338178825Sdfr
339178825Sdfr out:
340233294Sstas    if (ktypes != (char **)(intptr_t)default_keytypes)
341178825Sdfr	krb5_config_free_strings(ktypes);
342178825Sdfr
343178825Sdfr    if (ret) {
344233294Sstas	krb5_warn(context, ret,
345178825Sdfr		  "failed to parse the [kadmin]default_keys values");
346178825Sdfr
347178825Sdfr	for (i = 0; i < *nkeyset; i++)
348178825Sdfr	    free_Key(&key_set[i]);
349178825Sdfr	free(key_set);
350178825Sdfr    } else if (*nkeyset == 0) {
351233294Sstas	krb5_warnx(context,
352178825Sdfr		   "failed to parse any of the [kadmin]default_keys values");
353178825Sdfr	ret = EINVAL; /* XXX */
354178825Sdfr    }
355178825Sdfr
356178825Sdfr    return ret;
357178825Sdfr}
358178825Sdfr
359178825Sdfr
360178825Sdfrkrb5_error_code
361233294Sstashdb_generate_key_set_password(krb5_context context,
362233294Sstas			      krb5_principal principal,
363233294Sstas			      const char *password,
364233294Sstas			      Key **keys, size_t *num_keys)
365178825Sdfr{
366178825Sdfr    krb5_error_code ret;
367233294Sstas    size_t i;
368178825Sdfr
369178825Sdfr    ret = hdb_generate_key_set(context, principal,
370178825Sdfr				keys, num_keys, 0);
371178825Sdfr    if (ret)
372178825Sdfr	return ret;
373178825Sdfr
374178825Sdfr    for (i = 0; i < (*num_keys); i++) {
375178825Sdfr	krb5_salt salt;
376178825Sdfr
377178825Sdfr	salt.salttype = (*keys)[i].salt->type;
378178825Sdfr	salt.saltvalue.length = (*keys)[i].salt->salt.length;
379178825Sdfr	salt.saltvalue.data = (*keys)[i].salt->salt.data;
380178825Sdfr
381178825Sdfr	ret = krb5_string_to_key_salt (context,
382178825Sdfr				       (*keys)[i].key.keytype,
383178825Sdfr				       password,
384178825Sdfr				       salt,
385178825Sdfr				       &(*keys)[i].key);
386178825Sdfr
387178825Sdfr	if(ret)
388178825Sdfr	    break;
389178825Sdfr    }
390178825Sdfr
391178825Sdfr    if(ret) {
392178825Sdfr	hdb_free_keys (context, *num_keys, *keys);
393178825Sdfr	return ret;
394178825Sdfr    }
395178825Sdfr    return ret;
396178825Sdfr}
397