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