1 /* $NetBSD: crypto-pk.c,v 1.2 2017/01/28 21:31:49 christos 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_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 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 return krb5_enomem(context); 68 69 m = EVP_MD_CTX_create(); 70 if (m == NULL) { 71 free(keydata); 72 return krb5_enomem(context); 73 } 74 75 counter = 0; 76 offset = 0; 77 do { 78 79 EVP_DigestInit_ex(m, EVP_sha1(), NULL); 80 EVP_DigestUpdate(m, &counter, 1); 81 EVP_DigestUpdate(m, dhdata, dhsize); 82 83 if (c_n) 84 EVP_DigestUpdate(m, c_n->data, c_n->length); 85 if (k_n) 86 EVP_DigestUpdate(m, k_n->data, k_n->length); 87 88 EVP_DigestFinal_ex(m, shaoutput, NULL); 89 90 memcpy((unsigned char *)keydata + offset, 91 shaoutput, 92 min(keylen - offset, sizeof(shaoutput))); 93 94 offset += sizeof(shaoutput); 95 counter++; 96 } while(offset < keylen); 97 memset(shaoutput, 0, sizeof(shaoutput)); 98 99 EVP_MD_CTX_destroy(m); 100 101 ret = krb5_random_to_key(context, type, keydata, keylen, key); 102 memset(keydata, 0, sizeof(keylen)); 103 free(keydata); 104 return ret; 105 } 106 107 static krb5_error_code 108 encode_uvinfo(krb5_context context, krb5_const_principal p, krb5_data *data) 109 { 110 KRB5PrincipalName pn; 111 krb5_error_code ret; 112 size_t size = 0; 113 114 pn.principalName = p->name; 115 pn.realm = p->realm; 116 117 ASN1_MALLOC_ENCODE(KRB5PrincipalName, data->data, data->length, 118 &pn, &size, ret); 119 if (ret) { 120 krb5_data_zero(data); 121 krb5_set_error_message(context, ret, 122 N_("Failed to encode KRB5PrincipalName", "")); 123 return ret; 124 } 125 if (data->length != size) 126 krb5_abortx(context, "asn1 compiler internal error"); 127 return 0; 128 } 129 130 static krb5_error_code 131 encode_otherinfo(krb5_context context, 132 const AlgorithmIdentifier *ai, 133 krb5_const_principal client, 134 krb5_const_principal server, 135 krb5_enctype enctype, 136 const krb5_data *as_req, 137 const krb5_data *pk_as_rep, 138 const Ticket *ticket, 139 krb5_data *other) 140 { 141 PkinitSP80056AOtherInfo otherinfo; 142 PkinitSuppPubInfo pubinfo; 143 krb5_error_code ret; 144 krb5_data pub; 145 size_t size = 0; 146 147 krb5_data_zero(other); 148 memset(&otherinfo, 0, sizeof(otherinfo)); 149 memset(&pubinfo, 0, sizeof(pubinfo)); 150 151 pubinfo.enctype = enctype; 152 pubinfo.as_REQ = *as_req; 153 pubinfo.pk_as_rep = *pk_as_rep; 154 pubinfo.ticket = *ticket; 155 ASN1_MALLOC_ENCODE(PkinitSuppPubInfo, pub.data, pub.length, 156 &pubinfo, &size, ret); 157 if (ret) { 158 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 159 return ret; 160 } 161 if (pub.length != size) 162 krb5_abortx(context, "asn1 compiler internal error"); 163 164 ret = encode_uvinfo(context, client, &otherinfo.partyUInfo); 165 if (ret) { 166 free(pub.data); 167 return ret; 168 } 169 ret = encode_uvinfo(context, server, &otherinfo.partyVInfo); 170 if (ret) { 171 free(otherinfo.partyUInfo.data); 172 free(pub.data); 173 return ret; 174 } 175 176 otherinfo.algorithmID = *ai; 177 otherinfo.suppPubInfo = &pub; 178 179 ASN1_MALLOC_ENCODE(PkinitSP80056AOtherInfo, other->data, other->length, 180 &otherinfo, &size, ret); 181 free(otherinfo.partyUInfo.data); 182 free(otherinfo.partyVInfo.data); 183 free(pub.data); 184 if (ret) { 185 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 186 return ret; 187 } 188 if (other->length != size) 189 krb5_abortx(context, "asn1 compiler internal error"); 190 191 return 0; 192 } 193 194 195 196 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 197 _krb5_pk_kdf(krb5_context context, 198 const struct AlgorithmIdentifier *ai, 199 const void *dhdata, 200 size_t dhsize, 201 krb5_const_principal client, 202 krb5_const_principal server, 203 krb5_enctype enctype, 204 const krb5_data *as_req, 205 const krb5_data *pk_as_rep, 206 const Ticket *ticket, 207 krb5_keyblock *key) 208 { 209 struct _krb5_encryption_type *et; 210 krb5_error_code ret; 211 krb5_data other; 212 size_t keylen, offset; 213 uint32_t counter; 214 unsigned char *keydata; 215 unsigned char shaoutput[SHA512_DIGEST_LENGTH]; 216 const EVP_MD *md; 217 EVP_MD_CTX *m; 218 219 if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha1, &ai->algorithm) == 0) { 220 md = EVP_sha1(); 221 } else if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha256, &ai->algorithm) == 0) { 222 md = EVP_sha256(); 223 } else if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha512, &ai->algorithm) == 0) { 224 md = EVP_sha512(); 225 } else { 226 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 227 N_("KDF not supported", "")); 228 return KRB5_PROG_ETYPE_NOSUPP; 229 } 230 if (ai->parameters != NULL && 231 (ai->parameters->length != 2 || 232 memcmp(ai->parameters->data, "\x05\x00", 2) != 0)) 233 { 234 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 235 N_("kdf params not NULL or the NULL-type", 236 "")); 237 return KRB5_PROG_ETYPE_NOSUPP; 238 } 239 240 et = _krb5_find_enctype(enctype); 241 if(et == NULL) { 242 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 243 N_("encryption type %d not supported", ""), 244 enctype); 245 return KRB5_PROG_ETYPE_NOSUPP; 246 } 247 keylen = (et->keytype->bits + 7) / 8; 248 249 keydata = malloc(keylen); 250 if (keydata == NULL) 251 return krb5_enomem(context); 252 253 ret = encode_otherinfo(context, ai, client, server, 254 enctype, as_req, pk_as_rep, ticket, &other); 255 if (ret) { 256 free(keydata); 257 return ret; 258 } 259 260 m = EVP_MD_CTX_create(); 261 if (m == NULL) { 262 free(keydata); 263 free(other.data); 264 return krb5_enomem(context); 265 } 266 267 offset = 0; 268 counter = 1; 269 do { 270 unsigned char cdata[4]; 271 272 EVP_DigestInit_ex(m, md, NULL); 273 _krb5_put_int(cdata, counter, 4); 274 EVP_DigestUpdate(m, cdata, 4); 275 EVP_DigestUpdate(m, dhdata, dhsize); 276 EVP_DigestUpdate(m, other.data, other.length); 277 278 EVP_DigestFinal_ex(m, shaoutput, NULL); 279 280 memcpy((unsigned char *)keydata + offset, 281 shaoutput, 282 min(keylen - offset, EVP_MD_CTX_size(m))); 283 284 offset += EVP_MD_CTX_size(m); 285 counter++; 286 } while(offset < keylen); 287 memset(shaoutput, 0, sizeof(shaoutput)); 288 289 EVP_MD_CTX_destroy(m); 290 free(other.data); 291 292 ret = krb5_random_to_key(context, enctype, keydata, keylen, key); 293 memset(keydata, 0, sizeof(keylen)); 294 free(keydata); 295 296 return ret; 297 } 298