1/*	$NetBSD: salt.c,v 1.1.1.1 2011/04/13 18:15:37 elric Exp $	*/
2
3/*
4 * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "krb5_locl.h"
37
38/* coverity[+alloc : arg-*3] */
39KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
40krb5_salttype_to_string (krb5_context context,
41			 krb5_enctype etype,
42			 krb5_salttype stype,
43			 char **string)
44{
45    struct _krb5_encryption_type *e;
46    struct salt_type *st;
47
48    e = _krb5_find_enctype (etype);
49    if (e == NULL) {
50	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
51			       "encryption type %d not supported",
52			       etype);
53	return KRB5_PROG_ETYPE_NOSUPP;
54    }
55    for (st = e->keytype->string_to_key; st && st->type; st++) {
56	if (st->type == stype) {
57	    *string = strdup (st->name);
58	    if (*string == NULL) {
59		krb5_set_error_message (context, ENOMEM,
60					N_("malloc: out of memory", ""));
61		return ENOMEM;
62	    }
63	    return 0;
64	}
65    }
66    krb5_set_error_message (context, HEIM_ERR_SALTTYPE_NOSUPP,
67			    "salttype %d not supported", stype);
68    return HEIM_ERR_SALTTYPE_NOSUPP;
69}
70
71KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
72krb5_string_to_salttype (krb5_context context,
73			 krb5_enctype etype,
74			 const char *string,
75			 krb5_salttype *salttype)
76{
77    struct _krb5_encryption_type *e;
78    struct salt_type *st;
79
80    e = _krb5_find_enctype (etype);
81    if (e == NULL) {
82	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
83			       N_("encryption type %d not supported", ""),
84			       etype);
85	return KRB5_PROG_ETYPE_NOSUPP;
86    }
87    for (st = e->keytype->string_to_key; st && st->type; st++) {
88	if (strcasecmp (st->name, string) == 0) {
89	    *salttype = st->type;
90	    return 0;
91	}
92    }
93    krb5_set_error_message(context, HEIM_ERR_SALTTYPE_NOSUPP,
94			   N_("salttype %s not supported", ""), string);
95    return HEIM_ERR_SALTTYPE_NOSUPP;
96}
97
98KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
99krb5_get_pw_salt(krb5_context context,
100		 krb5_const_principal principal,
101		 krb5_salt *salt)
102{
103    size_t len;
104    int i;
105    krb5_error_code ret;
106    char *p;
107
108    salt->salttype = KRB5_PW_SALT;
109    len = strlen(principal->realm);
110    for (i = 0; i < principal->name.name_string.len; ++i)
111	len += strlen(principal->name.name_string.val[i]);
112    ret = krb5_data_alloc (&salt->saltvalue, len);
113    if (ret)
114	return ret;
115    p = salt->saltvalue.data;
116    memcpy (p, principal->realm, strlen(principal->realm));
117    p += strlen(principal->realm);
118    for (i = 0; i < principal->name.name_string.len; ++i) {
119	memcpy (p,
120		principal->name.name_string.val[i],
121		strlen(principal->name.name_string.val[i]));
122	p += strlen(principal->name.name_string.val[i]);
123    }
124    return 0;
125}
126
127KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
128krb5_free_salt(krb5_context context,
129	       krb5_salt salt)
130{
131    krb5_data_free(&salt.saltvalue);
132    return 0;
133}
134
135KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
136krb5_string_to_key_data (krb5_context context,
137			 krb5_enctype enctype,
138			 krb5_data password,
139			 krb5_principal principal,
140			 krb5_keyblock *key)
141{
142    krb5_error_code ret;
143    krb5_salt salt;
144
145    ret = krb5_get_pw_salt(context, principal, &salt);
146    if(ret)
147	return ret;
148    ret = krb5_string_to_key_data_salt(context, enctype, password, salt, key);
149    krb5_free_salt(context, salt);
150    return ret;
151}
152
153KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
154krb5_string_to_key (krb5_context context,
155		    krb5_enctype enctype,
156		    const char *password,
157		    krb5_principal principal,
158		    krb5_keyblock *key)
159{
160    krb5_data pw;
161    pw.data = rk_UNCONST(password);
162    pw.length = strlen(password);
163    return krb5_string_to_key_data(context, enctype, pw, principal, key);
164}
165
166KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
167krb5_string_to_key_data_salt (krb5_context context,
168			      krb5_enctype enctype,
169			      krb5_data password,
170			      krb5_salt salt,
171			      krb5_keyblock *key)
172{
173    krb5_data opaque;
174    krb5_data_zero(&opaque);
175    return krb5_string_to_key_data_salt_opaque(context, enctype, password,
176					       salt, opaque, key);
177}
178
179/*
180 * Do a string -> key for encryption type `enctype' operation on
181 * `password' (with salt `salt' and the enctype specific data string
182 * `opaque'), returning the resulting key in `key'
183 */
184
185KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
186krb5_string_to_key_data_salt_opaque (krb5_context context,
187				     krb5_enctype enctype,
188				     krb5_data password,
189				     krb5_salt salt,
190				     krb5_data opaque,
191				     krb5_keyblock *key)
192{
193    struct _krb5_encryption_type *et =_krb5_find_enctype(enctype);
194    struct salt_type *st;
195    if(et == NULL) {
196	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
197			       N_("encryption type %d not supported", ""),
198			       enctype);
199	return KRB5_PROG_ETYPE_NOSUPP;
200    }
201    for(st = et->keytype->string_to_key; st && st->type; st++)
202	if(st->type == salt.salttype)
203	    return (*st->string_to_key)(context, enctype, password,
204					salt, opaque, key);
205    krb5_set_error_message(context, HEIM_ERR_SALTTYPE_NOSUPP,
206			   N_("salt type %d not supported", ""),
207			   salt.salttype);
208    return HEIM_ERR_SALTTYPE_NOSUPP;
209}
210
211/*
212 * Do a string -> key for encryption type `enctype' operation on the
213 * string `password' (with salt `salt'), returning the resulting key
214 * in `key'
215 */
216
217KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
218krb5_string_to_key_salt (krb5_context context,
219			 krb5_enctype enctype,
220			 const char *password,
221			 krb5_salt salt,
222			 krb5_keyblock *key)
223{
224    krb5_data pw;
225    pw.data = rk_UNCONST(password);
226    pw.length = strlen(password);
227    return krb5_string_to_key_data_salt(context, enctype, pw, salt, key);
228}
229
230KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
231krb5_string_to_key_salt_opaque (krb5_context context,
232				krb5_enctype enctype,
233				const char *password,
234				krb5_salt salt,
235				krb5_data opaque,
236				krb5_keyblock *key)
237{
238    krb5_data pw;
239    pw.data = rk_UNCONST(password);
240    pw.length = strlen(password);
241    return krb5_string_to_key_data_salt_opaque(context, enctype,
242					       pw, salt, opaque, key);
243}
244
245
246KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
247krb5_string_to_key_derived(krb5_context context,
248			   const void *str,
249			   size_t len,
250			   krb5_enctype etype,
251			   krb5_keyblock *key)
252{
253    struct _krb5_encryption_type *et = _krb5_find_enctype(etype);
254    krb5_error_code ret;
255    struct _krb5_key_data kd;
256    size_t keylen;
257    u_char *tmp;
258
259    if(et == NULL) {
260	krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
261				N_("encryption type %d not supported", ""),
262				etype);
263	return KRB5_PROG_ETYPE_NOSUPP;
264    }
265    keylen = et->keytype->bits / 8;
266
267    ALLOC(kd.key, 1);
268    if(kd.key == NULL) {
269	krb5_set_error_message (context, ENOMEM,
270				N_("malloc: out of memory", ""));
271	return ENOMEM;
272    }
273    ret = krb5_data_alloc(&kd.key->keyvalue, et->keytype->size);
274    if(ret) {
275	free(kd.key);
276	return ret;
277    }
278    kd.key->keytype = etype;
279    tmp = malloc (keylen);
280    if(tmp == NULL) {
281	krb5_free_keyblock(context, kd.key);
282	krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
283	return ENOMEM;
284    }
285    ret = _krb5_n_fold(str, len, tmp, keylen);
286    if (ret) {
287	free(tmp);
288	krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
289	return ret;
290    }
291    kd.schedule = NULL;
292    _krb5_DES3_random_to_key(context, kd.key, tmp, keylen);
293    memset(tmp, 0, keylen);
294    free(tmp);
295    ret = _krb5_derive_key(context,
296			   et,
297			   &kd,
298			   "kerberos", /* XXX well known constant */
299			   strlen("kerberos"));
300    if (ret) {
301	_krb5_free_key_data(context, &kd, et);
302	return ret;
303    }
304    ret = krb5_copy_keyblock_contents(context, kd.key, key);
305    _krb5_free_key_data(context, &kd, et);
306    return ret;
307}
308