155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "krb5_locl.h" 3555682Smarkm 36233294Sstasstruct _krb5_key_usage { 3755682Smarkm unsigned usage; 38233294Sstas struct _krb5_key_data key; 3955682Smarkm}; 4055682Smarkm 4155682Smarkm 42233294Sstas#ifndef HEIMDAL_SMALLER 43233294Sstas#define DES3_OLD_ENCTYPE 1 4455682Smarkm#endif 4555682Smarkm 46233294Sstasstatic krb5_error_code _get_derived_key(krb5_context, krb5_crypto, 47233294Sstas unsigned, struct _krb5_key_data**); 48233294Sstasstatic struct _krb5_key_data *_new_derived_key(krb5_crypto crypto, unsigned usage); 4955682Smarkm 50233294Sstasstatic void free_key_schedule(krb5_context, 51233294Sstas struct _krb5_key_data *, 52233294Sstas struct _krb5_encryption_type *); 5355682Smarkm 54233294Sstas/* 55233294Sstas * Converts etype to a user readable string and sets as a side effect 56233294Sstas * the krb5_error_message containing this string. Returns 57233294Sstas * KRB5_PROG_ETYPE_NOSUPP in not the conversion of the etype failed in 58233294Sstas * which case the error code of the etype convesion is returned. 5955682Smarkm */ 6055682Smarkm 6155682Smarkmstatic krb5_error_code 62233294Sstasunsupported_enctype(krb5_context context, krb5_enctype etype) 6355682Smarkm{ 64178828Sdfr krb5_error_code ret; 65233294Sstas char *name; 6655682Smarkm 67233294Sstas ret = krb5_enctype_to_string(context, etype, &name); 68233294Sstas if (ret) 69120948Snectar return ret; 70120948Snectar 71233294Sstas krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 72233294Sstas N_("Encryption type %s not supported", ""), 73233294Sstas name); 74233294Sstas free(name); 75233294Sstas return KRB5_PROG_ETYPE_NOSUPP; 76120948Snectar} 77120948Snectar 78120948Snectar/* 79120948Snectar * 80120948Snectar */ 81120948Snectar 82233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 83120948Snectarkrb5_enctype_keysize(krb5_context context, 84120948Snectar krb5_enctype type, 85120948Snectar size_t *keysize) 86120948Snectar{ 87233294Sstas struct _krb5_encryption_type *et = _krb5_find_enctype(type); 88120948Snectar if(et == NULL) { 89233294Sstas return unsupported_enctype (context, type); 90120948Snectar } 91120948Snectar *keysize = et->keytype->size; 92120948Snectar return 0; 93120948Snectar} 94120948Snectar 95233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 96178828Sdfrkrb5_enctype_keybits(krb5_context context, 97178828Sdfr krb5_enctype type, 98178828Sdfr size_t *keybits) 99178828Sdfr{ 100233294Sstas struct _krb5_encryption_type *et = _krb5_find_enctype(type); 101178828Sdfr if(et == NULL) { 102233294Sstas return unsupported_enctype (context, type); 103178828Sdfr } 104178828Sdfr *keybits = et->keytype->bits; 105178828Sdfr return 0; 106178828Sdfr} 107178828Sdfr 108233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 10955682Smarkmkrb5_generate_random_keyblock(krb5_context context, 11055682Smarkm krb5_enctype type, 11155682Smarkm krb5_keyblock *key) 11255682Smarkm{ 11355682Smarkm krb5_error_code ret; 114233294Sstas struct _krb5_encryption_type *et = _krb5_find_enctype(type); 11578536Sassar if(et == NULL) { 116233294Sstas return unsupported_enctype (context, type); 11778536Sassar } 11855682Smarkm ret = krb5_data_alloc(&key->keyvalue, et->keytype->size); 119233294Sstas if(ret) 12055682Smarkm return ret; 12155682Smarkm key->keytype = type; 12255682Smarkm if(et->keytype->random_key) 12355682Smarkm (*et->keytype->random_key)(context, key); 12455682Smarkm else 125233294Sstas krb5_generate_random_block(key->keyvalue.data, 12655682Smarkm key->keyvalue.length); 12755682Smarkm return 0; 12855682Smarkm} 12955682Smarkm 13055682Smarkmstatic krb5_error_code 13155682Smarkm_key_schedule(krb5_context context, 132233294Sstas struct _krb5_key_data *key) 13355682Smarkm{ 13455682Smarkm krb5_error_code ret; 135233294Sstas struct _krb5_encryption_type *et = _krb5_find_enctype(key->key->keytype); 136233294Sstas struct _krb5_key_type *kt; 13755682Smarkm 138233294Sstas if (et == NULL) { 139233294Sstas return unsupported_enctype (context, 140233294Sstas key->key->keytype); 141233294Sstas } 142233294Sstas 143233294Sstas kt = et->keytype; 144233294Sstas 14555682Smarkm if(kt->schedule == NULL) 14655682Smarkm return 0; 14772448Sassar if (key->schedule != NULL) 14872448Sassar return 0; 14955682Smarkm ALLOC(key->schedule, 1); 15078536Sassar if(key->schedule == NULL) { 151233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 15255682Smarkm return ENOMEM; 15378536Sassar } 15455682Smarkm ret = krb5_data_alloc(key->schedule, kt->schedule_size); 15555682Smarkm if(ret) { 15655682Smarkm free(key->schedule); 15755682Smarkm key->schedule = NULL; 15855682Smarkm return ret; 15955682Smarkm } 160233294Sstas (*kt->schedule)(context, kt, key); 16155682Smarkm return 0; 16255682Smarkm} 16355682Smarkm 16455682Smarkm/************************************************************ 16555682Smarkm * * 16655682Smarkm ************************************************************/ 16755682Smarkm 168233294Sstasstatic krb5_error_code 169233294SstasSHA1_checksum(krb5_context context, 170233294Sstas struct _krb5_key_data *key, 17172448Sassar const void *data, 17255682Smarkm size_t len, 17372448Sassar unsigned usage, 17455682Smarkm Checksum *C) 17555682Smarkm{ 176233294Sstas if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_sha1(), NULL) != 1) 177233294Sstas krb5_abortx(context, "sha1 checksum failed"); 178233294Sstas return 0; 17955682Smarkm} 18055682Smarkm 181233294Sstas/* HMAC according to RFC2104 */ 182233294Sstaskrb5_error_code 183233294Sstas_krb5_internal_hmac(krb5_context context, 184233294Sstas struct _krb5_checksum_type *cm, 18572448Sassar const void *data, 18655682Smarkm size_t len, 18772448Sassar unsigned usage, 188233294Sstas struct _krb5_key_data *keyblock, 189233294Sstas Checksum *result) 19055682Smarkm{ 19155682Smarkm unsigned char *ipad, *opad; 19255682Smarkm unsigned char *key; 19355682Smarkm size_t key_len; 194233294Sstas size_t i; 195233294Sstas 196127811Snectar ipad = malloc(cm->blocksize + len); 197127811Snectar if (ipad == NULL) 198127811Snectar return ENOMEM; 199127811Snectar opad = malloc(cm->blocksize + cm->checksumsize); 200127811Snectar if (opad == NULL) { 201127811Snectar free(ipad); 202127811Snectar return ENOMEM; 203127811Snectar } 204127811Snectar memset(ipad, 0x36, cm->blocksize); 205127811Snectar memset(opad, 0x5c, cm->blocksize); 206127811Snectar 20755682Smarkm if(keyblock->key->keyvalue.length > cm->blocksize){ 208233294Sstas (*cm->checksum)(context, 209233294Sstas keyblock, 210233294Sstas keyblock->key->keyvalue.data, 211233294Sstas keyblock->key->keyvalue.length, 21272448Sassar usage, 21355682Smarkm result); 21455682Smarkm key = result->checksum.data; 21555682Smarkm key_len = result->checksum.length; 21655682Smarkm } else { 21755682Smarkm key = keyblock->key->keyvalue.data; 21855682Smarkm key_len = keyblock->key->keyvalue.length; 21955682Smarkm } 22055682Smarkm for(i = 0; i < key_len; i++){ 22155682Smarkm ipad[i] ^= key[i]; 22255682Smarkm opad[i] ^= key[i]; 22355682Smarkm } 22455682Smarkm memcpy(ipad + cm->blocksize, data, len); 22572448Sassar (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len, 22672448Sassar usage, result); 227233294Sstas memcpy(opad + cm->blocksize, result->checksum.data, 22855682Smarkm result->checksum.length); 229233294Sstas (*cm->checksum)(context, keyblock, opad, 23072448Sassar cm->blocksize + cm->checksumsize, usage, result); 23155682Smarkm memset(ipad, 0, cm->blocksize + len); 23255682Smarkm free(ipad); 23355682Smarkm memset(opad, 0, cm->blocksize + cm->checksumsize); 23455682Smarkm free(opad); 235127811Snectar 236127811Snectar return 0; 23755682Smarkm} 23855682Smarkm 239233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 240127811Snectarkrb5_hmac(krb5_context context, 241127811Snectar krb5_cksumtype cktype, 242127811Snectar const void *data, 243127811Snectar size_t len, 244233294Sstas unsigned usage, 245127811Snectar krb5_keyblock *key, 246127811Snectar Checksum *result) 247127811Snectar{ 248233294Sstas struct _krb5_checksum_type *c = _krb5_find_checksum(cktype); 249233294Sstas struct _krb5_key_data kd; 250127811Snectar krb5_error_code ret; 251127811Snectar 252127811Snectar if (c == NULL) { 253233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 254233294Sstas N_("checksum type %d not supported", ""), 255233294Sstas cktype); 256127811Snectar return KRB5_PROG_SUMTYPE_NOSUPP; 257127811Snectar } 258127811Snectar 259127811Snectar kd.key = key; 260127811Snectar kd.schedule = NULL; 261127811Snectar 262233294Sstas ret = _krb5_internal_hmac(context, c, data, len, usage, &kd, result); 263127811Snectar 264127811Snectar if (kd.schedule) 265127811Snectar krb5_free_data(context, kd.schedule); 266127811Snectar 267127811Snectar return ret; 268233294Sstas} 269127811Snectar 270233294Sstaskrb5_error_code 271233294Sstas_krb5_SP_HMAC_SHA1_checksum(krb5_context context, 272233294Sstas struct _krb5_key_data *key, 273233294Sstas const void *data, 274233294Sstas size_t len, 275233294Sstas unsigned usage, 276233294Sstas Checksum *result) 27755682Smarkm{ 278233294Sstas struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1); 279120948Snectar Checksum res; 280120948Snectar char sha1_data[20]; 281127811Snectar krb5_error_code ret; 28255682Smarkm 283120948Snectar res.checksum.data = sha1_data; 284120948Snectar res.checksum.length = sizeof(sha1_data); 285120948Snectar 286233294Sstas ret = _krb5_internal_hmac(context, c, data, len, usage, key, &res); 287127811Snectar if (ret) 288127811Snectar krb5_abortx(context, "hmac failed"); 289120948Snectar memcpy(result->checksum.data, res.checksum.data, result->checksum.length); 290233294Sstas return 0; 29155682Smarkm} 29255682Smarkm 293233294Sstasstruct _krb5_checksum_type _krb5_checksum_sha1 = { 29455682Smarkm CKSUMTYPE_SHA1, 29555682Smarkm "sha1", 29655682Smarkm 64, 29755682Smarkm 20, 29855682Smarkm F_CPROOF, 29955682Smarkm SHA1_checksum, 30055682Smarkm NULL 30155682Smarkm}; 30255682Smarkm 303233294Sstasstruct _krb5_checksum_type * 304233294Sstas_krb5_find_checksum(krb5_cksumtype type) 30555682Smarkm{ 30655682Smarkm int i; 307233294Sstas for(i = 0; i < _krb5_num_checksums; i++) 308233294Sstas if(_krb5_checksum_types[i]->type == type) 309233294Sstas return _krb5_checksum_types[i]; 31055682Smarkm return NULL; 31155682Smarkm} 31255682Smarkm 31355682Smarkmstatic krb5_error_code 314233294Sstasget_checksum_key(krb5_context context, 31555682Smarkm krb5_crypto crypto, 31655682Smarkm unsigned usage, /* not krb5_key_usage */ 317233294Sstas struct _krb5_checksum_type *ct, 318233294Sstas struct _krb5_key_data **key) 31955682Smarkm{ 32055682Smarkm krb5_error_code ret = 0; 32155682Smarkm 32255682Smarkm if(ct->flags & F_DERIVED) 32355682Smarkm ret = _get_derived_key(context, crypto, usage, key); 32455682Smarkm else if(ct->flags & F_VARIANT) { 325233294Sstas size_t i; 32655682Smarkm 32755682Smarkm *key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */); 32878536Sassar if(*key == NULL) { 329233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 33055682Smarkm return ENOMEM; 33178536Sassar } 33255682Smarkm ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key); 333233294Sstas if(ret) 33455682Smarkm return ret; 33555682Smarkm for(i = 0; i < (*key)->key->keyvalue.length; i++) 33655682Smarkm ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0; 33755682Smarkm } else { 338233294Sstas *key = &crypto->key; 33955682Smarkm } 34055682Smarkm if(ret == 0) 34155682Smarkm ret = _key_schedule(context, *key); 34255682Smarkm return ret; 34355682Smarkm} 34455682Smarkm 34555682Smarkmstatic krb5_error_code 346127811Snectarcreate_checksum (krb5_context context, 347233294Sstas struct _krb5_checksum_type *ct, 348127811Snectar krb5_crypto crypto, 349127811Snectar unsigned usage, 350127811Snectar void *data, 351127811Snectar size_t len, 352127811Snectar Checksum *result) 35355682Smarkm{ 35455682Smarkm krb5_error_code ret; 355233294Sstas struct _krb5_key_data *dkey; 35655682Smarkm int keyed_checksum; 357233294Sstas 358178828Sdfr if (ct->flags & F_DISABLED) { 359233294Sstas krb5_clear_error_message (context); 360178828Sdfr return KRB5_PROG_SUMTYPE_NOSUPP; 361178828Sdfr } 36255682Smarkm keyed_checksum = (ct->flags & F_KEYED) != 0; 36378536Sassar if(keyed_checksum && crypto == NULL) { 364233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 365233294Sstas N_("Checksum type %s is keyed but no " 366233294Sstas "crypto context (key) was passed in", ""), 367233294Sstas ct->name); 36855682Smarkm return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ 36978536Sassar } 37072448Sassar if(keyed_checksum) { 37155682Smarkm ret = get_checksum_key(context, crypto, usage, ct, &dkey); 37272448Sassar if (ret) 37372448Sassar return ret; 37472448Sassar } else 37555682Smarkm dkey = NULL; 37655682Smarkm result->cksumtype = ct->type; 377178828Sdfr ret = krb5_data_alloc(&result->checksum, ct->checksumsize); 378178828Sdfr if (ret) 379178828Sdfr return (ret); 380233294Sstas return (*ct->checksum)(context, dkey, data, len, usage, result); 38155682Smarkm} 38255682Smarkm 383127811Snectarstatic int 384233294Sstasarcfour_checksum_p(struct _krb5_checksum_type *ct, krb5_crypto crypto) 38555682Smarkm{ 386127811Snectar return (ct->type == CKSUMTYPE_HMAC_MD5) && 387127811Snectar (crypto->key.key->keytype == KEYTYPE_ARCFOUR); 388127811Snectar} 389127811Snectar 390233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 391127811Snectarkrb5_create_checksum(krb5_context context, 392127811Snectar krb5_crypto crypto, 393127811Snectar krb5_key_usage usage, 394127811Snectar int type, 395127811Snectar void *data, 396127811Snectar size_t len, 397127811Snectar Checksum *result) 398127811Snectar{ 399233294Sstas struct _krb5_checksum_type *ct = NULL; 400127811Snectar unsigned keyusage; 40155682Smarkm 402127811Snectar /* type 0 -> pick from crypto */ 40378536Sassar if (type) { 404233294Sstas ct = _krb5_find_checksum(type); 40578536Sassar } else if (crypto) { 40655682Smarkm ct = crypto->et->keyed_checksum; 40778536Sassar if (ct == NULL) 40878536Sassar ct = crypto->et->checksum; 40978536Sassar } 41078536Sassar 41178536Sassar if(ct == NULL) { 412233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 413233294Sstas N_("checksum type %d not supported", ""), 414233294Sstas type); 41555682Smarkm return KRB5_PROG_SUMTYPE_NOSUPP; 41678536Sassar } 41755682Smarkm 418127811Snectar if (arcfour_checksum_p(ct, crypto)) { 419127811Snectar keyusage = usage; 420233294Sstas _krb5_usage2arcfour(context, &keyusage); 421127811Snectar } else 422127811Snectar keyusage = CHECKSUM_USAGE(usage); 423127811Snectar 424127811Snectar return create_checksum(context, ct, crypto, keyusage, 425127811Snectar data, len, result); 42655682Smarkm} 42755682Smarkm 42855682Smarkmstatic krb5_error_code 42955682Smarkmverify_checksum(krb5_context context, 43055682Smarkm krb5_crypto crypto, 43155682Smarkm unsigned usage, /* not krb5_key_usage */ 43255682Smarkm void *data, 43355682Smarkm size_t len, 43455682Smarkm Checksum *cksum) 43555682Smarkm{ 43655682Smarkm krb5_error_code ret; 437233294Sstas struct _krb5_key_data *dkey; 43855682Smarkm int keyed_checksum; 43955682Smarkm Checksum c; 440233294Sstas struct _krb5_checksum_type *ct; 44155682Smarkm 442233294Sstas ct = _krb5_find_checksum(cksum->cksumtype); 443178828Sdfr if (ct == NULL || (ct->flags & F_DISABLED)) { 444233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 445233294Sstas N_("checksum type %d not supported", ""), 446233294Sstas cksum->cksumtype); 44755682Smarkm return KRB5_PROG_SUMTYPE_NOSUPP; 44878536Sassar } 44978536Sassar if(ct->checksumsize != cksum->checksum.length) { 450233294Sstas krb5_clear_error_message (context); 451233294Sstas krb5_set_error_message(context, KRB5KRB_AP_ERR_BAD_INTEGRITY, 452233294Sstas N_("Decrypt integrity check failed for checksum type %s, " 453233294Sstas "length was %u, expected %u", ""), 454233294Sstas ct->name, (unsigned)cksum->checksum.length, 455233294Sstas (unsigned)ct->checksumsize); 456233294Sstas 45755682Smarkm return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */ 45878536Sassar } 45955682Smarkm keyed_checksum = (ct->flags & F_KEYED) != 0; 460233294Sstas if(keyed_checksum) { 461233294Sstas struct _krb5_checksum_type *kct; 462233294Sstas if (crypto == NULL) { 463233294Sstas krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP, 464233294Sstas N_("Checksum type %s is keyed but no " 465233294Sstas "crypto context (key) was passed in", ""), 466233294Sstas ct->name); 467233294Sstas return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ 468233294Sstas } 469233294Sstas kct = crypto->et->keyed_checksum; 470234027Sstas if (kct == NULL || kct->type != ct->type) { 471233294Sstas krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP, 472233294Sstas N_("Checksum type %s is keyed, but " 473233294Sstas "the key type %s passed didnt have that checksum " 474233294Sstas "type as the keyed type", ""), 475233294Sstas ct->name, crypto->et->name); 476233294Sstas return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ 477233294Sstas } 478233294Sstas 47955682Smarkm ret = get_checksum_key(context, crypto, usage, ct, &dkey); 480233294Sstas if (ret) 481233294Sstas return ret; 482233294Sstas } else 48355682Smarkm dkey = NULL; 48455682Smarkm 485233294Sstas /* 486233294Sstas * If checksum have a verify function, lets use that instead of 487233294Sstas * calling ->checksum and then compare result. 488233294Sstas */ 489233294Sstas 490233294Sstas if(ct->verify) { 491233294Sstas ret = (*ct->verify)(context, dkey, data, len, usage, cksum); 492233294Sstas if (ret) 493233294Sstas krb5_set_error_message(context, ret, 494233294Sstas N_("Decrypt integrity check failed for checksum " 495233294Sstas "type %s, key type %s", ""), 496233294Sstas ct->name, (crypto != NULL)? crypto->et->name : "(none)"); 497233294Sstas return ret; 498233294Sstas } 499233294Sstas 50055682Smarkm ret = krb5_data_alloc (&c.checksum, ct->checksumsize); 50155682Smarkm if (ret) 50255682Smarkm return ret; 50355682Smarkm 504233294Sstas ret = (*ct->checksum)(context, dkey, data, len, usage, &c); 505233294Sstas if (ret) { 506233294Sstas krb5_data_free(&c.checksum); 507233294Sstas return ret; 508233294Sstas } 50955682Smarkm 510233294Sstas if(krb5_data_ct_cmp(&c.checksum, &cksum->checksum) != 0) { 51155682Smarkm ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; 512233294Sstas krb5_set_error_message(context, ret, 513233294Sstas N_("Decrypt integrity check failed for checksum " 514233294Sstas "type %s, key type %s", ""), 515233294Sstas ct->name, crypto ? crypto->et->name : "(unkeyed)"); 51678536Sassar } else { 51755682Smarkm ret = 0; 51878536Sassar } 51955682Smarkm krb5_data_free (&c.checksum); 52055682Smarkm return ret; 52155682Smarkm} 52255682Smarkm 523233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 52455682Smarkmkrb5_verify_checksum(krb5_context context, 52555682Smarkm krb5_crypto crypto, 526233294Sstas krb5_key_usage usage, 52755682Smarkm void *data, 52855682Smarkm size_t len, 52955682Smarkm Checksum *cksum) 53055682Smarkm{ 531233294Sstas struct _krb5_checksum_type *ct; 532127811Snectar unsigned keyusage; 533127811Snectar 534233294Sstas ct = _krb5_find_checksum(cksum->cksumtype); 535127811Snectar if(ct == NULL) { 536233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 537233294Sstas N_("checksum type %d not supported", ""), 538233294Sstas cksum->cksumtype); 539127811Snectar return KRB5_PROG_SUMTYPE_NOSUPP; 540127811Snectar } 541127811Snectar 542127811Snectar if (arcfour_checksum_p(ct, crypto)) { 543127811Snectar keyusage = usage; 544233294Sstas _krb5_usage2arcfour(context, &keyusage); 545127811Snectar } else 546127811Snectar keyusage = CHECKSUM_USAGE(usage); 547127811Snectar 548127811Snectar return verify_checksum(context, crypto, keyusage, 549127811Snectar data, len, cksum); 55055682Smarkm} 55155682Smarkm 552233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 553178828Sdfrkrb5_crypto_get_checksum_type(krb5_context context, 554178828Sdfr krb5_crypto crypto, 555178828Sdfr krb5_cksumtype *type) 556178828Sdfr{ 557233294Sstas struct _krb5_checksum_type *ct = NULL; 558233294Sstas 559178828Sdfr if (crypto != NULL) { 560178828Sdfr ct = crypto->et->keyed_checksum; 561178828Sdfr if (ct == NULL) 562178828Sdfr ct = crypto->et->checksum; 563178828Sdfr } 564233294Sstas 565178828Sdfr if (ct == NULL) { 566233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 567233294Sstas N_("checksum type not found", "")); 568178828Sdfr return KRB5_PROG_SUMTYPE_NOSUPP; 569233294Sstas } 570178828Sdfr 571178828Sdfr *type = ct->type; 572233294Sstas 573233294Sstas return 0; 574178828Sdfr} 575178828Sdfr 576178828Sdfr 577233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 57855682Smarkmkrb5_checksumsize(krb5_context context, 57955682Smarkm krb5_cksumtype type, 58055682Smarkm size_t *size) 58155682Smarkm{ 582233294Sstas struct _krb5_checksum_type *ct = _krb5_find_checksum(type); 58378536Sassar if(ct == NULL) { 584233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 585233294Sstas N_("checksum type %d not supported", ""), 586233294Sstas type); 58755682Smarkm return KRB5_PROG_SUMTYPE_NOSUPP; 58878536Sassar } 58955682Smarkm *size = ct->checksumsize; 59055682Smarkm return 0; 59155682Smarkm} 59255682Smarkm 593233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 59455682Smarkmkrb5_checksum_is_keyed(krb5_context context, 59555682Smarkm krb5_cksumtype type) 59655682Smarkm{ 597233294Sstas struct _krb5_checksum_type *ct = _krb5_find_checksum(type); 59878536Sassar if(ct == NULL) { 599178828Sdfr if (context) 600233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 601233294Sstas N_("checksum type %d not supported", ""), 602233294Sstas type); 60355682Smarkm return KRB5_PROG_SUMTYPE_NOSUPP; 60478536Sassar } 60555682Smarkm return ct->flags & F_KEYED; 60655682Smarkm} 60755682Smarkm 608233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 60955682Smarkmkrb5_checksum_is_collision_proof(krb5_context context, 61055682Smarkm krb5_cksumtype type) 61155682Smarkm{ 612233294Sstas struct _krb5_checksum_type *ct = _krb5_find_checksum(type); 61378536Sassar if(ct == NULL) { 614178828Sdfr if (context) 615233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 616233294Sstas N_("checksum type %d not supported", ""), 617233294Sstas type); 61855682Smarkm return KRB5_PROG_SUMTYPE_NOSUPP; 61978536Sassar } 62055682Smarkm return ct->flags & F_CPROOF; 62155682Smarkm} 62255682Smarkm 623233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 624178828Sdfrkrb5_checksum_disable(krb5_context context, 625178828Sdfr krb5_cksumtype type) 626178828Sdfr{ 627233294Sstas struct _krb5_checksum_type *ct = _krb5_find_checksum(type); 628178828Sdfr if(ct == NULL) { 629178828Sdfr if (context) 630233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 631233294Sstas N_("checksum type %d not supported", ""), 632233294Sstas type); 633178828Sdfr return KRB5_PROG_SUMTYPE_NOSUPP; 634178828Sdfr } 635178828Sdfr ct->flags |= F_DISABLED; 636178828Sdfr return 0; 637178828Sdfr} 638178828Sdfr 63955682Smarkm/************************************************************ 64055682Smarkm * * 64155682Smarkm ************************************************************/ 64255682Smarkm 643233294Sstasstruct _krb5_encryption_type * 644233294Sstas_krb5_find_enctype(krb5_enctype type) 64555682Smarkm{ 646120948Snectar int i; 647233294Sstas for(i = 0; i < _krb5_num_etypes; i++) 648233294Sstas if(_krb5_etypes[i]->type == type) 649233294Sstas return _krb5_etypes[i]; 65055682Smarkm return NULL; 65155682Smarkm} 65255682Smarkm 65355682Smarkm 654233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 65555682Smarkmkrb5_enctype_to_string(krb5_context context, 65655682Smarkm krb5_enctype etype, 65755682Smarkm char **string) 65855682Smarkm{ 659233294Sstas struct _krb5_encryption_type *e; 660233294Sstas e = _krb5_find_enctype(etype); 66178536Sassar if(e == NULL) { 662233294Sstas krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, 663233294Sstas N_("encryption type %d not supported", ""), 664233294Sstas etype); 665178828Sdfr *string = NULL; 66655682Smarkm return KRB5_PROG_ETYPE_NOSUPP; 66778536Sassar } 66855682Smarkm *string = strdup(e->name); 66978536Sassar if(*string == NULL) { 670233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 67155682Smarkm return ENOMEM; 67278536Sassar } 67355682Smarkm return 0; 67455682Smarkm} 67555682Smarkm 676233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 67755682Smarkmkrb5_string_to_enctype(krb5_context context, 67855682Smarkm const char *string, 67955682Smarkm krb5_enctype *etype) 68055682Smarkm{ 68155682Smarkm int i; 682233294Sstas for(i = 0; i < _krb5_num_etypes; i++) 683233294Sstas if(strcasecmp(_krb5_etypes[i]->name, string) == 0){ 684233294Sstas *etype = _krb5_etypes[i]->type; 68555682Smarkm return 0; 68655682Smarkm } 687233294Sstas krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, 688233294Sstas N_("encryption type %s not supported", ""), 689233294Sstas string); 69055682Smarkm return KRB5_PROG_ETYPE_NOSUPP; 69155682Smarkm} 69255682Smarkm 693233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 69455682Smarkmkrb5_enctype_to_keytype(krb5_context context, 69555682Smarkm krb5_enctype etype, 69655682Smarkm krb5_keytype *keytype) 69755682Smarkm{ 698233294Sstas struct _krb5_encryption_type *e = _krb5_find_enctype(etype); 69978536Sassar if(e == NULL) { 700233294Sstas return unsupported_enctype (context, etype); 70178536Sassar } 70255682Smarkm *keytype = e->keytype->type; /* XXX */ 70355682Smarkm return 0; 70455682Smarkm} 70555682Smarkm 706233294Sstas/** 707233294Sstas * Check if a enctype is valid, return 0 if it is. 708233294Sstas * 709233294Sstas * @param context Kerberos context 710233294Sstas * @param etype enctype to check if its valid or not 711233294Sstas * 712233294Sstas * @return Return an error code for an failure or 0 on success (enctype valid). 713233294Sstas * @ingroup krb5_crypto 714233294Sstas */ 715233294Sstas 716233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 717233294Sstaskrb5_enctype_valid(krb5_context context, 718233294Sstas krb5_enctype etype) 71955682Smarkm{ 720233294Sstas struct _krb5_encryption_type *e = _krb5_find_enctype(etype); 721233294Sstas if(e && (e->flags & F_DISABLED) == 0) 722233294Sstas return 0; 723233294Sstas if (context == NULL) 724233294Sstas return KRB5_PROG_ETYPE_NOSUPP; 725233294Sstas if(e == NULL) { 726233294Sstas return unsupported_enctype (context, etype); 72755682Smarkm } 728233294Sstas /* Must be (e->flags & F_DISABLED) */ 729233294Sstas krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, 730233294Sstas N_("encryption type %s is disabled", ""), 731233294Sstas e->name); 732233294Sstas return KRB5_PROG_ETYPE_NOSUPP; 73355682Smarkm} 73455682Smarkm 735233294Sstas/** 736233294Sstas * Return the coresponding encryption type for a checksum type. 737233294Sstas * 738233294Sstas * @param context Kerberos context 739233294Sstas * @param ctype The checksum type to get the result enctype for 740233294Sstas * @param etype The returned encryption, when the matching etype is 741233294Sstas * not found, etype is set to ETYPE_NULL. 742233294Sstas * 743233294Sstas * @return Return an error code for an failure or 0 on success. 744233294Sstas * @ingroup krb5_crypto 74555682Smarkm */ 74655682Smarkm 747233294Sstas 748233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 749233294Sstaskrb5_cksumtype_to_enctype(krb5_context context, 750233294Sstas krb5_cksumtype ctype, 751233294Sstas krb5_enctype *etype) 75255682Smarkm{ 753233294Sstas int i; 75455682Smarkm 755233294Sstas *etype = ETYPE_NULL; 75655682Smarkm 757233294Sstas for(i = 0; i < _krb5_num_etypes; i++) { 758233294Sstas if(_krb5_etypes[i]->keyed_checksum && 759233294Sstas _krb5_etypes[i]->keyed_checksum->type == ctype) 760233294Sstas { 761233294Sstas *etype = _krb5_etypes[i]->type; 762233294Sstas return 0; 763233294Sstas } 76478536Sassar } 76555682Smarkm 766233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 767233294Sstas N_("checksum type %d not supported", ""), 768233294Sstas (int)ctype); 769233294Sstas return KRB5_PROG_SUMTYPE_NOSUPP; 77055682Smarkm} 77155682Smarkm 772233294Sstas 773233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 774233294Sstaskrb5_cksumtype_valid(krb5_context context, 775178828Sdfr krb5_cksumtype ctype) 776178828Sdfr{ 777233294Sstas struct _krb5_checksum_type *c = _krb5_find_checksum(ctype); 778178828Sdfr if (c == NULL) { 779233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 780233294Sstas N_("checksum type %d not supported", ""), 781233294Sstas ctype); 782178828Sdfr return KRB5_PROG_SUMTYPE_NOSUPP; 783178828Sdfr } 784178828Sdfr if (c->flags & F_DISABLED) { 785233294Sstas krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, 786233294Sstas N_("checksum type %s is disabled", ""), 787233294Sstas c->name); 788178828Sdfr return KRB5_PROG_SUMTYPE_NOSUPP; 789178828Sdfr } 790178828Sdfr return 0; 791178828Sdfr} 792178828Sdfr 793178828Sdfr 79455682Smarkmstatic krb5_boolean 79555682Smarkmderived_crypto(krb5_context context, 79655682Smarkm krb5_crypto crypto) 79755682Smarkm{ 79855682Smarkm return (crypto->et->flags & F_DERIVED) != 0; 79955682Smarkm} 80055682Smarkm 80172448Sassarstatic krb5_boolean 80272448Sassarspecial_crypto(krb5_context context, 80372448Sassar krb5_crypto crypto) 80472448Sassar{ 80572448Sassar return (crypto->et->flags & F_SPECIAL) != 0; 80672448Sassar} 80755682Smarkm 80855682Smarkm#define CHECKSUMSIZE(C) ((C)->checksumsize) 80955682Smarkm#define CHECKSUMTYPE(C) ((C)->type) 81055682Smarkm 81155682Smarkmstatic krb5_error_code 81255682Smarkmencrypt_internal_derived(krb5_context context, 81355682Smarkm krb5_crypto crypto, 81455682Smarkm unsigned usage, 815178828Sdfr const void *data, 81655682Smarkm size_t len, 81772448Sassar krb5_data *result, 81872448Sassar void *ivec) 81955682Smarkm{ 82090929Snectar size_t sz, block_sz, checksum_sz, total_sz; 82155682Smarkm Checksum cksum; 82255682Smarkm unsigned char *p, *q; 82355682Smarkm krb5_error_code ret; 824233294Sstas struct _krb5_key_data *dkey; 825233294Sstas const struct _krb5_encryption_type *et = crypto->et; 826233294Sstas 82755682Smarkm checksum_sz = CHECKSUMSIZE(et->keyed_checksum); 82855682Smarkm 82990929Snectar sz = et->confoundersize + len; 830120948Snectar block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ 83190929Snectar total_sz = block_sz + checksum_sz; 83290929Snectar p = calloc(1, total_sz); 83390929Snectar if(p == NULL) { 834233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 83555682Smarkm return ENOMEM; 83690929Snectar } 837233294Sstas 83855682Smarkm q = p; 83955682Smarkm krb5_generate_random_block(q, et->confoundersize); /* XXX */ 84055682Smarkm q += et->confoundersize; 84155682Smarkm memcpy(q, data, len); 842233294Sstas 843233294Sstas ret = create_checksum(context, 844127811Snectar et->keyed_checksum, 845233294Sstas crypto, 84655682Smarkm INTEGRITY_USAGE(usage), 847233294Sstas p, 84855682Smarkm block_sz, 84955682Smarkm &cksum); 85072448Sassar if(ret == 0 && cksum.checksum.length != checksum_sz) { 85172448Sassar free_Checksum (&cksum); 852233294Sstas krb5_clear_error_message (context); 85372448Sassar ret = KRB5_CRYPTO_INTERNAL; 85472448Sassar } 85590929Snectar if(ret) 85690929Snectar goto fail; 85755682Smarkm memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length); 85872448Sassar free_Checksum (&cksum); 85955682Smarkm ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); 86090929Snectar if(ret) 86190929Snectar goto fail; 86255682Smarkm ret = _key_schedule(context, dkey); 86390929Snectar if(ret) 86490929Snectar goto fail; 86590929Snectar ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec); 86690929Snectar if (ret) 86790929Snectar goto fail; 86855682Smarkm result->data = p; 86990929Snectar result->length = total_sz; 87055682Smarkm return 0; 87190929Snectar fail: 87290929Snectar memset(p, 0, total_sz); 87390929Snectar free(p); 87490929Snectar return ret; 87555682Smarkm} 87655682Smarkm 87790929Snectar 87855682Smarkmstatic krb5_error_code 87955682Smarkmencrypt_internal(krb5_context context, 88055682Smarkm krb5_crypto crypto, 881178828Sdfr const void *data, 88255682Smarkm size_t len, 88372448Sassar krb5_data *result, 88472448Sassar void *ivec) 88555682Smarkm{ 88655682Smarkm size_t sz, block_sz, checksum_sz; 88755682Smarkm Checksum cksum; 88855682Smarkm unsigned char *p, *q; 88955682Smarkm krb5_error_code ret; 890233294Sstas const struct _krb5_encryption_type *et = crypto->et; 891233294Sstas 89278536Sassar checksum_sz = CHECKSUMSIZE(et->checksum); 893233294Sstas 89455682Smarkm sz = et->confoundersize + checksum_sz + len; 895120948Snectar block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ 89655682Smarkm p = calloc(1, block_sz); 89778536Sassar if(p == NULL) { 898233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 89955682Smarkm return ENOMEM; 90078536Sassar } 901233294Sstas 90255682Smarkm q = p; 90355682Smarkm krb5_generate_random_block(q, et->confoundersize); /* XXX */ 90455682Smarkm q += et->confoundersize; 90555682Smarkm memset(q, 0, checksum_sz); 90655682Smarkm q += checksum_sz; 90755682Smarkm memcpy(q, data, len); 90855682Smarkm 909233294Sstas ret = create_checksum(context, 910127811Snectar et->checksum, 91178536Sassar crypto, 91255682Smarkm 0, 913233294Sstas p, 91455682Smarkm block_sz, 91555682Smarkm &cksum); 91655682Smarkm if(ret == 0 && cksum.checksum.length != checksum_sz) { 917233294Sstas krb5_clear_error_message (context); 91890929Snectar free_Checksum(&cksum); 91955682Smarkm ret = KRB5_CRYPTO_INTERNAL; 92055682Smarkm } 92190929Snectar if(ret) 92290929Snectar goto fail; 92355682Smarkm memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length); 92455682Smarkm free_Checksum(&cksum); 92555682Smarkm ret = _key_schedule(context, &crypto->key); 92690929Snectar if(ret) 92790929Snectar goto fail; 92890929Snectar ret = (*et->encrypt)(context, &crypto->key, p, block_sz, 1, 0, ivec); 92990929Snectar if (ret) { 93055682Smarkm memset(p, 0, block_sz); 93155682Smarkm free(p); 93255682Smarkm return ret; 93355682Smarkm } 93455682Smarkm result->data = p; 93555682Smarkm result->length = block_sz; 93655682Smarkm return 0; 93790929Snectar fail: 93890929Snectar memset(p, 0, block_sz); 93990929Snectar free(p); 94090929Snectar return ret; 94155682Smarkm} 94255682Smarkm 94355682Smarkmstatic krb5_error_code 94472448Sassarencrypt_internal_special(krb5_context context, 94572448Sassar krb5_crypto crypto, 94672448Sassar int usage, 947178828Sdfr const void *data, 94872448Sassar size_t len, 94972448Sassar krb5_data *result, 95072448Sassar void *ivec) 95172448Sassar{ 952233294Sstas struct _krb5_encryption_type *et = crypto->et; 95378536Sassar size_t cksum_sz = CHECKSUMSIZE(et->checksum); 95472448Sassar size_t sz = len + cksum_sz + et->confoundersize; 95572448Sassar char *tmp, *p; 95690929Snectar krb5_error_code ret; 95772448Sassar 95872448Sassar tmp = malloc (sz); 95978536Sassar if (tmp == NULL) { 960233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 96172448Sassar return ENOMEM; 96278536Sassar } 96372448Sassar p = tmp; 96472448Sassar memset (p, 0, cksum_sz); 96572448Sassar p += cksum_sz; 96672448Sassar krb5_generate_random_block(p, et->confoundersize); 96772448Sassar p += et->confoundersize; 96872448Sassar memcpy (p, data, len); 96990929Snectar ret = (*et->encrypt)(context, &crypto->key, tmp, sz, TRUE, usage, ivec); 97090929Snectar if (ret) { 97190929Snectar memset(tmp, 0, sz); 97290929Snectar free(tmp); 97390929Snectar return ret; 97490929Snectar } 97572448Sassar result->data = tmp; 97672448Sassar result->length = sz; 97772448Sassar return 0; 97872448Sassar} 97972448Sassar 98072448Sassarstatic krb5_error_code 98155682Smarkmdecrypt_internal_derived(krb5_context context, 98255682Smarkm krb5_crypto crypto, 98355682Smarkm unsigned usage, 98455682Smarkm void *data, 98555682Smarkm size_t len, 98672448Sassar krb5_data *result, 98772448Sassar void *ivec) 98855682Smarkm{ 98955682Smarkm size_t checksum_sz; 99055682Smarkm Checksum cksum; 99155682Smarkm unsigned char *p; 99255682Smarkm krb5_error_code ret; 993233294Sstas struct _krb5_key_data *dkey; 994233294Sstas struct _krb5_encryption_type *et = crypto->et; 99555682Smarkm unsigned long l; 996233294Sstas 99772448Sassar checksum_sz = CHECKSUMSIZE(et->keyed_checksum); 998178828Sdfr if (len < checksum_sz + et->confoundersize) { 999233294Sstas krb5_set_error_message(context, KRB5_BAD_MSIZE, 1000233294Sstas N_("Encrypted data shorter then " 1001233294Sstas "checksum + confunder", "")); 1002178828Sdfr return KRB5_BAD_MSIZE; 100378536Sassar } 100472448Sassar 1005127811Snectar if (((len - checksum_sz) % et->padsize) != 0) { 1006233294Sstas krb5_clear_error_message(context); 1007127811Snectar return KRB5_BAD_MSIZE; 1008127811Snectar } 1009127811Snectar 101055682Smarkm p = malloc(len); 101178536Sassar if(len != 0 && p == NULL) { 1012233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 101355682Smarkm return ENOMEM; 101478536Sassar } 101555682Smarkm memcpy(p, data, len); 101655682Smarkm 101755682Smarkm len -= checksum_sz; 101855682Smarkm 101955682Smarkm ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); 102055682Smarkm if(ret) { 102155682Smarkm free(p); 102255682Smarkm return ret; 102355682Smarkm } 102455682Smarkm ret = _key_schedule(context, dkey); 102555682Smarkm if(ret) { 102655682Smarkm free(p); 102755682Smarkm return ret; 102855682Smarkm } 102990929Snectar ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec); 103090929Snectar if (ret) { 103190929Snectar free(p); 103290929Snectar return ret; 103390929Snectar } 103455682Smarkm 103555682Smarkm cksum.checksum.data = p + len; 103655682Smarkm cksum.checksum.length = checksum_sz; 103755682Smarkm cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); 103855682Smarkm 103955682Smarkm ret = verify_checksum(context, 104055682Smarkm crypto, 104155682Smarkm INTEGRITY_USAGE(usage), 104255682Smarkm p, 104355682Smarkm len, 104455682Smarkm &cksum); 104555682Smarkm if(ret) { 104655682Smarkm free(p); 104755682Smarkm return ret; 104855682Smarkm } 104955682Smarkm l = len - et->confoundersize; 105055682Smarkm memmove(p, p + et->confoundersize, l); 105155682Smarkm result->data = realloc(p, l); 1052178828Sdfr if(result->data == NULL && l != 0) { 105355682Smarkm free(p); 1054233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 105555682Smarkm return ENOMEM; 105655682Smarkm } 105755682Smarkm result->length = l; 105855682Smarkm return 0; 105955682Smarkm} 106055682Smarkm 106155682Smarkmstatic krb5_error_code 106255682Smarkmdecrypt_internal(krb5_context context, 106355682Smarkm krb5_crypto crypto, 106455682Smarkm void *data, 106555682Smarkm size_t len, 106672448Sassar krb5_data *result, 106772448Sassar void *ivec) 106855682Smarkm{ 106955682Smarkm krb5_error_code ret; 107055682Smarkm unsigned char *p; 107155682Smarkm Checksum cksum; 107255682Smarkm size_t checksum_sz, l; 1073233294Sstas struct _krb5_encryption_type *et = crypto->et; 1074233294Sstas 1075127811Snectar if ((len % et->padsize) != 0) { 1076233294Sstas krb5_clear_error_message(context); 1077127811Snectar return KRB5_BAD_MSIZE; 1078127811Snectar } 1079233294Sstas checksum_sz = CHECKSUMSIZE(et->checksum); 1080233294Sstas if (len < checksum_sz + et->confoundersize) { 1081233294Sstas krb5_set_error_message(context, KRB5_BAD_MSIZE, 1082233294Sstas N_("Encrypted data shorter then " 1083233294Sstas "checksum + confunder", "")); 1084233294Sstas return KRB5_BAD_MSIZE; 1085233294Sstas } 1086127811Snectar 108755682Smarkm p = malloc(len); 108878536Sassar if(len != 0 && p == NULL) { 1089233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 109055682Smarkm return ENOMEM; 109178536Sassar } 109255682Smarkm memcpy(p, data, len); 1093233294Sstas 109455682Smarkm ret = _key_schedule(context, &crypto->key); 109555682Smarkm if(ret) { 109655682Smarkm free(p); 109755682Smarkm return ret; 109855682Smarkm } 109990929Snectar ret = (*et->encrypt)(context, &crypto->key, p, len, 0, 0, ivec); 110090929Snectar if (ret) { 110190929Snectar free(p); 110290929Snectar return ret; 110390929Snectar } 110455682Smarkm ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz); 110555682Smarkm if(ret) { 110672448Sassar free(p); 110772448Sassar return ret; 110855682Smarkm } 110955682Smarkm memset(p + et->confoundersize, 0, checksum_sz); 111078536Sassar cksum.cksumtype = CHECKSUMTYPE(et->checksum); 111155682Smarkm ret = verify_checksum(context, NULL, 0, p, len, &cksum); 111255682Smarkm free_Checksum(&cksum); 111355682Smarkm if(ret) { 111455682Smarkm free(p); 111555682Smarkm return ret; 111655682Smarkm } 111755682Smarkm l = len - et->confoundersize - checksum_sz; 111855682Smarkm memmove(p, p + et->confoundersize + checksum_sz, l); 111955682Smarkm result->data = realloc(p, l); 1120178828Sdfr if(result->data == NULL && l != 0) { 112155682Smarkm free(p); 1122233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 112355682Smarkm return ENOMEM; 112455682Smarkm } 112555682Smarkm result->length = l; 112655682Smarkm return 0; 112755682Smarkm} 112855682Smarkm 112972448Sassarstatic krb5_error_code 113072448Sassardecrypt_internal_special(krb5_context context, 113172448Sassar krb5_crypto crypto, 113272448Sassar int usage, 113372448Sassar void *data, 113472448Sassar size_t len, 113572448Sassar krb5_data *result, 113672448Sassar void *ivec) 113772448Sassar{ 1138233294Sstas struct _krb5_encryption_type *et = crypto->et; 113978536Sassar size_t cksum_sz = CHECKSUMSIZE(et->checksum); 114072448Sassar size_t sz = len - cksum_sz - et->confoundersize; 1141127811Snectar unsigned char *p; 114290929Snectar krb5_error_code ret; 114372448Sassar 1144127811Snectar if ((len % et->padsize) != 0) { 1145233294Sstas krb5_clear_error_message(context); 1146127811Snectar return KRB5_BAD_MSIZE; 1147127811Snectar } 1148233294Sstas if (len < cksum_sz + et->confoundersize) { 1149233294Sstas krb5_set_error_message(context, KRB5_BAD_MSIZE, 1150233294Sstas N_("Encrypted data shorter then " 1151233294Sstas "checksum + confunder", "")); 1152233294Sstas return KRB5_BAD_MSIZE; 1153233294Sstas } 1154127811Snectar 1155127811Snectar p = malloc (len); 1156127811Snectar if (p == NULL) { 1157233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 115872448Sassar return ENOMEM; 115978536Sassar } 1160127811Snectar memcpy(p, data, len); 1161233294Sstas 1162127811Snectar ret = (*et->encrypt)(context, &crypto->key, p, len, FALSE, usage, ivec); 116390929Snectar if (ret) { 1164127811Snectar free(p); 116590929Snectar return ret; 116690929Snectar } 116772448Sassar 1168127811Snectar memmove (p, p + cksum_sz + et->confoundersize, sz); 1169127811Snectar result->data = realloc(p, sz); 1170178828Sdfr if(result->data == NULL && sz != 0) { 1171127811Snectar free(p); 1172233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1173127811Snectar return ENOMEM; 1174127811Snectar } 117572448Sassar result->length = sz; 117672448Sassar return 0; 117772448Sassar} 117872448Sassar 1179233294Sstasstatic krb5_crypto_iov * 1180233294Sstasfind_iv(krb5_crypto_iov *data, size_t num_data, unsigned type) 1181233294Sstas{ 1182233294Sstas size_t i; 1183233294Sstas for (i = 0; i < num_data; i++) 1184233294Sstas if (data[i].flags == type) 1185233294Sstas return &data[i]; 1186233294Sstas return NULL; 1187233294Sstas} 118872448Sassar 1189233294Sstas/** 1190233294Sstas * Inline encrypt a kerberos message 1191233294Sstas * 1192233294Sstas * @param context Kerberos context 1193233294Sstas * @param crypto Kerberos crypto context 1194233294Sstas * @param usage Key usage for this buffer 1195233294Sstas * @param data array of buffers to process 1196233294Sstas * @param num_data length of array 1197233294Sstas * @param ivec initial cbc/cts vector 1198233294Sstas * 1199233294Sstas * @return Return an error code or 0. 1200233294Sstas * @ingroup krb5_crypto 1201233294Sstas * 1202233294Sstas * Kerberos encrypted data look like this: 1203233294Sstas * 1204233294Sstas * 1. KRB5_CRYPTO_TYPE_HEADER 1205233294Sstas * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...] 1206233294Sstas * KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver 1207233294Sstas * have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is 1208233294Sstas * commonly used headers and trailers. 1209233294Sstas * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1 1210233294Sstas * 4. KRB5_CRYPTO_TYPE_TRAILER 1211233294Sstas */ 1212233294Sstas 1213233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1214233294Sstaskrb5_encrypt_iov_ivec(krb5_context context, 1215233294Sstas krb5_crypto crypto, 1216233294Sstas unsigned usage, 1217233294Sstas krb5_crypto_iov *data, 1218233294Sstas int num_data, 1219233294Sstas void *ivec) 1220233294Sstas{ 1221233294Sstas size_t headersz, trailersz, len; 1222233294Sstas int i; 1223233294Sstas size_t sz, block_sz, pad_sz; 1224233294Sstas Checksum cksum; 1225233294Sstas unsigned char *p, *q; 1226233294Sstas krb5_error_code ret; 1227233294Sstas struct _krb5_key_data *dkey; 1228233294Sstas const struct _krb5_encryption_type *et = crypto->et; 1229233294Sstas krb5_crypto_iov *tiv, *piv, *hiv; 1230233294Sstas 1231233294Sstas if (num_data < 0) { 1232233294Sstas krb5_clear_error_message(context); 1233233294Sstas return KRB5_CRYPTO_INTERNAL; 1234233294Sstas } 1235233294Sstas 1236233294Sstas if(!derived_crypto(context, crypto)) { 1237233294Sstas krb5_clear_error_message(context); 1238233294Sstas return KRB5_CRYPTO_INTERNAL; 1239233294Sstas } 1240233294Sstas 1241233294Sstas headersz = et->confoundersize; 1242233294Sstas trailersz = CHECKSUMSIZE(et->keyed_checksum); 1243233294Sstas 1244233294Sstas for (len = 0, i = 0; i < num_data; i++) { 1245233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) 1246233294Sstas continue; 1247233294Sstas len += data[i].data.length; 1248233294Sstas } 1249233294Sstas 1250233294Sstas sz = headersz + len; 1251233294Sstas block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ 1252233294Sstas 1253233294Sstas pad_sz = block_sz - sz; 1254233294Sstas 1255233294Sstas /* header */ 1256233294Sstas 1257233294Sstas hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER); 1258233294Sstas if (hiv == NULL || hiv->data.length != headersz) 1259233294Sstas return KRB5_BAD_MSIZE; 1260233294Sstas 1261233294Sstas krb5_generate_random_block(hiv->data.data, hiv->data.length); 1262233294Sstas 1263233294Sstas /* padding */ 1264233294Sstas piv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_PADDING); 1265233294Sstas /* its ok to have no TYPE_PADDING if there is no padding */ 1266233294Sstas if (piv == NULL && pad_sz != 0) 1267233294Sstas return KRB5_BAD_MSIZE; 1268233294Sstas if (piv) { 1269233294Sstas if (piv->data.length < pad_sz) 1270233294Sstas return KRB5_BAD_MSIZE; 1271233294Sstas piv->data.length = pad_sz; 1272233294Sstas if (pad_sz) 1273233294Sstas memset(piv->data.data, pad_sz, pad_sz); 1274233294Sstas else 1275233294Sstas piv = NULL; 1276233294Sstas } 1277233294Sstas 1278233294Sstas /* trailer */ 1279233294Sstas tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); 1280233294Sstas if (tiv == NULL || tiv->data.length != trailersz) 1281233294Sstas return KRB5_BAD_MSIZE; 1282233294Sstas 1283233294Sstas /* 1284233294Sstas * XXX replace with EVP_Sign? at least make create_checksum an iov 1285233294Sstas * function. 1286233294Sstas * XXX CTS EVP is broken, can't handle multi buffers :( 1287233294Sstas */ 1288233294Sstas 1289233294Sstas len = block_sz; 1290233294Sstas for (i = 0; i < num_data; i++) { 1291233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1292233294Sstas continue; 1293233294Sstas len += data[i].data.length; 1294233294Sstas } 1295233294Sstas 1296233294Sstas p = q = malloc(len); 1297233294Sstas 1298233294Sstas memcpy(q, hiv->data.data, hiv->data.length); 1299233294Sstas q += hiv->data.length; 1300233294Sstas for (i = 0; i < num_data; i++) { 1301233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && 1302233294Sstas data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1303233294Sstas continue; 1304233294Sstas memcpy(q, data[i].data.data, data[i].data.length); 1305233294Sstas q += data[i].data.length; 1306233294Sstas } 1307233294Sstas if (piv) 1308233294Sstas memset(q, 0, piv->data.length); 1309233294Sstas 1310233294Sstas ret = create_checksum(context, 1311233294Sstas et->keyed_checksum, 1312233294Sstas crypto, 1313233294Sstas INTEGRITY_USAGE(usage), 1314233294Sstas p, 1315233294Sstas len, 1316233294Sstas &cksum); 1317233294Sstas free(p); 1318233294Sstas if(ret == 0 && cksum.checksum.length != trailersz) { 1319233294Sstas free_Checksum (&cksum); 1320233294Sstas krb5_clear_error_message (context); 1321233294Sstas ret = KRB5_CRYPTO_INTERNAL; 1322233294Sstas } 1323233294Sstas if(ret) 1324233294Sstas return ret; 1325233294Sstas 1326233294Sstas /* save cksum at end */ 1327233294Sstas memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length); 1328233294Sstas free_Checksum (&cksum); 1329233294Sstas 1330233294Sstas /* XXX replace with EVP_Cipher */ 1331233294Sstas p = q = malloc(block_sz); 1332233294Sstas if(p == NULL) 1333233294Sstas return ENOMEM; 1334233294Sstas 1335233294Sstas memcpy(q, hiv->data.data, hiv->data.length); 1336233294Sstas q += hiv->data.length; 1337233294Sstas 1338233294Sstas for (i = 0; i < num_data; i++) { 1339233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) 1340233294Sstas continue; 1341233294Sstas memcpy(q, data[i].data.data, data[i].data.length); 1342233294Sstas q += data[i].data.length; 1343233294Sstas } 1344233294Sstas if (piv) 1345233294Sstas memset(q, 0, piv->data.length); 1346233294Sstas 1347233294Sstas 1348233294Sstas ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); 1349233294Sstas if(ret) { 1350233294Sstas free(p); 1351233294Sstas return ret; 1352233294Sstas } 1353233294Sstas ret = _key_schedule(context, dkey); 1354233294Sstas if(ret) { 1355233294Sstas free(p); 1356233294Sstas return ret; 1357233294Sstas } 1358233294Sstas 1359233294Sstas ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec); 1360233294Sstas if (ret) { 1361233294Sstas free(p); 1362233294Sstas return ret; 1363233294Sstas } 1364233294Sstas 1365233294Sstas /* now copy data back to buffers */ 1366233294Sstas q = p; 1367233294Sstas 1368233294Sstas memcpy(hiv->data.data, q, hiv->data.length); 1369233294Sstas q += hiv->data.length; 1370233294Sstas 1371233294Sstas for (i = 0; i < num_data; i++) { 1372233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) 1373233294Sstas continue; 1374233294Sstas memcpy(data[i].data.data, q, data[i].data.length); 1375233294Sstas q += data[i].data.length; 1376233294Sstas } 1377233294Sstas if (piv) 1378233294Sstas memcpy(piv->data.data, q, pad_sz); 1379233294Sstas 1380233294Sstas free(p); 1381233294Sstas 1382233294Sstas return ret; 1383233294Sstas} 1384233294Sstas 1385233294Sstas/** 1386233294Sstas * Inline decrypt a Kerberos message. 1387233294Sstas * 1388233294Sstas * @param context Kerberos context 1389233294Sstas * @param crypto Kerberos crypto context 1390233294Sstas * @param usage Key usage for this buffer 1391233294Sstas * @param data array of buffers to process 1392233294Sstas * @param num_data length of array 1393233294Sstas * @param ivec initial cbc/cts vector 1394233294Sstas * 1395233294Sstas * @return Return an error code or 0. 1396233294Sstas * @ingroup krb5_crypto 1397233294Sstas * 1398233294Sstas * 1. KRB5_CRYPTO_TYPE_HEADER 1399233294Sstas * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in 1400233294Sstas * any order, however the receiver have to aware of the 1401233294Sstas * order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted 1402233294Sstas * protocol headers and trailers. The output data will be of same 1403233294Sstas * size as the input data or shorter. 1404233294Sstas */ 1405233294Sstas 1406233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1407233294Sstaskrb5_decrypt_iov_ivec(krb5_context context, 1408233294Sstas krb5_crypto crypto, 1409233294Sstas unsigned usage, 1410233294Sstas krb5_crypto_iov *data, 1411233294Sstas unsigned int num_data, 1412233294Sstas void *ivec) 1413233294Sstas{ 1414233294Sstas unsigned int i; 1415233294Sstas size_t headersz, trailersz, len; 1416233294Sstas Checksum cksum; 1417233294Sstas unsigned char *p, *q; 1418233294Sstas krb5_error_code ret; 1419233294Sstas struct _krb5_key_data *dkey; 1420233294Sstas struct _krb5_encryption_type *et = crypto->et; 1421233294Sstas krb5_crypto_iov *tiv, *hiv; 1422233294Sstas 1423233294Sstas if(!derived_crypto(context, crypto)) { 1424233294Sstas krb5_clear_error_message(context); 1425233294Sstas return KRB5_CRYPTO_INTERNAL; 1426233294Sstas } 1427233294Sstas 1428233294Sstas headersz = et->confoundersize; 1429233294Sstas 1430233294Sstas hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER); 1431233294Sstas if (hiv == NULL || hiv->data.length != headersz) 1432233294Sstas return KRB5_BAD_MSIZE; 1433233294Sstas 1434233294Sstas /* trailer */ 1435233294Sstas trailersz = CHECKSUMSIZE(et->keyed_checksum); 1436233294Sstas 1437233294Sstas tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); 1438233294Sstas if (tiv->data.length != trailersz) 1439233294Sstas return KRB5_BAD_MSIZE; 1440233294Sstas 1441233294Sstas /* Find length of data we will decrypt */ 1442233294Sstas 1443233294Sstas len = headersz; 1444233294Sstas for (i = 0; i < num_data; i++) { 1445233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) 1446233294Sstas continue; 1447233294Sstas len += data[i].data.length; 1448233294Sstas } 1449233294Sstas 1450233294Sstas if ((len % et->padsize) != 0) { 1451233294Sstas krb5_clear_error_message(context); 1452233294Sstas return KRB5_BAD_MSIZE; 1453233294Sstas } 1454233294Sstas 1455233294Sstas /* XXX replace with EVP_Cipher */ 1456233294Sstas 1457233294Sstas p = q = malloc(len); 1458233294Sstas if (p == NULL) 1459233294Sstas return ENOMEM; 1460233294Sstas 1461233294Sstas memcpy(q, hiv->data.data, hiv->data.length); 1462233294Sstas q += hiv->data.length; 1463233294Sstas 1464233294Sstas for (i = 0; i < num_data; i++) { 1465233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) 1466233294Sstas continue; 1467233294Sstas memcpy(q, data[i].data.data, data[i].data.length); 1468233294Sstas q += data[i].data.length; 1469233294Sstas } 1470233294Sstas 1471233294Sstas ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); 1472233294Sstas if(ret) { 1473233294Sstas free(p); 1474233294Sstas return ret; 1475233294Sstas } 1476233294Sstas ret = _key_schedule(context, dkey); 1477233294Sstas if(ret) { 1478233294Sstas free(p); 1479233294Sstas return ret; 1480233294Sstas } 1481233294Sstas 1482233294Sstas ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec); 1483233294Sstas if (ret) { 1484233294Sstas free(p); 1485233294Sstas return ret; 1486233294Sstas } 1487233294Sstas 1488233294Sstas /* copy data back to buffers */ 1489233294Sstas memcpy(hiv->data.data, p, hiv->data.length); 1490233294Sstas q = p + hiv->data.length; 1491233294Sstas for (i = 0; i < num_data; i++) { 1492233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) 1493233294Sstas continue; 1494233294Sstas memcpy(data[i].data.data, q, data[i].data.length); 1495233294Sstas q += data[i].data.length; 1496233294Sstas } 1497233294Sstas 1498233294Sstas free(p); 1499233294Sstas 1500233294Sstas /* check signature */ 1501233294Sstas for (i = 0; i < num_data; i++) { 1502233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1503233294Sstas continue; 1504233294Sstas len += data[i].data.length; 1505233294Sstas } 1506233294Sstas 1507233294Sstas p = q = malloc(len); 1508233294Sstas if (p == NULL) 1509233294Sstas return ENOMEM; 1510233294Sstas 1511233294Sstas memcpy(q, hiv->data.data, hiv->data.length); 1512233294Sstas q += hiv->data.length; 1513233294Sstas for (i = 0; i < num_data; i++) { 1514233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && 1515233294Sstas data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1516233294Sstas continue; 1517233294Sstas memcpy(q, data[i].data.data, data[i].data.length); 1518233294Sstas q += data[i].data.length; 1519233294Sstas } 1520233294Sstas 1521233294Sstas cksum.checksum.data = tiv->data.data; 1522233294Sstas cksum.checksum.length = tiv->data.length; 1523233294Sstas cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); 1524233294Sstas 1525233294Sstas ret = verify_checksum(context, 1526233294Sstas crypto, 1527233294Sstas INTEGRITY_USAGE(usage), 1528233294Sstas p, 1529233294Sstas len, 1530233294Sstas &cksum); 1531233294Sstas free(p); 1532233294Sstas return ret; 1533233294Sstas} 1534233294Sstas 1535233294Sstas/** 1536233294Sstas * Create a Kerberos message checksum. 1537233294Sstas * 1538233294Sstas * @param context Kerberos context 1539233294Sstas * @param crypto Kerberos crypto context 1540233294Sstas * @param usage Key usage for this buffer 1541233294Sstas * @param data array of buffers to process 1542233294Sstas * @param num_data length of array 1543233294Sstas * @param type output data 1544233294Sstas * 1545233294Sstas * @return Return an error code or 0. 1546233294Sstas * @ingroup krb5_crypto 1547233294Sstas */ 1548233294Sstas 1549233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1550233294Sstaskrb5_create_checksum_iov(krb5_context context, 1551233294Sstas krb5_crypto crypto, 1552233294Sstas unsigned usage, 1553233294Sstas krb5_crypto_iov *data, 1554233294Sstas unsigned int num_data, 1555233294Sstas krb5_cksumtype *type) 1556233294Sstas{ 1557233294Sstas Checksum cksum; 1558233294Sstas krb5_crypto_iov *civ; 1559233294Sstas krb5_error_code ret; 1560233294Sstas size_t i; 1561233294Sstas size_t len; 1562233294Sstas char *p, *q; 1563233294Sstas 1564233294Sstas if(!derived_crypto(context, crypto)) { 1565233294Sstas krb5_clear_error_message(context); 1566233294Sstas return KRB5_CRYPTO_INTERNAL; 1567233294Sstas } 1568233294Sstas 1569233294Sstas civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); 1570233294Sstas if (civ == NULL) 1571233294Sstas return KRB5_BAD_MSIZE; 1572233294Sstas 1573233294Sstas len = 0; 1574233294Sstas for (i = 0; i < num_data; i++) { 1575233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && 1576233294Sstas data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1577233294Sstas continue; 1578233294Sstas len += data[i].data.length; 1579233294Sstas } 1580233294Sstas 1581233294Sstas p = q = malloc(len); 1582233294Sstas 1583233294Sstas for (i = 0; i < num_data; i++) { 1584233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && 1585233294Sstas data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1586233294Sstas continue; 1587233294Sstas memcpy(q, data[i].data.data, data[i].data.length); 1588233294Sstas q += data[i].data.length; 1589233294Sstas } 1590233294Sstas 1591233294Sstas ret = krb5_create_checksum(context, crypto, usage, 0, p, len, &cksum); 1592233294Sstas free(p); 1593233294Sstas if (ret) 1594233294Sstas return ret; 1595233294Sstas 1596233294Sstas if (type) 1597233294Sstas *type = cksum.cksumtype; 1598233294Sstas 1599233294Sstas if (cksum.checksum.length > civ->data.length) { 1600233294Sstas krb5_set_error_message(context, KRB5_BAD_MSIZE, 1601233294Sstas N_("Checksum larger then input buffer", "")); 1602233294Sstas free_Checksum(&cksum); 1603233294Sstas return KRB5_BAD_MSIZE; 1604233294Sstas } 1605233294Sstas 1606233294Sstas civ->data.length = cksum.checksum.length; 1607233294Sstas memcpy(civ->data.data, cksum.checksum.data, civ->data.length); 1608233294Sstas free_Checksum(&cksum); 1609233294Sstas 1610233294Sstas return 0; 1611233294Sstas} 1612233294Sstas 1613233294Sstas/** 1614233294Sstas * Verify a Kerberos message checksum. 1615233294Sstas * 1616233294Sstas * @param context Kerberos context 1617233294Sstas * @param crypto Kerberos crypto context 1618233294Sstas * @param usage Key usage for this buffer 1619233294Sstas * @param data array of buffers to process 1620233294Sstas * @param num_data length of array 1621233294Sstas * @param type return checksum type if not NULL 1622233294Sstas * 1623233294Sstas * @return Return an error code or 0. 1624233294Sstas * @ingroup krb5_crypto 1625233294Sstas */ 1626233294Sstas 1627233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1628233294Sstaskrb5_verify_checksum_iov(krb5_context context, 1629233294Sstas krb5_crypto crypto, 1630233294Sstas unsigned usage, 1631233294Sstas krb5_crypto_iov *data, 1632233294Sstas unsigned int num_data, 1633233294Sstas krb5_cksumtype *type) 1634233294Sstas{ 1635233294Sstas struct _krb5_encryption_type *et = crypto->et; 1636233294Sstas Checksum cksum; 1637233294Sstas krb5_crypto_iov *civ; 1638233294Sstas krb5_error_code ret; 1639233294Sstas size_t i; 1640233294Sstas size_t len; 1641233294Sstas char *p, *q; 1642233294Sstas 1643233294Sstas if(!derived_crypto(context, crypto)) { 1644233294Sstas krb5_clear_error_message(context); 1645233294Sstas return KRB5_CRYPTO_INTERNAL; 1646233294Sstas } 1647233294Sstas 1648233294Sstas civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); 1649233294Sstas if (civ == NULL) 1650233294Sstas return KRB5_BAD_MSIZE; 1651233294Sstas 1652233294Sstas len = 0; 1653233294Sstas for (i = 0; i < num_data; i++) { 1654233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && 1655233294Sstas data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1656233294Sstas continue; 1657233294Sstas len += data[i].data.length; 1658233294Sstas } 1659233294Sstas 1660233294Sstas p = q = malloc(len); 1661233294Sstas 1662233294Sstas for (i = 0; i < num_data; i++) { 1663233294Sstas if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && 1664233294Sstas data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) 1665233294Sstas continue; 1666233294Sstas memcpy(q, data[i].data.data, data[i].data.length); 1667233294Sstas q += data[i].data.length; 1668233294Sstas } 1669233294Sstas 1670233294Sstas cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); 1671233294Sstas cksum.checksum.length = civ->data.length; 1672233294Sstas cksum.checksum.data = civ->data.data; 1673233294Sstas 1674233294Sstas ret = krb5_verify_checksum(context, crypto, usage, p, len, &cksum); 1675233294Sstas free(p); 1676233294Sstas 1677233294Sstas if (ret == 0 && type) 1678233294Sstas *type = cksum.cksumtype; 1679233294Sstas 1680233294Sstas return ret; 1681233294Sstas} 1682233294Sstas 1683233294Sstas 1684233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1685233294Sstaskrb5_crypto_length(krb5_context context, 1686233294Sstas krb5_crypto crypto, 1687233294Sstas int type, 1688233294Sstas size_t *len) 1689233294Sstas{ 1690233294Sstas if (!derived_crypto(context, crypto)) { 1691233294Sstas krb5_set_error_message(context, EINVAL, "not a derived crypto"); 1692233294Sstas return EINVAL; 1693233294Sstas } 1694233294Sstas 1695233294Sstas switch(type) { 1696233294Sstas case KRB5_CRYPTO_TYPE_EMPTY: 1697233294Sstas *len = 0; 1698233294Sstas return 0; 1699233294Sstas case KRB5_CRYPTO_TYPE_HEADER: 1700233294Sstas *len = crypto->et->blocksize; 1701233294Sstas return 0; 1702233294Sstas case KRB5_CRYPTO_TYPE_DATA: 1703233294Sstas case KRB5_CRYPTO_TYPE_SIGN_ONLY: 1704233294Sstas /* len must already been filled in */ 1705233294Sstas return 0; 1706233294Sstas case KRB5_CRYPTO_TYPE_PADDING: 1707233294Sstas if (crypto->et->padsize > 1) 1708233294Sstas *len = crypto->et->padsize; 1709233294Sstas else 1710233294Sstas *len = 0; 1711233294Sstas return 0; 1712233294Sstas case KRB5_CRYPTO_TYPE_TRAILER: 1713233294Sstas *len = CHECKSUMSIZE(crypto->et->keyed_checksum); 1714233294Sstas return 0; 1715233294Sstas case KRB5_CRYPTO_TYPE_CHECKSUM: 1716233294Sstas if (crypto->et->keyed_checksum) 1717233294Sstas *len = CHECKSUMSIZE(crypto->et->keyed_checksum); 1718233294Sstas else 1719233294Sstas *len = CHECKSUMSIZE(crypto->et->checksum); 1720233294Sstas return 0; 1721233294Sstas } 1722233294Sstas krb5_set_error_message(context, EINVAL, 1723233294Sstas "%d not a supported type", type); 1724233294Sstas return EINVAL; 1725233294Sstas} 1726233294Sstas 1727233294Sstas 1728233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1729233294Sstaskrb5_crypto_length_iov(krb5_context context, 1730233294Sstas krb5_crypto crypto, 1731233294Sstas krb5_crypto_iov *data, 1732233294Sstas unsigned int num_data) 1733233294Sstas{ 1734233294Sstas krb5_error_code ret; 1735233294Sstas size_t i; 1736233294Sstas 1737233294Sstas for (i = 0; i < num_data; i++) { 1738233294Sstas ret = krb5_crypto_length(context, crypto, 1739233294Sstas data[i].flags, 1740233294Sstas &data[i].data.length); 1741233294Sstas if (ret) 1742233294Sstas return ret; 1743233294Sstas } 1744233294Sstas return 0; 1745233294Sstas} 1746233294Sstas 1747233294Sstas 1748233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 174972448Sassarkrb5_encrypt_ivec(krb5_context context, 175072448Sassar krb5_crypto crypto, 175172448Sassar unsigned usage, 1752178828Sdfr const void *data, 175372448Sassar size_t len, 175472448Sassar krb5_data *result, 175572448Sassar void *ivec) 175672448Sassar{ 175772448Sassar if(derived_crypto(context, crypto)) 1758233294Sstas return encrypt_internal_derived(context, crypto, usage, 175972448Sassar data, len, result, ivec); 176072448Sassar else if (special_crypto(context, crypto)) 176172448Sassar return encrypt_internal_special (context, crypto, usage, 176272448Sassar data, len, result, ivec); 176372448Sassar else 176472448Sassar return encrypt_internal(context, crypto, data, len, result, ivec); 176572448Sassar} 176672448Sassar 1767233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 176855682Smarkmkrb5_encrypt(krb5_context context, 176955682Smarkm krb5_crypto crypto, 177055682Smarkm unsigned usage, 1771178828Sdfr const void *data, 177255682Smarkm size_t len, 177355682Smarkm krb5_data *result) 177455682Smarkm{ 177572448Sassar return krb5_encrypt_ivec(context, crypto, usage, data, len, result, NULL); 177655682Smarkm} 177755682Smarkm 1778233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 177955682Smarkmkrb5_encrypt_EncryptedData(krb5_context context, 178055682Smarkm krb5_crypto crypto, 178155682Smarkm unsigned usage, 178255682Smarkm void *data, 178355682Smarkm size_t len, 178455682Smarkm int kvno, 178555682Smarkm EncryptedData *result) 178655682Smarkm{ 178755682Smarkm result->etype = CRYPTO_ETYPE(crypto); 178855682Smarkm if(kvno){ 178955682Smarkm ALLOC(result->kvno, 1); 179055682Smarkm *result->kvno = kvno; 179155682Smarkm }else 179255682Smarkm result->kvno = NULL; 179355682Smarkm return krb5_encrypt(context, crypto, usage, data, len, &result->cipher); 179455682Smarkm} 179555682Smarkm 1796233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 179772448Sassarkrb5_decrypt_ivec(krb5_context context, 179872448Sassar krb5_crypto crypto, 179972448Sassar unsigned usage, 180072448Sassar void *data, 180172448Sassar size_t len, 180272448Sassar krb5_data *result, 180372448Sassar void *ivec) 180472448Sassar{ 180572448Sassar if(derived_crypto(context, crypto)) 1806233294Sstas return decrypt_internal_derived(context, crypto, usage, 180772448Sassar data, len, result, ivec); 180872448Sassar else if (special_crypto (context, crypto)) 180972448Sassar return decrypt_internal_special(context, crypto, usage, 181072448Sassar data, len, result, ivec); 181172448Sassar else 181272448Sassar return decrypt_internal(context, crypto, data, len, result, ivec); 181372448Sassar} 181472448Sassar 1815233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 181655682Smarkmkrb5_decrypt(krb5_context context, 181755682Smarkm krb5_crypto crypto, 181855682Smarkm unsigned usage, 181955682Smarkm void *data, 182055682Smarkm size_t len, 182155682Smarkm krb5_data *result) 182255682Smarkm{ 182372448Sassar return krb5_decrypt_ivec (context, crypto, usage, data, len, result, 182472448Sassar NULL); 182555682Smarkm} 182655682Smarkm 1827233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 182855682Smarkmkrb5_decrypt_EncryptedData(krb5_context context, 182955682Smarkm krb5_crypto crypto, 183055682Smarkm unsigned usage, 183172448Sassar const EncryptedData *e, 183255682Smarkm krb5_data *result) 183355682Smarkm{ 1834233294Sstas return krb5_decrypt(context, crypto, usage, 183555682Smarkm e->cipher.data, e->cipher.length, result); 183655682Smarkm} 183755682Smarkm 183855682Smarkm/************************************************************ 183955682Smarkm * * 184055682Smarkm ************************************************************/ 184155682Smarkm 1842233294Sstaskrb5_error_code 1843233294Sstas_krb5_derive_key(krb5_context context, 1844233294Sstas struct _krb5_encryption_type *et, 1845233294Sstas struct _krb5_key_data *key, 1846233294Sstas const void *constant, 1847233294Sstas size_t len) 184878536Sassar{ 1849233294Sstas unsigned char *k = NULL; 185055682Smarkm unsigned int nblocks = 0, i; 185155682Smarkm krb5_error_code ret = 0; 1852233294Sstas struct _krb5_key_type *kt = et->keytype; 1853178828Sdfr 185455682Smarkm ret = _key_schedule(context, key); 185555682Smarkm if(ret) 185655682Smarkm return ret; 1857178828Sdfr if(et->blocksize * 8 < kt->bits || len != et->blocksize) { 185855682Smarkm nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8); 185955682Smarkm k = malloc(nblocks * et->blocksize); 186078536Sassar if(k == NULL) { 1861233294Sstas ret = ENOMEM; 1862233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1863233294Sstas goto out; 186478536Sassar } 1865178828Sdfr ret = _krb5_n_fold(constant, len, k, et->blocksize); 1866178828Sdfr if (ret) { 1867233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1868233294Sstas goto out; 1869178828Sdfr } 1870233294Sstas 187155682Smarkm for(i = 0; i < nblocks; i++) { 187255682Smarkm if(i > 0) 1873233294Sstas memcpy(k + i * et->blocksize, 187455682Smarkm k + (i - 1) * et->blocksize, 187555682Smarkm et->blocksize); 187678536Sassar (*et->encrypt)(context, key, k + i * et->blocksize, et->blocksize, 187778536Sassar 1, 0, NULL); 187855682Smarkm } 187955682Smarkm } else { 188072448Sassar /* this case is probably broken, but won't be run anyway */ 188155682Smarkm void *c = malloc(len); 188255682Smarkm size_t res_len = (kt->bits + 7) / 8; 188355682Smarkm 188478536Sassar if(len != 0 && c == NULL) { 1885233294Sstas ret = ENOMEM; 1886233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1887233294Sstas goto out; 188878536Sassar } 188955682Smarkm memcpy(c, constant, len); 189078536Sassar (*et->encrypt)(context, key, c, len, 1, 0, NULL); 189155682Smarkm k = malloc(res_len); 189278536Sassar if(res_len != 0 && k == NULL) { 189378536Sassar free(c); 1894233294Sstas ret = ENOMEM; 1895233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1896233294Sstas goto out; 189778536Sassar } 1898178828Sdfr ret = _krb5_n_fold(c, len, k, res_len); 1899233294Sstas free(c); 1900178828Sdfr if (ret) { 1901233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1902233294Sstas goto out; 1903178828Sdfr } 190455682Smarkm } 1905233294Sstas 190655682Smarkm /* XXX keytype dependent post-processing */ 190755682Smarkm switch(kt->type) { 1908233294Sstas case ETYPE_OLD_DES3_CBC_SHA1: 1909233294Sstas _krb5_DES3_random_to_key(context, key->key, k, nblocks * et->blocksize); 191055682Smarkm break; 1911233294Sstas case ENCTYPE_AES128_CTS_HMAC_SHA1_96: 1912233294Sstas case ENCTYPE_AES256_CTS_HMAC_SHA1_96: 1913120948Snectar memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length); 1914120948Snectar break; 191555682Smarkm default: 191655682Smarkm ret = KRB5_CRYPTO_INTERNAL; 1917233294Sstas krb5_set_error_message(context, ret, 1918233294Sstas N_("derive_key() called with unknown keytype (%u)", ""), 1919233294Sstas kt->type); 192055682Smarkm break; 192155682Smarkm } 1922233294Sstas out: 1923178828Sdfr if (key->schedule) { 1924233294Sstas free_key_schedule(context, key, et); 1925178828Sdfr key->schedule = NULL; 1926178828Sdfr } 1927233294Sstas if (k) { 1928233294Sstas memset(k, 0, nblocks * et->blocksize); 1929233294Sstas free(k); 1930233294Sstas } 193155682Smarkm return ret; 193255682Smarkm} 193355682Smarkm 1934233294Sstasstatic struct _krb5_key_data * 193555682Smarkm_new_derived_key(krb5_crypto crypto, unsigned usage) 193655682Smarkm{ 1937233294Sstas struct _krb5_key_usage *d = crypto->key_usage; 193855682Smarkm d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d)); 193955682Smarkm if(d == NULL) 194055682Smarkm return NULL; 194155682Smarkm crypto->key_usage = d; 194255682Smarkm d += crypto->num_key_usage++; 194355682Smarkm memset(d, 0, sizeof(*d)); 194455682Smarkm d->usage = usage; 194555682Smarkm return &d->key; 194655682Smarkm} 194755682Smarkm 1948233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 194978536Sassarkrb5_derive_key(krb5_context context, 195078536Sassar const krb5_keyblock *key, 195178536Sassar krb5_enctype etype, 195278536Sassar const void *constant, 195378536Sassar size_t constant_len, 195478536Sassar krb5_keyblock **derived_key) 195578536Sassar{ 195678536Sassar krb5_error_code ret; 1957233294Sstas struct _krb5_encryption_type *et; 1958233294Sstas struct _krb5_key_data d; 195978536Sassar 1960178828Sdfr *derived_key = NULL; 1961178828Sdfr 1962233294Sstas et = _krb5_find_enctype (etype); 196378536Sassar if (et == NULL) { 1964233294Sstas return unsupported_enctype (context, etype); 196578536Sassar } 196678536Sassar 1967178828Sdfr ret = krb5_copy_keyblock(context, key, &d.key); 196878536Sassar if (ret) 196978536Sassar return ret; 197078536Sassar 197178536Sassar d.schedule = NULL; 1972233294Sstas ret = _krb5_derive_key(context, et, &d, constant, constant_len); 1973178828Sdfr if (ret == 0) 1974178828Sdfr ret = krb5_copy_keyblock(context, d.key, derived_key); 1975233294Sstas _krb5_free_key_data(context, &d, et); 197678536Sassar return ret; 197778536Sassar} 197878536Sassar 197955682Smarkmstatic krb5_error_code 1980233294Sstas_get_derived_key(krb5_context context, 1981233294Sstas krb5_crypto crypto, 1982233294Sstas unsigned usage, 1983233294Sstas struct _krb5_key_data **key) 198455682Smarkm{ 198555682Smarkm int i; 1986233294Sstas struct _krb5_key_data *d; 198755682Smarkm unsigned char constant[5]; 198855682Smarkm 198955682Smarkm for(i = 0; i < crypto->num_key_usage; i++) 199055682Smarkm if(crypto->key_usage[i].usage == usage) { 199155682Smarkm *key = &crypto->key_usage[i].key; 199255682Smarkm return 0; 199355682Smarkm } 199455682Smarkm d = _new_derived_key(crypto, usage); 199578536Sassar if(d == NULL) { 1996233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 199755682Smarkm return ENOMEM; 199878536Sassar } 199955682Smarkm krb5_copy_keyblock(context, crypto->key.key, &d->key); 200055682Smarkm _krb5_put_int(constant, usage, 5); 2001233294Sstas _krb5_derive_key(context, crypto->et, d, constant, sizeof(constant)); 200255682Smarkm *key = d; 200355682Smarkm return 0; 200455682Smarkm} 200555682Smarkm 2006233294Sstas/** 2007233294Sstas * Create a crypto context used for all encryption and signature 2008233294Sstas * operation. The encryption type to use is taken from the key, but 2009233294Sstas * can be overridden with the enctype parameter. This can be useful 2010233294Sstas * for encryptions types which is compatiable (DES for example). 2011233294Sstas * 2012233294Sstas * To free the crypto context, use krb5_crypto_destroy(). 2013233294Sstas * 2014233294Sstas * @param context Kerberos context 2015233294Sstas * @param key the key block information with all key data 2016233294Sstas * @param etype the encryption type 2017233294Sstas * @param crypto the resulting crypto context 2018233294Sstas * 2019233294Sstas * @return Return an error code or 0. 2020233294Sstas * 2021233294Sstas * @ingroup krb5_crypto 2022233294Sstas */ 202355682Smarkm 2024233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 202555682Smarkmkrb5_crypto_init(krb5_context context, 202678536Sassar const krb5_keyblock *key, 202755682Smarkm krb5_enctype etype, 202855682Smarkm krb5_crypto *crypto) 202955682Smarkm{ 203055682Smarkm krb5_error_code ret; 203155682Smarkm ALLOC(*crypto, 1); 203278536Sassar if(*crypto == NULL) { 2033233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 203455682Smarkm return ENOMEM; 203578536Sassar } 203655682Smarkm if(etype == ETYPE_NULL) 203755682Smarkm etype = key->keytype; 2038233294Sstas (*crypto)->et = _krb5_find_enctype(etype); 2039178828Sdfr if((*crypto)->et == NULL || ((*crypto)->et->flags & F_DISABLED)) { 204055682Smarkm free(*crypto); 2041178828Sdfr *crypto = NULL; 2042233294Sstas return unsupported_enctype(context, etype); 204355682Smarkm } 2044102647Snectar if((*crypto)->et->keytype->size != key->keyvalue.length) { 2045102647Snectar free(*crypto); 2046178828Sdfr *crypto = NULL; 2047233294Sstas krb5_set_error_message (context, KRB5_BAD_KEYSIZE, 2048233294Sstas "encryption key has bad length"); 2049102647Snectar return KRB5_BAD_KEYSIZE; 2050102647Snectar } 205155682Smarkm ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key); 205255682Smarkm if(ret) { 205355682Smarkm free(*crypto); 2054178828Sdfr *crypto = NULL; 205555682Smarkm return ret; 205655682Smarkm } 205755682Smarkm (*crypto)->key.schedule = NULL; 205855682Smarkm (*crypto)->num_key_usage = 0; 205955682Smarkm (*crypto)->key_usage = NULL; 206055682Smarkm return 0; 206155682Smarkm} 206255682Smarkm 206355682Smarkmstatic void 2064233294Sstasfree_key_schedule(krb5_context context, 2065233294Sstas struct _krb5_key_data *key, 2066233294Sstas struct _krb5_encryption_type *et) 206755682Smarkm{ 2068233294Sstas if (et->keytype->cleanup) 2069233294Sstas (*et->keytype->cleanup)(context, key); 2070233294Sstas memset(key->schedule->data, 0, key->schedule->length); 2071233294Sstas krb5_free_data(context, key->schedule); 2072233294Sstas} 2073233294Sstas 2074233294Sstasvoid 2075233294Sstas_krb5_free_key_data(krb5_context context, struct _krb5_key_data *key, 2076233294Sstas struct _krb5_encryption_type *et) 2077233294Sstas{ 207855682Smarkm krb5_free_keyblock(context, key->key); 207955682Smarkm if(key->schedule) { 2080233294Sstas free_key_schedule(context, key, et); 2081233294Sstas key->schedule = NULL; 208255682Smarkm } 208355682Smarkm} 208455682Smarkm 208555682Smarkmstatic void 2086233294Sstasfree_key_usage(krb5_context context, struct _krb5_key_usage *ku, 2087233294Sstas struct _krb5_encryption_type *et) 208855682Smarkm{ 2089233294Sstas _krb5_free_key_data(context, &ku->key, et); 209055682Smarkm} 209155682Smarkm 2092233294Sstas/** 2093233294Sstas * Free a crypto context created by krb5_crypto_init(). 2094233294Sstas * 2095233294Sstas * @param context Kerberos context 2096233294Sstas * @param crypto crypto context to free 2097233294Sstas * 2098233294Sstas * @return Return an error code or 0. 2099233294Sstas * 2100233294Sstas * @ingroup krb5_crypto 2101233294Sstas */ 2102233294Sstas 2103233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 210455682Smarkmkrb5_crypto_destroy(krb5_context context, 210555682Smarkm krb5_crypto crypto) 210655682Smarkm{ 210755682Smarkm int i; 2108233294Sstas 210955682Smarkm for(i = 0; i < crypto->num_key_usage; i++) 2110233294Sstas free_key_usage(context, &crypto->key_usage[i], crypto->et); 211155682Smarkm free(crypto->key_usage); 2112233294Sstas _krb5_free_key_data(context, &crypto->key, crypto->et); 211355682Smarkm free (crypto); 211455682Smarkm return 0; 211555682Smarkm} 211655682Smarkm 2117233294Sstas/** 2118233294Sstas * Return the blocksize used algorithm referenced by the crypto context 2119233294Sstas * 2120233294Sstas * @param context Kerberos context 2121233294Sstas * @param crypto crypto context to query 2122233294Sstas * @param blocksize the resulting blocksize 2123233294Sstas * 2124233294Sstas * @return Return an error code or 0. 2125233294Sstas * 2126233294Sstas * @ingroup krb5_crypto 2127233294Sstas */ 2128233294Sstas 2129233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2130103426Snectarkrb5_crypto_getblocksize(krb5_context context, 2131103426Snectar krb5_crypto crypto, 2132103426Snectar size_t *blocksize) 2133103426Snectar{ 2134103426Snectar *blocksize = crypto->et->blocksize; 2135103426Snectar return 0; 2136103426Snectar} 2137103426Snectar 2138233294Sstas/** 2139233294Sstas * Return the encryption type used by the crypto context 2140233294Sstas * 2141233294Sstas * @param context Kerberos context 2142233294Sstas * @param crypto crypto context to query 2143233294Sstas * @param enctype the resulting encryption type 2144233294Sstas * 2145233294Sstas * @return Return an error code or 0. 2146233294Sstas * 2147233294Sstas * @ingroup krb5_crypto 2148233294Sstas */ 2149233294Sstas 2150233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2151178828Sdfrkrb5_crypto_getenctype(krb5_context context, 2152178828Sdfr krb5_crypto crypto, 2153178828Sdfr krb5_enctype *enctype) 2154178828Sdfr{ 2155178828Sdfr *enctype = crypto->et->type; 2156233294Sstas return 0; 2157178828Sdfr} 2158178828Sdfr 2159233294Sstas/** 2160233294Sstas * Return the padding size used by the crypto context 2161233294Sstas * 2162233294Sstas * @param context Kerberos context 2163233294Sstas * @param crypto crypto context to query 2164233294Sstas * @param padsize the return padding size 2165233294Sstas * 2166233294Sstas * @return Return an error code or 0. 2167233294Sstas * 2168233294Sstas * @ingroup krb5_crypto 2169233294Sstas */ 2170233294Sstas 2171233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2172178828Sdfrkrb5_crypto_getpadsize(krb5_context context, 2173178828Sdfr krb5_crypto crypto, 2174233294Sstas size_t *padsize) 2175178828Sdfr{ 2176178828Sdfr *padsize = crypto->et->padsize; 2177178828Sdfr return 0; 2178178828Sdfr} 2179178828Sdfr 2180233294Sstas/** 2181233294Sstas * Return the confounder size used by the crypto context 2182233294Sstas * 2183233294Sstas * @param context Kerberos context 2184233294Sstas * @param crypto crypto context to query 2185233294Sstas * @param confoundersize the returned confounder size 2186233294Sstas * 2187233294Sstas * @return Return an error code or 0. 2188233294Sstas * 2189233294Sstas * @ingroup krb5_crypto 2190233294Sstas */ 2191233294Sstas 2192233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2193178828Sdfrkrb5_crypto_getconfoundersize(krb5_context context, 2194178828Sdfr krb5_crypto crypto, 2195178828Sdfr size_t *confoundersize) 2196178828Sdfr{ 2197178828Sdfr *confoundersize = crypto->et->confoundersize; 2198178828Sdfr return 0; 2199178828Sdfr} 2200178828Sdfr 2201233294Sstas 2202233294Sstas/** 2203233294Sstas * Disable encryption type 2204233294Sstas * 2205233294Sstas * @param context Kerberos 5 context 2206233294Sstas * @param enctype encryption type to disable 2207233294Sstas * 2208233294Sstas * @return Return an error code or 0. 2209233294Sstas * 2210233294Sstas * @ingroup krb5_crypto 2211233294Sstas */ 2212233294Sstas 2213233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2214178828Sdfrkrb5_enctype_disable(krb5_context context, 2215178828Sdfr krb5_enctype enctype) 2216178828Sdfr{ 2217233294Sstas struct _krb5_encryption_type *et = _krb5_find_enctype(enctype); 2218178828Sdfr if(et == NULL) { 2219178828Sdfr if (context) 2220233294Sstas krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, 2221233294Sstas N_("encryption type %d not supported", ""), 2222233294Sstas enctype); 2223178828Sdfr return KRB5_PROG_ETYPE_NOSUPP; 2224178828Sdfr } 2225178828Sdfr et->flags |= F_DISABLED; 2226178828Sdfr return 0; 2227178828Sdfr} 2228178828Sdfr 2229233294Sstas/** 2230233294Sstas * Enable encryption type 2231233294Sstas * 2232233294Sstas * @param context Kerberos 5 context 2233233294Sstas * @param enctype encryption type to enable 2234233294Sstas * 2235233294Sstas * @return Return an error code or 0. 2236233294Sstas * 2237233294Sstas * @ingroup krb5_crypto 2238233294Sstas */ 2239233294Sstas 2240233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2241233294Sstaskrb5_enctype_enable(krb5_context context, 2242233294Sstas krb5_enctype enctype) 224355682Smarkm{ 2244233294Sstas struct _krb5_encryption_type *et = _krb5_find_enctype(enctype); 224578536Sassar if(et == NULL) { 2246233294Sstas if (context) 2247233294Sstas krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, 2248233294Sstas N_("encryption type %d not supported", ""), 2249233294Sstas enctype); 225055682Smarkm return KRB5_PROG_ETYPE_NOSUPP; 225178536Sassar } 2252233294Sstas et->flags &= ~F_DISABLED; 2253233294Sstas return 0; 2254233294Sstas} 2255178828Sdfr 2256233294Sstas/** 2257233294Sstas * Enable or disable all weak encryption types 2258233294Sstas * 2259233294Sstas * @param context Kerberos 5 context 2260233294Sstas * @param enable true to enable, false to disable 2261233294Sstas * 2262233294Sstas * @return Return an error code or 0. 2263233294Sstas * 2264233294Sstas * @ingroup krb5_crypto 2265233294Sstas */ 2266233294Sstas 2267233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2268233294Sstaskrb5_allow_weak_crypto(krb5_context context, 2269233294Sstas krb5_boolean enable) 2270233294Sstas{ 2271233294Sstas int i; 2272233294Sstas 2273233294Sstas for(i = 0; i < _krb5_num_etypes; i++) 2274233294Sstas if(_krb5_etypes[i]->flags & F_WEAK) { 2275233294Sstas if(enable) 2276233294Sstas _krb5_etypes[i]->flags &= ~F_DISABLED; 2277233294Sstas else 2278233294Sstas _krb5_etypes[i]->flags |= F_DISABLED; 2279233294Sstas } 2280233294Sstas return 0; 228155682Smarkm} 228255682Smarkm 228372448Sassarstatic size_t 228472448Sassarwrapped_length (krb5_context context, 228572448Sassar krb5_crypto crypto, 228672448Sassar size_t data_len) 228772448Sassar{ 2288233294Sstas struct _krb5_encryption_type *et = crypto->et; 2289120948Snectar size_t padsize = et->padsize; 2290178828Sdfr size_t checksumsize = CHECKSUMSIZE(et->checksum); 229172448Sassar size_t res; 229272448Sassar 2293178828Sdfr res = et->confoundersize + checksumsize + data_len; 2294120948Snectar res = (res + padsize - 1) / padsize * padsize; 229572448Sassar return res; 229672448Sassar} 229772448Sassar 229872448Sassarstatic size_t 229972448Sassarwrapped_length_dervied (krb5_context context, 230072448Sassar krb5_crypto crypto, 230172448Sassar size_t data_len) 230272448Sassar{ 2303233294Sstas struct _krb5_encryption_type *et = crypto->et; 2304120948Snectar size_t padsize = et->padsize; 230572448Sassar size_t res; 230672448Sassar 230772448Sassar res = et->confoundersize + data_len; 2308120948Snectar res = (res + padsize - 1) / padsize * padsize; 2309178828Sdfr if (et->keyed_checksum) 2310178828Sdfr res += et->keyed_checksum->checksumsize; 2311178828Sdfr else 2312178828Sdfr res += et->checksum->checksumsize; 231372448Sassar return res; 231472448Sassar} 231572448Sassar 231655682Smarkm/* 231755682Smarkm * Return the size of an encrypted packet of length `data_len' 231855682Smarkm */ 231955682Smarkm 2320233294SstasKRB5_LIB_FUNCTION size_t KRB5_LIB_CALL 232155682Smarkmkrb5_get_wrapped_length (krb5_context context, 232255682Smarkm krb5_crypto crypto, 232355682Smarkm size_t data_len) 232455682Smarkm{ 232572448Sassar if (derived_crypto (context, crypto)) 232672448Sassar return wrapped_length_dervied (context, crypto, data_len); 232772448Sassar else 232872448Sassar return wrapped_length (context, crypto, data_len); 232955682Smarkm} 233055682Smarkm 2331178828Sdfr/* 2332178828Sdfr * Return the size of an encrypted packet of length `data_len' 2333178828Sdfr */ 2334178828Sdfr 2335178828Sdfrstatic size_t 2336178828Sdfrcrypto_overhead (krb5_context context, 2337178828Sdfr krb5_crypto crypto) 2338178828Sdfr{ 2339233294Sstas struct _krb5_encryption_type *et = crypto->et; 2340178828Sdfr size_t res; 2341178828Sdfr 2342178828Sdfr res = CHECKSUMSIZE(et->checksum); 2343178828Sdfr res += et->confoundersize; 2344178828Sdfr if (et->padsize > 1) 2345178828Sdfr res += et->padsize; 2346178828Sdfr return res; 2347178828Sdfr} 2348178828Sdfr 2349178828Sdfrstatic size_t 2350178828Sdfrcrypto_overhead_dervied (krb5_context context, 2351178828Sdfr krb5_crypto crypto) 2352178828Sdfr{ 2353233294Sstas struct _krb5_encryption_type *et = crypto->et; 2354178828Sdfr size_t res; 2355178828Sdfr 2356178828Sdfr if (et->keyed_checksum) 2357178828Sdfr res = CHECKSUMSIZE(et->keyed_checksum); 2358178828Sdfr else 2359178828Sdfr res = CHECKSUMSIZE(et->checksum); 2360178828Sdfr res += et->confoundersize; 2361178828Sdfr if (et->padsize > 1) 2362178828Sdfr res += et->padsize; 2363178828Sdfr return res; 2364178828Sdfr} 2365178828Sdfr 2366233294SstasKRB5_LIB_FUNCTION size_t KRB5_LIB_CALL 2367178828Sdfrkrb5_crypto_overhead (krb5_context context, krb5_crypto crypto) 2368178828Sdfr{ 2369178828Sdfr if (derived_crypto (context, crypto)) 2370178828Sdfr return crypto_overhead_dervied (context, crypto); 2371178828Sdfr else 2372178828Sdfr return crypto_overhead (context, crypto); 2373178828Sdfr} 2374178828Sdfr 2375233294Sstas/** 2376233294Sstas * Converts the random bytestring to a protocol key according to 2377233294Sstas * Kerberos crypto frame work. It may be assumed that all the bits of 2378233294Sstas * the input string are equally random, even though the entropy 2379233294Sstas * present in the random source may be limited. 2380233294Sstas * 2381233294Sstas * @param context Kerberos 5 context 2382233294Sstas * @param type the enctype resulting key will be of 2383233294Sstas * @param data input random data to convert to a key 2384233294Sstas * @param size size of input random data, at least krb5_enctype_keysize() long 2385233294Sstas * @param key key, output key, free with krb5_free_keyblock_contents() 2386233294Sstas * 2387233294Sstas * @return Return an error code or 0. 2388233294Sstas * 2389233294Sstas * @ingroup krb5_crypto 2390233294Sstas */ 2391233294Sstas 2392233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2393178828Sdfrkrb5_random_to_key(krb5_context context, 2394178828Sdfr krb5_enctype type, 2395178828Sdfr const void *data, 2396178828Sdfr size_t size, 2397178828Sdfr krb5_keyblock *key) 2398178828Sdfr{ 2399178828Sdfr krb5_error_code ret; 2400233294Sstas struct _krb5_encryption_type *et = _krb5_find_enctype(type); 2401178828Sdfr if(et == NULL) { 2402233294Sstas krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 2403233294Sstas N_("encryption type %d not supported", ""), 2404233294Sstas type); 2405178828Sdfr return KRB5_PROG_ETYPE_NOSUPP; 2406178828Sdfr } 2407178828Sdfr if ((et->keytype->bits + 7) / 8 > size) { 2408233294Sstas krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 2409233294Sstas N_("encryption key %s needs %d bytes " 2410233294Sstas "of random to make an encryption key " 2411233294Sstas "out of it", ""), 2412233294Sstas et->name, (int)et->keytype->size); 2413178828Sdfr return KRB5_PROG_ETYPE_NOSUPP; 2414178828Sdfr } 2415178828Sdfr ret = krb5_data_alloc(&key->keyvalue, et->keytype->size); 2416233294Sstas if(ret) 2417178828Sdfr return ret; 2418178828Sdfr key->keytype = type; 2419178828Sdfr if (et->keytype->random_to_key) 2420178828Sdfr (*et->keytype->random_to_key)(context, key, data, size); 2421178828Sdfr else 2422178828Sdfr memcpy(key->keyvalue.data, data, et->keytype->size); 2423178828Sdfr 2424178828Sdfr return 0; 2425178828Sdfr} 2426178828Sdfr 2427178828Sdfr 2428178828Sdfr 2429233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2430178828Sdfrkrb5_crypto_prf_length(krb5_context context, 2431178828Sdfr krb5_enctype type, 2432178828Sdfr size_t *length) 2433178828Sdfr{ 2434233294Sstas struct _krb5_encryption_type *et = _krb5_find_enctype(type); 2435178828Sdfr 2436178828Sdfr if(et == NULL || et->prf_length == 0) { 2437233294Sstas krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 2438233294Sstas N_("encryption type %d not supported", ""), 2439233294Sstas type); 2440178828Sdfr return KRB5_PROG_ETYPE_NOSUPP; 2441178828Sdfr } 2442178828Sdfr 2443178828Sdfr *length = et->prf_length; 2444178828Sdfr return 0; 2445178828Sdfr} 2446178828Sdfr 2447233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2448178828Sdfrkrb5_crypto_prf(krb5_context context, 2449178828Sdfr const krb5_crypto crypto, 2450233294Sstas const krb5_data *input, 2451178828Sdfr krb5_data *output) 2452178828Sdfr{ 2453233294Sstas struct _krb5_encryption_type *et = crypto->et; 2454178828Sdfr 2455178828Sdfr krb5_data_zero(output); 2456178828Sdfr 2457178828Sdfr if(et->prf == NULL) { 2458233294Sstas krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 2459233294Sstas "kerberos prf for %s not supported", 2460233294Sstas et->name); 2461178828Sdfr return KRB5_PROG_ETYPE_NOSUPP; 2462178828Sdfr } 2463178828Sdfr 2464178828Sdfr return (*et->prf)(context, crypto, input, output); 2465178828Sdfr} 2466178828Sdfr 2467233294Sstasstatic krb5_error_code 2468233294Sstaskrb5_crypto_prfplus(krb5_context context, 2469233294Sstas const krb5_crypto crypto, 2470233294Sstas const krb5_data *input, 2471233294Sstas size_t length, 2472233294Sstas krb5_data *output) 2473233294Sstas{ 2474233294Sstas krb5_error_code ret; 2475233294Sstas krb5_data input2; 2476233294Sstas unsigned char i = 1; 2477233294Sstas unsigned char *p; 2478178828Sdfr 2479233294Sstas krb5_data_zero(&input2); 2480233294Sstas krb5_data_zero(output); 2481178828Sdfr 2482233294Sstas krb5_clear_error_message(context); 248355682Smarkm 2484233294Sstas ret = krb5_data_alloc(output, length); 2485233294Sstas if (ret) goto out; 2486233294Sstas ret = krb5_data_alloc(&input2, input->length + 1); 2487233294Sstas if (ret) goto out; 248857416Smarkm 2489233294Sstas krb5_clear_error_message(context); 2490233294Sstas 2491233294Sstas memcpy(((unsigned char *)input2.data) + 1, input->data, input->length); 2492233294Sstas 2493233294Sstas p = output->data; 2494233294Sstas 2495233294Sstas while (length) { 2496233294Sstas krb5_data block; 2497233294Sstas 2498233294Sstas ((unsigned char *)input2.data)[0] = i++; 2499233294Sstas 2500233294Sstas ret = krb5_crypto_prf(context, crypto, &input2, &block); 2501233294Sstas if (ret) 2502233294Sstas goto out; 2503233294Sstas 2504233294Sstas if (block.length < length) { 2505233294Sstas memcpy(p, block.data, block.length); 2506233294Sstas length -= block.length; 2507233294Sstas } else { 2508233294Sstas memcpy(p, block.data, length); 2509233294Sstas length = 0; 2510233294Sstas } 2511233294Sstas p += block.length; 2512233294Sstas krb5_data_free(&block); 2513233294Sstas } 2514233294Sstas 2515233294Sstas out: 2516233294Sstas krb5_data_free(&input2); 2517233294Sstas if (ret) 2518233294Sstas krb5_data_free(output); 251955682Smarkm return 0; 252055682Smarkm} 252155682Smarkm 2522233294Sstas/** 2523233294Sstas * The FX-CF2 key derivation function, used in FAST and preauth framework. 2524233294Sstas * 2525233294Sstas * @param context Kerberos 5 context 2526233294Sstas * @param crypto1 first key to combine 2527233294Sstas * @param crypto2 second key to combine 2528233294Sstas * @param pepper1 factor to combine with first key to garante uniqueness 2529233294Sstas * @param pepper2 factor to combine with second key to garante uniqueness 2530233294Sstas * @param enctype the encryption type of the resulting key 2531233294Sstas * @param res allocated key, free with krb5_free_keyblock_contents() 2532233294Sstas * 2533233294Sstas * @return Return an error code or 0. 2534233294Sstas * 2535233294Sstas * @ingroup krb5_crypto 2536233294Sstas */ 253755682Smarkm 2538233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2539233294Sstaskrb5_crypto_fx_cf2(krb5_context context, 2540233294Sstas const krb5_crypto crypto1, 2541233294Sstas const krb5_crypto crypto2, 2542233294Sstas krb5_data *pepper1, 2543233294Sstas krb5_data *pepper2, 2544233294Sstas krb5_enctype enctype, 2545233294Sstas krb5_keyblock *res) 254672448Sassar{ 254772448Sassar krb5_error_code ret; 2548233294Sstas krb5_data os1, os2; 2549233294Sstas size_t i, keysize; 255072448Sassar 2551233294Sstas memset(res, 0, sizeof(*res)); 2552233294Sstas 2553233294Sstas ret = krb5_enctype_keysize(context, enctype, &keysize); 255472448Sassar if (ret) 2555233294Sstas return ret; 255672448Sassar 2557233294Sstas ret = krb5_data_alloc(&res->keyvalue, keysize); 2558233294Sstas if (ret) 2559233294Sstas goto out; 2560233294Sstas ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1); 2561233294Sstas if (ret) 2562233294Sstas goto out; 2563233294Sstas ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2); 2564233294Sstas if (ret) 2565233294Sstas goto out; 256672448Sassar 2567233294Sstas res->keytype = enctype; 2568233294Sstas { 2569233294Sstas unsigned char *p1 = os1.data, *p2 = os2.data, *p3 = res->keyvalue.data; 2570233294Sstas for (i = 0; i < keysize; i++) 2571233294Sstas p3[i] = p1[i] ^ p2[i]; 2572233294Sstas } 2573233294Sstas out: 2574233294Sstas if (ret) 2575233294Sstas krb5_data_free(&res->keyvalue); 2576233294Sstas krb5_data_free(&os1); 2577233294Sstas krb5_data_free(&os2); 257872448Sassar 2579233294Sstas return ret; 2580233294Sstas} 258172448Sassar 258272448Sassar 258372448Sassar 2584233294Sstas#ifndef HEIMDAL_SMALLER 258572448Sassar 2586233294Sstas/** 2587233294Sstas * Deprecated: keytypes doesn't exists, they are really enctypes. 2588233294Sstas * 2589233294Sstas * @ingroup krb5_deprecated 2590233294Sstas */ 259172448Sassar 2592233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2593233294Sstaskrb5_keytype_to_enctypes (krb5_context context, 2594233294Sstas krb5_keytype keytype, 2595233294Sstas unsigned *len, 2596233294Sstas krb5_enctype **val) 2597233294Sstas KRB5_DEPRECATED_FUNCTION("Use X instead") 2598233294Sstas{ 2599233294Sstas int i; 2600233294Sstas unsigned n = 0; 2601233294Sstas krb5_enctype *ret; 2602233294Sstas 2603233294Sstas for (i = _krb5_num_etypes - 1; i >= 0; --i) { 2604233294Sstas if (_krb5_etypes[i]->keytype->type == keytype 2605233294Sstas && !(_krb5_etypes[i]->flags & F_PSEUDO) 2606233294Sstas && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0) 2607233294Sstas ++n; 2608233294Sstas } 2609233294Sstas if (n == 0) { 2610233294Sstas krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, 2611233294Sstas "Keytype have no mapping"); 2612233294Sstas return KRB5_PROG_KEYTYPE_NOSUPP; 2613233294Sstas } 2614233294Sstas 2615233294Sstas ret = malloc(n * sizeof(*ret)); 2616233294Sstas if (ret == NULL && n != 0) { 2617233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 2618233294Sstas return ENOMEM; 2619233294Sstas } 2620233294Sstas n = 0; 2621233294Sstas for (i = _krb5_num_etypes - 1; i >= 0; --i) { 2622233294Sstas if (_krb5_etypes[i]->keytype->type == keytype 2623233294Sstas && !(_krb5_etypes[i]->flags & F_PSEUDO) 2624233294Sstas && krb5_enctype_valid(context, _krb5_etypes[i]->type) == 0) 2625233294Sstas ret[n++] = _krb5_etypes[i]->type; 2626233294Sstas } 2627233294Sstas *len = n; 2628233294Sstas *val = ret; 262972448Sassar return 0; 263072448Sassar} 2631233294Sstas 2632233294Sstas/** 2633233294Sstas * Deprecated: keytypes doesn't exists, they are really enctypes. 2634233294Sstas * 2635233294Sstas * @ingroup krb5_deprecated 2636233294Sstas */ 2637233294Sstas 2638233294Sstas/* if two enctypes have compatible keys */ 2639233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 2640233294Sstaskrb5_enctypes_compatible_keys(krb5_context context, 2641233294Sstas krb5_enctype etype1, 2642233294Sstas krb5_enctype etype2) 2643233294Sstas KRB5_DEPRECATED_FUNCTION("Use X instead") 2644233294Sstas{ 2645233294Sstas struct _krb5_encryption_type *e1 = _krb5_find_enctype(etype1); 2646233294Sstas struct _krb5_encryption_type *e2 = _krb5_find_enctype(etype2); 2647233294Sstas return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype; 2648233294Sstas} 2649233294Sstas 2650233294Sstas#endif /* HEIMDAL_SMALLER */ 2651