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