1 /* $NetBSD: crypto-pk.c,v 1.3 2019/12/15 22:50:50 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
_krb5_pk_octetstring2key(krb5_context context,krb5_enctype type,const void * dhdata,size_t dhsize,const heim_octet_string * c_n,const heim_octet_string * k_n,krb5_keyblock * key)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_s(shaoutput, sizeof(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_s(keydata, sizeof(keylen), 0, sizeof(keylen));
103 free(keydata);
104 return ret;
105 }
106
107 static krb5_error_code
encode_uvinfo(krb5_context context,krb5_const_principal p,krb5_data * data)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
encode_otherinfo(krb5_context context,const AlgorithmIdentifier * ai,krb5_const_principal client,krb5_const_principal server,krb5_enctype enctype,const krb5_data * as_req,const krb5_data * pk_as_rep,const Ticket * ticket,krb5_data * other)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
_krb5_pk_kdf(krb5_context context,const struct AlgorithmIdentifier * ai,const void * dhdata,size_t dhsize,krb5_const_principal client,krb5_const_principal server,krb5_enctype enctype,const krb5_data * as_req,const krb5_data * pk_as_rep,const Ticket * ticket,krb5_keyblock * key)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_s(shaoutput, sizeof(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_s(keydata, sizeof(keylen), 0, sizeof(keylen));
294 free(keydata);
295
296 return ret;
297 }
298