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