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