1226031Sstas/* 2226031Sstas * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan 3226031Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4226031Sstas * All rights reserved. 5226031Sstas * 6226031Sstas * Redistribution and use in source and binary forms, with or without 7226031Sstas * modification, are permitted provided that the following conditions 8226031Sstas * are met: 9226031Sstas * 10226031Sstas * 1. Redistributions of source code must retain the above copyright 11226031Sstas * notice, this list of conditions and the following disclaimer. 12226031Sstas * 13226031Sstas * 2. Redistributions in binary form must reproduce the above copyright 14226031Sstas * notice, this list of conditions and the following disclaimer in the 15226031Sstas * documentation and/or other materials provided with the distribution. 16226031Sstas * 17226031Sstas * 3. Neither the name of the Institute nor the names of its contributors 18226031Sstas * may be used to endorse or promote products derived from this software 19226031Sstas * without specific prior written permission. 20226031Sstas * 21226031Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24226031Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31226031Sstas * SUCH DAMAGE. 32226031Sstas */ 33226031Sstas 34226031Sstas#include "krb5_locl.h" 35226031Sstas 36226031Sstas#include <pkinit_asn1.h> 37226031Sstas 38226031Sstaskrb5_error_code 39226031Sstas_krb5_pk_octetstring2key(krb5_context context, 40226031Sstas krb5_enctype type, 41226031Sstas const void *dhdata, 42226031Sstas size_t dhsize, 43226031Sstas const heim_octet_string *c_n, 44226031Sstas const heim_octet_string *k_n, 45226031Sstas krb5_keyblock *key) 46226031Sstas{ 47226031Sstas struct _krb5_encryption_type *et = _krb5_find_enctype(type); 48226031Sstas krb5_error_code ret; 49226031Sstas size_t keylen, offset; 50226031Sstas void *keydata; 51226031Sstas unsigned char counter; 52226031Sstas unsigned char shaoutput[SHA_DIGEST_LENGTH]; 53226031Sstas EVP_MD_CTX *m; 54226031Sstas 55226031Sstas if(et == NULL) { 56226031Sstas krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 57226031Sstas N_("encryption type %d not supported", ""), 58226031Sstas type); 59226031Sstas return KRB5_PROG_ETYPE_NOSUPP; 60226031Sstas } 61226031Sstas keylen = (et->keytype->bits + 7) / 8; 62226031Sstas 63226031Sstas keydata = malloc(keylen); 64226031Sstas if (keydata == NULL) { 65226031Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 66226031Sstas return ENOMEM; 67226031Sstas } 68226031Sstas 69226031Sstas m = EVP_MD_CTX_create(); 70226031Sstas if (m == NULL) { 71226031Sstas free(keydata); 72226031Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 73226031Sstas return ENOMEM; 74226031Sstas } 75226031Sstas 76226031Sstas counter = 0; 77226031Sstas offset = 0; 78226031Sstas do { 79226031Sstas 80226031Sstas EVP_DigestInit_ex(m, EVP_sha1(), NULL); 81226031Sstas EVP_DigestUpdate(m, &counter, 1); 82226031Sstas EVP_DigestUpdate(m, dhdata, dhsize); 83226031Sstas 84226031Sstas if (c_n) 85226031Sstas EVP_DigestUpdate(m, c_n->data, c_n->length); 86226031Sstas if (k_n) 87226031Sstas EVP_DigestUpdate(m, k_n->data, k_n->length); 88226031Sstas 89226031Sstas EVP_DigestFinal_ex(m, shaoutput, NULL); 90226031Sstas 91226031Sstas memcpy((unsigned char *)keydata + offset, 92226031Sstas shaoutput, 93226031Sstas min(keylen - offset, sizeof(shaoutput))); 94226031Sstas 95226031Sstas offset += sizeof(shaoutput); 96226031Sstas counter++; 97226031Sstas } while(offset < keylen); 98226031Sstas memset(shaoutput, 0, sizeof(shaoutput)); 99226031Sstas 100226031Sstas EVP_MD_CTX_destroy(m); 101226031Sstas 102226031Sstas ret = krb5_random_to_key(context, type, keydata, keylen, key); 103226031Sstas memset(keydata, 0, sizeof(keylen)); 104226031Sstas free(keydata); 105226031Sstas return ret; 106226031Sstas} 107226031Sstas 108226031Sstasstatic krb5_error_code 109226031Sstasencode_uvinfo(krb5_context context, krb5_const_principal p, krb5_data *data) 110226031Sstas{ 111226031Sstas KRB5PrincipalName pn; 112226031Sstas krb5_error_code ret; 113226031Sstas size_t size = 0; 114226031Sstas 115226031Sstas pn.principalName = p->name; 116226031Sstas pn.realm = p->realm; 117226031Sstas 118226031Sstas ASN1_MALLOC_ENCODE(KRB5PrincipalName, data->data, data->length, 119226031Sstas &pn, &size, ret); 120226031Sstas if (ret) { 121226031Sstas krb5_data_zero(data); 122226031Sstas krb5_set_error_message(context, ret, 123226031Sstas N_("Failed to encode KRB5PrincipalName", "")); 124226031Sstas return ret; 125226031Sstas } 126226031Sstas if (data->length != size) 127226031Sstas krb5_abortx(context, "asn1 compiler internal error"); 128226031Sstas return 0; 129226031Sstas} 130226031Sstas 131226031Sstasstatic krb5_error_code 132226031Sstasencode_otherinfo(krb5_context context, 133226031Sstas const AlgorithmIdentifier *ai, 134226031Sstas krb5_const_principal client, 135226031Sstas krb5_const_principal server, 136226031Sstas krb5_enctype enctype, 137226031Sstas const krb5_data *as_req, 138226031Sstas const krb5_data *pk_as_rep, 139226031Sstas const Ticket *ticket, 140226031Sstas krb5_data *other) 141226031Sstas{ 142226031Sstas PkinitSP80056AOtherInfo otherinfo; 143226031Sstas PkinitSuppPubInfo pubinfo; 144226031Sstas krb5_error_code ret; 145226031Sstas krb5_data pub; 146226031Sstas size_t size = 0; 147226031Sstas 148226031Sstas krb5_data_zero(other); 149226031Sstas memset(&otherinfo, 0, sizeof(otherinfo)); 150226031Sstas memset(&pubinfo, 0, sizeof(pubinfo)); 151226031Sstas 152226031Sstas pubinfo.enctype = enctype; 153226031Sstas pubinfo.as_REQ = *as_req; 154226031Sstas pubinfo.pk_as_rep = *pk_as_rep; 155226031Sstas pubinfo.ticket = *ticket; 156226031Sstas ASN1_MALLOC_ENCODE(PkinitSuppPubInfo, pub.data, pub.length, 157226031Sstas &pubinfo, &size, ret); 158226031Sstas if (ret) { 159226031Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 160226031Sstas return ret; 161226031Sstas } 162226031Sstas if (pub.length != size) 163226031Sstas krb5_abortx(context, "asn1 compiler internal error"); 164226031Sstas 165226031Sstas ret = encode_uvinfo(context, client, &otherinfo.partyUInfo); 166226031Sstas if (ret) { 167226031Sstas free(pub.data); 168226031Sstas return ret; 169226031Sstas } 170226031Sstas ret = encode_uvinfo(context, server, &otherinfo.partyVInfo); 171226031Sstas if (ret) { 172226031Sstas free(otherinfo.partyUInfo.data); 173226031Sstas free(pub.data); 174226031Sstas return ret; 175226031Sstas } 176226031Sstas 177226031Sstas otherinfo.algorithmID = *ai; 178226031Sstas otherinfo.suppPubInfo = &pub; 179226031Sstas 180226031Sstas ASN1_MALLOC_ENCODE(PkinitSP80056AOtherInfo, other->data, other->length, 181226031Sstas &otherinfo, &size, ret); 182226031Sstas free(otherinfo.partyUInfo.data); 183226031Sstas free(otherinfo.partyVInfo.data); 184226031Sstas free(pub.data); 185226031Sstas if (ret) { 186226031Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 187226031Sstas return ret; 188226031Sstas } 189226031Sstas if (other->length != size) 190226031Sstas krb5_abortx(context, "asn1 compiler internal error"); 191226031Sstas 192226031Sstas return 0; 193226031Sstas} 194226031Sstas 195226031Sstas 196226031Sstas 197226031Sstaskrb5_error_code 198226031Sstas_krb5_pk_kdf(krb5_context context, 199226031Sstas const struct AlgorithmIdentifier *ai, 200226031Sstas const void *dhdata, 201226031Sstas size_t dhsize, 202226031Sstas krb5_const_principal client, 203226031Sstas krb5_const_principal server, 204226031Sstas krb5_enctype enctype, 205226031Sstas const krb5_data *as_req, 206226031Sstas const krb5_data *pk_as_rep, 207226031Sstas const Ticket *ticket, 208226031Sstas krb5_keyblock *key) 209226031Sstas{ 210226031Sstas struct _krb5_encryption_type *et; 211226031Sstas krb5_error_code ret; 212226031Sstas krb5_data other; 213226031Sstas size_t keylen, offset; 214226031Sstas uint32_t counter; 215226031Sstas unsigned char *keydata; 216226031Sstas unsigned char shaoutput[SHA512_DIGEST_LENGTH]; 217226031Sstas const EVP_MD *md; 218226031Sstas EVP_MD_CTX *m; 219226031Sstas 220226031Sstas if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha1, &ai->algorithm) == 0) { 221226031Sstas md = EVP_sha1(); 222226031Sstas } else if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha256, &ai->algorithm) == 0) { 223226031Sstas md = EVP_sha256(); 224226031Sstas } else if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha512, &ai->algorithm) == 0) { 225226031Sstas md = EVP_sha512(); 226226031Sstas } else { 227226031Sstas krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 228226031Sstas N_("KDF not supported", "")); 229226031Sstas return KRB5_PROG_ETYPE_NOSUPP; 230226031Sstas } 231226031Sstas if (ai->parameters != NULL && 232226031Sstas (ai->parameters->length != 2 || 233226031Sstas memcmp(ai->parameters->data, "\x05\x00", 2) != 0)) 234226031Sstas { 235226031Sstas krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 236226031Sstas N_("kdf params not NULL or the NULL-type", 237226031Sstas "")); 238226031Sstas return KRB5_PROG_ETYPE_NOSUPP; 239226031Sstas } 240226031Sstas 241226031Sstas et = _krb5_find_enctype(enctype); 242226031Sstas if(et == NULL) { 243226031Sstas krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 244226031Sstas N_("encryption type %d not supported", ""), 245226031Sstas enctype); 246226031Sstas return KRB5_PROG_ETYPE_NOSUPP; 247226031Sstas } 248226031Sstas keylen = (et->keytype->bits + 7) / 8; 249226031Sstas 250226031Sstas keydata = malloc(keylen); 251226031Sstas if (keydata == NULL) { 252226031Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 253226031Sstas return ENOMEM; 254226031Sstas } 255226031Sstas 256226031Sstas ret = encode_otherinfo(context, ai, client, server, 257226031Sstas enctype, as_req, pk_as_rep, ticket, &other); 258226031Sstas if (ret) { 259226031Sstas free(keydata); 260226031Sstas return ret; 261226031Sstas } 262226031Sstas 263226031Sstas m = EVP_MD_CTX_create(); 264226031Sstas if (m == NULL) { 265226031Sstas free(keydata); 266226031Sstas free(other.data); 267226031Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 268226031Sstas return ENOMEM; 269226031Sstas } 270226031Sstas 271226031Sstas offset = 0; 272226031Sstas counter = 1; 273226031Sstas do { 274226031Sstas unsigned char cdata[4]; 275226031Sstas 276226031Sstas EVP_DigestInit_ex(m, md, NULL); 277226031Sstas _krb5_put_int(cdata, counter, 4); 278226031Sstas EVP_DigestUpdate(m, cdata, 4); 279226031Sstas EVP_DigestUpdate(m, dhdata, dhsize); 280226031Sstas EVP_DigestUpdate(m, other.data, other.length); 281226031Sstas 282226031Sstas EVP_DigestFinal_ex(m, shaoutput, NULL); 283226031Sstas 284226031Sstas memcpy((unsigned char *)keydata + offset, 285226031Sstas shaoutput, 286226031Sstas min(keylen - offset, EVP_MD_CTX_size(m))); 287226031Sstas 288226031Sstas offset += EVP_MD_CTX_size(m); 289226031Sstas counter++; 290226031Sstas } while(offset < keylen); 291226031Sstas memset(shaoutput, 0, sizeof(shaoutput)); 292226031Sstas 293226031Sstas EVP_MD_CTX_destroy(m); 294226031Sstas free(other.data); 295226031Sstas 296226031Sstas ret = krb5_random_to_key(context, enctype, keydata, keylen, key); 297226031Sstas memset(keydata, 0, sizeof(keylen)); 298226031Sstas free(keydata); 299226031Sstas 300226031Sstas return ret; 301226031Sstas} 302