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