source: trunk/server/source4/heimdal/lib/krb5/crypto.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

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