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