xref: /freebsd/crypto/heimdal/lib/kadm5/set_keys.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
1 /*
2  * Copyright (c) 1997 - 2000 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 "kadm5_locl.h"
35 
36 RCSID("$Id: set_keys.c,v 1.23 2000/11/15 23:13:30 assar Exp $");
37 
38 /*
39  * the known and used DES enctypes
40  */
41 
42 static krb5_enctype des_types[] = { ETYPE_DES_CBC_CRC,
43  				    ETYPE_DES_CBC_MD4,
44  				    ETYPE_DES_CBC_MD5 };
45 static unsigned n_des_types = sizeof(des_types) / sizeof(des_types[0]);
46 
47 static krb5_error_code
48 make_keys(krb5_context context, krb5_principal principal, const char *password,
49 	  Key **keys_ret, size_t *num_keys_ret)
50 {
51     krb5_enctype all_etypes[] = { ETYPE_DES3_CBC_SHA1,
52 				  ETYPE_DES_CBC_MD5,
53 				  ETYPE_DES_CBC_MD4,
54 				  ETYPE_DES_CBC_CRC };
55 
56 
57     krb5_enctype e;
58 
59     krb5_error_code ret = 0;
60     char **ktypes, **kp;
61 
62     Key *keys = NULL, *tmp;
63     int num_keys = 0;
64     Key key;
65 
66     int i;
67     char *v4_ktypes[] = {"des3:pw-salt", "v4", NULL};
68 
69     ktypes = krb5_config_get_strings(context, NULL, "kadmin",
70 				     "default_keys", NULL);
71 
72     /* for each entry in `default_keys' try to parse it as a sequence
73        of etype:salttype:salt, syntax of this if something like:
74        [(des|des3|etype):](pw|afs3)[:string], if etype is omitted it
75        means everything, and if string is omitted is means the default
76        string (for that principal). Additional special values:
77        v5 == pw-salt, and
78        v4 == pw-salt:
79     */
80 
81     if (ktypes == NULL
82 	&& krb5_config_get_bool (context, NULL, "kadmin",
83 				 "use_v4_salt", NULL))
84 	ktypes = v4_ktypes;
85 
86     for(kp = ktypes; kp && *kp; kp++) {
87 	krb5_enctype *etypes;
88 	int num_etypes;
89 	krb5_salt salt;
90 	krb5_boolean salt_set;
91 
92 	const char *p;
93 	char buf[3][256];
94 	int num_buf = 0;
95 
96 	p = *kp;
97 	if(strcmp(p, "v5") == 0)
98 	    p = "pw-salt";
99 	else if(strcmp(p, "v4") == 0)
100 	    p = "des:pw-salt:";
101 
102 	/* split p in a list of :-separated strings */
103 	for(num_buf = 0; num_buf < 3; num_buf++)
104 	    if(strsep_copy(&p, ":", buf[num_buf], sizeof(buf[num_buf])) == -1)
105 		break;
106 
107 	etypes = NULL;
108 	num_etypes = 0;
109 	memset(&salt, 0, sizeof(salt));
110 	salt_set = FALSE;
111 
112 	for(i = 0; i < num_buf; i++) {
113 	    if(etypes == NULL) {
114 		/* this might be a etype specifier */
115 		/* XXX there should be a string_to_etypes handling
116                    special cases like `des' and `all' */
117 		if(strcmp(buf[i], "des") == 0) {
118 		    etypes = all_etypes + 1;
119 		    num_etypes = 3;
120 		    continue;
121 		} else if(strcmp(buf[i], "des3") == 0) {
122 		    e = ETYPE_DES3_CBC_SHA1;
123 		    etypes = &e;
124 		    num_etypes = 1;
125 		    continue;
126 		} else {
127 		    ret = krb5_string_to_enctype(context, buf[i], &e);
128 		    if(ret == 0) {
129 			etypes = &e;
130 			num_etypes = 1;
131 			continue;
132 		    }
133 		}
134 	    }
135 	    if(salt.salttype == 0) {
136 		/* interpret string as a salt specifier, if no etype
137                    is set, this sets default values */
138 		/* XXX should perhaps use string_to_salttype, but that
139                    interface sucks */
140 		if(strcmp(buf[i], "pw-salt") == 0) {
141 		    if(etypes == NULL) {
142 			etypes = all_etypes;
143 			num_etypes = 4;
144 		    }
145 		    salt.salttype = KRB5_PW_SALT;
146 		} else if(strcmp(buf[i], "afs3-salt") == 0) {
147 		    if(etypes == NULL) {
148 			etypes = all_etypes + 1;
149 			num_etypes = 3;
150 		    }
151 		    salt.salttype = KRB5_AFS3_SALT;
152 		}
153 	    } else {
154 		/* if there is a final string, use it as the string to
155                    salt with, this is mostly useful with null salt for
156                    v4 compat, and a cell name for afs compat */
157 		salt.saltvalue.data = buf[i];
158 		salt.saltvalue.length = strlen(buf[i]);
159 		salt_set = TRUE;
160 	    }
161 	}
162 
163 	if(etypes == NULL || salt.salttype == 0) {
164 	    krb5_warnx(context, "bad value for default_keys `%s'", *kp);
165 	    continue;
166 	}
167 
168 	if(!salt_set && salt.salttype == KRB5_PW_SALT)
169 	    /* make up default salt */
170 	    ret = krb5_get_pw_salt(context, principal, &salt);
171 	memset(&key, 0, sizeof(key));
172 	for(i = 0; i < num_etypes; i++) {
173 	    ret = krb5_string_to_key_salt (context,
174 					   etypes[i],
175 					   password,
176 					   salt,
177 					   &key.key);
178 
179 	    if(ret)
180 		goto out;
181 
182 	    if (salt.salttype != KRB5_PW_SALT || salt_set) {
183 		key.salt = malloc (sizeof(*key.salt));
184 		if (key.salt == NULL) {
185 		    free_Key(&key);
186 		    ret = ENOMEM;
187 		    goto out;
188 		}
189 		key.salt->type = salt.salttype;
190 		krb5_data_zero (&key.salt->salt);
191 
192 		/* is the salt has not been set explicitly, it will be
193 		   the default salt, so there's no need to explicitly
194 		   copy it */
195 		if (salt_set) {
196 		    ret = krb5_data_copy(&key.salt->salt,
197 					 salt.saltvalue.data,
198 					 salt.saltvalue.length);
199 		    if (ret) {
200 			free_Key(&key);
201 			goto out;
202 		    }
203 		}
204 	    }
205 	    tmp = realloc(keys, (num_keys + 1) * sizeof(*keys));
206 	    if(tmp == NULL) {
207 		free_Key(&key);
208 		ret = ENOMEM;
209 		goto out;
210 	    }
211 	    keys = tmp;
212 	    keys[num_keys++] = key;
213 	}
214     }
215 
216     if(num_keys == 0) {
217 	/* if we didn't manage to find a single valid key, create a
218            default set */
219 	/* XXX only do this is there is no `default_keys'? */
220 	krb5_salt v5_salt;
221 	tmp = realloc(keys, (num_keys + 4) * sizeof(*keys));
222 	if(tmp == NULL) {
223 	    ret = ENOMEM;
224 	    goto out;
225 	}
226 	keys = tmp;
227 	ret = krb5_get_pw_salt(context, principal, &v5_salt);
228 	if(ret)
229 	    goto out;
230 	for(i = 0; i < 4; i++) {
231 	    memset(&key, 0, sizeof(key));
232 	    ret = krb5_string_to_key_salt(context, all_etypes[i], password,
233 					  v5_salt, &key.key);
234 	    if(ret) {
235 		krb5_free_salt(context, v5_salt);
236 		goto out;
237 	    }
238 	    keys[num_keys++] = key;
239 	}
240 	krb5_free_salt(context, v5_salt);
241     }
242 
243   out:
244     if(ret == 0) {
245 	*keys_ret = keys;
246 	*num_keys_ret = num_keys;
247     } else {
248 	for(i = 0; i < num_keys; i++) {
249 	    free_Key(&keys[i]);
250 	}
251 	free(keys);
252     }
253     return ret;
254 }
255 
256 /*
257  * Set the keys of `ent' to the string-to-key of `password'
258  */
259 
260 kadm5_ret_t
261 _kadm5_set_keys(kadm5_server_context *context,
262 		hdb_entry *ent,
263 		const char *password)
264 {
265     kadm5_ret_t ret;
266     Key *keys;
267     size_t num_keys;
268 
269     ret = make_keys(context->context, ent->principal, password,
270 		    &keys, &num_keys);
271 
272     if(ret)
273 	return ret;
274 
275     _kadm5_free_keys (context, ent->keys.len, ent->keys.val);
276     ent->keys.val = keys;
277     ent->keys.len = num_keys;
278     ent->kvno++;
279     return 0;
280 }
281 
282 /*
283  * Set the keys of `ent' to (`n_key_data', `key_data')
284  */
285 
286 kadm5_ret_t
287 _kadm5_set_keys2(kadm5_server_context *context,
288 		 hdb_entry *ent,
289 		 int16_t n_key_data,
290 		 krb5_key_data *key_data)
291 {
292     krb5_error_code ret;
293     int i;
294     unsigned len;
295     Key *keys;
296 
297     len  = n_key_data;
298     keys = malloc (len * sizeof(*keys));
299     if (keys == NULL)
300 	return ENOMEM;
301 
302     _kadm5_init_keys (keys, len);
303 
304     for(i = 0; i < n_key_data; i++) {
305 	keys[i].mkvno = NULL;
306 	keys[i].key.keytype = key_data[i].key_data_type[0];
307 	ret = krb5_data_copy(&keys[i].key.keyvalue,
308 			     key_data[i].key_data_contents[0],
309 			     key_data[i].key_data_length[0]);
310 	if(ret)
311 	    goto out;
312 	if(key_data[i].key_data_ver == 2) {
313 	    Salt *salt;
314 
315 	    salt = malloc(sizeof(*salt));
316 	    if(salt == NULL) {
317 		ret = ENOMEM;
318 		goto out;
319 	    }
320 	    keys[i].salt = salt;
321 	    salt->type = key_data[i].key_data_type[1];
322 	    krb5_data_copy(&salt->salt,
323 			   key_data[i].key_data_contents[1],
324 			   key_data[i].key_data_length[1]);
325 	} else
326 	    keys[i].salt = NULL;
327     }
328     _kadm5_free_keys (context, ent->keys.len, ent->keys.val);
329     ent->keys.len = len;
330     ent->keys.val = keys;
331     ent->kvno++;
332     return 0;
333  out:
334     _kadm5_free_keys (context, len, keys);
335     return ret;
336 }
337 
338 /*
339  * Set the keys of `ent' to `n_keys, keys'
340  */
341 
342 kadm5_ret_t
343 _kadm5_set_keys3(kadm5_server_context *context,
344 		 hdb_entry *ent,
345 		 int n_keys,
346 		 krb5_keyblock *keyblocks)
347 {
348     krb5_error_code ret;
349     int i;
350     unsigned len;
351     Key *keys;
352 
353     len  = n_keys;
354     keys = malloc (len * sizeof(*keys));
355     if (keys == NULL)
356 	return ENOMEM;
357 
358     _kadm5_init_keys (keys, len);
359 
360     for(i = 0; i < n_keys; i++) {
361 	keys[i].mkvno = NULL;
362 	ret = krb5_copy_keyblock_contents (context->context,
363 					   &keyblocks[i],
364 					   &keys[i].key);
365 	if(ret)
366 	    goto out;
367 	keys[i].salt = NULL;
368     }
369     _kadm5_free_keys (context, ent->keys.len, ent->keys.val);
370     ent->keys.len = len;
371     ent->keys.val = keys;
372     ent->kvno++;
373     return 0;
374  out:
375     _kadm5_free_keys (context, len, keys);
376     return ret;
377 }
378 
379 /*
380  * Set the keys of `ent' to random keys and return them in `n_keys'
381  * and `new_keys'.
382  */
383 
384 kadm5_ret_t
385 _kadm5_set_keys_randomly (kadm5_server_context *context,
386 			  hdb_entry *ent,
387 			  krb5_keyblock **new_keys,
388 			  int *n_keys)
389 {
390     kadm5_ret_t ret = 0;
391     int i;
392     unsigned len;
393     krb5_keyblock *keys;
394     Key *hkeys;
395 
396     len  = n_des_types + 1;
397     keys = malloc (len * sizeof(*keys));
398     if (keys == NULL)
399 	return ENOMEM;
400 
401     for (i = 0; i < len; ++i) {
402 	keys[i].keyvalue.length = 0;
403 	keys[i].keyvalue.data   = NULL;
404     }
405 
406     hkeys = malloc (len * sizeof(*hkeys));
407     if (hkeys == NULL) {
408 	free (keys);
409 	return ENOMEM;
410     }
411 
412     _kadm5_init_keys (hkeys, len);
413 
414     ret = krb5_generate_random_keyblock (context->context,
415 					 des_types[0],
416 					 &keys[0]);
417     if (ret)
418 	goto out;
419 
420     ret = krb5_copy_keyblock_contents (context->context,
421 				       &keys[0],
422 				       &hkeys[0].key);
423     if (ret)
424 	goto out;
425 
426     for (i = 1; i < n_des_types; ++i) {
427 	ret = krb5_copy_keyblock_contents (context->context,
428 					   &keys[0],
429 					   &keys[i]);
430 	if (ret)
431 	    goto out;
432 	keys[i].keytype = des_types[i];
433 	ret = krb5_copy_keyblock_contents (context->context,
434 					   &keys[0],
435 					   &hkeys[i].key);
436 	if (ret)
437 	    goto out;
438 	hkeys[i].key.keytype = des_types[i];
439     }
440 
441     ret = krb5_generate_random_keyblock (context->context,
442 					 ETYPE_DES3_CBC_SHA1,
443 					 &keys[n_des_types]);
444     if (ret)
445 	goto out;
446 
447     ret = krb5_copy_keyblock_contents (context->context,
448 				       &keys[n_des_types],
449 				       &hkeys[n_des_types].key);
450     if (ret)
451 	goto out;
452 
453     _kadm5_free_keys (context, ent->keys.len, ent->keys.val);
454     ent->keys.len = len;
455     ent->keys.val = hkeys;
456     ent->kvno++;
457     *new_keys     = keys;
458     *n_keys       = len;
459     return ret;
460 out:
461     for (i = 0; i < len; ++i)
462 	krb5_free_keyblock_contents (context->context, &keys[i]);
463     free (keys);
464     _kadm5_free_keys (context, len, hkeys);
465     return ret;
466 }
467