xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/krb5/crypto-pk.c (revision 241bea01a19bbb306af27777a870b86d41cb3fda)
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