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