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
36struct _krb5_key_usage {
37    unsigned usage;
38    struct _krb5_key_data key;
39};
40
41
42#ifndef HEIMDAL_SMALLER
43#define DES3_OLD_ENCTYPE 1
44#endif
45
46static krb5_error_code _get_derived_key(krb5_context, krb5_crypto,
47					unsigned, struct _krb5_key_data**);
48static struct _krb5_key_data *_new_derived_key(krb5_crypto crypto, unsigned usage);
49
50static void free_key_schedule(krb5_context,
51			      struct _krb5_key_data *,
52			      struct _krb5_encryption_type *);
53
54/*
55 * Converts etype to a user readable string and sets as a side effect
56 * the krb5_error_message containing this string. Returns
57 * KRB5_PROG_ETYPE_NOSUPP in not the conversion of the etype failed in
58 * which case the error code of the etype convesion is returned.
59 */
60
61static krb5_error_code
62unsupported_enctype(krb5_context context, krb5_enctype etype)
63{
64    krb5_error_code ret;
65    char *name;
66
67    ret = krb5_enctype_to_string(context, etype, &name);
68    if (ret)
69	return ret;
70
71    krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
72			   N_("Encryption type %s not supported", ""),
73			   name);
74    free(name);
75    return KRB5_PROG_ETYPE_NOSUPP;
76}
77
78/*
79 *
80 */
81
82KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
83krb5_enctype_keysize(krb5_context context,
84		     krb5_enctype type,
85		     size_t *keysize)
86{
87    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
88    if(et == NULL) {
89        return unsupported_enctype (context, type);
90    }
91    *keysize = et->keytype->size;
92    return 0;
93}
94
95KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
96krb5_enctype_keybits(krb5_context context,
97		     krb5_enctype type,
98		     size_t *keybits)
99{
100    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
101    if(et == NULL) {
102        return unsupported_enctype (context, type);
103    }
104    *keybits = et->keytype->bits;
105    return 0;
106}
107
108KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
109krb5_generate_random_keyblock(krb5_context context,
110			      krb5_enctype type,
111			      krb5_keyblock *key)
112{
113    krb5_error_code ret;
114    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
115    if(et == NULL) {
116        return unsupported_enctype (context, type);
117    }
118    ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
119    if(ret)
120	return ret;
121    key->keytype = type;
122    if(et->keytype->random_key)
123	(*et->keytype->random_key)(context, key);
124    else
125	krb5_generate_random_block(key->keyvalue.data,
126				   key->keyvalue.length);
127    return 0;
128}
129
130static krb5_error_code
131_key_schedule(krb5_context context,
132	      struct _krb5_key_data *key)
133{
134    krb5_error_code ret;
135    struct _krb5_encryption_type *et = _krb5_find_enctype(key->key->keytype);
136    struct _krb5_key_type *kt;
137
138    if (et == NULL) {
139        return unsupported_enctype (context,
140                               key->key->keytype);
141    }
142
143    kt = et->keytype;
144
145    if(kt->schedule == NULL)
146	return 0;
147    if (key->schedule != NULL)
148	return 0;
149    ALLOC(key->schedule, 1);
150    if(key->schedule == NULL) {
151	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
152	return ENOMEM;
153    }
154    ret = krb5_data_alloc(key->schedule, kt->schedule_size);
155    if(ret) {
156	free(key->schedule);
157	key->schedule = NULL;
158	return ret;
159    }
160    (*kt->schedule)(context, kt, key);
161    return 0;
162}
163
164/************************************************************
165 *                                                          *
166 ************************************************************/
167
168static krb5_error_code
169SHA1_checksum(krb5_context context,
170	      struct _krb5_key_data *key,
171	      const void *data,
172	      size_t len,
173	      unsigned usage,
174	      Checksum *C)
175{
176    if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_sha1(), NULL) != 1)
177	krb5_abortx(context, "sha1 checksum failed");
178    return 0;
179}
180
181/* HMAC according to RFC2104 */
182krb5_error_code
183_krb5_internal_hmac(krb5_context context,
184		    struct _krb5_checksum_type *cm,
185		    const void *data,
186		    size_t len,
187		    unsigned usage,
188		    struct _krb5_key_data *keyblock,
189		    Checksum *result)
190{
191    unsigned char *ipad, *opad;
192    unsigned char *key;
193    size_t key_len;
194    size_t i;
195
196    ipad = malloc(cm->blocksize + len);
197    if (ipad == NULL)
198	return ENOMEM;
199    opad = malloc(cm->blocksize + cm->checksumsize);
200    if (opad == NULL) {
201	free(ipad);
202	return ENOMEM;
203    }
204    memset(ipad, 0x36, cm->blocksize);
205    memset(opad, 0x5c, cm->blocksize);
206
207    if(keyblock->key->keyvalue.length > cm->blocksize){
208	(*cm->checksum)(context,
209			keyblock,
210			keyblock->key->keyvalue.data,
211			keyblock->key->keyvalue.length,
212			usage,
213			result);
214	key = result->checksum.data;
215	key_len = result->checksum.length;
216    } else {
217	key = keyblock->key->keyvalue.data;
218	key_len = keyblock->key->keyvalue.length;
219    }
220    for(i = 0; i < key_len; i++){
221	ipad[i] ^= key[i];
222	opad[i] ^= key[i];
223    }
224    memcpy(ipad + cm->blocksize, data, len);
225    (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len,
226		    usage, result);
227    memcpy(opad + cm->blocksize, result->checksum.data,
228	   result->checksum.length);
229    (*cm->checksum)(context, keyblock, opad,
230		    cm->blocksize + cm->checksumsize, usage, result);
231    memset(ipad, 0, cm->blocksize + len);
232    free(ipad);
233    memset(opad, 0, cm->blocksize + cm->checksumsize);
234    free(opad);
235
236    return 0;
237}
238
239KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
240krb5_hmac(krb5_context context,
241	  krb5_cksumtype cktype,
242	  const void *data,
243	  size_t len,
244	  unsigned usage,
245	  krb5_keyblock *key,
246	  Checksum *result)
247{
248    struct _krb5_checksum_type *c = _krb5_find_checksum(cktype);
249    struct _krb5_key_data kd;
250    krb5_error_code ret;
251
252    if (c == NULL) {
253	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
254				N_("checksum type %d not supported", ""),
255				cktype);
256	return KRB5_PROG_SUMTYPE_NOSUPP;
257    }
258
259    kd.key = key;
260    kd.schedule = NULL;
261
262    ret = _krb5_internal_hmac(context, c, data, len, usage, &kd, result);
263
264    if (kd.schedule)
265	krb5_free_data(context, kd.schedule);
266
267    return ret;
268}
269
270krb5_error_code
271_krb5_SP_HMAC_SHA1_checksum(krb5_context context,
272			    struct _krb5_key_data *key,
273			    const void *data,
274			    size_t len,
275			    unsigned usage,
276			    Checksum *result)
277{
278    struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1);
279    Checksum res;
280    char sha1_data[20];
281    krb5_error_code ret;
282
283    res.checksum.data = sha1_data;
284    res.checksum.length = sizeof(sha1_data);
285
286    ret = _krb5_internal_hmac(context, c, data, len, usage, key, &res);
287    if (ret)
288	krb5_abortx(context, "hmac failed");
289    memcpy(result->checksum.data, res.checksum.data, result->checksum.length);
290    return 0;
291}
292
293struct _krb5_checksum_type _krb5_checksum_sha1 = {
294    CKSUMTYPE_SHA1,
295    "sha1",
296    64,
297    20,
298    F_CPROOF,
299    SHA1_checksum,
300    NULL
301};
302
303struct _krb5_checksum_type *
304_krb5_find_checksum(krb5_cksumtype type)
305{
306    int i;
307    for(i = 0; i < _krb5_num_checksums; i++)
308	if(_krb5_checksum_types[i]->type == type)
309	    return _krb5_checksum_types[i];
310    return NULL;
311}
312
313static krb5_error_code
314get_checksum_key(krb5_context context,
315		 krb5_crypto crypto,
316		 unsigned usage,  /* not krb5_key_usage */
317		 struct _krb5_checksum_type *ct,
318		 struct _krb5_key_data **key)
319{
320    krb5_error_code ret = 0;
321
322    if(ct->flags & F_DERIVED)
323	ret = _get_derived_key(context, crypto, usage, key);
324    else if(ct->flags & F_VARIANT) {
325	size_t i;
326
327	*key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */);
328	if(*key == NULL) {
329	    krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
330	    return ENOMEM;
331	}
332	ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key);
333	if(ret)
334	    return ret;
335	for(i = 0; i < (*key)->key->keyvalue.length; i++)
336	    ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0;
337    } else {
338	*key = &crypto->key;
339    }
340    if(ret == 0)
341	ret = _key_schedule(context, *key);
342    return ret;
343}
344
345static krb5_error_code
346create_checksum (krb5_context context,
347		 struct _krb5_checksum_type *ct,
348		 krb5_crypto crypto,
349		 unsigned usage,
350		 void *data,
351		 size_t len,
352		 Checksum *result)
353{
354    krb5_error_code ret;
355    struct _krb5_key_data *dkey;
356    int keyed_checksum;
357
358    if (ct->flags & F_DISABLED) {
359	krb5_clear_error_message (context);
360	return KRB5_PROG_SUMTYPE_NOSUPP;
361    }
362    keyed_checksum = (ct->flags & F_KEYED) != 0;
363    if(keyed_checksum && crypto == NULL) {
364	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
365				N_("Checksum type %s is keyed but no "
366				   "crypto context (key) was passed in", ""),
367				ct->name);
368	return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
369    }
370    if(keyed_checksum) {
371	ret = get_checksum_key(context, crypto, usage, ct, &dkey);
372	if (ret)
373	    return ret;
374    } else
375	dkey = NULL;
376    result->cksumtype = ct->type;
377    ret = krb5_data_alloc(&result->checksum, ct->checksumsize);
378    if (ret)
379	return (ret);
380    return (*ct->checksum)(context, dkey, data, len, usage, result);
381}
382
383static int
384arcfour_checksum_p(struct _krb5_checksum_type *ct, krb5_crypto crypto)
385{
386    return (ct->type == CKSUMTYPE_HMAC_MD5) &&
387	(crypto->key.key->keytype == KEYTYPE_ARCFOUR);
388}
389
390KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
391krb5_create_checksum(krb5_context context,
392		     krb5_crypto crypto,
393		     krb5_key_usage usage,
394		     int type,
395		     void *data,
396		     size_t len,
397		     Checksum *result)
398{
399    struct _krb5_checksum_type *ct = NULL;
400    unsigned keyusage;
401
402    /* type 0 -> pick from crypto */
403    if (type) {
404	ct = _krb5_find_checksum(type);
405    } else if (crypto) {
406	ct = crypto->et->keyed_checksum;
407	if (ct == NULL)
408	    ct = crypto->et->checksum;
409    }
410
411    if(ct == NULL) {
412	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
413				N_("checksum type %d not supported", ""),
414				type);
415	return KRB5_PROG_SUMTYPE_NOSUPP;
416    }
417
418    if (arcfour_checksum_p(ct, crypto)) {
419	keyusage = usage;
420	_krb5_usage2arcfour(context, &keyusage);
421    } else
422	keyusage = CHECKSUM_USAGE(usage);
423
424    return create_checksum(context, ct, crypto, keyusage,
425			   data, len, result);
426}
427
428static krb5_error_code
429verify_checksum(krb5_context context,
430		krb5_crypto crypto,
431		unsigned usage, /* not krb5_key_usage */
432		void *data,
433		size_t len,
434		Checksum *cksum)
435{
436    krb5_error_code ret;
437    struct _krb5_key_data *dkey;
438    int keyed_checksum;
439    Checksum c;
440    struct _krb5_checksum_type *ct;
441
442    ct = _krb5_find_checksum(cksum->cksumtype);
443    if (ct == NULL || (ct->flags & F_DISABLED)) {
444	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
445				N_("checksum type %d not supported", ""),
446				cksum->cksumtype);
447	return KRB5_PROG_SUMTYPE_NOSUPP;
448    }
449    if(ct->checksumsize != cksum->checksum.length) {
450	krb5_clear_error_message (context);
451	krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY,
452			       N_("Decrypt integrity check failed for checksum type %s, "
453				  "length was %u, expected %u", ""),
454			       ct->name, (unsigned)cksum->checksum.length,
455			       (unsigned)ct->checksumsize);
456
457	return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
458    }
459    keyed_checksum = (ct->flags & F_KEYED) != 0;
460    if(keyed_checksum) {
461	struct _krb5_checksum_type *kct;
462	if (crypto == NULL) {
463	    krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
464				   N_("Checksum type %s is keyed but no "
465				      "crypto context (key) was passed in", ""),
466				   ct->name);
467	    return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
468	}
469	kct = crypto->et->keyed_checksum;
470	if (kct == NULL || kct->type != ct->type) {
471	    krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP,
472				   N_("Checksum type %s is keyed, but "
473				      "the key type %s passed didnt have that checksum "
474				      "type as the keyed type", ""),
475				    ct->name, crypto->et->name);
476	    return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
477	}
478
479	ret = get_checksum_key(context, crypto, usage, ct, &dkey);
480	if (ret)
481	    return ret;
482    } else
483	dkey = NULL;
484
485    /*
486     * If checksum have a verify function, lets use that instead of
487     * calling ->checksum and then compare result.
488     */
489
490    if(ct->verify) {
491	ret = (*ct->verify)(context, dkey, data, len, usage, cksum);
492	if (ret)
493	    krb5_set_error_message(context, ret,
494				   N_("Decrypt integrity check failed for checksum "
495				      "type %s, key type %s", ""),
496				   ct->name, (crypto != NULL)? crypto->et->name : "(none)");
497	return ret;
498    }
499
500    ret = krb5_data_alloc (&c.checksum, ct->checksumsize);
501    if (ret)
502	return ret;
503
504    ret = (*ct->checksum)(context, dkey, data, len, usage, &c);
505    if (ret) {
506	krb5_data_free(&c.checksum);
507	return ret;
508    }
509
510    if(krb5_data_ct_cmp(&c.checksum, &cksum->checksum) != 0) {
511	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
512	krb5_set_error_message(context, ret,
513			       N_("Decrypt integrity check failed for checksum "
514				  "type %s, key type %s", ""),
515			       ct->name, crypto ? crypto->et->name : "(unkeyed)");
516    } else {
517	ret = 0;
518    }
519    krb5_data_free (&c.checksum);
520    return ret;
521}
522
523KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
524krb5_verify_checksum(krb5_context context,
525		     krb5_crypto crypto,
526		     krb5_key_usage usage,
527		     void *data,
528		     size_t len,
529		     Checksum *cksum)
530{
531    struct _krb5_checksum_type *ct;
532    unsigned keyusage;
533
534    ct = _krb5_find_checksum(cksum->cksumtype);
535    if(ct == NULL) {
536	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
537				N_("checksum type %d not supported", ""),
538				cksum->cksumtype);
539	return KRB5_PROG_SUMTYPE_NOSUPP;
540    }
541
542    if (arcfour_checksum_p(ct, crypto)) {
543	keyusage = usage;
544	_krb5_usage2arcfour(context, &keyusage);
545    } else
546	keyusage = CHECKSUM_USAGE(usage);
547
548    return verify_checksum(context, crypto, keyusage,
549			   data, len, cksum);
550}
551
552KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
553krb5_crypto_get_checksum_type(krb5_context context,
554                              krb5_crypto crypto,
555			      krb5_cksumtype *type)
556{
557    struct _krb5_checksum_type *ct = NULL;
558
559    if (crypto != NULL) {
560        ct = crypto->et->keyed_checksum;
561        if (ct == NULL)
562            ct = crypto->et->checksum;
563    }
564
565    if (ct == NULL) {
566	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
567				N_("checksum type not found", ""));
568        return KRB5_PROG_SUMTYPE_NOSUPP;
569    }
570
571    *type = ct->type;
572
573    return 0;
574}
575
576
577KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
578krb5_checksumsize(krb5_context context,
579		  krb5_cksumtype type,
580		  size_t *size)
581{
582    struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
583    if(ct == NULL) {
584	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
585				N_("checksum type %d not supported", ""),
586				type);
587	return KRB5_PROG_SUMTYPE_NOSUPP;
588    }
589    *size = ct->checksumsize;
590    return 0;
591}
592
593KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
594krb5_checksum_is_keyed(krb5_context context,
595		       krb5_cksumtype type)
596{
597    struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
598    if(ct == NULL) {
599	if (context)
600	    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
601				    N_("checksum type %d not supported", ""),
602				    type);
603	return KRB5_PROG_SUMTYPE_NOSUPP;
604    }
605    return ct->flags & F_KEYED;
606}
607
608KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
609krb5_checksum_is_collision_proof(krb5_context context,
610				 krb5_cksumtype type)
611{
612    struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
613    if(ct == NULL) {
614	if (context)
615	    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
616				    N_("checksum type %d not supported", ""),
617				    type);
618	return KRB5_PROG_SUMTYPE_NOSUPP;
619    }
620    return ct->flags & F_CPROOF;
621}
622
623KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
624krb5_checksum_disable(krb5_context context,
625		      krb5_cksumtype type)
626{
627    struct _krb5_checksum_type *ct = _krb5_find_checksum(type);
628    if(ct == NULL) {
629	if (context)
630	    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
631				    N_("checksum type %d not supported", ""),
632				    type);
633	return KRB5_PROG_SUMTYPE_NOSUPP;
634    }
635    ct->flags |= F_DISABLED;
636    return 0;
637}
638
639/************************************************************
640 *                                                          *
641 ************************************************************/
642
643struct _krb5_encryption_type *
644_krb5_find_enctype(krb5_enctype type)
645{
646    int i;
647    for(i = 0; i < _krb5_num_etypes; i++)
648	if(_krb5_etypes[i]->type == type)
649	    return _krb5_etypes[i];
650    return NULL;
651}
652
653
654KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
655krb5_enctype_to_string(krb5_context context,
656		       krb5_enctype etype,
657		       char **string)
658{
659    struct _krb5_encryption_type *e;
660    e = _krb5_find_enctype(etype);
661    if(e == NULL) {
662	krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
663				N_("encryption type %d not supported", ""),
664				etype);
665	*string = NULL;
666	return KRB5_PROG_ETYPE_NOSUPP;
667    }
668    *string = strdup(e->name);
669    if(*string == NULL) {
670	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
671	return ENOMEM;
672    }
673    return 0;
674}
675
676KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
677krb5_string_to_enctype(krb5_context context,
678		       const char *string,
679		       krb5_enctype *etype)
680{
681    int i;
682    for(i = 0; i < _krb5_num_etypes; i++)
683	if(strcasecmp(_krb5_etypes[i]->name, string) == 0){
684	    *etype = _krb5_etypes[i]->type;
685	    return 0;
686	}
687    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
688			    N_("encryption type %s not supported", ""),
689			    string);
690    return KRB5_PROG_ETYPE_NOSUPP;
691}
692
693KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
694krb5_enctype_to_keytype(krb5_context context,
695			krb5_enctype etype,
696			krb5_keytype *keytype)
697{
698    struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
699    if(e == NULL) {
700        return unsupported_enctype (context, etype);
701    }
702    *keytype = e->keytype->type; /* XXX */
703    return 0;
704}
705
706/**
707 * Check if a enctype is valid, return 0 if it is.
708 *
709 * @param context Kerberos context
710 * @param etype enctype to check if its valid or not
711 *
712 * @return Return an error code for an failure or 0 on success (enctype valid).
713 * @ingroup krb5_crypto
714 */
715
716KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
717krb5_enctype_valid(krb5_context context,
718		   krb5_enctype etype)
719{
720    struct _krb5_encryption_type *e = _krb5_find_enctype(etype);
721    if(e && (e->flags & F_DISABLED) == 0)
722	return 0;
723    if (context == NULL)
724	return KRB5_PROG_ETYPE_NOSUPP;
725    if(e == NULL) {
726        return unsupported_enctype (context, etype);
727    }
728    /* Must be (e->flags & F_DISABLED) */
729    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
730			    N_("encryption type %s is disabled", ""),
731			    e->name);
732    return KRB5_PROG_ETYPE_NOSUPP;
733}
734
735/**
736 * Return the coresponding encryption type for a checksum type.
737 *
738 * @param context Kerberos context
739 * @param ctype The checksum type to get the result enctype for
740 * @param etype The returned encryption, when the matching etype is
741 * not found, etype is set to ETYPE_NULL.
742 *
743 * @return Return an error code for an failure or 0 on success.
744 * @ingroup krb5_crypto
745 */
746
747
748KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
749krb5_cksumtype_to_enctype(krb5_context context,
750			  krb5_cksumtype ctype,
751			  krb5_enctype *etype)
752{
753    int i;
754
755    *etype = ETYPE_NULL;
756
757    for(i = 0; i < _krb5_num_etypes; i++) {
758	if(_krb5_etypes[i]->keyed_checksum &&
759	   _krb5_etypes[i]->keyed_checksum->type == ctype)
760	    {
761		*etype = _krb5_etypes[i]->type;
762		return 0;
763	    }
764    }
765
766    krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
767			    N_("checksum type %d not supported", ""),
768			    (int)ctype);
769    return KRB5_PROG_SUMTYPE_NOSUPP;
770}
771
772
773KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
774krb5_cksumtype_valid(krb5_context context,
775		     krb5_cksumtype ctype)
776{
777    struct _krb5_checksum_type *c = _krb5_find_checksum(ctype);
778    if (c == NULL) {
779	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
780				N_("checksum type %d not supported", ""),
781				ctype);
782	return KRB5_PROG_SUMTYPE_NOSUPP;
783    }
784    if (c->flags & F_DISABLED) {
785	krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP,
786				N_("checksum type %s is disabled", ""),
787				c->name);
788	return KRB5_PROG_SUMTYPE_NOSUPP;
789    }
790    return 0;
791}
792
793
794static krb5_boolean
795derived_crypto(krb5_context context,
796	       krb5_crypto crypto)
797{
798    return (crypto->et->flags & F_DERIVED) != 0;
799}
800
801static krb5_boolean
802special_crypto(krb5_context context,
803	       krb5_crypto crypto)
804{
805    return (crypto->et->flags & F_SPECIAL) != 0;
806}
807
808#define CHECKSUMSIZE(C) ((C)->checksumsize)
809#define CHECKSUMTYPE(C) ((C)->type)
810
811static krb5_error_code
812encrypt_internal_derived(krb5_context context,
813			 krb5_crypto crypto,
814			 unsigned usage,
815			 const void *data,
816			 size_t len,
817			 krb5_data *result,
818			 void *ivec)
819{
820    size_t sz, block_sz, checksum_sz, total_sz;
821    Checksum cksum;
822    unsigned char *p, *q;
823    krb5_error_code ret;
824    struct _krb5_key_data *dkey;
825    const struct _krb5_encryption_type *et = crypto->et;
826
827    checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
828
829    sz = et->confoundersize + len;
830    block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
831    total_sz = block_sz + checksum_sz;
832    p = calloc(1, total_sz);
833    if(p == NULL) {
834	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
835	return ENOMEM;
836    }
837
838    q = p;
839    krb5_generate_random_block(q, et->confoundersize); /* XXX */
840    q += et->confoundersize;
841    memcpy(q, data, len);
842
843    ret = create_checksum(context,
844			  et->keyed_checksum,
845			  crypto,
846			  INTEGRITY_USAGE(usage),
847			  p,
848			  block_sz,
849			  &cksum);
850    if(ret == 0 && cksum.checksum.length != checksum_sz) {
851	free_Checksum (&cksum);
852	krb5_clear_error_message (context);
853	ret = KRB5_CRYPTO_INTERNAL;
854    }
855    if(ret)
856	goto fail;
857    memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
858    free_Checksum (&cksum);
859    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
860    if(ret)
861	goto fail;
862    ret = _key_schedule(context, dkey);
863    if(ret)
864	goto fail;
865    ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
866    if (ret)
867	goto fail;
868    result->data = p;
869    result->length = total_sz;
870    return 0;
871 fail:
872    memset(p, 0, total_sz);
873    free(p);
874    return ret;
875}
876
877
878static krb5_error_code
879encrypt_internal(krb5_context context,
880		 krb5_crypto crypto,
881		 const void *data,
882		 size_t len,
883		 krb5_data *result,
884		 void *ivec)
885{
886    size_t sz, block_sz, checksum_sz;
887    Checksum cksum;
888    unsigned char *p, *q;
889    krb5_error_code ret;
890    const struct _krb5_encryption_type *et = crypto->et;
891
892    checksum_sz = CHECKSUMSIZE(et->checksum);
893
894    sz = et->confoundersize + checksum_sz + len;
895    block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
896    p = calloc(1, block_sz);
897    if(p == NULL) {
898	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
899	return ENOMEM;
900    }
901
902    q = p;
903    krb5_generate_random_block(q, et->confoundersize); /* XXX */
904    q += et->confoundersize;
905    memset(q, 0, checksum_sz);
906    q += checksum_sz;
907    memcpy(q, data, len);
908
909    ret = create_checksum(context,
910			  et->checksum,
911			  crypto,
912			  0,
913			  p,
914			  block_sz,
915			  &cksum);
916    if(ret == 0 && cksum.checksum.length != checksum_sz) {
917	krb5_clear_error_message (context);
918	free_Checksum(&cksum);
919	ret = KRB5_CRYPTO_INTERNAL;
920    }
921    if(ret)
922	goto fail;
923    memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length);
924    free_Checksum(&cksum);
925    ret = _key_schedule(context, &crypto->key);
926    if(ret)
927	goto fail;
928    ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec);
929    if (ret) {
930	memset(p, 0, block_sz);
931	free(p);
932	return ret;
933    }
934    result->data = p;
935    result->length = block_sz;
936    return 0;
937 fail:
938    memset(p, 0, block_sz);
939    free(p);
940    return ret;
941}
942
943static krb5_error_code
944encrypt_internal_special(krb5_context context,
945			 krb5_crypto crypto,
946			 int usage,
947			 const void *data,
948			 size_t len,
949			 krb5_data *result,
950			 void *ivec)
951{
952    struct _krb5_encryption_type *et = crypto->et;
953    size_t cksum_sz = CHECKSUMSIZE(et->checksum);
954    size_t sz = len + cksum_sz + et->confoundersize;
955    char *tmp, *p;
956    krb5_error_code ret;
957
958    tmp = malloc (sz);
959    if (tmp == NULL) {
960	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
961	return ENOMEM;
962    }
963    p = tmp;
964    memset (p, 0, cksum_sz);
965    p += cksum_sz;
966    krb5_generate_random_block(p, et->confoundersize);
967    p += et->confoundersize;
968    memcpy (p, data, len);
969    ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec);
970    if (ret) {
971	memset(tmp, 0, sz);
972	free(tmp);
973	return ret;
974    }
975    result->data   = tmp;
976    result->length = sz;
977    return 0;
978}
979
980static krb5_error_code
981decrypt_internal_derived(krb5_context context,
982			 krb5_crypto crypto,
983			 unsigned usage,
984			 void *data,
985			 size_t len,
986			 krb5_data *result,
987			 void *ivec)
988{
989    size_t checksum_sz;
990    Checksum cksum;
991    unsigned char *p;
992    krb5_error_code ret;
993    struct _krb5_key_data *dkey;
994    struct _krb5_encryption_type *et = crypto->et;
995    unsigned long l;
996
997    checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
998    if (len < checksum_sz + et->confoundersize) {
999	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1000			       N_("Encrypted data shorter then "
1001				  "checksum + confunder", ""));
1002	return KRB5_BAD_MSIZE;
1003    }
1004
1005    if (((len - checksum_sz) % et->padsize) != 0) {
1006	krb5_clear_error_message(context);
1007	return KRB5_BAD_MSIZE;
1008    }
1009
1010    p = malloc(len);
1011    if(len != 0 && p == NULL) {
1012	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1013	return ENOMEM;
1014    }
1015    memcpy(p, data, len);
1016
1017    len -= checksum_sz;
1018
1019    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1020    if(ret) {
1021	free(p);
1022	return ret;
1023    }
1024    ret = _key_schedule(context, dkey);
1025    if(ret) {
1026	free(p);
1027	return ret;
1028    }
1029    ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
1030    if (ret) {
1031	free(p);
1032	return ret;
1033    }
1034
1035    cksum.checksum.data   = p + len;
1036    cksum.checksum.length = checksum_sz;
1037    cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
1038
1039    ret = verify_checksum(context,
1040			  crypto,
1041			  INTEGRITY_USAGE(usage),
1042			  p,
1043			  len,
1044			  &cksum);
1045    if(ret) {
1046	free(p);
1047	return ret;
1048    }
1049    l = len - et->confoundersize;
1050    memmove(p, p + et->confoundersize, l);
1051    result->data = realloc(p, l);
1052    if(result->data == NULL && l != 0) {
1053	free(p);
1054	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1055	return ENOMEM;
1056    }
1057    result->length = l;
1058    return 0;
1059}
1060
1061static krb5_error_code
1062decrypt_internal(krb5_context context,
1063		 krb5_crypto crypto,
1064		 void *data,
1065		 size_t len,
1066		 krb5_data *result,
1067		 void *ivec)
1068{
1069    krb5_error_code ret;
1070    unsigned char *p;
1071    Checksum cksum;
1072    size_t checksum_sz, l;
1073    struct _krb5_encryption_type *et = crypto->et;
1074
1075    if ((len % et->padsize) != 0) {
1076	krb5_clear_error_message(context);
1077	return KRB5_BAD_MSIZE;
1078    }
1079    checksum_sz = CHECKSUMSIZE(et->checksum);
1080    if (len < checksum_sz + et->confoundersize) {
1081	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1082			       N_("Encrypted data shorter then "
1083				  "checksum + confunder", ""));
1084	return KRB5_BAD_MSIZE;
1085    }
1086
1087    p = malloc(len);
1088    if(len != 0 && p == NULL) {
1089	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1090	return ENOMEM;
1091    }
1092    memcpy(p, data, len);
1093
1094    ret = _key_schedule(context, &crypto->key);
1095    if(ret) {
1096	free(p);
1097	return ret;
1098    }
1099    ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec);
1100    if (ret) {
1101	free(p);
1102	return ret;
1103    }
1104    ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
1105    if(ret) {
1106 	free(p);
1107 	return ret;
1108    }
1109    memset(p + et->confoundersize, 0, checksum_sz);
1110    cksum.cksumtype = CHECKSUMTYPE(et->checksum);
1111    ret = verify_checksum(context, NULL, 0, p, len, &cksum);
1112    free_Checksum(&cksum);
1113    if(ret) {
1114	free(p);
1115	return ret;
1116    }
1117    l = len - et->confoundersize - checksum_sz;
1118    memmove(p, p + et->confoundersize + checksum_sz, l);
1119    result->data = realloc(p, l);
1120    if(result->data == NULL && l != 0) {
1121	free(p);
1122	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1123	return ENOMEM;
1124    }
1125    result->length = l;
1126    return 0;
1127}
1128
1129static krb5_error_code
1130decrypt_internal_special(krb5_context context,
1131			 krb5_crypto crypto,
1132			 int usage,
1133			 void *data,
1134			 size_t len,
1135			 krb5_data *result,
1136			 void *ivec)
1137{
1138    struct _krb5_encryption_type *et = crypto->et;
1139    size_t cksum_sz = CHECKSUMSIZE(et->checksum);
1140    size_t sz = len - cksum_sz - et->confoundersize;
1141    unsigned char *p;
1142    krb5_error_code ret;
1143
1144    if ((len % et->padsize) != 0) {
1145	krb5_clear_error_message(context);
1146	return KRB5_BAD_MSIZE;
1147    }
1148    if (len < cksum_sz + et->confoundersize) {
1149	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1150			       N_("Encrypted data shorter then "
1151				  "checksum + confunder", ""));
1152	return KRB5_BAD_MSIZE;
1153    }
1154
1155    p = malloc (len);
1156    if (p == NULL) {
1157	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1158	return ENOMEM;
1159    }
1160    memcpy(p, data, len);
1161
1162    ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec);
1163    if (ret) {
1164	free(p);
1165	return ret;
1166    }
1167
1168    memmove (p, p + cksum_sz + et->confoundersize, sz);
1169    result->data = realloc(p, sz);
1170    if(result->data == NULL && sz != 0) {
1171	free(p);
1172	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1173	return ENOMEM;
1174    }
1175    result->length = sz;
1176    return 0;
1177}
1178
1179static krb5_crypto_iov *
1180find_iv(krb5_crypto_iov *data, size_t num_data, unsigned type)
1181{
1182    size_t i;
1183    for (i = 0; i < num_data; i++)
1184	if (data[i].flags == type)
1185	    return &data[i];
1186    return NULL;
1187}
1188
1189/**
1190 * Inline encrypt a kerberos message
1191 *
1192 * @param context Kerberos context
1193 * @param crypto Kerberos crypto context
1194 * @param usage Key usage for this buffer
1195 * @param data array of buffers to process
1196 * @param num_data length of array
1197 * @param ivec initial cbc/cts vector
1198 *
1199 * @return Return an error code or 0.
1200 * @ingroup krb5_crypto
1201 *
1202 * Kerberos encrypted data look like this:
1203 *
1204 * 1. KRB5_CRYPTO_TYPE_HEADER
1205 * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...]
1206 *    KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver
1207 *    have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is
1208 *    commonly used headers and trailers.
1209 * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1
1210 * 4. KRB5_CRYPTO_TYPE_TRAILER
1211 */
1212
1213KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1214krb5_encrypt_iov_ivec(krb5_context context,
1215		      krb5_crypto crypto,
1216		      unsigned usage,
1217		      krb5_crypto_iov *data,
1218		      int num_data,
1219		      void *ivec)
1220{
1221    size_t headersz, trailersz, len;
1222    int i;
1223    size_t sz, block_sz, pad_sz;
1224    Checksum cksum;
1225    unsigned char *p, *q;
1226    krb5_error_code ret;
1227    struct _krb5_key_data *dkey;
1228    const struct _krb5_encryption_type *et = crypto->et;
1229    krb5_crypto_iov *tiv, *piv, *hiv;
1230
1231    if (num_data < 0) {
1232        krb5_clear_error_message(context);
1233	return KRB5_CRYPTO_INTERNAL;
1234    }
1235
1236    if(!derived_crypto(context, crypto)) {
1237	krb5_clear_error_message(context);
1238	return KRB5_CRYPTO_INTERNAL;
1239    }
1240
1241    headersz = et->confoundersize;
1242    trailersz = CHECKSUMSIZE(et->keyed_checksum);
1243
1244    for (len = 0, i = 0; i < num_data; i++) {
1245	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1246	    continue;
1247	len += data[i].data.length;
1248    }
1249
1250    sz = headersz + len;
1251    block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */
1252
1253    pad_sz = block_sz - sz;
1254
1255    /* header */
1256
1257    hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1258    if (hiv == NULL || hiv->data.length != headersz)
1259	return KRB5_BAD_MSIZE;
1260
1261    krb5_generate_random_block(hiv->data.data, hiv->data.length);
1262
1263    /* padding */
1264    piv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
1265    /* its ok to have no TYPE_PADDING if there is no padding */
1266    if (piv == NULL && pad_sz != 0)
1267	return KRB5_BAD_MSIZE;
1268    if (piv) {
1269	if (piv->data.length < pad_sz)
1270	    return KRB5_BAD_MSIZE;
1271	piv->data.length = pad_sz;
1272	if (pad_sz)
1273	    memset(piv->data.data, pad_sz, pad_sz);
1274	else
1275	    piv = NULL;
1276    }
1277
1278    /* trailer */
1279    tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1280    if (tiv == NULL || tiv->data.length != trailersz)
1281	return KRB5_BAD_MSIZE;
1282
1283    /*
1284     * XXX replace with EVP_Sign? at least make create_checksum an iov
1285     * function.
1286     * XXX CTS EVP is broken, can't handle multi buffers :(
1287     */
1288
1289    len = block_sz;
1290    for (i = 0; i < num_data; i++) {
1291	if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1292	    continue;
1293	len += data[i].data.length;
1294    }
1295
1296    p = q = malloc(len);
1297
1298    memcpy(q, hiv->data.data, hiv->data.length);
1299    q += hiv->data.length;
1300    for (i = 0; i < num_data; i++) {
1301	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1302	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1303	    continue;
1304	memcpy(q, data[i].data.data, data[i].data.length);
1305	q += data[i].data.length;
1306    }
1307    if (piv)
1308	memset(q, 0, piv->data.length);
1309
1310    ret = create_checksum(context,
1311			  et->keyed_checksum,
1312			  crypto,
1313			  INTEGRITY_USAGE(usage),
1314			  p,
1315			  len,
1316			  &cksum);
1317    free(p);
1318    if(ret == 0 && cksum.checksum.length != trailersz) {
1319	free_Checksum (&cksum);
1320	krb5_clear_error_message (context);
1321	ret = KRB5_CRYPTO_INTERNAL;
1322    }
1323    if(ret)
1324	return ret;
1325
1326    /* save cksum at end */
1327    memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length);
1328    free_Checksum (&cksum);
1329
1330    /* XXX replace with EVP_Cipher */
1331    p = q = malloc(block_sz);
1332    if(p == NULL)
1333	return ENOMEM;
1334
1335    memcpy(q, hiv->data.data, hiv->data.length);
1336    q += hiv->data.length;
1337
1338    for (i = 0; i < num_data; i++) {
1339	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1340	    continue;
1341	memcpy(q, data[i].data.data, data[i].data.length);
1342	q += data[i].data.length;
1343    }
1344    if (piv)
1345	memset(q, 0, piv->data.length);
1346
1347
1348    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1349    if(ret) {
1350	free(p);
1351	return ret;
1352    }
1353    ret = _key_schedule(context, dkey);
1354    if(ret) {
1355	free(p);
1356	return ret;
1357    }
1358
1359    ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec);
1360    if (ret) {
1361	free(p);
1362	return ret;
1363    }
1364
1365    /* now copy data back to buffers */
1366    q = p;
1367
1368    memcpy(hiv->data.data, q, hiv->data.length);
1369    q += hiv->data.length;
1370
1371    for (i = 0; i < num_data; i++) {
1372	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1373	    continue;
1374	memcpy(data[i].data.data, q, data[i].data.length);
1375	q += data[i].data.length;
1376    }
1377    if (piv)
1378	memcpy(piv->data.data, q, pad_sz);
1379
1380    free(p);
1381
1382    return ret;
1383}
1384
1385/**
1386 * Inline decrypt a Kerberos message.
1387 *
1388 * @param context Kerberos context
1389 * @param crypto Kerberos crypto context
1390 * @param usage Key usage for this buffer
1391 * @param data array of buffers to process
1392 * @param num_data length of array
1393 * @param ivec initial cbc/cts vector
1394 *
1395 * @return Return an error code or 0.
1396 * @ingroup krb5_crypto
1397 *
1398 * 1. KRB5_CRYPTO_TYPE_HEADER
1399 * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in
1400 *  any order, however the receiver have to aware of the
1401 *  order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted
1402 *  protocol headers and trailers. The output data will be of same
1403 *  size as the input data or shorter.
1404 */
1405
1406KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1407krb5_decrypt_iov_ivec(krb5_context context,
1408		      krb5_crypto crypto,
1409		      unsigned usage,
1410		      krb5_crypto_iov *data,
1411		      unsigned int num_data,
1412		      void *ivec)
1413{
1414    unsigned int i;
1415    size_t headersz, trailersz, len;
1416    Checksum cksum;
1417    unsigned char *p, *q;
1418    krb5_error_code ret;
1419    struct _krb5_key_data *dkey;
1420    struct _krb5_encryption_type *et = crypto->et;
1421    krb5_crypto_iov *tiv, *hiv;
1422
1423    if(!derived_crypto(context, crypto)) {
1424	krb5_clear_error_message(context);
1425	return KRB5_CRYPTO_INTERNAL;
1426    }
1427
1428    headersz = et->confoundersize;
1429
1430    hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
1431    if (hiv == NULL || hiv->data.length != headersz)
1432	return KRB5_BAD_MSIZE;
1433
1434    /* trailer */
1435    trailersz = CHECKSUMSIZE(et->keyed_checksum);
1436
1437    tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
1438    if (tiv->data.length != trailersz)
1439	return KRB5_BAD_MSIZE;
1440
1441    /* Find length of data we will decrypt */
1442
1443    len = headersz;
1444    for (i = 0; i < num_data; i++) {
1445	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1446	    continue;
1447	len += data[i].data.length;
1448    }
1449
1450    if ((len % et->padsize) != 0) {
1451	krb5_clear_error_message(context);
1452	return KRB5_BAD_MSIZE;
1453    }
1454
1455    /* XXX replace with EVP_Cipher */
1456
1457    p = q = malloc(len);
1458    if (p == NULL)
1459	return ENOMEM;
1460
1461    memcpy(q, hiv->data.data, hiv->data.length);
1462    q += hiv->data.length;
1463
1464    for (i = 0; i < num_data; i++) {
1465	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1466	    continue;
1467	memcpy(q, data[i].data.data, data[i].data.length);
1468	q += data[i].data.length;
1469    }
1470
1471    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
1472    if(ret) {
1473	free(p);
1474	return ret;
1475    }
1476    ret = _key_schedule(context, dkey);
1477    if(ret) {
1478	free(p);
1479	return ret;
1480    }
1481
1482    ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec);
1483    if (ret) {
1484	free(p);
1485	return ret;
1486    }
1487
1488    /* copy data back to buffers */
1489    memcpy(hiv->data.data, p, hiv->data.length);
1490    q = p + hiv->data.length;
1491    for (i = 0; i < num_data; i++) {
1492	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA)
1493	    continue;
1494	memcpy(data[i].data.data, q, data[i].data.length);
1495	q += data[i].data.length;
1496    }
1497
1498    free(p);
1499
1500    /* check signature */
1501    for (i = 0; i < num_data; i++) {
1502	if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1503	    continue;
1504	len += data[i].data.length;
1505    }
1506
1507    p = q = malloc(len);
1508    if (p == NULL)
1509	return ENOMEM;
1510
1511    memcpy(q, hiv->data.data, hiv->data.length);
1512    q += hiv->data.length;
1513    for (i = 0; i < num_data; i++) {
1514	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1515	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1516	    continue;
1517	memcpy(q, data[i].data.data, data[i].data.length);
1518	q += data[i].data.length;
1519    }
1520
1521    cksum.checksum.data   = tiv->data.data;
1522    cksum.checksum.length = tiv->data.length;
1523    cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
1524
1525    ret = verify_checksum(context,
1526			  crypto,
1527			  INTEGRITY_USAGE(usage),
1528			  p,
1529			  len,
1530			  &cksum);
1531    free(p);
1532    return ret;
1533}
1534
1535/**
1536 * Create a Kerberos message checksum.
1537 *
1538 * @param context Kerberos context
1539 * @param crypto Kerberos crypto context
1540 * @param usage Key usage for this buffer
1541 * @param data array of buffers to process
1542 * @param num_data length of array
1543 * @param type output data
1544 *
1545 * @return Return an error code or 0.
1546 * @ingroup krb5_crypto
1547 */
1548
1549KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1550krb5_create_checksum_iov(krb5_context context,
1551			 krb5_crypto crypto,
1552			 unsigned usage,
1553			 krb5_crypto_iov *data,
1554			 unsigned int num_data,
1555			 krb5_cksumtype *type)
1556{
1557    Checksum cksum;
1558    krb5_crypto_iov *civ;
1559    krb5_error_code ret;
1560    size_t i;
1561    size_t len;
1562    char *p, *q;
1563
1564    if(!derived_crypto(context, crypto)) {
1565	krb5_clear_error_message(context);
1566	return KRB5_CRYPTO_INTERNAL;
1567    }
1568
1569    civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
1570    if (civ == NULL)
1571	return KRB5_BAD_MSIZE;
1572
1573    len = 0;
1574    for (i = 0; i < num_data; i++) {
1575	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1576	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1577	    continue;
1578	len += data[i].data.length;
1579    }
1580
1581    p = q = malloc(len);
1582
1583    for (i = 0; i < num_data; i++) {
1584	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1585	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1586	    continue;
1587	memcpy(q, data[i].data.data, data[i].data.length);
1588	q += data[i].data.length;
1589    }
1590
1591    ret = krb5_create_checksum(context, crypto, usage, 0, p, len, &cksum);
1592    free(p);
1593    if (ret)
1594	return ret;
1595
1596    if (type)
1597	*type = cksum.cksumtype;
1598
1599    if (cksum.checksum.length > civ->data.length) {
1600	krb5_set_error_message(context, KRB5_BAD_MSIZE,
1601			       N_("Checksum larger then input buffer", ""));
1602	free_Checksum(&cksum);
1603	return KRB5_BAD_MSIZE;
1604    }
1605
1606    civ->data.length = cksum.checksum.length;
1607    memcpy(civ->data.data, cksum.checksum.data, civ->data.length);
1608    free_Checksum(&cksum);
1609
1610    return 0;
1611}
1612
1613/**
1614 * Verify a Kerberos message checksum.
1615 *
1616 * @param context Kerberos context
1617 * @param crypto Kerberos crypto context
1618 * @param usage Key usage for this buffer
1619 * @param data array of buffers to process
1620 * @param num_data length of array
1621 * @param type return checksum type if not NULL
1622 *
1623 * @return Return an error code or 0.
1624 * @ingroup krb5_crypto
1625 */
1626
1627KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1628krb5_verify_checksum_iov(krb5_context context,
1629			 krb5_crypto crypto,
1630			 unsigned usage,
1631			 krb5_crypto_iov *data,
1632			 unsigned int num_data,
1633			 krb5_cksumtype *type)
1634{
1635    struct _krb5_encryption_type *et = crypto->et;
1636    Checksum cksum;
1637    krb5_crypto_iov *civ;
1638    krb5_error_code ret;
1639    size_t i;
1640    size_t len;
1641    char *p, *q;
1642
1643    if(!derived_crypto(context, crypto)) {
1644	krb5_clear_error_message(context);
1645	return KRB5_CRYPTO_INTERNAL;
1646    }
1647
1648    civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
1649    if (civ == NULL)
1650	return KRB5_BAD_MSIZE;
1651
1652    len = 0;
1653    for (i = 0; i < num_data; i++) {
1654	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1655	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1656	    continue;
1657	len += data[i].data.length;
1658    }
1659
1660    p = q = malloc(len);
1661
1662    for (i = 0; i < num_data; i++) {
1663	if (data[i].flags != KRB5_CRYPTO_TYPE_DATA &&
1664	    data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY)
1665	    continue;
1666	memcpy(q, data[i].data.data, data[i].data.length);
1667	q += data[i].data.length;
1668    }
1669
1670    cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum);
1671    cksum.checksum.length = civ->data.length;
1672    cksum.checksum.data = civ->data.data;
1673
1674    ret = krb5_verify_checksum(context, crypto, usage, p, len, &cksum);
1675    free(p);
1676
1677    if (ret == 0 && type)
1678	*type = cksum.cksumtype;
1679
1680    return ret;
1681}
1682
1683
1684KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1685krb5_crypto_length(krb5_context context,
1686		   krb5_crypto crypto,
1687		   int type,
1688		   size_t *len)
1689{
1690    if (!derived_crypto(context, crypto)) {
1691	krb5_set_error_message(context, EINVAL, "not a derived crypto");
1692	return EINVAL;
1693    }
1694
1695    switch(type) {
1696    case KRB5_CRYPTO_TYPE_EMPTY:
1697	*len = 0;
1698	return 0;
1699    case KRB5_CRYPTO_TYPE_HEADER:
1700	*len = crypto->et->blocksize;
1701	return 0;
1702    case KRB5_CRYPTO_TYPE_DATA:
1703    case KRB5_CRYPTO_TYPE_SIGN_ONLY:
1704	/* len must already been filled in */
1705	return 0;
1706    case KRB5_CRYPTO_TYPE_PADDING:
1707	if (crypto->et->padsize > 1)
1708	    *len = crypto->et->padsize;
1709	else
1710	    *len = 0;
1711	return 0;
1712    case KRB5_CRYPTO_TYPE_TRAILER:
1713	*len = CHECKSUMSIZE(crypto->et->keyed_checksum);
1714	return 0;
1715    case KRB5_CRYPTO_TYPE_CHECKSUM:
1716	if (crypto->et->keyed_checksum)
1717	    *len = CHECKSUMSIZE(crypto->et->keyed_checksum);
1718	else
1719	    *len = CHECKSUMSIZE(crypto->et->checksum);
1720	return 0;
1721    }
1722    krb5_set_error_message(context, EINVAL,
1723			   "%d not a supported type", type);
1724    return EINVAL;
1725}
1726
1727
1728KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1729krb5_crypto_length_iov(krb5_context context,
1730		       krb5_crypto crypto,
1731		       krb5_crypto_iov *data,
1732		       unsigned int num_data)
1733{
1734    krb5_error_code ret;
1735    size_t i;
1736
1737    for (i = 0; i < num_data; i++) {
1738	ret = krb5_crypto_length(context, crypto,
1739				 data[i].flags,
1740				 &data[i].data.length);
1741	if (ret)
1742	    return ret;
1743    }
1744    return 0;
1745}
1746
1747
1748KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1749krb5_encrypt_ivec(krb5_context context,
1750		  krb5_crypto crypto,
1751		  unsigned usage,
1752		  const void *data,
1753		  size_t len,
1754		  krb5_data *result,
1755		  void *ivec)
1756{
1757    if(derived_crypto(context, crypto))
1758	return encrypt_internal_derived(context, crypto, usage,
1759					data, len, result, ivec);
1760    else if (special_crypto(context, crypto))
1761	return encrypt_internal_special (context, crypto, usage,
1762					 data, len, result, ivec);
1763    else
1764	return encrypt_internal(context, crypto, data, len, result, ivec);
1765}
1766
1767KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1768krb5_encrypt(krb5_context context,
1769	     krb5_crypto crypto,
1770	     unsigned usage,
1771	     const void *data,
1772	     size_t len,
1773	     krb5_data *result)
1774{
1775    return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL);
1776}
1777
1778KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1779krb5_encrypt_EncryptedData(krb5_context context,
1780			   krb5_crypto crypto,
1781			   unsigned usage,
1782			   void *data,
1783			   size_t len,
1784			   int kvno,
1785			   EncryptedData *result)
1786{
1787    result->etype = CRYPTO_ETYPE(crypto);
1788    if(kvno){
1789	ALLOC(result->kvno, 1);
1790	*result->kvno = kvno;
1791    }else
1792	result->kvno = NULL;
1793    return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
1794}
1795
1796KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1797krb5_decrypt_ivec(krb5_context context,
1798		  krb5_crypto crypto,
1799		  unsigned usage,
1800		  void *data,
1801		  size_t len,
1802		  krb5_data *result,
1803		  void *ivec)
1804{
1805    if(derived_crypto(context, crypto))
1806	return decrypt_internal_derived(context, crypto, usage,
1807					data, len, result, ivec);
1808    else if (special_crypto (context, crypto))
1809	return decrypt_internal_special(context, crypto, usage,
1810					data, len, result, ivec);
1811    else
1812	return decrypt_internal(context, crypto, data, len, result, ivec);
1813}
1814
1815KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1816krb5_decrypt(krb5_context context,
1817	     krb5_crypto crypto,
1818	     unsigned usage,
1819	     void *data,
1820	     size_t len,
1821	     krb5_data *result)
1822{
1823    return krb5_decrypt_ivec (context, crypto, usage, data, len, result,
1824			      NULL);
1825}
1826
1827KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1828krb5_decrypt_EncryptedData(krb5_context context,
1829			   krb5_crypto crypto,
1830			   unsigned usage,
1831			   const EncryptedData *e,
1832			   krb5_data *result)
1833{
1834    return krb5_decrypt(context, crypto, usage,
1835			e->cipher.data, e->cipher.length, result);
1836}
1837
1838/************************************************************
1839 *                                                          *
1840 ************************************************************/
1841
1842krb5_error_code
1843_krb5_derive_key(krb5_context context,
1844		 struct _krb5_encryption_type *et,
1845		 struct _krb5_key_data *key,
1846		 const void *constant,
1847		 size_t len)
1848{
1849    unsigned char *k = NULL;
1850    unsigned int nblocks = 0, i;
1851    krb5_error_code ret = 0;
1852    struct _krb5_key_type *kt = et->keytype;
1853
1854    ret = _key_schedule(context, key);
1855    if(ret)
1856	return ret;
1857    if(et->blocksize * 8 < kt->bits || len != et->blocksize) {
1858	nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
1859	k = malloc(nblocks * et->blocksize);
1860	if(k == NULL) {
1861	    ret = ENOMEM;
1862	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1863	    goto out;
1864	}
1865	ret = _krb5_n_fold(constant, len, k, et->blocksize);
1866	if (ret) {
1867	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1868	    goto out;
1869	}
1870
1871	for(i = 0; i < nblocks; i++) {
1872	    if(i > 0)
1873		memcpy(k + i * et->blocksize,
1874		       k + (i - 1) * et->blocksize,
1875		       et->blocksize);
1876	    (*et->encrypt)(context, key, k + i * et->blocksize, et->blocksize,
1877			   1, 0, NULL);
1878	}
1879    } else {
1880	/* this case is probably broken, but won't be run anyway */
1881	void *c = malloc(len);
1882	size_t res_len = (kt->bits + 7) / 8;
1883
1884	if(len != 0 && c == NULL) {
1885	    ret = ENOMEM;
1886	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1887	    goto out;
1888	}
1889	memcpy(c, constant, len);
1890	(*et->encrypt)(context, key, c, len, 1, 0, NULL);
1891	k = malloc(res_len);
1892	if(res_len != 0 && k == NULL) {
1893	    free(c);
1894	    ret = ENOMEM;
1895	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1896	    goto out;
1897	}
1898	ret = _krb5_n_fold(c, len, k, res_len);
1899	free(c);
1900	if (ret) {
1901	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1902	    goto out;
1903	}
1904    }
1905
1906    /* XXX keytype dependent post-processing */
1907    switch(kt->type) {
1908    case ETYPE_OLD_DES3_CBC_SHA1:
1909	_krb5_DES3_random_to_key(context, key->key, k, nblocks * et->blocksize);
1910	break;
1911    case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
1912    case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
1913	memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length);
1914	break;
1915    default:
1916	ret = KRB5_CRYPTO_INTERNAL;
1917	krb5_set_error_message(context, ret,
1918			       N_("derive_key() called with unknown keytype (%u)", ""),
1919			       kt->type);
1920	break;
1921    }
1922 out:
1923    if (key->schedule) {
1924	free_key_schedule(context, key, et);
1925	key->schedule = NULL;
1926    }
1927    if (k) {
1928	memset(k, 0, nblocks * et->blocksize);
1929	free(k);
1930    }
1931    return ret;
1932}
1933
1934static struct _krb5_key_data *
1935_new_derived_key(krb5_crypto crypto, unsigned usage)
1936{
1937    struct _krb5_key_usage *d = crypto->key_usage;
1938    d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
1939    if(d == NULL)
1940	return NULL;
1941    crypto->key_usage = d;
1942    d += crypto->num_key_usage++;
1943    memset(d, 0, sizeof(*d));
1944    d->usage = usage;
1945    return &d->key;
1946}
1947
1948KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1949krb5_derive_key(krb5_context context,
1950		const krb5_keyblock *key,
1951		krb5_enctype etype,
1952		const void *constant,
1953		size_t constant_len,
1954		krb5_keyblock **derived_key)
1955{
1956    krb5_error_code ret;
1957    struct _krb5_encryption_type *et;
1958    struct _krb5_key_data d;
1959
1960    *derived_key = NULL;
1961
1962    et = _krb5_find_enctype (etype);
1963    if (et == NULL) {
1964        return unsupported_enctype (context, etype);
1965    }
1966
1967    ret = krb5_copy_keyblock(context, key, &d.key);
1968    if (ret)
1969	return ret;
1970
1971    d.schedule = NULL;
1972    ret = _krb5_derive_key(context, et, &d, constant, constant_len);
1973    if (ret == 0)
1974	ret = krb5_copy_keyblock(context, d.key, derived_key);
1975    _krb5_free_key_data(context, &d, et);
1976    return ret;
1977}
1978
1979static krb5_error_code
1980_get_derived_key(krb5_context context,
1981		 krb5_crypto crypto,
1982		 unsigned usage,
1983		 struct _krb5_key_data **key)
1984{
1985    int i;
1986    struct _krb5_key_data *d;
1987    unsigned char constant[5];
1988
1989    for(i = 0; i < crypto->num_key_usage; i++)
1990	if(crypto->key_usage[i].usage == usage) {
1991	    *key = &crypto->key_usage[i].key;
1992	    return 0;
1993	}
1994    d = _new_derived_key(crypto, usage);
1995    if(d == NULL) {
1996	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1997	return ENOMEM;
1998    }
1999    krb5_copy_keyblock(context, crypto->key.key, &d->key);
2000    _krb5_put_int(constant, usage, 5);
2001    _krb5_derive_key(context, crypto->et, d, constant, sizeof(constant));
2002    *key = d;
2003    return 0;
2004}
2005
2006/**
2007 * Create a crypto context used for all encryption and signature
2008 * operation. The encryption type to use is taken from the key, but
2009 * can be overridden with the enctype parameter.  This can be useful
2010 * for encryptions types which is compatiable (DES for example).
2011 *
2012 * To free the crypto context, use krb5_crypto_destroy().
2013 *
2014 * @param context Kerberos context
2015 * @param key the key block information with all key data
2016 * @param etype the encryption type
2017 * @param crypto the resulting crypto context
2018 *
2019 * @return Return an error code or 0.
2020 *
2021 * @ingroup krb5_crypto
2022 */
2023
2024KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2025krb5_crypto_init(krb5_context context,
2026		 const krb5_keyblock *key,
2027		 krb5_enctype etype,
2028		 krb5_crypto *crypto)
2029{
2030    krb5_error_code ret;
2031    ALLOC(*crypto, 1);
2032    if(*crypto == NULL) {
2033	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
2034	return ENOMEM;
2035    }
2036    if(etype == ETYPE_NULL)
2037	etype = key->keytype;
2038    (*crypto)->et = _krb5_find_enctype(etype);
2039    if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) {
2040	free(*crypto);
2041	*crypto = NULL;
2042	return unsupported_enctype(context, etype);
2043    }
2044    if((*crypto)->et->keytype->size != key->keyvalue.length) {
2045	free(*crypto);
2046	*crypto = NULL;
2047	krb5_set_error_message (context, KRB5_BAD_KEYSIZE,
2048				"encryption key has bad length");
2049	return KRB5_BAD_KEYSIZE;
2050    }
2051    ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
2052    if(ret) {
2053	free(*crypto);
2054	*crypto = NULL;
2055	return ret;
2056    }
2057    (*crypto)->key.schedule = NULL;
2058    (*crypto)->num_key_usage = 0;
2059    (*crypto)->key_usage = NULL;
2060    return 0;
2061}
2062
2063static void
2064free_key_schedule(krb5_context context,
2065		  struct _krb5_key_data *key,
2066		  struct _krb5_encryption_type *et)
2067{
2068    if (et->keytype->cleanup)
2069	(*et->keytype->cleanup)(context, key);
2070    memset(key->schedule->data, 0, key->schedule->length);
2071    krb5_free_data(context, key->schedule);
2072}
2073
2074void
2075_krb5_free_key_data(krb5_context context, struct _krb5_key_data *key,
2076	      struct _krb5_encryption_type *et)
2077{
2078    krb5_free_keyblock(context, key->key);
2079    if(key->schedule) {
2080	free_key_schedule(context, key, et);
2081	key->schedule = NULL;
2082    }
2083}
2084
2085static void
2086free_key_usage(krb5_context context, struct _krb5_key_usage *ku,
2087	       struct _krb5_encryption_type *et)
2088{
2089    _krb5_free_key_data(context, &ku->key, et);
2090}
2091
2092/**
2093 * Free a crypto context created by krb5_crypto_init().
2094 *
2095 * @param context Kerberos context
2096 * @param crypto crypto context to free
2097 *
2098 * @return Return an error code or 0.
2099 *
2100 * @ingroup krb5_crypto
2101 */
2102
2103KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2104krb5_crypto_destroy(krb5_context context,
2105		    krb5_crypto crypto)
2106{
2107    int i;
2108
2109    for(i = 0; i < crypto->num_key_usage; i++)
2110	free_key_usage(context, &crypto->key_usage[i], crypto->et);
2111    free(crypto->key_usage);
2112    _krb5_free_key_data(context, &crypto->key, crypto->et);
2113    free (crypto);
2114    return 0;
2115}
2116
2117/**
2118 * Return the blocksize used algorithm referenced by the crypto context
2119 *
2120 * @param context Kerberos context
2121 * @param crypto crypto context to query
2122 * @param blocksize the resulting blocksize
2123 *
2124 * @return Return an error code or 0.
2125 *
2126 * @ingroup krb5_crypto
2127 */
2128
2129KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2130krb5_crypto_getblocksize(krb5_context context,
2131			 krb5_crypto crypto,
2132			 size_t *blocksize)
2133{
2134    *blocksize = crypto->et->blocksize;
2135    return 0;
2136}
2137
2138/**
2139 * Return the encryption type used by the crypto context
2140 *
2141 * @param context Kerberos context
2142 * @param crypto crypto context to query
2143 * @param enctype the resulting encryption type
2144 *
2145 * @return Return an error code or 0.
2146 *
2147 * @ingroup krb5_crypto
2148 */
2149
2150KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2151krb5_crypto_getenctype(krb5_context context,
2152		       krb5_crypto crypto,
2153		       krb5_enctype *enctype)
2154{
2155    *enctype = crypto->et->type;
2156    return 0;
2157}
2158
2159/**
2160 * Return the padding size used by the crypto context
2161 *
2162 * @param context Kerberos context
2163 * @param crypto crypto context to query
2164 * @param padsize the return padding size
2165 *
2166 * @return Return an error code or 0.
2167 *
2168 * @ingroup krb5_crypto
2169 */
2170
2171KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2172krb5_crypto_getpadsize(krb5_context context,
2173                       krb5_crypto crypto,
2174                       size_t *padsize)
2175{
2176    *padsize = crypto->et->padsize;
2177    return 0;
2178}
2179
2180/**
2181 * Return the confounder size used by the crypto context
2182 *
2183 * @param context Kerberos context
2184 * @param crypto crypto context to query
2185 * @param confoundersize the returned confounder size
2186 *
2187 * @return Return an error code or 0.
2188 *
2189 * @ingroup krb5_crypto
2190 */
2191
2192KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2193krb5_crypto_getconfoundersize(krb5_context context,
2194                              krb5_crypto crypto,
2195                              size_t *confoundersize)
2196{
2197    *confoundersize = crypto->et->confoundersize;
2198    return 0;
2199}
2200
2201
2202/**
2203 * Disable encryption type
2204 *
2205 * @param context Kerberos 5 context
2206 * @param enctype encryption type to disable
2207 *
2208 * @return Return an error code or 0.
2209 *
2210 * @ingroup krb5_crypto
2211 */
2212
2213KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2214krb5_enctype_disable(krb5_context context,
2215		     krb5_enctype enctype)
2216{
2217    struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2218    if(et == NULL) {
2219	if (context)
2220	    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2221				    N_("encryption type %d not supported", ""),
2222				    enctype);
2223	return KRB5_PROG_ETYPE_NOSUPP;
2224    }
2225    et->flags |= F_DISABLED;
2226    return 0;
2227}
2228
2229/**
2230 * Enable encryption type
2231 *
2232 * @param context Kerberos 5 context
2233 * @param enctype encryption type to enable
2234 *
2235 * @return Return an error code or 0.
2236 *
2237 * @ingroup krb5_crypto
2238 */
2239
2240KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2241krb5_enctype_enable(krb5_context context,
2242		    krb5_enctype enctype)
2243{
2244    struct _krb5_encryption_type *et = _krb5_find_enctype(enctype);
2245    if(et == NULL) {
2246	if (context)
2247	    krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP,
2248				    N_("encryption type %d not supported", ""),
2249				    enctype);
2250	return KRB5_PROG_ETYPE_NOSUPP;
2251    }
2252    et->flags &= ~F_DISABLED;
2253    return 0;
2254}
2255
2256/**
2257 * Enable or disable all weak encryption types
2258 *
2259 * @param context Kerberos 5 context
2260 * @param enable true to enable, false to disable
2261 *
2262 * @return Return an error code or 0.
2263 *
2264 * @ingroup krb5_crypto
2265 */
2266
2267KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2268krb5_allow_weak_crypto(krb5_context context,
2269		       krb5_boolean enable)
2270{
2271    int i;
2272
2273    for(i = 0; i < _krb5_num_etypes; i++)
2274	if(_krb5_etypes[i]->flags & F_WEAK) {
2275	    if(enable)
2276		_krb5_etypes[i]->flags &= ~F_DISABLED;
2277	    else
2278		_krb5_etypes[i]->flags |= F_DISABLED;
2279	}
2280    return 0;
2281}
2282
2283static size_t
2284wrapped_length (krb5_context context,
2285		krb5_crypto  crypto,
2286		size_t       data_len)
2287{
2288    struct _krb5_encryption_type *et = crypto->et;
2289    size_t padsize = et->padsize;
2290    size_t checksumsize = CHECKSUMSIZE(et->checksum);
2291    size_t res;
2292
2293    res =  et->confoundersize + checksumsize + data_len;
2294    res =  (res + padsize - 1) / padsize * padsize;
2295    return res;
2296}
2297
2298static size_t
2299wrapped_length_dervied (krb5_context context,
2300			krb5_crypto  crypto,
2301			size_t       data_len)
2302{
2303    struct _krb5_encryption_type *et = crypto->et;
2304    size_t padsize = et->padsize;
2305    size_t res;
2306
2307    res =  et->confoundersize + data_len;
2308    res =  (res + padsize - 1) / padsize * padsize;
2309    if (et->keyed_checksum)
2310	res += et->keyed_checksum->checksumsize;
2311    else
2312	res += et->checksum->checksumsize;
2313    return res;
2314}
2315
2316/*
2317 * Return the size of an encrypted packet of length `data_len'
2318 */
2319
2320KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2321krb5_get_wrapped_length (krb5_context context,
2322			 krb5_crypto  crypto,
2323			 size_t       data_len)
2324{
2325    if (derived_crypto (context, crypto))
2326	return wrapped_length_dervied (context, crypto, data_len);
2327    else
2328	return wrapped_length (context, crypto, data_len);
2329}
2330
2331/*
2332 * Return the size of an encrypted packet of length `data_len'
2333 */
2334
2335static size_t
2336crypto_overhead (krb5_context context,
2337		 krb5_crypto  crypto)
2338{
2339    struct _krb5_encryption_type *et = crypto->et;
2340    size_t res;
2341
2342    res = CHECKSUMSIZE(et->checksum);
2343    res += et->confoundersize;
2344    if (et->padsize > 1)
2345	res += et->padsize;
2346    return res;
2347}
2348
2349static size_t
2350crypto_overhead_dervied (krb5_context context,
2351			 krb5_crypto  crypto)
2352{
2353    struct _krb5_encryption_type *et = crypto->et;
2354    size_t res;
2355
2356    if (et->keyed_checksum)
2357	res = CHECKSUMSIZE(et->keyed_checksum);
2358    else
2359	res = CHECKSUMSIZE(et->checksum);
2360    res += et->confoundersize;
2361    if (et->padsize > 1)
2362	res += et->padsize;
2363    return res;
2364}
2365
2366KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
2367krb5_crypto_overhead (krb5_context context, krb5_crypto crypto)
2368{
2369    if (derived_crypto (context, crypto))
2370	return crypto_overhead_dervied (context, crypto);
2371    else
2372	return crypto_overhead (context, crypto);
2373}
2374
2375/**
2376 * Converts the random bytestring to a protocol key according to
2377 * Kerberos crypto frame work. It may be assumed that all the bits of
2378 * the input string are equally random, even though the entropy
2379 * present in the random source may be limited.
2380 *
2381 * @param context Kerberos 5 context
2382 * @param type the enctype resulting key will be of
2383 * @param data input random data to convert to a key
2384 * @param size size of input random data, at least krb5_enctype_keysize() long
2385 * @param key key, output key, free with krb5_free_keyblock_contents()
2386 *
2387 * @return Return an error code or 0.
2388 *
2389 * @ingroup krb5_crypto
2390 */
2391
2392KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2393krb5_random_to_key(krb5_context context,
2394		   krb5_enctype type,
2395		   const void *data,
2396		   size_t size,
2397		   krb5_keyblock *key)
2398{
2399    krb5_error_code ret;
2400    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2401    if(et == NULL) {
2402	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2403			       N_("encryption type %d not supported", ""),
2404			       type);
2405	return KRB5_PROG_ETYPE_NOSUPP;
2406    }
2407    if ((et->keytype->bits + 7) / 8 > size) {
2408	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2409			       N_("encryption key %s needs %d bytes "
2410				  "of random to make an encryption key "
2411				  "out of it", ""),
2412			       et->name, (int)et->keytype->size);
2413	return KRB5_PROG_ETYPE_NOSUPP;
2414    }
2415    ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
2416    if(ret)
2417	return ret;
2418    key->keytype = type;
2419    if (et->keytype->random_to_key)
2420 	(*et->keytype->random_to_key)(context, key, data, size);
2421    else
2422	memcpy(key->keyvalue.data, data, et->keytype->size);
2423
2424    return 0;
2425}
2426
2427
2428
2429KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2430krb5_crypto_prf_length(krb5_context context,
2431		       krb5_enctype type,
2432		       size_t *length)
2433{
2434    struct _krb5_encryption_type *et = _krb5_find_enctype(type);
2435
2436    if(et == NULL || et->prf_length == 0) {
2437	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2438			       N_("encryption type %d not supported", ""),
2439			       type);
2440	return KRB5_PROG_ETYPE_NOSUPP;
2441    }
2442
2443    *length = et->prf_length;
2444    return 0;
2445}
2446
2447KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2448krb5_crypto_prf(krb5_context context,
2449		const krb5_crypto crypto,
2450		const krb5_data *input,
2451		krb5_data *output)
2452{
2453    struct _krb5_encryption_type *et = crypto->et;
2454
2455    krb5_data_zero(output);
2456
2457    if(et->prf == NULL) {
2458	krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
2459			       "kerberos prf for %s not supported",
2460			       et->name);
2461	return KRB5_PROG_ETYPE_NOSUPP;
2462    }
2463
2464    return (*et->prf)(context, crypto, input, output);
2465}
2466
2467static krb5_error_code
2468krb5_crypto_prfplus(krb5_context context,
2469		    const krb5_crypto crypto,
2470		    const krb5_data *input,
2471		    size_t length,
2472		    krb5_data *output)
2473{
2474    krb5_error_code ret;
2475    krb5_data input2;
2476    unsigned char i = 1;
2477    unsigned char *p;
2478
2479    krb5_data_zero(&input2);
2480    krb5_data_zero(output);
2481
2482    krb5_clear_error_message(context);
2483
2484    ret = krb5_data_alloc(output, length);
2485    if (ret) goto out;
2486    ret = krb5_data_alloc(&input2, input->length + 1);
2487    if (ret) goto out;
2488
2489    krb5_clear_error_message(context);
2490
2491    memcpy(((unsigned char *)input2.data) + 1, input->data, input->length);
2492
2493    p = output->data;
2494
2495    while (length) {
2496	krb5_data block;
2497
2498	((unsigned char *)input2.data)[0] = i++;
2499
2500	ret = krb5_crypto_prf(context, crypto, &input2, &block);
2501	if (ret)
2502	    goto out;
2503
2504	if (block.length < length) {
2505	    memcpy(p, block.data, block.length);
2506	    length -= block.length;
2507	} else {
2508	    memcpy(p, block.data, length);
2509	    length = 0;
2510	}
2511	p += block.length;
2512	krb5_data_free(&block);
2513    }
2514
2515 out:
2516    krb5_data_free(&input2);
2517    if (ret)
2518	krb5_data_free(output);
2519    return 0;
2520}
2521
2522/**
2523 * The FX-CF2 key derivation function, used in FAST and preauth framework.
2524 *
2525 * @param context Kerberos 5 context
2526 * @param crypto1 first key to combine
2527 * @param crypto2 second key to combine
2528 * @param pepper1 factor to combine with first key to garante uniqueness
2529 * @param pepper2 factor to combine with second key to garante uniqueness
2530 * @param enctype the encryption type of the resulting key
2531 * @param res allocated key, free with krb5_free_keyblock_contents()
2532 *
2533 * @return Return an error code or 0.
2534 *
2535 * @ingroup krb5_crypto
2536 */
2537
2538KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2539krb5_crypto_fx_cf2(krb5_context context,
2540		   const krb5_crypto crypto1,
2541		   const krb5_crypto crypto2,
2542		   krb5_data *pepper1,
2543		   krb5_data *pepper2,
2544		   krb5_enctype enctype,
2545		   krb5_keyblock *res)
2546{
2547    krb5_error_code ret;
2548    krb5_data os1, os2;
2549    size_t i, keysize;
2550
2551    memset(res, 0, sizeof(*res));
2552
2553    ret = krb5_enctype_keysize(context, enctype, &keysize);
2554    if (ret)
2555	return ret;
2556
2557    ret = krb5_data_alloc(&res->keyvalue, keysize);
2558    if (ret)
2559	goto out;
2560    ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1);
2561    if (ret)
2562	goto out;
2563    ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2);
2564    if (ret)
2565	goto out;
2566
2567    res->keytype = enctype;
2568    {
2569	unsigned char *p1 = os1.data, *p2 = os2.data, *p3 = res->keyvalue.data;
2570	for (i = 0; i < keysize; i++)
2571	    p3[i] = p1[i] ^ p2[i];
2572    }
2573 out:
2574    if (ret)
2575	krb5_data_free(&res->keyvalue);
2576    krb5_data_free(&os1);
2577    krb5_data_free(&os2);
2578
2579    return ret;
2580}
2581
2582
2583
2584#ifndef HEIMDAL_SMALLER
2585
2586/**
2587 * Deprecated: keytypes doesn't exists, they are really enctypes.
2588 *
2589 * @ingroup krb5_deprecated
2590 */
2591
2592KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2593krb5_keytype_to_enctypes (krb5_context context,
2594			  krb5_keytype keytype,
2595			  unsigned *len,
2596			  krb5_enctype **val)
2597    KRB5_DEPRECATED_FUNCTION("Use X instead")
2598{
2599    int i;
2600    unsigned n = 0;
2601    krb5_enctype *ret;
2602
2603    for (i = _krb5_num_etypes - 1; i >= 0; --i) {
2604	if (_krb5_etypes[i]->keytype->type == keytype
2605	    && !(_krb5_etypes[i]->flags & F_PSEUDO)
2606	    && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
2607	    ++n;
2608    }
2609    if (n == 0) {
2610	krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
2611			       "Keytype have no mapping");
2612	return KRB5_PROG_KEYTYPE_NOSUPP;
2613    }
2614
2615    ret = malloc(n * sizeof(*ret));
2616    if (ret == NULL && n != 0) {
2617	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
2618	return ENOMEM;
2619    }
2620    n = 0;
2621    for (i = _krb5_num_etypes - 1; i >= 0; --i) {
2622	if (_krb5_etypes[i]->keytype->type == keytype
2623	    && !(_krb5_etypes[i]->flags & F_PSEUDO)
2624	    && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0)
2625	    ret[n++] = _krb5_etypes[i]->type;
2626    }
2627    *len = n;
2628    *val = ret;
2629    return 0;
2630}
2631
2632/**
2633 * Deprecated: keytypes doesn't exists, they are really enctypes.
2634 *
2635 * @ingroup krb5_deprecated
2636 */
2637
2638/* if two enctypes have compatible keys */
2639KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2640krb5_enctypes_compatible_keys(krb5_context context,
2641			      krb5_enctype etype1,
2642			      krb5_enctype etype2)
2643    KRB5_DEPRECATED_FUNCTION("Use X instead")
2644{
2645    struct _krb5_encryption_type *e1 = _krb5_find_enctype(etype1);
2646    struct _krb5_encryption_type *e2 = _krb5_find_enctype(etype2);
2647    return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
2648}
2649
2650#endif /* HEIMDAL_SMALLER */
2651