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