1 /* 2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "krb5_locl.h" 35 36 #include <pkinit_asn1.h> 37 38 krb5_error_code 39 _krb5_pk_octetstring2key(krb5_context context, 40 krb5_enctype type, 41 const void *dhdata, 42 size_t dhsize, 43 const heim_octet_string *c_n, 44 const heim_octet_string *k_n, 45 krb5_keyblock *key) 46 { 47 struct _krb5_encryption_type *et = _krb5_find_enctype(type); 48 krb5_error_code ret; 49 size_t keylen, offset; 50 void *keydata; 51 unsigned char counter; 52 unsigned char shaoutput[SHA_DIGEST_LENGTH]; 53 EVP_MD_CTX *m; 54 55 if(et == NULL) { 56 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 57 N_("encryption type %d not supported", ""), 58 type); 59 return KRB5_PROG_ETYPE_NOSUPP; 60 } 61 keylen = (et->keytype->bits + 7) / 8; 62 63 keydata = malloc(keylen); 64 if (keydata == NULL) { 65 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 66 return ENOMEM; 67 } 68 69 m = EVP_MD_CTX_create(); 70 if (m == NULL) { 71 free(keydata); 72 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 73 return ENOMEM; 74 } 75 76 counter = 0; 77 offset = 0; 78 do { 79 80 EVP_DigestInit_ex(m, EVP_sha1(), NULL); 81 EVP_DigestUpdate(m, &counter, 1); 82 EVP_DigestUpdate(m, dhdata, dhsize); 83 84 if (c_n) 85 EVP_DigestUpdate(m, c_n->data, c_n->length); 86 if (k_n) 87 EVP_DigestUpdate(m, k_n->data, k_n->length); 88 89 EVP_DigestFinal_ex(m, shaoutput, NULL); 90 91 memcpy((unsigned char *)keydata + offset, 92 shaoutput, 93 min(keylen - offset, sizeof(shaoutput))); 94 95 offset += sizeof(shaoutput); 96 counter++; 97 } while(offset < keylen); 98 memset(shaoutput, 0, sizeof(shaoutput)); 99 100 EVP_MD_CTX_destroy(m); 101 102 ret = krb5_random_to_key(context, type, keydata, keylen, key); 103 memset(keydata, 0, sizeof(keylen)); 104 free(keydata); 105 return ret; 106 } 107 108 static krb5_error_code 109 encode_uvinfo(krb5_context context, krb5_const_principal p, krb5_data *data) 110 { 111 KRB5PrincipalName pn; 112 krb5_error_code ret; 113 size_t size = 0; 114 115 pn.principalName = p->name; 116 pn.realm = p->realm; 117 118 ASN1_MALLOC_ENCODE(KRB5PrincipalName, data->data, data->length, 119 &pn, &size, ret); 120 if (ret) { 121 krb5_data_zero(data); 122 krb5_set_error_message(context, ret, 123 N_("Failed to encode KRB5PrincipalName", "")); 124 return ret; 125 } 126 if (data->length != size) 127 krb5_abortx(context, "asn1 compiler internal error"); 128 return 0; 129 } 130 131 static krb5_error_code 132 encode_otherinfo(krb5_context context, 133 const AlgorithmIdentifier *ai, 134 krb5_const_principal client, 135 krb5_const_principal server, 136 krb5_enctype enctype, 137 const krb5_data *as_req, 138 const krb5_data *pk_as_rep, 139 const Ticket *ticket, 140 krb5_data *other) 141 { 142 PkinitSP80056AOtherInfo otherinfo; 143 PkinitSuppPubInfo pubinfo; 144 krb5_error_code ret; 145 krb5_data pub; 146 size_t size = 0; 147 148 krb5_data_zero(other); 149 memset(&otherinfo, 0, sizeof(otherinfo)); 150 memset(&pubinfo, 0, sizeof(pubinfo)); 151 152 pubinfo.enctype = enctype; 153 pubinfo.as_REQ = *as_req; 154 pubinfo.pk_as_rep = *pk_as_rep; 155 pubinfo.ticket = *ticket; 156 ASN1_MALLOC_ENCODE(PkinitSuppPubInfo, pub.data, pub.length, 157 &pubinfo, &size, ret); 158 if (ret) { 159 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 160 return ret; 161 } 162 if (pub.length != size) 163 krb5_abortx(context, "asn1 compiler internal error"); 164 165 ret = encode_uvinfo(context, client, &otherinfo.partyUInfo); 166 if (ret) { 167 free(pub.data); 168 return ret; 169 } 170 ret = encode_uvinfo(context, server, &otherinfo.partyVInfo); 171 if (ret) { 172 free(otherinfo.partyUInfo.data); 173 free(pub.data); 174 return ret; 175 } 176 177 otherinfo.algorithmID = *ai; 178 otherinfo.suppPubInfo = &pub; 179 180 ASN1_MALLOC_ENCODE(PkinitSP80056AOtherInfo, other->data, other->length, 181 &otherinfo, &size, ret); 182 free(otherinfo.partyUInfo.data); 183 free(otherinfo.partyVInfo.data); 184 free(pub.data); 185 if (ret) { 186 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 187 return ret; 188 } 189 if (other->length != size) 190 krb5_abortx(context, "asn1 compiler internal error"); 191 192 return 0; 193 } 194 195 196 197 krb5_error_code 198 _krb5_pk_kdf(krb5_context context, 199 const struct AlgorithmIdentifier *ai, 200 const void *dhdata, 201 size_t dhsize, 202 krb5_const_principal client, 203 krb5_const_principal server, 204 krb5_enctype enctype, 205 const krb5_data *as_req, 206 const krb5_data *pk_as_rep, 207 const Ticket *ticket, 208 krb5_keyblock *key) 209 { 210 struct _krb5_encryption_type *et; 211 krb5_error_code ret; 212 krb5_data other; 213 size_t keylen, offset; 214 uint32_t counter; 215 unsigned char *keydata; 216 unsigned char shaoutput[SHA512_DIGEST_LENGTH]; 217 const EVP_MD *md; 218 EVP_MD_CTX *m; 219 220 if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha1, &ai->algorithm) == 0) { 221 md = EVP_sha1(); 222 } else if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha256, &ai->algorithm) == 0) { 223 md = EVP_sha256(); 224 } else if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha512, &ai->algorithm) == 0) { 225 md = EVP_sha512(); 226 } else { 227 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 228 N_("KDF not supported", "")); 229 return KRB5_PROG_ETYPE_NOSUPP; 230 } 231 if (ai->parameters != NULL && 232 (ai->parameters->length != 2 || 233 memcmp(ai->parameters->data, "\x05\x00", 2) != 0)) 234 { 235 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 236 N_("kdf params not NULL or the NULL-type", 237 "")); 238 return KRB5_PROG_ETYPE_NOSUPP; 239 } 240 241 et = _krb5_find_enctype(enctype); 242 if(et == NULL) { 243 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 244 N_("encryption type %d not supported", ""), 245 enctype); 246 return KRB5_PROG_ETYPE_NOSUPP; 247 } 248 keylen = (et->keytype->bits + 7) / 8; 249 250 keydata = malloc(keylen); 251 if (keydata == NULL) { 252 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 253 return ENOMEM; 254 } 255 256 ret = encode_otherinfo(context, ai, client, server, 257 enctype, as_req, pk_as_rep, ticket, &other); 258 if (ret) { 259 free(keydata); 260 return ret; 261 } 262 263 m = EVP_MD_CTX_create(); 264 if (m == NULL) { 265 free(keydata); 266 free(other.data); 267 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 268 return ENOMEM; 269 } 270 271 offset = 0; 272 counter = 1; 273 do { 274 unsigned char cdata[4]; 275 276 EVP_DigestInit_ex(m, md, NULL); 277 _krb5_put_int(cdata, counter, 4); 278 EVP_DigestUpdate(m, cdata, 4); 279 EVP_DigestUpdate(m, dhdata, dhsize); 280 EVP_DigestUpdate(m, other.data, other.length); 281 282 EVP_DigestFinal_ex(m, shaoutput, NULL); 283 284 memcpy((unsigned char *)keydata + offset, 285 shaoutput, 286 min(keylen - offset, EVP_MD_CTX_size(m))); 287 288 offset += EVP_MD_CTX_size(m); 289 counter++; 290 } while(offset < keylen); 291 memset(shaoutput, 0, sizeof(shaoutput)); 292 293 EVP_MD_CTX_destroy(m); 294 free(other.data); 295 296 ret = krb5_random_to_key(context, enctype, keydata, keylen, key); 297 memset(keydata, 0, sizeof(keylen)); 298 free(keydata); 299 300 return ret; 301 } 302