1 /* $NetBSD: crypto-pk.c,v 1.1.1.1 2011/04/13 18:15:32 elric 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; 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; 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 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[SHA_DIGEST_LENGTH]; 217 EVP_MD_CTX *m; 218 219 if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha1, &ai->algorithm) != 0) { 220 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 221 N_("KDF not supported", "")); 222 return KRB5_PROG_ETYPE_NOSUPP; 223 } 224 if (ai->parameters != NULL && 225 (ai->parameters->length != 2 || 226 memcmp(ai->parameters->data, "\x05\x00", 2) != 0)) 227 { 228 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 229 N_("kdf params not NULL or the NULL-type", 230 "")); 231 return KRB5_PROG_ETYPE_NOSUPP; 232 } 233 234 et = _krb5_find_enctype(enctype); 235 if(et == NULL) { 236 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 237 N_("encryption type %d not supported", ""), 238 enctype); 239 return KRB5_PROG_ETYPE_NOSUPP; 240 } 241 keylen = (et->keytype->bits + 7) / 8; 242 243 keydata = malloc(keylen); 244 if (keydata == NULL) { 245 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 246 return ENOMEM; 247 } 248 249 ret = encode_otherinfo(context, ai, client, server, 250 enctype, as_req, pk_as_rep, ticket, &other); 251 if (ret) { 252 free(keydata); 253 return ret; 254 } 255 256 m = EVP_MD_CTX_create(); 257 if (m == NULL) { 258 free(keydata); 259 free(other.data); 260 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 261 return ENOMEM; 262 } 263 264 offset = 0; 265 counter = 1; 266 do { 267 unsigned char cdata[4]; 268 269 EVP_DigestInit_ex(m, EVP_sha1(), NULL); 270 _krb5_put_int(cdata, counter, 4); 271 EVP_DigestUpdate(m, cdata, 4); 272 EVP_DigestUpdate(m, dhdata, dhsize); 273 EVP_DigestUpdate(m, other.data, other.length); 274 275 EVP_DigestFinal_ex(m, shaoutput, NULL); 276 277 memcpy((unsigned char *)keydata + offset, 278 shaoutput, 279 min(keylen - offset, sizeof(shaoutput))); 280 281 offset += sizeof(shaoutput); 282 counter++; 283 } while(offset < keylen); 284 memset(shaoutput, 0, sizeof(shaoutput)); 285 286 EVP_MD_CTX_destroy(m); 287 free(other.data); 288 289 ret = krb5_random_to_key(context, enctype, keydata, keylen, key); 290 memset(keydata, 0, sizeof(keylen)); 291 free(keydata); 292 293 return ret; 294 } 295