1/*
2 * Copyright (c) 1997 - 2008 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 "krb5_locl.h"
35
36/* coverity[+alloc : arg-*3] */
37KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
38krb5_salttype_to_string (krb5_context context,
39			 krb5_enctype etype,
40			 krb5_salttype stype,
41			 char **string)
42{
43    struct _krb5_encryption_type *e;
44    struct salt_type *st;
45
46    (void) fbsd_ossl_provider_load();
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    (void) fbsd_ossl_provider_load();
81
82    e = _krb5_find_enctype (etype);
83    if (e == NULL) {
84	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
85			       N_("encryption type %d not supported", ""),
86			       etype);
87	return KRB5_PROG_ETYPE_NOSUPP;
88    }
89    for (st = e->keytype->string_to_key; st && st->type; st++) {
90	if (strcasecmp (st->name, string) == 0) {
91	    *salttype = st->type;
92	    return 0;
93	}
94    }
95    krb5_set_error_message(context, HEIM_ERR_SALTTYPE_NOSUPP,
96			   N_("salttype %s not supported", ""), string);
97    return HEIM_ERR_SALTTYPE_NOSUPP;
98}
99
100KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
101krb5_get_pw_salt(krb5_context context,
102		 krb5_const_principal principal,
103		 krb5_salt *salt)
104{
105    size_t len;
106    size_t i;
107    krb5_error_code ret;
108    char *p;
109
110    salt->salttype = KRB5_PW_SALT;
111    len = strlen(principal->realm);
112    for (i = 0; i < principal->name.name_string.len; ++i)
113	len += strlen(principal->name.name_string.val[i]);
114    ret = krb5_data_alloc (&salt->saltvalue, len);
115    if (ret)
116	return ret;
117    p = salt->saltvalue.data;
118    memcpy (p, principal->realm, strlen(principal->realm));
119    p += strlen(principal->realm);
120    for (i = 0; i < principal->name.name_string.len; ++i) {
121	memcpy (p,
122		principal->name.name_string.val[i],
123		strlen(principal->name.name_string.val[i]));
124	p += strlen(principal->name.name_string.val[i]);
125    }
126    return 0;
127}
128
129KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
130krb5_free_salt(krb5_context context,
131	       krb5_salt salt)
132{
133    krb5_data_free(&salt.saltvalue);
134    return 0;
135}
136
137KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
138krb5_string_to_key_data (krb5_context context,
139			 krb5_enctype enctype,
140			 krb5_data password,
141			 krb5_principal principal,
142			 krb5_keyblock *key)
143{
144    krb5_error_code ret;
145    krb5_salt salt;
146
147    ret = krb5_get_pw_salt(context, principal, &salt);
148    if(ret)
149	return ret;
150    ret = krb5_string_to_key_data_salt(context, enctype, password, salt, key);
151    krb5_free_salt(context, salt);
152    return ret;
153}
154
155KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
156krb5_string_to_key (krb5_context context,
157		    krb5_enctype enctype,
158		    const char *password,
159		    krb5_principal principal,
160		    krb5_keyblock *key)
161{
162    krb5_data pw;
163    pw.data = rk_UNCONST(password);
164    pw.length = strlen(password);
165    return krb5_string_to_key_data(context, enctype, pw, principal, key);
166}
167
168KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
169krb5_string_to_key_data_salt (krb5_context context,
170			      krb5_enctype enctype,
171			      krb5_data password,
172			      krb5_salt salt,
173			      krb5_keyblock *key)
174{
175    krb5_data opaque;
176    krb5_data_zero(&opaque);
177    return krb5_string_to_key_data_salt_opaque(context, enctype, password,
178					       salt, opaque, key);
179}
180
181/*
182 * Do a string -> key for encryption type `enctype' operation on
183 * `password' (with salt `salt' and the enctype specific data string
184 * `opaque'), returning the resulting key in `key'
185 */
186
187KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
188krb5_string_to_key_data_salt_opaque (krb5_context context,
189				     krb5_enctype enctype,
190				     krb5_data password,
191				     krb5_salt salt,
192				     krb5_data opaque,
193				     krb5_keyblock *key)
194{
195    struct _krb5_encryption_type *et =_krb5_find_enctype(enctype);
196    struct salt_type *st;
197    if(et == NULL) {
198	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
199			       N_("encryption type %d not supported", ""),
200			       enctype);
201	return KRB5_PROG_ETYPE_NOSUPP;
202    }
203    (void) fbsd_ossl_provider_load();
204    for(st = et->keytype->string_to_key; st && st->type; st++)
205	if(st->type == salt.salttype)
206	    return (*st->string_to_key)(context, enctype, password,
207					salt, opaque, key);
208    krb5_set_error_message(context, HEIM_ERR_SALTTYPE_NOSUPP,
209			   N_("salt type %d not supported", ""),
210			   salt.salttype);
211    return HEIM_ERR_SALTTYPE_NOSUPP;
212}
213
214/*
215 * Do a string -> key for encryption type `enctype' operation on the
216 * string `password' (with salt `salt'), returning the resulting key
217 * in `key'
218 */
219
220KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
221krb5_string_to_key_salt (krb5_context context,
222			 krb5_enctype enctype,
223			 const char *password,
224			 krb5_salt salt,
225			 krb5_keyblock *key)
226{
227    krb5_data pw;
228    pw.data = rk_UNCONST(password);
229    pw.length = strlen(password);
230    return krb5_string_to_key_data_salt(context, enctype, pw, salt, key);
231}
232
233KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
234krb5_string_to_key_salt_opaque (krb5_context context,
235				krb5_enctype enctype,
236				const char *password,
237				krb5_salt salt,
238				krb5_data opaque,
239				krb5_keyblock *key)
240{
241    krb5_data pw;
242    pw.data = rk_UNCONST(password);
243    pw.length = strlen(password);
244    return krb5_string_to_key_data_salt_opaque(context, enctype,
245					       pw, salt, opaque, key);
246}
247
248
249KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
250krb5_string_to_key_derived(krb5_context context,
251			   const void *str,
252			   size_t len,
253			   krb5_enctype etype,
254			   krb5_keyblock *key)
255{
256    struct _krb5_encryption_type *et = _krb5_find_enctype(etype);
257    krb5_error_code ret;
258    struct _krb5_key_data kd;
259    size_t keylen;
260    u_char *tmp;
261
262    if(et == NULL) {
263	krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
264				N_("encryption type %d not supported", ""),
265				etype);
266	return KRB5_PROG_ETYPE_NOSUPP;
267    }
268    keylen = et->keytype->bits / 8;
269
270    ALLOC(kd.key, 1);
271    if(kd.key == NULL) {
272	krb5_set_error_message (context, ENOMEM,
273				N_("malloc: out of memory", ""));
274	return ENOMEM;
275    }
276    ret = krb5_data_alloc(&kd.key->keyvalue, et->keytype->size);
277    if(ret) {
278	free(kd.key);
279	return ret;
280    }
281    kd.key->keytype = etype;
282    tmp = malloc (keylen);
283    if(tmp == NULL) {
284	krb5_free_keyblock(context, kd.key);
285	krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
286	return ENOMEM;
287    }
288    ret = _krb5_n_fold(str, len, tmp, keylen);
289    if (ret) {
290	free(tmp);
291	krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", ""));
292	return ret;
293    }
294    kd.schedule = NULL;
295    _krb5_DES3_random_to_key(context, kd.key, tmp, keylen);
296    memset(tmp, 0, keylen);
297    free(tmp);
298    ret = _krb5_derive_key(context,
299			   et,
300			   &kd,
301			   "kerberos", /* XXX well known constant */
302			   strlen("kerberos"));
303    if (ret) {
304	_krb5_free_key_data(context, &kd, et);
305	return ret;
306    }
307    ret = krb5_copy_keyblock_contents(context, kd.key, key);
308    _krb5_free_key_data(context, &kd, et);
309    return ret;
310}
311