1*0a6a1f1dSLionel Sambuc /*	$NetBSD: pkinit.c,v 1.1.1.2 2014/04/24 12:45:50 pettai Exp $	*/
2ebfedea0SLionel Sambuc 
3ebfedea0SLionel Sambuc /*
4ebfedea0SLionel Sambuc  * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
5ebfedea0SLionel Sambuc  * (Royal Institute of Technology, Stockholm, Sweden).
6ebfedea0SLionel Sambuc  * All rights reserved.
7ebfedea0SLionel Sambuc  *
8ebfedea0SLionel Sambuc  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
9ebfedea0SLionel Sambuc  *
10ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
11ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
12ebfedea0SLionel Sambuc  * are met:
13ebfedea0SLionel Sambuc  *
14ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
15ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
16ebfedea0SLionel Sambuc  *
17ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
18ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
19ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
20ebfedea0SLionel Sambuc  *
21ebfedea0SLionel Sambuc  * 3. Neither the name of the Institute nor the names of its contributors
22ebfedea0SLionel Sambuc  *    may be used to endorse or promote products derived from this software
23ebfedea0SLionel Sambuc  *    without specific prior written permission.
24ebfedea0SLionel Sambuc  *
25ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26ebfedea0SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27ebfedea0SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ebfedea0SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29ebfedea0SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30ebfedea0SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31ebfedea0SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32ebfedea0SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33ebfedea0SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34ebfedea0SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35ebfedea0SLionel Sambuc  * SUCH DAMAGE.
36ebfedea0SLionel Sambuc  */
37ebfedea0SLionel Sambuc 
38ebfedea0SLionel Sambuc #include "krb5_locl.h"
39ebfedea0SLionel Sambuc 
40ebfedea0SLionel Sambuc struct krb5_dh_moduli {
41ebfedea0SLionel Sambuc     char *name;
42ebfedea0SLionel Sambuc     unsigned long bits;
43ebfedea0SLionel Sambuc     heim_integer p;
44ebfedea0SLionel Sambuc     heim_integer g;
45ebfedea0SLionel Sambuc     heim_integer q;
46ebfedea0SLionel Sambuc };
47ebfedea0SLionel Sambuc 
48ebfedea0SLionel Sambuc #ifdef PKINIT
49ebfedea0SLionel Sambuc 
50ebfedea0SLionel Sambuc #include <krb5/cms_asn1.h>
51ebfedea0SLionel Sambuc #include <krb5/pkcs8_asn1.h>
52ebfedea0SLionel Sambuc #include <krb5/pkcs9_asn1.h>
53ebfedea0SLionel Sambuc #include <krb5/pkcs12_asn1.h>
54ebfedea0SLionel Sambuc #include <krb5/pkinit_asn1.h>
55ebfedea0SLionel Sambuc #include <krb5/asn1_err.h>
56ebfedea0SLionel Sambuc 
57ebfedea0SLionel Sambuc #include <krb5/der.h>
58ebfedea0SLionel Sambuc 
59ebfedea0SLionel Sambuc struct krb5_pk_cert {
60ebfedea0SLionel Sambuc     hx509_cert cert;
61ebfedea0SLionel Sambuc };
62ebfedea0SLionel Sambuc 
63ebfedea0SLionel Sambuc struct krb5_pk_init_ctx_data {
64ebfedea0SLionel Sambuc     struct krb5_pk_identity *id;
65ebfedea0SLionel Sambuc     enum { USE_RSA, USE_DH, USE_ECDH } keyex;
66ebfedea0SLionel Sambuc     union {
67ebfedea0SLionel Sambuc 	DH *dh;
68ebfedea0SLionel Sambuc #ifdef HAVE_OPENSSL
69ebfedea0SLionel Sambuc 	EC_KEY *eckey;
70ebfedea0SLionel Sambuc #endif
71ebfedea0SLionel Sambuc     } u;
72ebfedea0SLionel Sambuc     krb5_data *clientDHNonce;
73ebfedea0SLionel Sambuc     struct krb5_dh_moduli **m;
74ebfedea0SLionel Sambuc     hx509_peer_info peer;
75ebfedea0SLionel Sambuc     enum krb5_pk_type type;
76ebfedea0SLionel Sambuc     unsigned int require_binding:1;
77ebfedea0SLionel Sambuc     unsigned int require_eku:1;
78ebfedea0SLionel Sambuc     unsigned int require_krbtgt_otherName:1;
79ebfedea0SLionel Sambuc     unsigned int require_hostname_match:1;
80ebfedea0SLionel Sambuc     unsigned int trustedCertifiers:1;
81ebfedea0SLionel Sambuc     unsigned int anonymous:1;
82ebfedea0SLionel Sambuc };
83ebfedea0SLionel Sambuc 
84ebfedea0SLionel Sambuc static void
85ebfedea0SLionel Sambuc pk_copy_error(krb5_context context,
86ebfedea0SLionel Sambuc 	      hx509_context hx509ctx,
87ebfedea0SLionel Sambuc 	      int hxret,
88ebfedea0SLionel Sambuc 	      const char *fmt,
89ebfedea0SLionel Sambuc 	      ...)
90ebfedea0SLionel Sambuc     __attribute__ ((format (printf, 4, 5)));
91ebfedea0SLionel Sambuc 
92ebfedea0SLionel Sambuc /*
93ebfedea0SLionel Sambuc  *
94ebfedea0SLionel Sambuc  */
95ebfedea0SLionel Sambuc 
96ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION void KRB5_LIB_CALL
_krb5_pk_cert_free(struct krb5_pk_cert * cert)97ebfedea0SLionel Sambuc _krb5_pk_cert_free(struct krb5_pk_cert *cert)
98ebfedea0SLionel Sambuc {
99ebfedea0SLionel Sambuc     if (cert->cert) {
100ebfedea0SLionel Sambuc 	hx509_cert_free(cert->cert);
101ebfedea0SLionel Sambuc     }
102ebfedea0SLionel Sambuc     free(cert);
103ebfedea0SLionel Sambuc }
104ebfedea0SLionel Sambuc 
105ebfedea0SLionel Sambuc static krb5_error_code
BN_to_integer(krb5_context context,BIGNUM * bn,heim_integer * integer)106ebfedea0SLionel Sambuc BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer)
107ebfedea0SLionel Sambuc {
108ebfedea0SLionel Sambuc     integer->length = BN_num_bytes(bn);
109ebfedea0SLionel Sambuc     integer->data = malloc(integer->length);
110ebfedea0SLionel Sambuc     if (integer->data == NULL) {
111ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
112ebfedea0SLionel Sambuc 	return ENOMEM;
113ebfedea0SLionel Sambuc     }
114ebfedea0SLionel Sambuc     BN_bn2bin(bn, integer->data);
115ebfedea0SLionel Sambuc     integer->negative = BN_is_negative(bn);
116ebfedea0SLionel Sambuc     return 0;
117ebfedea0SLionel Sambuc }
118ebfedea0SLionel Sambuc 
119ebfedea0SLionel Sambuc static BIGNUM *
integer_to_BN(krb5_context context,const char * field,const heim_integer * f)120ebfedea0SLionel Sambuc integer_to_BN(krb5_context context, const char *field, const heim_integer *f)
121ebfedea0SLionel Sambuc {
122ebfedea0SLionel Sambuc     BIGNUM *bn;
123ebfedea0SLionel Sambuc 
124ebfedea0SLionel Sambuc     bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL);
125ebfedea0SLionel Sambuc     if (bn == NULL) {
126ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM,
127ebfedea0SLionel Sambuc 			       N_("PKINIT: parsing BN failed %s", ""), field);
128ebfedea0SLionel Sambuc 	return NULL;
129ebfedea0SLionel Sambuc     }
130ebfedea0SLionel Sambuc     BN_set_negative(bn, f->negative);
131ebfedea0SLionel Sambuc     return bn;
132ebfedea0SLionel Sambuc }
133ebfedea0SLionel Sambuc 
134ebfedea0SLionel Sambuc static krb5_error_code
select_dh_group(krb5_context context,DH * dh,unsigned long bits,struct krb5_dh_moduli ** moduli)135ebfedea0SLionel Sambuc select_dh_group(krb5_context context, DH *dh, unsigned long bits,
136ebfedea0SLionel Sambuc 		struct krb5_dh_moduli **moduli)
137ebfedea0SLionel Sambuc {
138ebfedea0SLionel Sambuc     const struct krb5_dh_moduli *m;
139ebfedea0SLionel Sambuc 
140ebfedea0SLionel Sambuc     if (bits == 0) {
141ebfedea0SLionel Sambuc 	m = moduli[1]; /* XXX */
142ebfedea0SLionel Sambuc 	if (m == NULL)
143ebfedea0SLionel Sambuc 	    m = moduli[0]; /* XXX */
144ebfedea0SLionel Sambuc     } else {
145ebfedea0SLionel Sambuc 	int i;
146ebfedea0SLionel Sambuc 	for (i = 0; moduli[i] != NULL; i++) {
147ebfedea0SLionel Sambuc 	    if (bits < moduli[i]->bits)
148ebfedea0SLionel Sambuc 		break;
149ebfedea0SLionel Sambuc 	}
150ebfedea0SLionel Sambuc 	if (moduli[i] == NULL) {
151ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, EINVAL,
152ebfedea0SLionel Sambuc 				   N_("Did not find a DH group parameter "
153ebfedea0SLionel Sambuc 				      "matching requirement of %lu bits", ""),
154ebfedea0SLionel Sambuc 				   bits);
155ebfedea0SLionel Sambuc 	    return EINVAL;
156ebfedea0SLionel Sambuc 	}
157ebfedea0SLionel Sambuc 	m = moduli[i];
158ebfedea0SLionel Sambuc     }
159ebfedea0SLionel Sambuc 
160ebfedea0SLionel Sambuc     dh->p = integer_to_BN(context, "p", &m->p);
161ebfedea0SLionel Sambuc     if (dh->p == NULL)
162ebfedea0SLionel Sambuc 	return ENOMEM;
163ebfedea0SLionel Sambuc     dh->g = integer_to_BN(context, "g", &m->g);
164ebfedea0SLionel Sambuc     if (dh->g == NULL)
165ebfedea0SLionel Sambuc 	return ENOMEM;
166ebfedea0SLionel Sambuc     dh->q = integer_to_BN(context, "q", &m->q);
167ebfedea0SLionel Sambuc     if (dh->q == NULL)
168ebfedea0SLionel Sambuc 	return ENOMEM;
169ebfedea0SLionel Sambuc 
170ebfedea0SLionel Sambuc     return 0;
171ebfedea0SLionel Sambuc }
172ebfedea0SLionel Sambuc 
173ebfedea0SLionel Sambuc struct certfind {
174ebfedea0SLionel Sambuc     const char *type;
175ebfedea0SLionel Sambuc     const heim_oid *oid;
176ebfedea0SLionel Sambuc };
177ebfedea0SLionel Sambuc 
178ebfedea0SLionel Sambuc /*
179ebfedea0SLionel Sambuc  * Try searchin the key by to use by first looking for for PK-INIT
180ebfedea0SLionel Sambuc  * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
181ebfedea0SLionel Sambuc  */
182ebfedea0SLionel Sambuc 
183ebfedea0SLionel Sambuc static krb5_error_code
find_cert(krb5_context context,struct krb5_pk_identity * id,hx509_query * q,hx509_cert * cert)184ebfedea0SLionel Sambuc find_cert(krb5_context context, struct krb5_pk_identity *id,
185ebfedea0SLionel Sambuc 	  hx509_query *q, hx509_cert *cert)
186ebfedea0SLionel Sambuc {
187ebfedea0SLionel Sambuc     struct certfind cf[4] = {
188ebfedea0SLionel Sambuc 	{ "MobileMe EKU" },
189ebfedea0SLionel Sambuc 	{ "PKINIT EKU" },
190ebfedea0SLionel Sambuc 	{ "MS EKU" },
191ebfedea0SLionel Sambuc 	{ "any (or no)" }
192ebfedea0SLionel Sambuc     };
193*0a6a1f1dSLionel Sambuc     int ret = HX509_CERT_NOT_FOUND;
194*0a6a1f1dSLionel Sambuc     size_t i, start = 1;
195ebfedea0SLionel Sambuc     unsigned oids[] = { 1, 2, 840, 113635, 100, 3, 2, 1 };
196ebfedea0SLionel Sambuc     const heim_oid mobileMe = { sizeof(oids)/sizeof(oids[0]), oids };
197ebfedea0SLionel Sambuc 
198ebfedea0SLionel Sambuc 
199ebfedea0SLionel Sambuc     if (id->flags & PKINIT_BTMM)
200ebfedea0SLionel Sambuc 	start = 0;
201ebfedea0SLionel Sambuc 
202ebfedea0SLionel Sambuc     cf[0].oid = &mobileMe;
203ebfedea0SLionel Sambuc     cf[1].oid = &asn1_oid_id_pkekuoid;
204ebfedea0SLionel Sambuc     cf[2].oid = &asn1_oid_id_pkinit_ms_eku;
205ebfedea0SLionel Sambuc     cf[3].oid = NULL;
206ebfedea0SLionel Sambuc 
207ebfedea0SLionel Sambuc     for (i = start; i < sizeof(cf)/sizeof(cf[0]); i++) {
208ebfedea0SLionel Sambuc 	ret = hx509_query_match_eku(q, cf[i].oid);
209ebfedea0SLionel Sambuc 	if (ret) {
210ebfedea0SLionel Sambuc 	    pk_copy_error(context, context->hx509ctx, ret,
211ebfedea0SLionel Sambuc 			  "Failed setting %s OID", cf[i].type);
212ebfedea0SLionel Sambuc 	    return ret;
213ebfedea0SLionel Sambuc 	}
214ebfedea0SLionel Sambuc 
215ebfedea0SLionel Sambuc 	ret = hx509_certs_find(context->hx509ctx, id->certs, q, cert);
216ebfedea0SLionel Sambuc 	if (ret == 0)
217ebfedea0SLionel Sambuc 	    break;
218ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
219ebfedea0SLionel Sambuc 		      "Failed finding certificate with %s OID", cf[i].type);
220ebfedea0SLionel Sambuc     }
221ebfedea0SLionel Sambuc     return ret;
222ebfedea0SLionel Sambuc }
223ebfedea0SLionel Sambuc 
224ebfedea0SLionel Sambuc 
225ebfedea0SLionel Sambuc static krb5_error_code
create_signature(krb5_context context,const heim_oid * eContentType,krb5_data * eContent,struct krb5_pk_identity * id,hx509_peer_info peer,krb5_data * sd_data)226ebfedea0SLionel Sambuc create_signature(krb5_context context,
227ebfedea0SLionel Sambuc 		 const heim_oid *eContentType,
228ebfedea0SLionel Sambuc 		 krb5_data *eContent,
229ebfedea0SLionel Sambuc 		 struct krb5_pk_identity *id,
230ebfedea0SLionel Sambuc 		 hx509_peer_info peer,
231ebfedea0SLionel Sambuc 		 krb5_data *sd_data)
232ebfedea0SLionel Sambuc {
233ebfedea0SLionel Sambuc     int ret, flags = 0;
234ebfedea0SLionel Sambuc 
235ebfedea0SLionel Sambuc     if (id->cert == NULL)
236ebfedea0SLionel Sambuc 	flags |= HX509_CMS_SIGNATURE_NO_SIGNER;
237ebfedea0SLionel Sambuc 
238ebfedea0SLionel Sambuc     ret = hx509_cms_create_signed_1(context->hx509ctx,
239ebfedea0SLionel Sambuc 				    flags,
240ebfedea0SLionel Sambuc 				    eContentType,
241ebfedea0SLionel Sambuc 				    eContent->data,
242ebfedea0SLionel Sambuc 				    eContent->length,
243ebfedea0SLionel Sambuc 				    NULL,
244ebfedea0SLionel Sambuc 				    id->cert,
245ebfedea0SLionel Sambuc 				    peer,
246ebfedea0SLionel Sambuc 				    NULL,
247ebfedea0SLionel Sambuc 				    id->certs,
248ebfedea0SLionel Sambuc 				    sd_data);
249ebfedea0SLionel Sambuc     if (ret) {
250ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
251ebfedea0SLionel Sambuc 		      "Create CMS signedData");
252ebfedea0SLionel Sambuc 	return ret;
253ebfedea0SLionel Sambuc     }
254ebfedea0SLionel Sambuc 
255ebfedea0SLionel Sambuc     return 0;
256ebfedea0SLionel Sambuc }
257ebfedea0SLionel Sambuc 
258ebfedea0SLionel Sambuc static int
cert2epi(hx509_context context,void * ctx,hx509_cert c)259ebfedea0SLionel Sambuc cert2epi(hx509_context context, void *ctx, hx509_cert c)
260ebfedea0SLionel Sambuc {
261ebfedea0SLionel Sambuc     ExternalPrincipalIdentifiers *ids = ctx;
262ebfedea0SLionel Sambuc     ExternalPrincipalIdentifier id;
263ebfedea0SLionel Sambuc     hx509_name subject = NULL;
264ebfedea0SLionel Sambuc     void *p;
265ebfedea0SLionel Sambuc     int ret;
266ebfedea0SLionel Sambuc 
267ebfedea0SLionel Sambuc     if (ids->len > 10)
268ebfedea0SLionel Sambuc 	return 0;
269ebfedea0SLionel Sambuc 
270ebfedea0SLionel Sambuc     memset(&id, 0, sizeof(id));
271ebfedea0SLionel Sambuc 
272ebfedea0SLionel Sambuc     ret = hx509_cert_get_subject(c, &subject);
273ebfedea0SLionel Sambuc     if (ret)
274ebfedea0SLionel Sambuc 	return ret;
275ebfedea0SLionel Sambuc 
276ebfedea0SLionel Sambuc     if (hx509_name_is_null_p(subject) != 0) {
277ebfedea0SLionel Sambuc 
278ebfedea0SLionel Sambuc 	id.subjectName = calloc(1, sizeof(*id.subjectName));
279ebfedea0SLionel Sambuc 	if (id.subjectName == NULL) {
280ebfedea0SLionel Sambuc 	    hx509_name_free(&subject);
281ebfedea0SLionel Sambuc 	    free_ExternalPrincipalIdentifier(&id);
282ebfedea0SLionel Sambuc 	    return ENOMEM;
283ebfedea0SLionel Sambuc 	}
284ebfedea0SLionel Sambuc 
285ebfedea0SLionel Sambuc 	ret = hx509_name_binary(subject, id.subjectName);
286ebfedea0SLionel Sambuc 	if (ret) {
287ebfedea0SLionel Sambuc 	    hx509_name_free(&subject);
288ebfedea0SLionel Sambuc 	    free_ExternalPrincipalIdentifier(&id);
289ebfedea0SLionel Sambuc 	    return ret;
290ebfedea0SLionel Sambuc 	}
291ebfedea0SLionel Sambuc     }
292ebfedea0SLionel Sambuc     hx509_name_free(&subject);
293ebfedea0SLionel Sambuc 
294ebfedea0SLionel Sambuc 
295ebfedea0SLionel Sambuc     id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber));
296ebfedea0SLionel Sambuc     if (id.issuerAndSerialNumber == NULL) {
297ebfedea0SLionel Sambuc 	free_ExternalPrincipalIdentifier(&id);
298ebfedea0SLionel Sambuc 	return ENOMEM;
299ebfedea0SLionel Sambuc     }
300ebfedea0SLionel Sambuc 
301ebfedea0SLionel Sambuc     {
302ebfedea0SLionel Sambuc 	IssuerAndSerialNumber iasn;
303ebfedea0SLionel Sambuc 	hx509_name issuer;
304*0a6a1f1dSLionel Sambuc 	size_t size = 0;
305ebfedea0SLionel Sambuc 
306ebfedea0SLionel Sambuc 	memset(&iasn, 0, sizeof(iasn));
307ebfedea0SLionel Sambuc 
308ebfedea0SLionel Sambuc 	ret = hx509_cert_get_issuer(c, &issuer);
309ebfedea0SLionel Sambuc 	if (ret) {
310ebfedea0SLionel Sambuc 	    free_ExternalPrincipalIdentifier(&id);
311ebfedea0SLionel Sambuc 	    return ret;
312ebfedea0SLionel Sambuc 	}
313ebfedea0SLionel Sambuc 
314ebfedea0SLionel Sambuc 	ret = hx509_name_to_Name(issuer, &iasn.issuer);
315ebfedea0SLionel Sambuc 	hx509_name_free(&issuer);
316ebfedea0SLionel Sambuc 	if (ret) {
317ebfedea0SLionel Sambuc 	    free_ExternalPrincipalIdentifier(&id);
318ebfedea0SLionel Sambuc 	    return ret;
319ebfedea0SLionel Sambuc 	}
320ebfedea0SLionel Sambuc 
321ebfedea0SLionel Sambuc 	ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber);
322ebfedea0SLionel Sambuc 	if (ret) {
323ebfedea0SLionel Sambuc 	    free_IssuerAndSerialNumber(&iasn);
324ebfedea0SLionel Sambuc 	    free_ExternalPrincipalIdentifier(&id);
325ebfedea0SLionel Sambuc 	    return ret;
326ebfedea0SLionel Sambuc 	}
327ebfedea0SLionel Sambuc 
328ebfedea0SLionel Sambuc 	ASN1_MALLOC_ENCODE(IssuerAndSerialNumber,
329ebfedea0SLionel Sambuc 			   id.issuerAndSerialNumber->data,
330ebfedea0SLionel Sambuc 			   id.issuerAndSerialNumber->length,
331ebfedea0SLionel Sambuc 			   &iasn, &size, ret);
332ebfedea0SLionel Sambuc 	free_IssuerAndSerialNumber(&iasn);
333ebfedea0SLionel Sambuc 	if (ret)
334ebfedea0SLionel Sambuc 	    return ret;
335ebfedea0SLionel Sambuc 	if (id.issuerAndSerialNumber->length != size)
336ebfedea0SLionel Sambuc 	    abort();
337ebfedea0SLionel Sambuc     }
338ebfedea0SLionel Sambuc 
339ebfedea0SLionel Sambuc     id.subjectKeyIdentifier = NULL;
340ebfedea0SLionel Sambuc 
341ebfedea0SLionel Sambuc     p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1));
342ebfedea0SLionel Sambuc     if (p == NULL) {
343ebfedea0SLionel Sambuc 	free_ExternalPrincipalIdentifier(&id);
344ebfedea0SLionel Sambuc 	return ENOMEM;
345ebfedea0SLionel Sambuc     }
346ebfedea0SLionel Sambuc 
347ebfedea0SLionel Sambuc     ids->val = p;
348ebfedea0SLionel Sambuc     ids->val[ids->len] = id;
349ebfedea0SLionel Sambuc     ids->len++;
350ebfedea0SLionel Sambuc 
351ebfedea0SLionel Sambuc     return 0;
352ebfedea0SLionel Sambuc }
353ebfedea0SLionel Sambuc 
354ebfedea0SLionel Sambuc static krb5_error_code
build_edi(krb5_context context,hx509_context hx509ctx,hx509_certs certs,ExternalPrincipalIdentifiers * ids)355ebfedea0SLionel Sambuc build_edi(krb5_context context,
356ebfedea0SLionel Sambuc 	  hx509_context hx509ctx,
357ebfedea0SLionel Sambuc 	  hx509_certs certs,
358ebfedea0SLionel Sambuc 	  ExternalPrincipalIdentifiers *ids)
359ebfedea0SLionel Sambuc {
360ebfedea0SLionel Sambuc     return hx509_certs_iter_f(hx509ctx, certs, cert2epi, ids);
361ebfedea0SLionel Sambuc }
362ebfedea0SLionel Sambuc 
363ebfedea0SLionel Sambuc static krb5_error_code
build_auth_pack(krb5_context context,unsigned nonce,krb5_pk_init_ctx ctx,const KDC_REQ_BODY * body,AuthPack * a)364ebfedea0SLionel Sambuc build_auth_pack(krb5_context context,
365ebfedea0SLionel Sambuc 		unsigned nonce,
366ebfedea0SLionel Sambuc 		krb5_pk_init_ctx ctx,
367ebfedea0SLionel Sambuc 		const KDC_REQ_BODY *body,
368ebfedea0SLionel Sambuc 		AuthPack *a)
369ebfedea0SLionel Sambuc {
370*0a6a1f1dSLionel Sambuc     size_t buf_size, len = 0;
371ebfedea0SLionel Sambuc     krb5_error_code ret;
372ebfedea0SLionel Sambuc     void *buf;
373ebfedea0SLionel Sambuc     krb5_timestamp sec;
374ebfedea0SLionel Sambuc     int32_t usec;
375ebfedea0SLionel Sambuc     Checksum checksum;
376ebfedea0SLionel Sambuc 
377ebfedea0SLionel Sambuc     krb5_clear_error_message(context);
378ebfedea0SLionel Sambuc 
379ebfedea0SLionel Sambuc     memset(&checksum, 0, sizeof(checksum));
380ebfedea0SLionel Sambuc 
381ebfedea0SLionel Sambuc     krb5_us_timeofday(context, &sec, &usec);
382ebfedea0SLionel Sambuc     a->pkAuthenticator.ctime = sec;
383ebfedea0SLionel Sambuc     a->pkAuthenticator.nonce = nonce;
384ebfedea0SLionel Sambuc 
385ebfedea0SLionel Sambuc     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
386ebfedea0SLionel Sambuc     if (ret)
387ebfedea0SLionel Sambuc 	return ret;
388ebfedea0SLionel Sambuc     if (buf_size != len)
389ebfedea0SLionel Sambuc 	krb5_abortx(context, "internal error in ASN.1 encoder");
390ebfedea0SLionel Sambuc 
391ebfedea0SLionel Sambuc     ret = krb5_create_checksum(context,
392ebfedea0SLionel Sambuc 			       NULL,
393ebfedea0SLionel Sambuc 			       0,
394ebfedea0SLionel Sambuc 			       CKSUMTYPE_SHA1,
395ebfedea0SLionel Sambuc 			       buf,
396ebfedea0SLionel Sambuc 			       len,
397ebfedea0SLionel Sambuc 			       &checksum);
398ebfedea0SLionel Sambuc     free(buf);
399ebfedea0SLionel Sambuc     if (ret)
400ebfedea0SLionel Sambuc 	return ret;
401ebfedea0SLionel Sambuc 
402ebfedea0SLionel Sambuc     ALLOC(a->pkAuthenticator.paChecksum, 1);
403ebfedea0SLionel Sambuc     if (a->pkAuthenticator.paChecksum == NULL) {
404ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM,
405ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
406ebfedea0SLionel Sambuc 	return ENOMEM;
407ebfedea0SLionel Sambuc     }
408ebfedea0SLionel Sambuc 
409ebfedea0SLionel Sambuc     ret = krb5_data_copy(a->pkAuthenticator.paChecksum,
410ebfedea0SLionel Sambuc 			 checksum.checksum.data, checksum.checksum.length);
411ebfedea0SLionel Sambuc     free_Checksum(&checksum);
412ebfedea0SLionel Sambuc     if (ret)
413ebfedea0SLionel Sambuc 	return ret;
414ebfedea0SLionel Sambuc 
415ebfedea0SLionel Sambuc     if (ctx->keyex == USE_DH || ctx->keyex == USE_ECDH) {
416ebfedea0SLionel Sambuc 	const char *moduli_file;
417ebfedea0SLionel Sambuc 	unsigned long dh_min_bits;
418ebfedea0SLionel Sambuc 	krb5_data dhbuf;
419*0a6a1f1dSLionel Sambuc 	size_t size = 0;
420ebfedea0SLionel Sambuc 
421ebfedea0SLionel Sambuc 	krb5_data_zero(&dhbuf);
422ebfedea0SLionel Sambuc 
423ebfedea0SLionel Sambuc 
424ebfedea0SLionel Sambuc 
425ebfedea0SLionel Sambuc 	moduli_file = krb5_config_get_string(context, NULL,
426ebfedea0SLionel Sambuc 					     "libdefaults",
427ebfedea0SLionel Sambuc 					     "moduli",
428ebfedea0SLionel Sambuc 					     NULL);
429ebfedea0SLionel Sambuc 
430ebfedea0SLionel Sambuc 	dh_min_bits =
431ebfedea0SLionel Sambuc 	    krb5_config_get_int_default(context, NULL, 0,
432ebfedea0SLionel Sambuc 					"libdefaults",
433ebfedea0SLionel Sambuc 					"pkinit_dh_min_bits",
434ebfedea0SLionel Sambuc 					NULL);
435ebfedea0SLionel Sambuc 
436ebfedea0SLionel Sambuc 	ret = _krb5_parse_moduli(context, moduli_file, &ctx->m);
437ebfedea0SLionel Sambuc 	if (ret)
438ebfedea0SLionel Sambuc 	    return ret;
439ebfedea0SLionel Sambuc 
440ebfedea0SLionel Sambuc 	ctx->u.dh = DH_new();
441ebfedea0SLionel Sambuc 	if (ctx->u.dh == NULL) {
442ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ENOMEM,
443ebfedea0SLionel Sambuc 				   N_("malloc: out of memory", ""));
444ebfedea0SLionel Sambuc 	    return ENOMEM;
445ebfedea0SLionel Sambuc 	}
446ebfedea0SLionel Sambuc 
447ebfedea0SLionel Sambuc 	ret = select_dh_group(context, ctx->u.dh, dh_min_bits, ctx->m);
448ebfedea0SLionel Sambuc 	if (ret)
449ebfedea0SLionel Sambuc 	    return ret;
450ebfedea0SLionel Sambuc 
451ebfedea0SLionel Sambuc 	if (DH_generate_key(ctx->u.dh) != 1) {
452ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ENOMEM,
453ebfedea0SLionel Sambuc 				   N_("pkinit: failed to generate DH key", ""));
454ebfedea0SLionel Sambuc 	    return ENOMEM;
455ebfedea0SLionel Sambuc 	}
456ebfedea0SLionel Sambuc 
457ebfedea0SLionel Sambuc 
458ebfedea0SLionel Sambuc 	if (1 /* support_cached_dh */) {
459ebfedea0SLionel Sambuc 	    ALLOC(a->clientDHNonce, 1);
460ebfedea0SLionel Sambuc 	    if (a->clientDHNonce == NULL) {
461ebfedea0SLionel Sambuc 		krb5_clear_error_message(context);
462ebfedea0SLionel Sambuc 		return ENOMEM;
463ebfedea0SLionel Sambuc 	    }
464ebfedea0SLionel Sambuc 	    ret = krb5_data_alloc(a->clientDHNonce, 40);
465ebfedea0SLionel Sambuc 	    if (a->clientDHNonce == NULL) {
466ebfedea0SLionel Sambuc 		krb5_clear_error_message(context);
467ebfedea0SLionel Sambuc 		return ret;
468ebfedea0SLionel Sambuc 	    }
469ebfedea0SLionel Sambuc 	    RAND_bytes(a->clientDHNonce->data, a->clientDHNonce->length);
470ebfedea0SLionel Sambuc 	    ret = krb5_copy_data(context, a->clientDHNonce,
471ebfedea0SLionel Sambuc 				 &ctx->clientDHNonce);
472ebfedea0SLionel Sambuc 	    if (ret)
473ebfedea0SLionel Sambuc 		return ret;
474ebfedea0SLionel Sambuc 	}
475ebfedea0SLionel Sambuc 
476ebfedea0SLionel Sambuc 	ALLOC(a->clientPublicValue, 1);
477ebfedea0SLionel Sambuc 	if (a->clientPublicValue == NULL)
478ebfedea0SLionel Sambuc 	    return ENOMEM;
479ebfedea0SLionel Sambuc 
480ebfedea0SLionel Sambuc 	if (ctx->keyex == USE_DH) {
481ebfedea0SLionel Sambuc 	    DH *dh = ctx->u.dh;
482ebfedea0SLionel Sambuc 	    DomainParameters dp;
483ebfedea0SLionel Sambuc 	    heim_integer dh_pub_key;
484ebfedea0SLionel Sambuc 
485ebfedea0SLionel Sambuc 	    ret = der_copy_oid(&asn1_oid_id_dhpublicnumber,
486ebfedea0SLionel Sambuc 			       &a->clientPublicValue->algorithm.algorithm);
487ebfedea0SLionel Sambuc 	    if (ret)
488ebfedea0SLionel Sambuc 		return ret;
489ebfedea0SLionel Sambuc 
490ebfedea0SLionel Sambuc 	    memset(&dp, 0, sizeof(dp));
491ebfedea0SLionel Sambuc 
492ebfedea0SLionel Sambuc 	    ret = BN_to_integer(context, dh->p, &dp.p);
493ebfedea0SLionel Sambuc 	    if (ret) {
494ebfedea0SLionel Sambuc 		free_DomainParameters(&dp);
495ebfedea0SLionel Sambuc 		return ret;
496ebfedea0SLionel Sambuc 	    }
497ebfedea0SLionel Sambuc 	    ret = BN_to_integer(context, dh->g, &dp.g);
498ebfedea0SLionel Sambuc 	    if (ret) {
499ebfedea0SLionel Sambuc 		free_DomainParameters(&dp);
500ebfedea0SLionel Sambuc 		return ret;
501ebfedea0SLionel Sambuc 	    }
502*0a6a1f1dSLionel Sambuc 	    dp.q = calloc(1, sizeof(*dp.q));
503*0a6a1f1dSLionel Sambuc 	    if (dp.q == NULL) {
504*0a6a1f1dSLionel Sambuc 		free_DomainParameters(&dp);
505*0a6a1f1dSLionel Sambuc 		return ENOMEM;
506*0a6a1f1dSLionel Sambuc 	    }
507*0a6a1f1dSLionel Sambuc 	    ret = BN_to_integer(context, dh->q, dp.q);
508ebfedea0SLionel Sambuc 	    if (ret) {
509ebfedea0SLionel Sambuc 		free_DomainParameters(&dp);
510ebfedea0SLionel Sambuc 		return ret;
511ebfedea0SLionel Sambuc 	    }
512ebfedea0SLionel Sambuc 	    dp.j = NULL;
513ebfedea0SLionel Sambuc 	    dp.validationParms = NULL;
514ebfedea0SLionel Sambuc 
515ebfedea0SLionel Sambuc 	    a->clientPublicValue->algorithm.parameters =
516ebfedea0SLionel Sambuc 		malloc(sizeof(*a->clientPublicValue->algorithm.parameters));
517ebfedea0SLionel Sambuc 	    if (a->clientPublicValue->algorithm.parameters == NULL) {
518ebfedea0SLionel Sambuc 		free_DomainParameters(&dp);
519ebfedea0SLionel Sambuc 		return ret;
520ebfedea0SLionel Sambuc 	    }
521ebfedea0SLionel Sambuc 
522ebfedea0SLionel Sambuc 	    ASN1_MALLOC_ENCODE(DomainParameters,
523ebfedea0SLionel Sambuc 			       a->clientPublicValue->algorithm.parameters->data,
524ebfedea0SLionel Sambuc 			       a->clientPublicValue->algorithm.parameters->length,
525ebfedea0SLionel Sambuc 			       &dp, &size, ret);
526ebfedea0SLionel Sambuc 	    free_DomainParameters(&dp);
527ebfedea0SLionel Sambuc 	    if (ret)
528ebfedea0SLionel Sambuc 		return ret;
529ebfedea0SLionel Sambuc 	    if (size != a->clientPublicValue->algorithm.parameters->length)
530ebfedea0SLionel Sambuc 		krb5_abortx(context, "Internal ASN1 encoder error");
531ebfedea0SLionel Sambuc 
532ebfedea0SLionel Sambuc 	    ret = BN_to_integer(context, dh->pub_key, &dh_pub_key);
533ebfedea0SLionel Sambuc 	    if (ret)
534ebfedea0SLionel Sambuc 		return ret;
535ebfedea0SLionel Sambuc 
536ebfedea0SLionel Sambuc 	    ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length,
537ebfedea0SLionel Sambuc 			       &dh_pub_key, &size, ret);
538ebfedea0SLionel Sambuc 	    der_free_heim_integer(&dh_pub_key);
539ebfedea0SLionel Sambuc 	    if (ret)
540ebfedea0SLionel Sambuc 		return ret;
541ebfedea0SLionel Sambuc 	    if (size != dhbuf.length)
542ebfedea0SLionel Sambuc 		krb5_abortx(context, "asn1 internal error");
543ebfedea0SLionel Sambuc 	} else if (ctx->keyex == USE_ECDH) {
544ebfedea0SLionel Sambuc #ifdef HAVE_OPENSSL
545ebfedea0SLionel Sambuc 	    ECParameters ecp;
546ebfedea0SLionel Sambuc 	    unsigned char *p;
547*0a6a1f1dSLionel Sambuc 	    int xlen;
548ebfedea0SLionel Sambuc 
549ebfedea0SLionel Sambuc 	    /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */
550ebfedea0SLionel Sambuc 
551ebfedea0SLionel Sambuc 	    ecp.element = choice_ECParameters_namedCurve;
552ebfedea0SLionel Sambuc 	    ret = der_copy_oid(&asn1_oid_id_ec_group_secp256r1,
553ebfedea0SLionel Sambuc 			       &ecp.u.namedCurve);
554ebfedea0SLionel Sambuc 	    if (ret)
555ebfedea0SLionel Sambuc 		return ret;
556ebfedea0SLionel Sambuc 
557ebfedea0SLionel Sambuc 	    ALLOC(a->clientPublicValue->algorithm.parameters, 1);
558ebfedea0SLionel Sambuc 	    if (a->clientPublicValue->algorithm.parameters == NULL) {
559ebfedea0SLionel Sambuc 		free_ECParameters(&ecp);
560ebfedea0SLionel Sambuc 		return ENOMEM;
561ebfedea0SLionel Sambuc 	    }
562*0a6a1f1dSLionel Sambuc 	    ASN1_MALLOC_ENCODE(ECParameters, p, xlen, &ecp, &size, ret);
563ebfedea0SLionel Sambuc 	    free_ECParameters(&ecp);
564ebfedea0SLionel Sambuc 	    if (ret)
565ebfedea0SLionel Sambuc 		return ret;
566*0a6a1f1dSLionel Sambuc 	    if ((int)size != xlen)
567ebfedea0SLionel Sambuc 		krb5_abortx(context, "asn1 internal error");
568ebfedea0SLionel Sambuc 
569ebfedea0SLionel Sambuc 	    a->clientPublicValue->algorithm.parameters->data = p;
570ebfedea0SLionel Sambuc 	    a->clientPublicValue->algorithm.parameters->length = size;
571ebfedea0SLionel Sambuc 
572ebfedea0SLionel Sambuc 	    /* copy in public key */
573ebfedea0SLionel Sambuc 
574ebfedea0SLionel Sambuc 	    ret = der_copy_oid(&asn1_oid_id_ecPublicKey,
575ebfedea0SLionel Sambuc 			       &a->clientPublicValue->algorithm.algorithm);
576ebfedea0SLionel Sambuc 	    if (ret)
577ebfedea0SLionel Sambuc 		return ret;
578ebfedea0SLionel Sambuc 
579ebfedea0SLionel Sambuc 	    ctx->u.eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
580ebfedea0SLionel Sambuc 	    if (ctx->u.eckey == NULL)
581ebfedea0SLionel Sambuc 		return ENOMEM;
582ebfedea0SLionel Sambuc 
583ebfedea0SLionel Sambuc 	    ret = EC_KEY_generate_key(ctx->u.eckey);
584ebfedea0SLionel Sambuc 	    if (ret != 1)
585ebfedea0SLionel Sambuc 		return EINVAL;
586ebfedea0SLionel Sambuc 
587ebfedea0SLionel Sambuc 	    /* encode onto dhkey */
588ebfedea0SLionel Sambuc 
589*0a6a1f1dSLionel Sambuc 	    xlen = i2o_ECPublicKey(ctx->u.eckey, NULL);
590*0a6a1f1dSLionel Sambuc 	    if (xlen <= 0)
591ebfedea0SLionel Sambuc 		abort();
592ebfedea0SLionel Sambuc 
593*0a6a1f1dSLionel Sambuc 	    dhbuf.data = malloc(xlen);
594ebfedea0SLionel Sambuc 	    if (dhbuf.data == NULL)
595ebfedea0SLionel Sambuc 		abort();
596*0a6a1f1dSLionel Sambuc 	    dhbuf.length = xlen;
597ebfedea0SLionel Sambuc 	    p = dhbuf.data;
598ebfedea0SLionel Sambuc 
599*0a6a1f1dSLionel Sambuc 	    xlen = i2o_ECPublicKey(ctx->u.eckey, &p);
600*0a6a1f1dSLionel Sambuc 	    if (xlen <= 0)
601ebfedea0SLionel Sambuc 		abort();
602ebfedea0SLionel Sambuc 
603ebfedea0SLionel Sambuc 	    /* XXX verify that this is right with RFC3279 */
604ebfedea0SLionel Sambuc #else
605ebfedea0SLionel Sambuc 	    return EINVAL;
606ebfedea0SLionel Sambuc #endif
607ebfedea0SLionel Sambuc 	} else
608ebfedea0SLionel Sambuc 	    krb5_abortx(context, "internal error");
609ebfedea0SLionel Sambuc 	a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8;
610ebfedea0SLionel Sambuc 	a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
611ebfedea0SLionel Sambuc     }
612ebfedea0SLionel Sambuc 
613ebfedea0SLionel Sambuc     {
614ebfedea0SLionel Sambuc 	a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes));
615ebfedea0SLionel Sambuc 	if (a->supportedCMSTypes == NULL)
616ebfedea0SLionel Sambuc 	    return ENOMEM;
617ebfedea0SLionel Sambuc 
618*0a6a1f1dSLionel Sambuc 	ret = hx509_crypto_available(context->hx509ctx, HX509_SELECT_ALL,
619*0a6a1f1dSLionel Sambuc 				     ctx->id->cert,
620ebfedea0SLionel Sambuc 				     &a->supportedCMSTypes->val,
621ebfedea0SLionel Sambuc 				     &a->supportedCMSTypes->len);
622ebfedea0SLionel Sambuc 	if (ret)
623ebfedea0SLionel Sambuc 	    return ret;
624ebfedea0SLionel Sambuc     }
625ebfedea0SLionel Sambuc 
626ebfedea0SLionel Sambuc     return ret;
627ebfedea0SLionel Sambuc }
628ebfedea0SLionel Sambuc 
629ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_pk_mk_ContentInfo(krb5_context context,const krb5_data * buf,const heim_oid * oid,struct ContentInfo * content_info)630ebfedea0SLionel Sambuc _krb5_pk_mk_ContentInfo(krb5_context context,
631ebfedea0SLionel Sambuc 			const krb5_data *buf,
632ebfedea0SLionel Sambuc 			const heim_oid *oid,
633ebfedea0SLionel Sambuc 			struct ContentInfo *content_info)
634ebfedea0SLionel Sambuc {
635ebfedea0SLionel Sambuc     krb5_error_code ret;
636ebfedea0SLionel Sambuc 
637ebfedea0SLionel Sambuc     ret = der_copy_oid(oid, &content_info->contentType);
638ebfedea0SLionel Sambuc     if (ret)
639ebfedea0SLionel Sambuc 	return ret;
640ebfedea0SLionel Sambuc     ALLOC(content_info->content, 1);
641ebfedea0SLionel Sambuc     if (content_info->content == NULL)
642ebfedea0SLionel Sambuc 	return ENOMEM;
643ebfedea0SLionel Sambuc     content_info->content->data = malloc(buf->length);
644ebfedea0SLionel Sambuc     if (content_info->content->data == NULL)
645ebfedea0SLionel Sambuc 	return ENOMEM;
646ebfedea0SLionel Sambuc     memcpy(content_info->content->data, buf->data, buf->length);
647ebfedea0SLionel Sambuc     content_info->content->length = buf->length;
648ebfedea0SLionel Sambuc     return 0;
649ebfedea0SLionel Sambuc }
650ebfedea0SLionel Sambuc 
651ebfedea0SLionel Sambuc static krb5_error_code
pk_mk_padata(krb5_context context,krb5_pk_init_ctx ctx,const KDC_REQ_BODY * req_body,unsigned nonce,METHOD_DATA * md)652ebfedea0SLionel Sambuc pk_mk_padata(krb5_context context,
653ebfedea0SLionel Sambuc 	     krb5_pk_init_ctx ctx,
654ebfedea0SLionel Sambuc 	     const KDC_REQ_BODY *req_body,
655ebfedea0SLionel Sambuc 	     unsigned nonce,
656ebfedea0SLionel Sambuc 	     METHOD_DATA *md)
657ebfedea0SLionel Sambuc {
658ebfedea0SLionel Sambuc     struct ContentInfo content_info;
659ebfedea0SLionel Sambuc     krb5_error_code ret;
660*0a6a1f1dSLionel Sambuc     const heim_oid *oid = NULL;
661*0a6a1f1dSLionel Sambuc     size_t size = 0;
662ebfedea0SLionel Sambuc     krb5_data buf, sd_buf;
663*0a6a1f1dSLionel Sambuc     int pa_type = -1;
664ebfedea0SLionel Sambuc 
665ebfedea0SLionel Sambuc     krb5_data_zero(&buf);
666ebfedea0SLionel Sambuc     krb5_data_zero(&sd_buf);
667ebfedea0SLionel Sambuc     memset(&content_info, 0, sizeof(content_info));
668ebfedea0SLionel Sambuc 
669ebfedea0SLionel Sambuc     if (ctx->type == PKINIT_WIN2K) {
670ebfedea0SLionel Sambuc 	AuthPack_Win2k ap;
671ebfedea0SLionel Sambuc 	krb5_timestamp sec;
672ebfedea0SLionel Sambuc 	int32_t usec;
673ebfedea0SLionel Sambuc 
674ebfedea0SLionel Sambuc 	memset(&ap, 0, sizeof(ap));
675ebfedea0SLionel Sambuc 
676ebfedea0SLionel Sambuc 	/* fill in PKAuthenticator */
677ebfedea0SLionel Sambuc 	ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName);
678ebfedea0SLionel Sambuc 	if (ret) {
679ebfedea0SLionel Sambuc 	    free_AuthPack_Win2k(&ap);
680ebfedea0SLionel Sambuc 	    krb5_clear_error_message(context);
681ebfedea0SLionel Sambuc 	    goto out;
682ebfedea0SLionel Sambuc 	}
683ebfedea0SLionel Sambuc 	ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm);
684ebfedea0SLionel Sambuc 	if (ret) {
685ebfedea0SLionel Sambuc 	    free_AuthPack_Win2k(&ap);
686ebfedea0SLionel Sambuc 	    krb5_clear_error_message(context);
687ebfedea0SLionel Sambuc 	    goto out;
688ebfedea0SLionel Sambuc 	}
689ebfedea0SLionel Sambuc 
690ebfedea0SLionel Sambuc 	krb5_us_timeofday(context, &sec, &usec);
691ebfedea0SLionel Sambuc 	ap.pkAuthenticator.ctime = sec;
692ebfedea0SLionel Sambuc 	ap.pkAuthenticator.cusec = usec;
693ebfedea0SLionel Sambuc 	ap.pkAuthenticator.nonce = nonce;
694ebfedea0SLionel Sambuc 
695ebfedea0SLionel Sambuc 	ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length,
696ebfedea0SLionel Sambuc 			   &ap, &size, ret);
697ebfedea0SLionel Sambuc 	free_AuthPack_Win2k(&ap);
698ebfedea0SLionel Sambuc 	if (ret) {
699ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
700ebfedea0SLionel Sambuc 				   N_("Failed encoding AuthPackWin: %d", ""),
701ebfedea0SLionel Sambuc 				   (int)ret);
702ebfedea0SLionel Sambuc 	    goto out;
703ebfedea0SLionel Sambuc 	}
704ebfedea0SLionel Sambuc 	if (buf.length != size)
705ebfedea0SLionel Sambuc 	    krb5_abortx(context, "internal ASN1 encoder error");
706ebfedea0SLionel Sambuc 
707ebfedea0SLionel Sambuc 	oid = &asn1_oid_id_pkcs7_data;
708ebfedea0SLionel Sambuc     } else if (ctx->type == PKINIT_27) {
709ebfedea0SLionel Sambuc 	AuthPack ap;
710ebfedea0SLionel Sambuc 
711ebfedea0SLionel Sambuc 	memset(&ap, 0, sizeof(ap));
712ebfedea0SLionel Sambuc 
713ebfedea0SLionel Sambuc 	ret = build_auth_pack(context, nonce, ctx, req_body, &ap);
714ebfedea0SLionel Sambuc 	if (ret) {
715ebfedea0SLionel Sambuc 	    free_AuthPack(&ap);
716ebfedea0SLionel Sambuc 	    goto out;
717ebfedea0SLionel Sambuc 	}
718ebfedea0SLionel Sambuc 
719ebfedea0SLionel Sambuc 	ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret);
720ebfedea0SLionel Sambuc 	free_AuthPack(&ap);
721ebfedea0SLionel Sambuc 	if (ret) {
722ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
723ebfedea0SLionel Sambuc 				   N_("Failed encoding AuthPack: %d", ""),
724ebfedea0SLionel Sambuc 				   (int)ret);
725ebfedea0SLionel Sambuc 	    goto out;
726ebfedea0SLionel Sambuc 	}
727ebfedea0SLionel Sambuc 	if (buf.length != size)
728ebfedea0SLionel Sambuc 	    krb5_abortx(context, "internal ASN1 encoder error");
729ebfedea0SLionel Sambuc 
730ebfedea0SLionel Sambuc 	oid = &asn1_oid_id_pkauthdata;
731ebfedea0SLionel Sambuc     } else
732ebfedea0SLionel Sambuc 	krb5_abortx(context, "internal pkinit error");
733ebfedea0SLionel Sambuc 
734ebfedea0SLionel Sambuc     ret = create_signature(context, oid, &buf, ctx->id,
735ebfedea0SLionel Sambuc 			   ctx->peer, &sd_buf);
736ebfedea0SLionel Sambuc     krb5_data_free(&buf);
737ebfedea0SLionel Sambuc     if (ret)
738ebfedea0SLionel Sambuc 	goto out;
739ebfedea0SLionel Sambuc 
740ebfedea0SLionel Sambuc     ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData, &sd_buf, &buf);
741ebfedea0SLionel Sambuc     krb5_data_free(&sd_buf);
742ebfedea0SLionel Sambuc     if (ret) {
743ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
744ebfedea0SLionel Sambuc 			       N_("ContentInfo wrapping of signedData failed",""));
745ebfedea0SLionel Sambuc 	goto out;
746ebfedea0SLionel Sambuc     }
747ebfedea0SLionel Sambuc 
748ebfedea0SLionel Sambuc     if (ctx->type == PKINIT_WIN2K) {
749ebfedea0SLionel Sambuc 	PA_PK_AS_REQ_Win2k winreq;
750ebfedea0SLionel Sambuc 
751ebfedea0SLionel Sambuc 	pa_type = KRB5_PADATA_PK_AS_REQ_WIN;
752ebfedea0SLionel Sambuc 
753ebfedea0SLionel Sambuc 	memset(&winreq, 0, sizeof(winreq));
754ebfedea0SLionel Sambuc 
755ebfedea0SLionel Sambuc 	winreq.signed_auth_pack = buf;
756ebfedea0SLionel Sambuc 
757ebfedea0SLionel Sambuc 	ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length,
758ebfedea0SLionel Sambuc 			   &winreq, &size, ret);
759ebfedea0SLionel Sambuc 	free_PA_PK_AS_REQ_Win2k(&winreq);
760ebfedea0SLionel Sambuc 
761ebfedea0SLionel Sambuc     } else if (ctx->type == PKINIT_27) {
762ebfedea0SLionel Sambuc 	PA_PK_AS_REQ req;
763ebfedea0SLionel Sambuc 
764ebfedea0SLionel Sambuc 	pa_type = KRB5_PADATA_PK_AS_REQ;
765ebfedea0SLionel Sambuc 
766ebfedea0SLionel Sambuc 	memset(&req, 0, sizeof(req));
767ebfedea0SLionel Sambuc 	req.signedAuthPack = buf;
768ebfedea0SLionel Sambuc 
769ebfedea0SLionel Sambuc 	if (ctx->trustedCertifiers) {
770ebfedea0SLionel Sambuc 
771ebfedea0SLionel Sambuc 	    req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers));
772ebfedea0SLionel Sambuc 	    if (req.trustedCertifiers == NULL) {
773ebfedea0SLionel Sambuc 		ret = ENOMEM;
774ebfedea0SLionel Sambuc 		krb5_set_error_message(context, ret,
775ebfedea0SLionel Sambuc 				       N_("malloc: out of memory", ""));
776ebfedea0SLionel Sambuc 		free_PA_PK_AS_REQ(&req);
777ebfedea0SLionel Sambuc 		goto out;
778ebfedea0SLionel Sambuc 	    }
779ebfedea0SLionel Sambuc 	    ret = build_edi(context, context->hx509ctx,
780ebfedea0SLionel Sambuc 			    ctx->id->anchors, req.trustedCertifiers);
781ebfedea0SLionel Sambuc 	    if (ret) {
782ebfedea0SLionel Sambuc 		krb5_set_error_message(context, ret,
783ebfedea0SLionel Sambuc 				       N_("pk-init: failed to build "
784ebfedea0SLionel Sambuc 					  "trustedCertifiers", ""));
785ebfedea0SLionel Sambuc 		free_PA_PK_AS_REQ(&req);
786ebfedea0SLionel Sambuc 		goto out;
787ebfedea0SLionel Sambuc 	    }
788ebfedea0SLionel Sambuc 	}
789ebfedea0SLionel Sambuc 	req.kdcPkId = NULL;
790ebfedea0SLionel Sambuc 
791ebfedea0SLionel Sambuc 	ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length,
792ebfedea0SLionel Sambuc 			   &req, &size, ret);
793ebfedea0SLionel Sambuc 
794ebfedea0SLionel Sambuc 	free_PA_PK_AS_REQ(&req);
795ebfedea0SLionel Sambuc 
796ebfedea0SLionel Sambuc     } else
797ebfedea0SLionel Sambuc 	krb5_abortx(context, "internal pkinit error");
798ebfedea0SLionel Sambuc     if (ret) {
799ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret, "PA-PK-AS-REQ %d", (int)ret);
800ebfedea0SLionel Sambuc 	goto out;
801ebfedea0SLionel Sambuc     }
802ebfedea0SLionel Sambuc     if (buf.length != size)
803ebfedea0SLionel Sambuc 	krb5_abortx(context, "Internal ASN1 encoder error");
804ebfedea0SLionel Sambuc 
805ebfedea0SLionel Sambuc     ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length);
806ebfedea0SLionel Sambuc     if (ret)
807ebfedea0SLionel Sambuc 	free(buf.data);
808ebfedea0SLionel Sambuc 
809ebfedea0SLionel Sambuc     if (ret == 0)
810ebfedea0SLionel Sambuc     	krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
811ebfedea0SLionel Sambuc 
812ebfedea0SLionel Sambuc  out:
813ebfedea0SLionel Sambuc     free_ContentInfo(&content_info);
814ebfedea0SLionel Sambuc 
815ebfedea0SLionel Sambuc     return ret;
816ebfedea0SLionel Sambuc }
817ebfedea0SLionel Sambuc 
818ebfedea0SLionel Sambuc 
819ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_pk_mk_padata(krb5_context context,void * c,int ic_flags,int win2k,const KDC_REQ_BODY * req_body,unsigned nonce,METHOD_DATA * md)820ebfedea0SLionel Sambuc _krb5_pk_mk_padata(krb5_context context,
821ebfedea0SLionel Sambuc 		   void *c,
822ebfedea0SLionel Sambuc 		   int ic_flags,
823ebfedea0SLionel Sambuc 		   int win2k,
824ebfedea0SLionel Sambuc 		   const KDC_REQ_BODY *req_body,
825ebfedea0SLionel Sambuc 		   unsigned nonce,
826ebfedea0SLionel Sambuc 		   METHOD_DATA *md)
827ebfedea0SLionel Sambuc {
828ebfedea0SLionel Sambuc     krb5_pk_init_ctx ctx = c;
829ebfedea0SLionel Sambuc     int win2k_compat;
830ebfedea0SLionel Sambuc 
831ebfedea0SLionel Sambuc     if (ctx->id->certs == NULL && ctx->anonymous == 0) {
832ebfedea0SLionel Sambuc 	krb5_set_error_message(context, HEIM_PKINIT_NO_PRIVATE_KEY,
833ebfedea0SLionel Sambuc 			       N_("PKINIT: No user certificate given", ""));
834ebfedea0SLionel Sambuc 	return HEIM_PKINIT_NO_PRIVATE_KEY;
835ebfedea0SLionel Sambuc     }
836ebfedea0SLionel Sambuc 
837ebfedea0SLionel Sambuc     win2k_compat = krb5_config_get_bool_default(context, NULL,
838ebfedea0SLionel Sambuc 						win2k,
839ebfedea0SLionel Sambuc 						"realms",
840ebfedea0SLionel Sambuc 						req_body->realm,
841ebfedea0SLionel Sambuc 						"pkinit_win2k",
842ebfedea0SLionel Sambuc 						NULL);
843ebfedea0SLionel Sambuc 
844ebfedea0SLionel Sambuc     if (win2k_compat) {
845ebfedea0SLionel Sambuc 	ctx->require_binding =
846ebfedea0SLionel Sambuc 	    krb5_config_get_bool_default(context, NULL,
847ebfedea0SLionel Sambuc 					 TRUE,
848ebfedea0SLionel Sambuc 					 "realms",
849ebfedea0SLionel Sambuc 					 req_body->realm,
850ebfedea0SLionel Sambuc 					 "pkinit_win2k_require_binding",
851ebfedea0SLionel Sambuc 					 NULL);
852ebfedea0SLionel Sambuc 	ctx->type = PKINIT_WIN2K;
853ebfedea0SLionel Sambuc     } else
854ebfedea0SLionel Sambuc 	ctx->type = PKINIT_27;
855ebfedea0SLionel Sambuc 
856ebfedea0SLionel Sambuc     ctx->require_eku =
857ebfedea0SLionel Sambuc 	krb5_config_get_bool_default(context, NULL,
858ebfedea0SLionel Sambuc 				     TRUE,
859ebfedea0SLionel Sambuc 				     "realms",
860ebfedea0SLionel Sambuc 				     req_body->realm,
861ebfedea0SLionel Sambuc 				     "pkinit_require_eku",
862ebfedea0SLionel Sambuc 				     NULL);
863ebfedea0SLionel Sambuc     if (ic_flags & KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK)
864ebfedea0SLionel Sambuc 	ctx->require_eku = 0;
865ebfedea0SLionel Sambuc     if (ctx->id->flags & PKINIT_BTMM)
866ebfedea0SLionel Sambuc 	ctx->require_eku = 0;
867ebfedea0SLionel Sambuc 
868ebfedea0SLionel Sambuc     ctx->require_krbtgt_otherName =
869ebfedea0SLionel Sambuc 	krb5_config_get_bool_default(context, NULL,
870ebfedea0SLionel Sambuc 				     TRUE,
871ebfedea0SLionel Sambuc 				     "realms",
872ebfedea0SLionel Sambuc 				     req_body->realm,
873ebfedea0SLionel Sambuc 				     "pkinit_require_krbtgt_otherName",
874ebfedea0SLionel Sambuc 				     NULL);
875ebfedea0SLionel Sambuc 
876ebfedea0SLionel Sambuc     ctx->require_hostname_match =
877ebfedea0SLionel Sambuc 	krb5_config_get_bool_default(context, NULL,
878ebfedea0SLionel Sambuc 				     FALSE,
879ebfedea0SLionel Sambuc 				     "realms",
880ebfedea0SLionel Sambuc 				     req_body->realm,
881ebfedea0SLionel Sambuc 				     "pkinit_require_hostname_match",
882ebfedea0SLionel Sambuc 				     NULL);
883ebfedea0SLionel Sambuc 
884ebfedea0SLionel Sambuc     ctx->trustedCertifiers =
885ebfedea0SLionel Sambuc 	krb5_config_get_bool_default(context, NULL,
886ebfedea0SLionel Sambuc 				     TRUE,
887ebfedea0SLionel Sambuc 				     "realms",
888ebfedea0SLionel Sambuc 				     req_body->realm,
889ebfedea0SLionel Sambuc 				     "pkinit_trustedCertifiers",
890ebfedea0SLionel Sambuc 				     NULL);
891ebfedea0SLionel Sambuc 
892ebfedea0SLionel Sambuc     return pk_mk_padata(context, ctx, req_body, nonce, md);
893ebfedea0SLionel Sambuc }
894ebfedea0SLionel Sambuc 
895ebfedea0SLionel Sambuc static krb5_error_code
pk_verify_sign(krb5_context context,const void * data,size_t length,struct krb5_pk_identity * id,heim_oid * contentType,krb5_data * content,struct krb5_pk_cert ** signer)896ebfedea0SLionel Sambuc pk_verify_sign(krb5_context context,
897ebfedea0SLionel Sambuc 	       const void *data,
898ebfedea0SLionel Sambuc 	       size_t length,
899ebfedea0SLionel Sambuc 	       struct krb5_pk_identity *id,
900ebfedea0SLionel Sambuc 	       heim_oid *contentType,
901ebfedea0SLionel Sambuc 	       krb5_data *content,
902ebfedea0SLionel Sambuc 	       struct krb5_pk_cert **signer)
903ebfedea0SLionel Sambuc {
904ebfedea0SLionel Sambuc     hx509_certs signer_certs;
905ebfedea0SLionel Sambuc     int ret, flags = 0;
906ebfedea0SLionel Sambuc 
907ebfedea0SLionel Sambuc     /* BTMM is broken in Leo and SnowLeo */
908ebfedea0SLionel Sambuc     if (id->flags & PKINIT_BTMM) {
909ebfedea0SLionel Sambuc 	flags |= HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH;
910ebfedea0SLionel Sambuc 	flags |= HX509_CMS_VS_NO_KU_CHECK;
911ebfedea0SLionel Sambuc 	flags |= HX509_CMS_VS_NO_VALIDATE;
912ebfedea0SLionel Sambuc     }
913ebfedea0SLionel Sambuc 
914ebfedea0SLionel Sambuc     *signer = NULL;
915ebfedea0SLionel Sambuc 
916ebfedea0SLionel Sambuc     ret = hx509_cms_verify_signed(context->hx509ctx,
917ebfedea0SLionel Sambuc 				  id->verify_ctx,
918ebfedea0SLionel Sambuc 				  flags,
919ebfedea0SLionel Sambuc 				  data,
920ebfedea0SLionel Sambuc 				  length,
921ebfedea0SLionel Sambuc 				  NULL,
922ebfedea0SLionel Sambuc 				  id->certpool,
923ebfedea0SLionel Sambuc 				  contentType,
924ebfedea0SLionel Sambuc 				  content,
925ebfedea0SLionel Sambuc 				  &signer_certs);
926ebfedea0SLionel Sambuc     if (ret) {
927ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
928ebfedea0SLionel Sambuc 		      "CMS verify signed failed");
929ebfedea0SLionel Sambuc 	return ret;
930ebfedea0SLionel Sambuc     }
931ebfedea0SLionel Sambuc 
932ebfedea0SLionel Sambuc     *signer = calloc(1, sizeof(**signer));
933ebfedea0SLionel Sambuc     if (*signer == NULL) {
934ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
935ebfedea0SLionel Sambuc 	ret = ENOMEM;
936ebfedea0SLionel Sambuc 	goto out;
937ebfedea0SLionel Sambuc     }
938ebfedea0SLionel Sambuc 
939ebfedea0SLionel Sambuc     ret = hx509_get_one_cert(context->hx509ctx, signer_certs, &(*signer)->cert);
940ebfedea0SLionel Sambuc     if (ret) {
941ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
942ebfedea0SLionel Sambuc 		      "Failed to get on of the signer certs");
943ebfedea0SLionel Sambuc 	goto out;
944ebfedea0SLionel Sambuc     }
945ebfedea0SLionel Sambuc 
946ebfedea0SLionel Sambuc  out:
947ebfedea0SLionel Sambuc     hx509_certs_free(&signer_certs);
948ebfedea0SLionel Sambuc     if (ret) {
949ebfedea0SLionel Sambuc 	if (*signer) {
950ebfedea0SLionel Sambuc 	    hx509_cert_free((*signer)->cert);
951ebfedea0SLionel Sambuc 	    free(*signer);
952ebfedea0SLionel Sambuc 	    *signer = NULL;
953ebfedea0SLionel Sambuc 	}
954ebfedea0SLionel Sambuc     }
955ebfedea0SLionel Sambuc 
956ebfedea0SLionel Sambuc     return ret;
957ebfedea0SLionel Sambuc }
958ebfedea0SLionel Sambuc 
959ebfedea0SLionel Sambuc static krb5_error_code
get_reply_key_win(krb5_context context,const krb5_data * content,unsigned nonce,krb5_keyblock ** key)960ebfedea0SLionel Sambuc get_reply_key_win(krb5_context context,
961ebfedea0SLionel Sambuc 		  const krb5_data *content,
962ebfedea0SLionel Sambuc 		  unsigned nonce,
963ebfedea0SLionel Sambuc 		  krb5_keyblock **key)
964ebfedea0SLionel Sambuc {
965ebfedea0SLionel Sambuc     ReplyKeyPack_Win2k key_pack;
966ebfedea0SLionel Sambuc     krb5_error_code ret;
967ebfedea0SLionel Sambuc     size_t size;
968ebfedea0SLionel Sambuc 
969ebfedea0SLionel Sambuc     ret = decode_ReplyKeyPack_Win2k(content->data,
970ebfedea0SLionel Sambuc 				    content->length,
971ebfedea0SLionel Sambuc 				    &key_pack,
972ebfedea0SLionel Sambuc 				    &size);
973ebfedea0SLionel Sambuc     if (ret) {
974ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
975ebfedea0SLionel Sambuc 			       N_("PKINIT decoding reply key failed", ""));
976ebfedea0SLionel Sambuc 	free_ReplyKeyPack_Win2k(&key_pack);
977ebfedea0SLionel Sambuc 	return ret;
978ebfedea0SLionel Sambuc     }
979ebfedea0SLionel Sambuc 
980*0a6a1f1dSLionel Sambuc     if ((unsigned)key_pack.nonce != nonce) {
981ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
982ebfedea0SLionel Sambuc 			       N_("PKINIT enckey nonce is wrong", ""));
983ebfedea0SLionel Sambuc 	free_ReplyKeyPack_Win2k(&key_pack);
984ebfedea0SLionel Sambuc 	return KRB5KRB_AP_ERR_MODIFIED;
985ebfedea0SLionel Sambuc     }
986ebfedea0SLionel Sambuc 
987ebfedea0SLionel Sambuc     *key = malloc (sizeof (**key));
988ebfedea0SLionel Sambuc     if (*key == NULL) {
989ebfedea0SLionel Sambuc 	free_ReplyKeyPack_Win2k(&key_pack);
990ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM,
991ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
992ebfedea0SLionel Sambuc 	return ENOMEM;
993ebfedea0SLionel Sambuc     }
994ebfedea0SLionel Sambuc 
995ebfedea0SLionel Sambuc     ret = copy_EncryptionKey(&key_pack.replyKey, *key);
996ebfedea0SLionel Sambuc     free_ReplyKeyPack_Win2k(&key_pack);
997ebfedea0SLionel Sambuc     if (ret) {
998ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
999ebfedea0SLionel Sambuc 			       N_("PKINIT failed copying reply key", ""));
1000ebfedea0SLionel Sambuc 	free(*key);
1001ebfedea0SLionel Sambuc 	*key = NULL;
1002ebfedea0SLionel Sambuc     }
1003ebfedea0SLionel Sambuc 
1004ebfedea0SLionel Sambuc     return ret;
1005ebfedea0SLionel Sambuc }
1006ebfedea0SLionel Sambuc 
1007ebfedea0SLionel Sambuc static krb5_error_code
get_reply_key(krb5_context context,const krb5_data * content,const krb5_data * req_buffer,krb5_keyblock ** key)1008ebfedea0SLionel Sambuc get_reply_key(krb5_context context,
1009ebfedea0SLionel Sambuc 	      const krb5_data *content,
1010ebfedea0SLionel Sambuc 	      const krb5_data *req_buffer,
1011ebfedea0SLionel Sambuc 	      krb5_keyblock **key)
1012ebfedea0SLionel Sambuc {
1013ebfedea0SLionel Sambuc     ReplyKeyPack key_pack;
1014ebfedea0SLionel Sambuc     krb5_error_code ret;
1015ebfedea0SLionel Sambuc     size_t size;
1016ebfedea0SLionel Sambuc 
1017ebfedea0SLionel Sambuc     ret = decode_ReplyKeyPack(content->data,
1018ebfedea0SLionel Sambuc 			      content->length,
1019ebfedea0SLionel Sambuc 			      &key_pack,
1020ebfedea0SLionel Sambuc 			      &size);
1021ebfedea0SLionel Sambuc     if (ret) {
1022ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
1023ebfedea0SLionel Sambuc 			       N_("PKINIT decoding reply key failed", ""));
1024ebfedea0SLionel Sambuc 	free_ReplyKeyPack(&key_pack);
1025ebfedea0SLionel Sambuc 	return ret;
1026ebfedea0SLionel Sambuc     }
1027ebfedea0SLionel Sambuc 
1028ebfedea0SLionel Sambuc     {
1029ebfedea0SLionel Sambuc 	krb5_crypto crypto;
1030ebfedea0SLionel Sambuc 
1031ebfedea0SLionel Sambuc 	/*
1032ebfedea0SLionel Sambuc 	 * XXX Verify kp.replyKey is a allowed enctype in the
1033ebfedea0SLionel Sambuc 	 * configuration file
1034ebfedea0SLionel Sambuc 	 */
1035ebfedea0SLionel Sambuc 
1036ebfedea0SLionel Sambuc 	ret = krb5_crypto_init(context, &key_pack.replyKey, 0, &crypto);
1037ebfedea0SLionel Sambuc 	if (ret) {
1038ebfedea0SLionel Sambuc 	    free_ReplyKeyPack(&key_pack);
1039ebfedea0SLionel Sambuc 	    return ret;
1040ebfedea0SLionel Sambuc 	}
1041ebfedea0SLionel Sambuc 
1042ebfedea0SLionel Sambuc 	ret = krb5_verify_checksum(context, crypto, 6,
1043ebfedea0SLionel Sambuc 				   req_buffer->data, req_buffer->length,
1044ebfedea0SLionel Sambuc 				   &key_pack.asChecksum);
1045ebfedea0SLionel Sambuc 	krb5_crypto_destroy(context, crypto);
1046ebfedea0SLionel Sambuc 	if (ret) {
1047ebfedea0SLionel Sambuc 	    free_ReplyKeyPack(&key_pack);
1048ebfedea0SLionel Sambuc 	    return ret;
1049ebfedea0SLionel Sambuc 	}
1050ebfedea0SLionel Sambuc     }
1051ebfedea0SLionel Sambuc 
1052ebfedea0SLionel Sambuc     *key = malloc (sizeof (**key));
1053ebfedea0SLionel Sambuc     if (*key == NULL) {
1054ebfedea0SLionel Sambuc 	free_ReplyKeyPack(&key_pack);
1055ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM,
1056ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
1057ebfedea0SLionel Sambuc 	return ENOMEM;
1058ebfedea0SLionel Sambuc     }
1059ebfedea0SLionel Sambuc 
1060ebfedea0SLionel Sambuc     ret = copy_EncryptionKey(&key_pack.replyKey, *key);
1061ebfedea0SLionel Sambuc     free_ReplyKeyPack(&key_pack);
1062ebfedea0SLionel Sambuc     if (ret) {
1063ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
1064ebfedea0SLionel Sambuc 			       N_("PKINIT failed copying reply key", ""));
1065ebfedea0SLionel Sambuc 	free(*key);
1066ebfedea0SLionel Sambuc 	*key = NULL;
1067ebfedea0SLionel Sambuc     }
1068ebfedea0SLionel Sambuc 
1069ebfedea0SLionel Sambuc     return ret;
1070ebfedea0SLionel Sambuc }
1071ebfedea0SLionel Sambuc 
1072ebfedea0SLionel Sambuc 
1073ebfedea0SLionel Sambuc static krb5_error_code
pk_verify_host(krb5_context context,const char * realm,const krb5_krbhst_info * hi,struct krb5_pk_init_ctx_data * ctx,struct krb5_pk_cert * host)1074ebfedea0SLionel Sambuc pk_verify_host(krb5_context context,
1075ebfedea0SLionel Sambuc 	       const char *realm,
1076ebfedea0SLionel Sambuc 	       const krb5_krbhst_info *hi,
1077ebfedea0SLionel Sambuc 	       struct krb5_pk_init_ctx_data *ctx,
1078ebfedea0SLionel Sambuc 	       struct krb5_pk_cert *host)
1079ebfedea0SLionel Sambuc {
1080ebfedea0SLionel Sambuc     krb5_error_code ret = 0;
1081ebfedea0SLionel Sambuc 
1082ebfedea0SLionel Sambuc     if (ctx->require_eku) {
1083ebfedea0SLionel Sambuc 	ret = hx509_cert_check_eku(context->hx509ctx, host->cert,
1084ebfedea0SLionel Sambuc 				   &asn1_oid_id_pkkdcekuoid, 0);
1085ebfedea0SLionel Sambuc 	if (ret) {
1086ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1087ebfedea0SLionel Sambuc 				   N_("No PK-INIT KDC EKU in kdc certificate", ""));
1088ebfedea0SLionel Sambuc 	    return ret;
1089ebfedea0SLionel Sambuc 	}
1090ebfedea0SLionel Sambuc     }
1091ebfedea0SLionel Sambuc     if (ctx->require_krbtgt_otherName) {
1092ebfedea0SLionel Sambuc 	hx509_octet_string_list list;
1093*0a6a1f1dSLionel Sambuc 	size_t i;
1094ebfedea0SLionel Sambuc 
1095ebfedea0SLionel Sambuc 	ret = hx509_cert_find_subjectAltName_otherName(context->hx509ctx,
1096ebfedea0SLionel Sambuc 						       host->cert,
1097ebfedea0SLionel Sambuc 						       &asn1_oid_id_pkinit_san,
1098ebfedea0SLionel Sambuc 						       &list);
1099ebfedea0SLionel Sambuc 	if (ret) {
1100ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1101ebfedea0SLionel Sambuc 				   N_("Failed to find the PK-INIT "
1102ebfedea0SLionel Sambuc 				      "subjectAltName in the KDC "
1103ebfedea0SLionel Sambuc 				      "certificate", ""));
1104ebfedea0SLionel Sambuc 
1105ebfedea0SLionel Sambuc 	    return ret;
1106ebfedea0SLionel Sambuc 	}
1107ebfedea0SLionel Sambuc 
1108ebfedea0SLionel Sambuc 	for (i = 0; i < list.len; i++) {
1109ebfedea0SLionel Sambuc 	    KRB5PrincipalName r;
1110ebfedea0SLionel Sambuc 
1111ebfedea0SLionel Sambuc 	    ret = decode_KRB5PrincipalName(list.val[i].data,
1112ebfedea0SLionel Sambuc 					   list.val[i].length,
1113ebfedea0SLionel Sambuc 					   &r,
1114ebfedea0SLionel Sambuc 					   NULL);
1115ebfedea0SLionel Sambuc 	    if (ret) {
1116ebfedea0SLionel Sambuc 		krb5_set_error_message(context, ret,
1117ebfedea0SLionel Sambuc 				       N_("Failed to decode the PK-INIT "
1118ebfedea0SLionel Sambuc 					  "subjectAltName in the "
1119ebfedea0SLionel Sambuc 					  "KDC certificate", ""));
1120ebfedea0SLionel Sambuc 
1121ebfedea0SLionel Sambuc 		break;
1122ebfedea0SLionel Sambuc 	    }
1123ebfedea0SLionel Sambuc 
1124ebfedea0SLionel Sambuc 	    if (r.principalName.name_string.len != 2 ||
1125ebfedea0SLionel Sambuc 		strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) != 0 ||
1126ebfedea0SLionel Sambuc 		strcmp(r.principalName.name_string.val[1], realm) != 0 ||
1127ebfedea0SLionel Sambuc 		strcmp(r.realm, realm) != 0)
1128ebfedea0SLionel Sambuc 		{
1129ebfedea0SLionel Sambuc 		    ret = KRB5_KDC_ERR_INVALID_CERTIFICATE;
1130ebfedea0SLionel Sambuc 		    krb5_set_error_message(context, ret,
1131ebfedea0SLionel Sambuc 					   N_("KDC have wrong realm name in "
1132ebfedea0SLionel Sambuc 					      "the certificate", ""));
1133ebfedea0SLionel Sambuc 		}
1134ebfedea0SLionel Sambuc 
1135ebfedea0SLionel Sambuc 	    free_KRB5PrincipalName(&r);
1136ebfedea0SLionel Sambuc 	    if (ret)
1137ebfedea0SLionel Sambuc 		break;
1138ebfedea0SLionel Sambuc 	}
1139ebfedea0SLionel Sambuc 	hx509_free_octet_string_list(&list);
1140ebfedea0SLionel Sambuc     }
1141ebfedea0SLionel Sambuc     if (ret)
1142ebfedea0SLionel Sambuc 	return ret;
1143ebfedea0SLionel Sambuc 
1144ebfedea0SLionel Sambuc     if (hi) {
1145ebfedea0SLionel Sambuc 	ret = hx509_verify_hostname(context->hx509ctx, host->cert,
1146ebfedea0SLionel Sambuc 				    ctx->require_hostname_match,
1147ebfedea0SLionel Sambuc 				    HX509_HN_HOSTNAME,
1148ebfedea0SLionel Sambuc 				    hi->hostname,
1149ebfedea0SLionel Sambuc 				    hi->ai->ai_addr, hi->ai->ai_addrlen);
1150ebfedea0SLionel Sambuc 
1151ebfedea0SLionel Sambuc 	if (ret)
1152ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1153ebfedea0SLionel Sambuc 				   N_("Address mismatch in "
1154ebfedea0SLionel Sambuc 				      "the KDC certificate", ""));
1155ebfedea0SLionel Sambuc     }
1156ebfedea0SLionel Sambuc     return ret;
1157ebfedea0SLionel Sambuc }
1158ebfedea0SLionel Sambuc 
1159ebfedea0SLionel Sambuc static krb5_error_code
pk_rd_pa_reply_enckey(krb5_context context,int type,const heim_octet_string * indata,const heim_oid * dataType,const char * realm,krb5_pk_init_ctx ctx,krb5_enctype etype,const krb5_krbhst_info * hi,unsigned nonce,const krb5_data * req_buffer,PA_DATA * pa,krb5_keyblock ** key)1160ebfedea0SLionel Sambuc pk_rd_pa_reply_enckey(krb5_context context,
1161ebfedea0SLionel Sambuc 		      int type,
1162ebfedea0SLionel Sambuc 		      const heim_octet_string *indata,
1163ebfedea0SLionel Sambuc 		      const heim_oid *dataType,
1164ebfedea0SLionel Sambuc 		      const char *realm,
1165ebfedea0SLionel Sambuc 		      krb5_pk_init_ctx ctx,
1166ebfedea0SLionel Sambuc 		      krb5_enctype etype,
1167ebfedea0SLionel Sambuc 		      const krb5_krbhst_info *hi,
1168ebfedea0SLionel Sambuc 	       	      unsigned nonce,
1169ebfedea0SLionel Sambuc 		      const krb5_data *req_buffer,
1170ebfedea0SLionel Sambuc 	       	      PA_DATA *pa,
1171ebfedea0SLionel Sambuc 	       	      krb5_keyblock **key)
1172ebfedea0SLionel Sambuc {
1173ebfedea0SLionel Sambuc     krb5_error_code ret;
1174ebfedea0SLionel Sambuc     struct krb5_pk_cert *host = NULL;
1175ebfedea0SLionel Sambuc     krb5_data content;
1176ebfedea0SLionel Sambuc     heim_oid contentType = { 0, NULL };
1177ebfedea0SLionel Sambuc     int flags = HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT;
1178ebfedea0SLionel Sambuc 
1179ebfedea0SLionel Sambuc     if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_envelopedData, dataType)) {
1180ebfedea0SLionel Sambuc 	krb5_set_error_message(context, EINVAL,
1181ebfedea0SLionel Sambuc 			       N_("PKINIT: Invalid content type", ""));
1182ebfedea0SLionel Sambuc 	return EINVAL;
1183ebfedea0SLionel Sambuc     }
1184ebfedea0SLionel Sambuc 
1185ebfedea0SLionel Sambuc     if (ctx->type == PKINIT_WIN2K)
1186ebfedea0SLionel Sambuc 	flags |= HX509_CMS_UE_ALLOW_WEAK;
1187ebfedea0SLionel Sambuc 
1188ebfedea0SLionel Sambuc     ret = hx509_cms_unenvelope(context->hx509ctx,
1189ebfedea0SLionel Sambuc 			       ctx->id->certs,
1190ebfedea0SLionel Sambuc 			       flags,
1191ebfedea0SLionel Sambuc 			       indata->data,
1192ebfedea0SLionel Sambuc 			       indata->length,
1193ebfedea0SLionel Sambuc 			       NULL,
1194ebfedea0SLionel Sambuc 			       0,
1195ebfedea0SLionel Sambuc 			       &contentType,
1196ebfedea0SLionel Sambuc 			       &content);
1197ebfedea0SLionel Sambuc     if (ret) {
1198ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
1199ebfedea0SLionel Sambuc 		      "Failed to unenvelope CMS data in PK-INIT reply");
1200ebfedea0SLionel Sambuc 	return ret;
1201ebfedea0SLionel Sambuc     }
1202ebfedea0SLionel Sambuc     der_free_oid(&contentType);
1203ebfedea0SLionel Sambuc 
1204ebfedea0SLionel Sambuc     /* win2k uses ContentInfo */
1205ebfedea0SLionel Sambuc     if (type == PKINIT_WIN2K) {
1206ebfedea0SLionel Sambuc 	heim_oid type2;
1207ebfedea0SLionel Sambuc 	heim_octet_string out;
1208ebfedea0SLionel Sambuc 
1209ebfedea0SLionel Sambuc 	ret = hx509_cms_unwrap_ContentInfo(&content, &type2, &out, NULL);
1210ebfedea0SLionel Sambuc 	if (ret) {
1211ebfedea0SLionel Sambuc 	    /* windows LH with interesting CMS packets */
1212ebfedea0SLionel Sambuc 	    size_t ph = 1 + der_length_len(content.length);
1213ebfedea0SLionel Sambuc 	    unsigned char *ptr = malloc(content.length + ph);
1214ebfedea0SLionel Sambuc 	    size_t l;
1215ebfedea0SLionel Sambuc 
1216ebfedea0SLionel Sambuc 	    memcpy(ptr + ph, content.data, content.length);
1217ebfedea0SLionel Sambuc 
1218ebfedea0SLionel Sambuc 	    ret = der_put_length_and_tag (ptr + ph - 1, ph, content.length,
1219ebfedea0SLionel Sambuc 					  ASN1_C_UNIV, CONS, UT_Sequence, &l);
1220ebfedea0SLionel Sambuc 	    if (ret)
1221ebfedea0SLionel Sambuc 		return ret;
1222ebfedea0SLionel Sambuc 	    free(content.data);
1223ebfedea0SLionel Sambuc 	    content.data = ptr;
1224ebfedea0SLionel Sambuc 	    content.length += ph;
1225ebfedea0SLionel Sambuc 
1226ebfedea0SLionel Sambuc 	    ret = hx509_cms_unwrap_ContentInfo(&content, &type2, &out, NULL);
1227ebfedea0SLionel Sambuc 	    if (ret)
1228ebfedea0SLionel Sambuc 		goto out;
1229ebfedea0SLionel Sambuc 	}
1230ebfedea0SLionel Sambuc 	if (der_heim_oid_cmp(&type2, &asn1_oid_id_pkcs7_signedData)) {
1231ebfedea0SLionel Sambuc 	    ret = EINVAL; /* XXX */
1232ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1233ebfedea0SLionel Sambuc 				   N_("PKINIT: Invalid content type", ""));
1234ebfedea0SLionel Sambuc 	    der_free_oid(&type2);
1235ebfedea0SLionel Sambuc 	    der_free_octet_string(&out);
1236ebfedea0SLionel Sambuc 	    goto out;
1237ebfedea0SLionel Sambuc 	}
1238ebfedea0SLionel Sambuc 	der_free_oid(&type2);
1239ebfedea0SLionel Sambuc 	krb5_data_free(&content);
1240ebfedea0SLionel Sambuc 	ret = krb5_data_copy(&content, out.data, out.length);
1241ebfedea0SLionel Sambuc 	der_free_octet_string(&out);
1242ebfedea0SLionel Sambuc 	if (ret) {
1243ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1244ebfedea0SLionel Sambuc 				   N_("malloc: out of memory", ""));
1245ebfedea0SLionel Sambuc 	    goto out;
1246ebfedea0SLionel Sambuc 	}
1247ebfedea0SLionel Sambuc     }
1248ebfedea0SLionel Sambuc 
1249ebfedea0SLionel Sambuc     ret = pk_verify_sign(context,
1250ebfedea0SLionel Sambuc 			 content.data,
1251ebfedea0SLionel Sambuc 			 content.length,
1252ebfedea0SLionel Sambuc 			 ctx->id,
1253ebfedea0SLionel Sambuc 			 &contentType,
1254ebfedea0SLionel Sambuc 			 &content,
1255ebfedea0SLionel Sambuc 			 &host);
1256ebfedea0SLionel Sambuc     if (ret)
1257ebfedea0SLionel Sambuc 	goto out;
1258ebfedea0SLionel Sambuc 
1259ebfedea0SLionel Sambuc     /* make sure that it is the kdc's certificate */
1260ebfedea0SLionel Sambuc     ret = pk_verify_host(context, realm, hi, ctx, host);
1261ebfedea0SLionel Sambuc     if (ret) {
1262ebfedea0SLionel Sambuc 	goto out;
1263ebfedea0SLionel Sambuc     }
1264ebfedea0SLionel Sambuc 
1265ebfedea0SLionel Sambuc #if 0
1266ebfedea0SLionel Sambuc     if (type == PKINIT_WIN2K) {
1267ebfedea0SLionel Sambuc 	if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) != 0) {
1268ebfedea0SLionel Sambuc 	    ret = KRB5KRB_AP_ERR_MSG_TYPE;
1269ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1270ebfedea0SLionel Sambuc 	    goto out;
1271ebfedea0SLionel Sambuc 	}
1272ebfedea0SLionel Sambuc     } else {
1273ebfedea0SLionel Sambuc 	if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkrkeydata) != 0) {
1274ebfedea0SLionel Sambuc 	    ret = KRB5KRB_AP_ERR_MSG_TYPE;
1275ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1276ebfedea0SLionel Sambuc 	    goto out;
1277ebfedea0SLionel Sambuc 	}
1278ebfedea0SLionel Sambuc     }
1279ebfedea0SLionel Sambuc #endif
1280ebfedea0SLionel Sambuc 
1281ebfedea0SLionel Sambuc     switch(type) {
1282ebfedea0SLionel Sambuc     case PKINIT_WIN2K:
1283ebfedea0SLionel Sambuc 	ret = get_reply_key(context, &content, req_buffer, key);
1284ebfedea0SLionel Sambuc 	if (ret != 0 && ctx->require_binding == 0)
1285ebfedea0SLionel Sambuc 	    ret = get_reply_key_win(context, &content, nonce, key);
1286ebfedea0SLionel Sambuc 	break;
1287ebfedea0SLionel Sambuc     case PKINIT_27:
1288ebfedea0SLionel Sambuc 	ret = get_reply_key(context, &content, req_buffer, key);
1289ebfedea0SLionel Sambuc 	break;
1290ebfedea0SLionel Sambuc     }
1291ebfedea0SLionel Sambuc     if (ret)
1292ebfedea0SLionel Sambuc 	goto out;
1293ebfedea0SLionel Sambuc 
1294ebfedea0SLionel Sambuc     /* XXX compare given etype with key->etype */
1295ebfedea0SLionel Sambuc 
1296ebfedea0SLionel Sambuc  out:
1297ebfedea0SLionel Sambuc     if (host)
1298ebfedea0SLionel Sambuc 	_krb5_pk_cert_free(host);
1299ebfedea0SLionel Sambuc     der_free_oid(&contentType);
1300ebfedea0SLionel Sambuc     krb5_data_free(&content);
1301ebfedea0SLionel Sambuc 
1302ebfedea0SLionel Sambuc     return ret;
1303ebfedea0SLionel Sambuc }
1304ebfedea0SLionel Sambuc 
1305ebfedea0SLionel Sambuc static krb5_error_code
pk_rd_pa_reply_dh(krb5_context context,const heim_octet_string * indata,const heim_oid * dataType,const char * realm,krb5_pk_init_ctx ctx,krb5_enctype etype,const krb5_krbhst_info * hi,const DHNonce * c_n,const DHNonce * k_n,unsigned nonce,PA_DATA * pa,krb5_keyblock ** key)1306ebfedea0SLionel Sambuc pk_rd_pa_reply_dh(krb5_context context,
1307ebfedea0SLionel Sambuc 		  const heim_octet_string *indata,
1308ebfedea0SLionel Sambuc 		  const heim_oid *dataType,
1309ebfedea0SLionel Sambuc 		  const char *realm,
1310ebfedea0SLionel Sambuc 		  krb5_pk_init_ctx ctx,
1311ebfedea0SLionel Sambuc 		  krb5_enctype etype,
1312ebfedea0SLionel Sambuc 		  const krb5_krbhst_info *hi,
1313ebfedea0SLionel Sambuc 		  const DHNonce *c_n,
1314ebfedea0SLionel Sambuc 		  const DHNonce *k_n,
1315ebfedea0SLionel Sambuc                   unsigned nonce,
1316ebfedea0SLionel Sambuc                   PA_DATA *pa,
1317ebfedea0SLionel Sambuc                   krb5_keyblock **key)
1318ebfedea0SLionel Sambuc {
1319ebfedea0SLionel Sambuc     const unsigned char *p;
1320ebfedea0SLionel Sambuc     unsigned char *dh_gen_key = NULL;
1321ebfedea0SLionel Sambuc     struct krb5_pk_cert *host = NULL;
1322ebfedea0SLionel Sambuc     BIGNUM *kdc_dh_pubkey = NULL;
1323ebfedea0SLionel Sambuc     KDCDHKeyInfo kdc_dh_info;
1324ebfedea0SLionel Sambuc     heim_oid contentType = { 0, NULL };
1325ebfedea0SLionel Sambuc     krb5_data content;
1326ebfedea0SLionel Sambuc     krb5_error_code ret;
1327ebfedea0SLionel Sambuc     int dh_gen_keylen = 0;
1328ebfedea0SLionel Sambuc     size_t size;
1329ebfedea0SLionel Sambuc 
1330ebfedea0SLionel Sambuc     krb5_data_zero(&content);
1331ebfedea0SLionel Sambuc     memset(&kdc_dh_info, 0, sizeof(kdc_dh_info));
1332ebfedea0SLionel Sambuc 
1333ebfedea0SLionel Sambuc     if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_signedData, dataType)) {
1334ebfedea0SLionel Sambuc 	krb5_set_error_message(context, EINVAL,
1335ebfedea0SLionel Sambuc 			       N_("PKINIT: Invalid content type", ""));
1336ebfedea0SLionel Sambuc 	return EINVAL;
1337ebfedea0SLionel Sambuc     }
1338ebfedea0SLionel Sambuc 
1339ebfedea0SLionel Sambuc     ret = pk_verify_sign(context,
1340ebfedea0SLionel Sambuc 			 indata->data,
1341ebfedea0SLionel Sambuc 			 indata->length,
1342ebfedea0SLionel Sambuc 			 ctx->id,
1343ebfedea0SLionel Sambuc 			 &contentType,
1344ebfedea0SLionel Sambuc 			 &content,
1345ebfedea0SLionel Sambuc 			 &host);
1346ebfedea0SLionel Sambuc     if (ret)
1347ebfedea0SLionel Sambuc 	goto out;
1348ebfedea0SLionel Sambuc 
1349ebfedea0SLionel Sambuc     /* make sure that it is the kdc's certificate */
1350ebfedea0SLionel Sambuc     ret = pk_verify_host(context, realm, hi, ctx, host);
1351ebfedea0SLionel Sambuc     if (ret)
1352ebfedea0SLionel Sambuc 	goto out;
1353ebfedea0SLionel Sambuc 
1354ebfedea0SLionel Sambuc     if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkdhkeydata)) {
1355ebfedea0SLionel Sambuc 	ret = KRB5KRB_AP_ERR_MSG_TYPE;
1356ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
1357ebfedea0SLionel Sambuc 			       N_("pkinit - dh reply contains wrong oid", ""));
1358ebfedea0SLionel Sambuc 	goto out;
1359ebfedea0SLionel Sambuc     }
1360ebfedea0SLionel Sambuc 
1361ebfedea0SLionel Sambuc     ret = decode_KDCDHKeyInfo(content.data,
1362ebfedea0SLionel Sambuc 			      content.length,
1363ebfedea0SLionel Sambuc 			      &kdc_dh_info,
1364ebfedea0SLionel Sambuc 			      &size);
1365ebfedea0SLionel Sambuc 
1366ebfedea0SLionel Sambuc     if (ret) {
1367ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
1368ebfedea0SLionel Sambuc 			       N_("pkinit - failed to decode "
1369ebfedea0SLionel Sambuc 				  "KDC DH Key Info", ""));
1370ebfedea0SLionel Sambuc 	goto out;
1371ebfedea0SLionel Sambuc     }
1372ebfedea0SLionel Sambuc 
1373ebfedea0SLionel Sambuc     if (kdc_dh_info.nonce != nonce) {
1374ebfedea0SLionel Sambuc 	ret = KRB5KRB_AP_ERR_MODIFIED;
1375ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
1376ebfedea0SLionel Sambuc 			       N_("PKINIT: DH nonce is wrong", ""));
1377ebfedea0SLionel Sambuc 	goto out;
1378ebfedea0SLionel Sambuc     }
1379ebfedea0SLionel Sambuc 
1380ebfedea0SLionel Sambuc     if (kdc_dh_info.dhKeyExpiration) {
1381ebfedea0SLionel Sambuc 	if (k_n == NULL) {
1382ebfedea0SLionel Sambuc 	    ret = KRB5KRB_ERR_GENERIC;
1383ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1384ebfedea0SLionel Sambuc 				   N_("pkinit; got key expiration "
1385ebfedea0SLionel Sambuc 				      "without server nonce", ""));
1386ebfedea0SLionel Sambuc 	    goto out;
1387ebfedea0SLionel Sambuc 	}
1388ebfedea0SLionel Sambuc 	if (c_n == NULL) {
1389ebfedea0SLionel Sambuc 	    ret = KRB5KRB_ERR_GENERIC;
1390ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1391ebfedea0SLionel Sambuc 				   N_("pkinit; got DH reuse but no "
1392ebfedea0SLionel Sambuc 				      "client nonce", ""));
1393ebfedea0SLionel Sambuc 	    goto out;
1394ebfedea0SLionel Sambuc 	}
1395ebfedea0SLionel Sambuc     } else {
1396ebfedea0SLionel Sambuc 	if (k_n) {
1397ebfedea0SLionel Sambuc 	    ret = KRB5KRB_ERR_GENERIC;
1398ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1399ebfedea0SLionel Sambuc 				   N_("pkinit: got server nonce "
1400ebfedea0SLionel Sambuc 				      "without key expiration", ""));
1401ebfedea0SLionel Sambuc 	    goto out;
1402ebfedea0SLionel Sambuc 	}
1403ebfedea0SLionel Sambuc 	c_n = NULL;
1404ebfedea0SLionel Sambuc     }
1405ebfedea0SLionel Sambuc 
1406ebfedea0SLionel Sambuc 
1407ebfedea0SLionel Sambuc     p = kdc_dh_info.subjectPublicKey.data;
1408ebfedea0SLionel Sambuc     size = (kdc_dh_info.subjectPublicKey.length + 7) / 8;
1409ebfedea0SLionel Sambuc 
1410ebfedea0SLionel Sambuc     if (ctx->keyex == USE_DH) {
1411ebfedea0SLionel Sambuc 	DHPublicKey k;
1412ebfedea0SLionel Sambuc 	ret = decode_DHPublicKey(p, size, &k, NULL);
1413ebfedea0SLionel Sambuc 	if (ret) {
1414ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1415ebfedea0SLionel Sambuc 				   N_("pkinit: can't decode "
1416ebfedea0SLionel Sambuc 				      "without key expiration", ""));
1417ebfedea0SLionel Sambuc 	    goto out;
1418ebfedea0SLionel Sambuc 	}
1419ebfedea0SLionel Sambuc 
1420ebfedea0SLionel Sambuc 	kdc_dh_pubkey = integer_to_BN(context, "DHPublicKey", &k);
1421ebfedea0SLionel Sambuc 	free_DHPublicKey(&k);
1422ebfedea0SLionel Sambuc 	if (kdc_dh_pubkey == NULL) {
1423ebfedea0SLionel Sambuc 	    ret = ENOMEM;
1424ebfedea0SLionel Sambuc 	    goto out;
1425ebfedea0SLionel Sambuc 	}
1426ebfedea0SLionel Sambuc 
1427ebfedea0SLionel Sambuc 
1428ebfedea0SLionel Sambuc 	size = DH_size(ctx->u.dh);
1429ebfedea0SLionel Sambuc 
1430ebfedea0SLionel Sambuc 	dh_gen_key = malloc(size);
1431ebfedea0SLionel Sambuc 	if (dh_gen_key == NULL) {
1432ebfedea0SLionel Sambuc 	    ret = ENOMEM;
1433ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1434ebfedea0SLionel Sambuc 	    goto out;
1435ebfedea0SLionel Sambuc 	}
1436ebfedea0SLionel Sambuc 
1437ebfedea0SLionel Sambuc 	dh_gen_keylen = DH_compute_key(dh_gen_key, kdc_dh_pubkey, ctx->u.dh);
1438ebfedea0SLionel Sambuc 	if (dh_gen_keylen == -1) {
1439ebfedea0SLionel Sambuc 	    ret = KRB5KRB_ERR_GENERIC;
1440ebfedea0SLionel Sambuc 	    dh_gen_keylen = 0;
1441ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1442ebfedea0SLionel Sambuc 				   N_("PKINIT: Can't compute Diffie-Hellman key", ""));
1443ebfedea0SLionel Sambuc 	    goto out;
1444ebfedea0SLionel Sambuc 	}
1445*0a6a1f1dSLionel Sambuc 	if (dh_gen_keylen < (int)size) {
1446ebfedea0SLionel Sambuc 	    size -= dh_gen_keylen;
1447ebfedea0SLionel Sambuc 	    memmove(dh_gen_key + size, dh_gen_key, dh_gen_keylen);
1448ebfedea0SLionel Sambuc 	    memset(dh_gen_key, 0, size);
1449ebfedea0SLionel Sambuc 	}
1450ebfedea0SLionel Sambuc 
1451ebfedea0SLionel Sambuc     } else {
1452ebfedea0SLionel Sambuc #ifdef HAVE_OPENSSL
1453ebfedea0SLionel Sambuc 	const EC_GROUP *group;
1454ebfedea0SLionel Sambuc 	EC_KEY *public = NULL;
1455ebfedea0SLionel Sambuc 
1456ebfedea0SLionel Sambuc 	group = EC_KEY_get0_group(ctx->u.eckey);
1457ebfedea0SLionel Sambuc 
1458ebfedea0SLionel Sambuc 	public = EC_KEY_new();
1459ebfedea0SLionel Sambuc 	if (public == NULL) {
1460ebfedea0SLionel Sambuc 	    ret = ENOMEM;
1461ebfedea0SLionel Sambuc 	    goto out;
1462ebfedea0SLionel Sambuc 	}
1463ebfedea0SLionel Sambuc 	if (EC_KEY_set_group(public, group) != 1) {
1464ebfedea0SLionel Sambuc 	    EC_KEY_free(public);
1465ebfedea0SLionel Sambuc 	    ret = ENOMEM;
1466ebfedea0SLionel Sambuc 	    goto out;
1467ebfedea0SLionel Sambuc 	}
1468ebfedea0SLionel Sambuc 
1469ebfedea0SLionel Sambuc 	if (o2i_ECPublicKey(&public, &p, size) == NULL) {
1470ebfedea0SLionel Sambuc 	    EC_KEY_free(public);
1471ebfedea0SLionel Sambuc 	    ret = KRB5KRB_ERR_GENERIC;
1472ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1473ebfedea0SLionel Sambuc 				   N_("PKINIT: Can't parse ECDH public key", ""));
1474ebfedea0SLionel Sambuc 	    goto out;
1475ebfedea0SLionel Sambuc 	}
1476ebfedea0SLionel Sambuc 
1477ebfedea0SLionel Sambuc 	size = (EC_GROUP_get_degree(group) + 7) / 8;
1478ebfedea0SLionel Sambuc 	dh_gen_key = malloc(size);
1479ebfedea0SLionel Sambuc 	if (dh_gen_key == NULL) {
1480ebfedea0SLionel Sambuc 	    EC_KEY_free(public);
1481ebfedea0SLionel Sambuc 	    ret = ENOMEM;
1482ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1483ebfedea0SLionel Sambuc 				   N_("malloc: out of memory", ""));
1484ebfedea0SLionel Sambuc 	    goto out;
1485ebfedea0SLionel Sambuc 	}
1486ebfedea0SLionel Sambuc 	dh_gen_keylen = ECDH_compute_key(dh_gen_key, size,
1487ebfedea0SLionel Sambuc 					 EC_KEY_get0_public_key(public), ctx->u.eckey, NULL);
1488ebfedea0SLionel Sambuc 	EC_KEY_free(public);
1489ebfedea0SLionel Sambuc 	if (dh_gen_keylen == -1) {
1490ebfedea0SLionel Sambuc 	    ret = KRB5KRB_ERR_GENERIC;
1491ebfedea0SLionel Sambuc 	    dh_gen_keylen = 0;
1492ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1493ebfedea0SLionel Sambuc 				   N_("PKINIT: Can't compute ECDH public key", ""));
1494ebfedea0SLionel Sambuc 	    goto out;
1495ebfedea0SLionel Sambuc 	}
1496ebfedea0SLionel Sambuc #else
1497ebfedea0SLionel Sambuc 	ret = EINVAL;
1498ebfedea0SLionel Sambuc #endif
1499ebfedea0SLionel Sambuc     }
1500ebfedea0SLionel Sambuc 
1501ebfedea0SLionel Sambuc     if (dh_gen_keylen <= 0) {
1502ebfedea0SLionel Sambuc 	ret = EINVAL;
1503ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
1504ebfedea0SLionel Sambuc 			       N_("PKINIT: resulting DH key <= 0", ""));
1505ebfedea0SLionel Sambuc 	dh_gen_keylen = 0;
1506ebfedea0SLionel Sambuc 	goto out;
1507ebfedea0SLionel Sambuc     }
1508ebfedea0SLionel Sambuc 
1509ebfedea0SLionel Sambuc     *key = malloc (sizeof (**key));
1510ebfedea0SLionel Sambuc     if (*key == NULL) {
1511ebfedea0SLionel Sambuc 	ret = ENOMEM;
1512ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
1513ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
1514ebfedea0SLionel Sambuc 	goto out;
1515ebfedea0SLionel Sambuc     }
1516ebfedea0SLionel Sambuc 
1517ebfedea0SLionel Sambuc     ret = _krb5_pk_octetstring2key(context,
1518ebfedea0SLionel Sambuc 				   etype,
1519ebfedea0SLionel Sambuc 				   dh_gen_key, dh_gen_keylen,
1520ebfedea0SLionel Sambuc 				   c_n, k_n,
1521ebfedea0SLionel Sambuc 				   *key);
1522ebfedea0SLionel Sambuc     if (ret) {
1523ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
1524ebfedea0SLionel Sambuc 			       N_("PKINIT: can't create key from DH key", ""));
1525ebfedea0SLionel Sambuc 	free(*key);
1526ebfedea0SLionel Sambuc 	*key = NULL;
1527ebfedea0SLionel Sambuc 	goto out;
1528ebfedea0SLionel Sambuc     }
1529ebfedea0SLionel Sambuc 
1530ebfedea0SLionel Sambuc  out:
1531ebfedea0SLionel Sambuc     if (kdc_dh_pubkey)
1532ebfedea0SLionel Sambuc 	BN_free(kdc_dh_pubkey);
1533ebfedea0SLionel Sambuc     if (dh_gen_key) {
1534ebfedea0SLionel Sambuc 	memset(dh_gen_key, 0, dh_gen_keylen);
1535ebfedea0SLionel Sambuc 	free(dh_gen_key);
1536ebfedea0SLionel Sambuc     }
1537ebfedea0SLionel Sambuc     if (host)
1538ebfedea0SLionel Sambuc 	_krb5_pk_cert_free(host);
1539ebfedea0SLionel Sambuc     if (content.data)
1540ebfedea0SLionel Sambuc 	krb5_data_free(&content);
1541ebfedea0SLionel Sambuc     der_free_oid(&contentType);
1542ebfedea0SLionel Sambuc     free_KDCDHKeyInfo(&kdc_dh_info);
1543ebfedea0SLionel Sambuc 
1544ebfedea0SLionel Sambuc     return ret;
1545ebfedea0SLionel Sambuc }
1546ebfedea0SLionel Sambuc 
1547ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_pk_rd_pa_reply(krb5_context context,const char * realm,void * c,krb5_enctype etype,const krb5_krbhst_info * hi,unsigned nonce,const krb5_data * req_buffer,PA_DATA * pa,krb5_keyblock ** key)1548ebfedea0SLionel Sambuc _krb5_pk_rd_pa_reply(krb5_context context,
1549ebfedea0SLionel Sambuc 		     const char *realm,
1550ebfedea0SLionel Sambuc 		     void *c,
1551ebfedea0SLionel Sambuc 		     krb5_enctype etype,
1552ebfedea0SLionel Sambuc 		     const krb5_krbhst_info *hi,
1553ebfedea0SLionel Sambuc 		     unsigned nonce,
1554ebfedea0SLionel Sambuc 		     const krb5_data *req_buffer,
1555ebfedea0SLionel Sambuc 		     PA_DATA *pa,
1556ebfedea0SLionel Sambuc 		     krb5_keyblock **key)
1557ebfedea0SLionel Sambuc {
1558ebfedea0SLionel Sambuc     krb5_pk_init_ctx ctx = c;
1559ebfedea0SLionel Sambuc     krb5_error_code ret;
1560ebfedea0SLionel Sambuc     size_t size;
1561ebfedea0SLionel Sambuc 
1562ebfedea0SLionel Sambuc     /* Check for IETF PK-INIT first */
1563ebfedea0SLionel Sambuc     if (ctx->type == PKINIT_27) {
1564ebfedea0SLionel Sambuc 	PA_PK_AS_REP rep;
1565ebfedea0SLionel Sambuc 	heim_octet_string os, data;
1566ebfedea0SLionel Sambuc 	heim_oid oid;
1567ebfedea0SLionel Sambuc 
1568ebfedea0SLionel Sambuc 	if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1569ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, EINVAL,
1570ebfedea0SLionel Sambuc 				   N_("PKINIT: wrong padata recv", ""));
1571ebfedea0SLionel Sambuc 	    return EINVAL;
1572ebfedea0SLionel Sambuc 	}
1573ebfedea0SLionel Sambuc 
1574ebfedea0SLionel Sambuc 	ret = decode_PA_PK_AS_REP(pa->padata_value.data,
1575ebfedea0SLionel Sambuc 				  pa->padata_value.length,
1576ebfedea0SLionel Sambuc 				  &rep,
1577ebfedea0SLionel Sambuc 				  &size);
1578ebfedea0SLionel Sambuc 	if (ret) {
1579ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1580ebfedea0SLionel Sambuc 				   N_("Failed to decode pkinit AS rep", ""));
1581ebfedea0SLionel Sambuc 	    return ret;
1582ebfedea0SLionel Sambuc 	}
1583ebfedea0SLionel Sambuc 
1584ebfedea0SLionel Sambuc 	switch (rep.element) {
1585ebfedea0SLionel Sambuc 	case choice_PA_PK_AS_REP_dhInfo:
1586ebfedea0SLionel Sambuc 	    _krb5_debug(context, 5, "krb5_get_init_creds: using pkinit dh");
1587ebfedea0SLionel Sambuc 	    os = rep.u.dhInfo.dhSignedData;
1588ebfedea0SLionel Sambuc 	    break;
1589ebfedea0SLionel Sambuc 	case choice_PA_PK_AS_REP_encKeyPack:
1590ebfedea0SLionel Sambuc 	    _krb5_debug(context, 5, "krb5_get_init_creds: using kinit enc reply key");
1591ebfedea0SLionel Sambuc 	    os = rep.u.encKeyPack;
1592ebfedea0SLionel Sambuc 	    break;
1593ebfedea0SLionel Sambuc 	default: {
1594ebfedea0SLionel Sambuc 	    PA_PK_AS_REP_BTMM btmm;
1595ebfedea0SLionel Sambuc 	    free_PA_PK_AS_REP(&rep);
1596ebfedea0SLionel Sambuc 	    memset(&rep, 0, sizeof(rep));
1597ebfedea0SLionel Sambuc 
1598ebfedea0SLionel Sambuc 	    _krb5_debug(context, 5, "krb5_get_init_creds: using BTMM kinit enc reply key");
1599ebfedea0SLionel Sambuc 
1600ebfedea0SLionel Sambuc 	    ret = decode_PA_PK_AS_REP_BTMM(pa->padata_value.data,
1601ebfedea0SLionel Sambuc 					   pa->padata_value.length,
1602ebfedea0SLionel Sambuc 					   &btmm,
1603ebfedea0SLionel Sambuc 					   &size);
1604ebfedea0SLionel Sambuc 	    if (ret) {
1605ebfedea0SLionel Sambuc 		krb5_set_error_message(context, EINVAL,
1606ebfedea0SLionel Sambuc 				       N_("PKINIT: -27 reply "
1607ebfedea0SLionel Sambuc 					  "invalid content type", ""));
1608ebfedea0SLionel Sambuc 		return EINVAL;
1609ebfedea0SLionel Sambuc 	    }
1610ebfedea0SLionel Sambuc 
1611ebfedea0SLionel Sambuc 	    if (btmm.dhSignedData || btmm.encKeyPack == NULL) {
1612ebfedea0SLionel Sambuc 		free_PA_PK_AS_REP_BTMM(&btmm);
1613ebfedea0SLionel Sambuc 		ret = EINVAL;
1614ebfedea0SLionel Sambuc 		krb5_set_error_message(context, ret,
1615ebfedea0SLionel Sambuc 				       N_("DH mode not supported for BTMM mode", ""));
1616ebfedea0SLionel Sambuc 		return ret;
1617ebfedea0SLionel Sambuc 	    }
1618ebfedea0SLionel Sambuc 
1619ebfedea0SLionel Sambuc 	    /*
1620ebfedea0SLionel Sambuc 	     * Transform to IETF style PK-INIT reply so that free works below
1621ebfedea0SLionel Sambuc 	     */
1622ebfedea0SLionel Sambuc 
1623ebfedea0SLionel Sambuc 	    rep.element = choice_PA_PK_AS_REP_encKeyPack;
1624ebfedea0SLionel Sambuc 	    rep.u.encKeyPack.data = btmm.encKeyPack->data;
1625ebfedea0SLionel Sambuc 	    rep.u.encKeyPack.length = btmm.encKeyPack->length;
1626ebfedea0SLionel Sambuc 	    btmm.encKeyPack->data = NULL;
1627ebfedea0SLionel Sambuc 	    btmm.encKeyPack->length = 0;
1628ebfedea0SLionel Sambuc 	    free_PA_PK_AS_REP_BTMM(&btmm);
1629ebfedea0SLionel Sambuc 	    os = rep.u.encKeyPack;
1630ebfedea0SLionel Sambuc 	}
1631ebfedea0SLionel Sambuc 	}
1632ebfedea0SLionel Sambuc 
1633ebfedea0SLionel Sambuc 	ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL);
1634ebfedea0SLionel Sambuc 	if (ret) {
1635ebfedea0SLionel Sambuc 	    free_PA_PK_AS_REP(&rep);
1636ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1637ebfedea0SLionel Sambuc 				   N_("PKINIT: failed to unwrap CI", ""));
1638ebfedea0SLionel Sambuc 	    return ret;
1639ebfedea0SLionel Sambuc 	}
1640ebfedea0SLionel Sambuc 
1641ebfedea0SLionel Sambuc 	switch (rep.element) {
1642ebfedea0SLionel Sambuc 	case choice_PA_PK_AS_REP_dhInfo:
1643ebfedea0SLionel Sambuc 	    ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi,
1644ebfedea0SLionel Sambuc 				    ctx->clientDHNonce,
1645ebfedea0SLionel Sambuc 				    rep.u.dhInfo.serverDHNonce,
1646ebfedea0SLionel Sambuc 				    nonce, pa, key);
1647ebfedea0SLionel Sambuc 	    break;
1648ebfedea0SLionel Sambuc 	case choice_PA_PK_AS_REP_encKeyPack:
1649ebfedea0SLionel Sambuc 	    ret = pk_rd_pa_reply_enckey(context, PKINIT_27, &data, &oid, realm,
1650ebfedea0SLionel Sambuc 					ctx, etype, hi, nonce, req_buffer, pa, key);
1651ebfedea0SLionel Sambuc 	    break;
1652ebfedea0SLionel Sambuc 	default:
1653ebfedea0SLionel Sambuc 	    krb5_abortx(context, "pk-init as-rep case not possible to happen");
1654ebfedea0SLionel Sambuc 	}
1655ebfedea0SLionel Sambuc 	der_free_octet_string(&data);
1656ebfedea0SLionel Sambuc 	der_free_oid(&oid);
1657ebfedea0SLionel Sambuc 	free_PA_PK_AS_REP(&rep);
1658ebfedea0SLionel Sambuc 
1659ebfedea0SLionel Sambuc     } else if (ctx->type == PKINIT_WIN2K) {
1660ebfedea0SLionel Sambuc 	PA_PK_AS_REP_Win2k w2krep;
1661ebfedea0SLionel Sambuc 
1662ebfedea0SLionel Sambuc 	/* Check for Windows encoding of the AS-REP pa data */
1663ebfedea0SLionel Sambuc 
1664ebfedea0SLionel Sambuc #if 0 /* should this be ? */
1665ebfedea0SLionel Sambuc 	if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1666ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, EINVAL,
1667ebfedea0SLionel Sambuc 				   "PKINIT: wrong padata recv");
1668ebfedea0SLionel Sambuc 	    return EINVAL;
1669ebfedea0SLionel Sambuc 	}
1670ebfedea0SLionel Sambuc #endif
1671ebfedea0SLionel Sambuc 
1672ebfedea0SLionel Sambuc 	memset(&w2krep, 0, sizeof(w2krep));
1673ebfedea0SLionel Sambuc 
1674ebfedea0SLionel Sambuc 	ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data,
1675ebfedea0SLionel Sambuc 					pa->padata_value.length,
1676ebfedea0SLionel Sambuc 					&w2krep,
1677ebfedea0SLionel Sambuc 					&size);
1678ebfedea0SLionel Sambuc 	if (ret) {
1679ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1680ebfedea0SLionel Sambuc 				   N_("PKINIT: Failed decoding windows "
1681ebfedea0SLionel Sambuc 				      "pkinit reply %d", ""), (int)ret);
1682ebfedea0SLionel Sambuc 	    return ret;
1683ebfedea0SLionel Sambuc 	}
1684ebfedea0SLionel Sambuc 
1685ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
1686ebfedea0SLionel Sambuc 
1687ebfedea0SLionel Sambuc 	switch (w2krep.element) {
1688ebfedea0SLionel Sambuc 	case choice_PA_PK_AS_REP_Win2k_encKeyPack: {
1689ebfedea0SLionel Sambuc 	    heim_octet_string data;
1690ebfedea0SLionel Sambuc 	    heim_oid oid;
1691ebfedea0SLionel Sambuc 
1692ebfedea0SLionel Sambuc 	    ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack,
1693ebfedea0SLionel Sambuc 					       &oid, &data, NULL);
1694ebfedea0SLionel Sambuc 	    free_PA_PK_AS_REP_Win2k(&w2krep);
1695ebfedea0SLionel Sambuc 	    if (ret) {
1696ebfedea0SLionel Sambuc 		krb5_set_error_message(context, ret,
1697ebfedea0SLionel Sambuc 				       N_("PKINIT: failed to unwrap CI", ""));
1698ebfedea0SLionel Sambuc 		return ret;
1699ebfedea0SLionel Sambuc 	    }
1700ebfedea0SLionel Sambuc 
1701ebfedea0SLionel Sambuc 	    ret = pk_rd_pa_reply_enckey(context, PKINIT_WIN2K, &data, &oid, realm,
1702ebfedea0SLionel Sambuc 					ctx, etype, hi, nonce, req_buffer, pa, key);
1703ebfedea0SLionel Sambuc 	    der_free_octet_string(&data);
1704ebfedea0SLionel Sambuc 	    der_free_oid(&oid);
1705ebfedea0SLionel Sambuc 
1706ebfedea0SLionel Sambuc 	    break;
1707ebfedea0SLionel Sambuc 	}
1708ebfedea0SLionel Sambuc 	default:
1709ebfedea0SLionel Sambuc 	    free_PA_PK_AS_REP_Win2k(&w2krep);
1710ebfedea0SLionel Sambuc 	    ret = EINVAL;
1711ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ret,
1712ebfedea0SLionel Sambuc 				   N_("PKINIT: win2k reply invalid "
1713ebfedea0SLionel Sambuc 				      "content type", ""));
1714ebfedea0SLionel Sambuc 	    break;
1715ebfedea0SLionel Sambuc 	}
1716ebfedea0SLionel Sambuc 
1717ebfedea0SLionel Sambuc     } else {
1718ebfedea0SLionel Sambuc 	ret = EINVAL;
1719ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
1720ebfedea0SLionel Sambuc 			       N_("PKINIT: unknown reply type", ""));
1721ebfedea0SLionel Sambuc     }
1722ebfedea0SLionel Sambuc 
1723ebfedea0SLionel Sambuc     return ret;
1724ebfedea0SLionel Sambuc }
1725ebfedea0SLionel Sambuc 
1726ebfedea0SLionel Sambuc struct prompter {
1727ebfedea0SLionel Sambuc     krb5_context context;
1728ebfedea0SLionel Sambuc     krb5_prompter_fct prompter;
1729ebfedea0SLionel Sambuc     void *prompter_data;
1730ebfedea0SLionel Sambuc };
1731ebfedea0SLionel Sambuc 
1732ebfedea0SLionel Sambuc static int
hx_pass_prompter(void * data,const hx509_prompt * prompter)1733ebfedea0SLionel Sambuc hx_pass_prompter(void *data, const hx509_prompt *prompter)
1734ebfedea0SLionel Sambuc {
1735ebfedea0SLionel Sambuc     krb5_error_code ret;
1736ebfedea0SLionel Sambuc     krb5_prompt prompt;
1737ebfedea0SLionel Sambuc     krb5_data password_data;
1738ebfedea0SLionel Sambuc     struct prompter *p = data;
1739ebfedea0SLionel Sambuc 
1740ebfedea0SLionel Sambuc     password_data.data   = prompter->reply.data;
1741ebfedea0SLionel Sambuc     password_data.length = prompter->reply.length;
1742ebfedea0SLionel Sambuc 
1743ebfedea0SLionel Sambuc     prompt.prompt = prompter->prompt;
1744ebfedea0SLionel Sambuc     prompt.hidden = hx509_prompt_hidden(prompter->type);
1745ebfedea0SLionel Sambuc     prompt.reply  = &password_data;
1746ebfedea0SLionel Sambuc 
1747ebfedea0SLionel Sambuc     switch (prompter->type) {
1748ebfedea0SLionel Sambuc     case HX509_PROMPT_TYPE_INFO:
1749ebfedea0SLionel Sambuc 	prompt.type   = KRB5_PROMPT_TYPE_INFO;
1750ebfedea0SLionel Sambuc 	break;
1751ebfedea0SLionel Sambuc     case HX509_PROMPT_TYPE_PASSWORD:
1752ebfedea0SLionel Sambuc     case HX509_PROMPT_TYPE_QUESTION:
1753ebfedea0SLionel Sambuc     default:
1754ebfedea0SLionel Sambuc 	prompt.type   = KRB5_PROMPT_TYPE_PASSWORD;
1755ebfedea0SLionel Sambuc 	break;
1756ebfedea0SLionel Sambuc     }
1757ebfedea0SLionel Sambuc 
1758ebfedea0SLionel Sambuc     ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt);
1759ebfedea0SLionel Sambuc     if (ret) {
1760ebfedea0SLionel Sambuc 	memset (prompter->reply.data, 0, prompter->reply.length);
1761ebfedea0SLionel Sambuc 	return 1;
1762ebfedea0SLionel Sambuc     }
1763ebfedea0SLionel Sambuc     return 0;
1764ebfedea0SLionel Sambuc }
1765ebfedea0SLionel Sambuc 
1766ebfedea0SLionel Sambuc static krb5_error_code
_krb5_pk_set_user_id(krb5_context context,krb5_principal principal,krb5_pk_init_ctx ctx,struct hx509_certs_data * certs)1767ebfedea0SLionel Sambuc _krb5_pk_set_user_id(krb5_context context,
1768ebfedea0SLionel Sambuc 		     krb5_principal principal,
1769ebfedea0SLionel Sambuc 		     krb5_pk_init_ctx ctx,
1770ebfedea0SLionel Sambuc 		     struct hx509_certs_data *certs)
1771ebfedea0SLionel Sambuc {
1772ebfedea0SLionel Sambuc     hx509_certs c = hx509_certs_ref(certs);
1773ebfedea0SLionel Sambuc     hx509_query *q = NULL;
1774ebfedea0SLionel Sambuc     int ret;
1775ebfedea0SLionel Sambuc 
1776ebfedea0SLionel Sambuc     if (ctx->id->certs)
1777ebfedea0SLionel Sambuc 	hx509_certs_free(&ctx->id->certs);
1778ebfedea0SLionel Sambuc     if (ctx->id->cert) {
1779ebfedea0SLionel Sambuc 	hx509_cert_free(ctx->id->cert);
1780ebfedea0SLionel Sambuc 	ctx->id->cert = NULL;
1781ebfedea0SLionel Sambuc     }
1782ebfedea0SLionel Sambuc 
1783ebfedea0SLionel Sambuc     ctx->id->certs = c;
1784ebfedea0SLionel Sambuc     ctx->anonymous = 0;
1785ebfedea0SLionel Sambuc 
1786ebfedea0SLionel Sambuc     ret = hx509_query_alloc(context->hx509ctx, &q);
1787ebfedea0SLionel Sambuc     if (ret) {
1788ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
1789ebfedea0SLionel Sambuc 		      "Allocate query to find signing certificate");
1790ebfedea0SLionel Sambuc 	return ret;
1791ebfedea0SLionel Sambuc     }
1792ebfedea0SLionel Sambuc 
1793ebfedea0SLionel Sambuc     hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
1794ebfedea0SLionel Sambuc     hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
1795ebfedea0SLionel Sambuc 
1796ebfedea0SLionel Sambuc     if (principal && strncmp("LKDC:SHA1.", krb5_principal_get_realm(context, principal), 9) == 0) {
1797ebfedea0SLionel Sambuc 	ctx->id->flags |= PKINIT_BTMM;
1798ebfedea0SLionel Sambuc     }
1799ebfedea0SLionel Sambuc 
1800ebfedea0SLionel Sambuc     ret = find_cert(context, ctx->id, q, &ctx->id->cert);
1801ebfedea0SLionel Sambuc     hx509_query_free(context->hx509ctx, q);
1802ebfedea0SLionel Sambuc 
1803ebfedea0SLionel Sambuc     if (ret == 0 && _krb5_have_debug(context, 2)) {
1804ebfedea0SLionel Sambuc 	hx509_name name;
1805ebfedea0SLionel Sambuc 	char *str, *sn;
1806ebfedea0SLionel Sambuc 	heim_integer i;
1807ebfedea0SLionel Sambuc 
1808ebfedea0SLionel Sambuc 	ret = hx509_cert_get_subject(ctx->id->cert, &name);
1809ebfedea0SLionel Sambuc 	if (ret)
1810ebfedea0SLionel Sambuc 	    goto out;
1811ebfedea0SLionel Sambuc 
1812ebfedea0SLionel Sambuc 	ret = hx509_name_to_string(name, &str);
1813ebfedea0SLionel Sambuc 	hx509_name_free(&name);
1814ebfedea0SLionel Sambuc 	if (ret)
1815ebfedea0SLionel Sambuc 	    goto out;
1816ebfedea0SLionel Sambuc 
1817ebfedea0SLionel Sambuc 	ret = hx509_cert_get_serialnumber(ctx->id->cert, &i);
1818ebfedea0SLionel Sambuc 	if (ret) {
1819ebfedea0SLionel Sambuc 	    free(str);
1820ebfedea0SLionel Sambuc 	    goto out;
1821ebfedea0SLionel Sambuc 	}
1822ebfedea0SLionel Sambuc 
1823ebfedea0SLionel Sambuc 	ret = der_print_hex_heim_integer(&i, &sn);
1824ebfedea0SLionel Sambuc 	der_free_heim_integer(&i);
1825ebfedea0SLionel Sambuc 	if (ret) {
1826ebfedea0SLionel Sambuc 	    free(name);
1827ebfedea0SLionel Sambuc 	    goto out;
1828ebfedea0SLionel Sambuc 	}
1829ebfedea0SLionel Sambuc 
1830ebfedea0SLionel Sambuc 	_krb5_debug(context, 2, "using cert: subject: %s sn: %s", str, sn);
1831ebfedea0SLionel Sambuc 	free(str);
1832ebfedea0SLionel Sambuc 	free(sn);
1833ebfedea0SLionel Sambuc     }
1834ebfedea0SLionel Sambuc  out:
1835ebfedea0SLionel Sambuc 
1836ebfedea0SLionel Sambuc     return ret;
1837ebfedea0SLionel Sambuc }
1838ebfedea0SLionel Sambuc 
1839ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_pk_load_id(krb5_context context,struct krb5_pk_identity ** ret_id,const char * user_id,const char * anchor_id,char * const * chain_list,char * const * revoke_list,krb5_prompter_fct prompter,void * prompter_data,char * password)1840ebfedea0SLionel Sambuc _krb5_pk_load_id(krb5_context context,
1841ebfedea0SLionel Sambuc 		 struct krb5_pk_identity **ret_id,
1842ebfedea0SLionel Sambuc 		 const char *user_id,
1843ebfedea0SLionel Sambuc 		 const char *anchor_id,
1844ebfedea0SLionel Sambuc 		 char * const *chain_list,
1845ebfedea0SLionel Sambuc 		 char * const *revoke_list,
1846ebfedea0SLionel Sambuc 		 krb5_prompter_fct prompter,
1847ebfedea0SLionel Sambuc 		 void *prompter_data,
1848ebfedea0SLionel Sambuc 		 char *password)
1849ebfedea0SLionel Sambuc {
1850ebfedea0SLionel Sambuc     struct krb5_pk_identity *id = NULL;
1851ebfedea0SLionel Sambuc     struct prompter p;
1852ebfedea0SLionel Sambuc     int ret;
1853ebfedea0SLionel Sambuc 
1854ebfedea0SLionel Sambuc     *ret_id = NULL;
1855ebfedea0SLionel Sambuc 
1856ebfedea0SLionel Sambuc     if (anchor_id == NULL) {
1857ebfedea0SLionel Sambuc 	krb5_set_error_message(context, HEIM_PKINIT_NO_VALID_CA,
1858ebfedea0SLionel Sambuc 			       N_("PKINIT: No anchor given", ""));
1859ebfedea0SLionel Sambuc 	return HEIM_PKINIT_NO_VALID_CA;
1860ebfedea0SLionel Sambuc     }
1861ebfedea0SLionel Sambuc 
1862ebfedea0SLionel Sambuc     /* load cert */
1863ebfedea0SLionel Sambuc 
1864ebfedea0SLionel Sambuc     id = calloc(1, sizeof(*id));
1865ebfedea0SLionel Sambuc     if (id == NULL) {
1866ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM,
1867ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
1868ebfedea0SLionel Sambuc 	return ENOMEM;
1869ebfedea0SLionel Sambuc     }
1870ebfedea0SLionel Sambuc 
1871ebfedea0SLionel Sambuc     if (user_id) {
1872ebfedea0SLionel Sambuc 	hx509_lock lock;
1873ebfedea0SLionel Sambuc 
1874ebfedea0SLionel Sambuc 	ret = hx509_lock_init(context->hx509ctx, &lock);
1875ebfedea0SLionel Sambuc 	if (ret) {
1876ebfedea0SLionel Sambuc 	    pk_copy_error(context, context->hx509ctx, ret, "Failed init lock");
1877ebfedea0SLionel Sambuc 	    goto out;
1878ebfedea0SLionel Sambuc 	}
1879ebfedea0SLionel Sambuc 
1880ebfedea0SLionel Sambuc 	if (password && password[0])
1881ebfedea0SLionel Sambuc 	    hx509_lock_add_password(lock, password);
1882ebfedea0SLionel Sambuc 
1883ebfedea0SLionel Sambuc 	if (prompter) {
1884ebfedea0SLionel Sambuc 	    p.context = context;
1885ebfedea0SLionel Sambuc 	    p.prompter = prompter;
1886ebfedea0SLionel Sambuc 	    p.prompter_data = prompter_data;
1887ebfedea0SLionel Sambuc 
1888ebfedea0SLionel Sambuc 	    ret = hx509_lock_set_prompter(lock, hx_pass_prompter, &p);
1889ebfedea0SLionel Sambuc 	    if (ret) {
1890ebfedea0SLionel Sambuc 		hx509_lock_free(lock);
1891ebfedea0SLionel Sambuc 		goto out;
1892ebfedea0SLionel Sambuc 	    }
1893ebfedea0SLionel Sambuc 	}
1894ebfedea0SLionel Sambuc 
1895ebfedea0SLionel Sambuc 	ret = hx509_certs_init(context->hx509ctx, user_id, 0, lock, &id->certs);
1896ebfedea0SLionel Sambuc         hx509_lock_free(lock);
1897ebfedea0SLionel Sambuc 	if (ret) {
1898ebfedea0SLionel Sambuc 	    pk_copy_error(context, context->hx509ctx, ret,
1899ebfedea0SLionel Sambuc 			  "Failed to init cert certs");
1900ebfedea0SLionel Sambuc 	    goto out;
1901ebfedea0SLionel Sambuc 	}
1902ebfedea0SLionel Sambuc     } else {
1903ebfedea0SLionel Sambuc 	id->certs = NULL;
1904ebfedea0SLionel Sambuc     }
1905ebfedea0SLionel Sambuc 
1906ebfedea0SLionel Sambuc     ret = hx509_certs_init(context->hx509ctx, anchor_id, 0, NULL, &id->anchors);
1907ebfedea0SLionel Sambuc     if (ret) {
1908ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
1909ebfedea0SLionel Sambuc 		      "Failed to init anchors");
1910ebfedea0SLionel Sambuc 	goto out;
1911ebfedea0SLionel Sambuc     }
1912ebfedea0SLionel Sambuc 
1913ebfedea0SLionel Sambuc     ret = hx509_certs_init(context->hx509ctx, "MEMORY:pkinit-cert-chain",
1914ebfedea0SLionel Sambuc 			   0, NULL, &id->certpool);
1915ebfedea0SLionel Sambuc     if (ret) {
1916ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
1917ebfedea0SLionel Sambuc 		      "Failed to init chain");
1918ebfedea0SLionel Sambuc 	goto out;
1919ebfedea0SLionel Sambuc     }
1920ebfedea0SLionel Sambuc 
1921ebfedea0SLionel Sambuc     while (chain_list && *chain_list) {
1922ebfedea0SLionel Sambuc 	ret = hx509_certs_append(context->hx509ctx, id->certpool,
1923ebfedea0SLionel Sambuc 				 NULL, *chain_list);
1924ebfedea0SLionel Sambuc 	if (ret) {
1925ebfedea0SLionel Sambuc 	    pk_copy_error(context, context->hx509ctx, ret,
1926ebfedea0SLionel Sambuc 			  "Failed to laod chain %s",
1927ebfedea0SLionel Sambuc 			  *chain_list);
1928ebfedea0SLionel Sambuc 	    goto out;
1929ebfedea0SLionel Sambuc 	}
1930ebfedea0SLionel Sambuc 	chain_list++;
1931ebfedea0SLionel Sambuc     }
1932ebfedea0SLionel Sambuc 
1933ebfedea0SLionel Sambuc     if (revoke_list) {
1934ebfedea0SLionel Sambuc 	ret = hx509_revoke_init(context->hx509ctx, &id->revokectx);
1935ebfedea0SLionel Sambuc 	if (ret) {
1936ebfedea0SLionel Sambuc 	    pk_copy_error(context, context->hx509ctx, ret,
1937ebfedea0SLionel Sambuc 			  "Failed init revoke list");
1938ebfedea0SLionel Sambuc 	    goto out;
1939ebfedea0SLionel Sambuc 	}
1940ebfedea0SLionel Sambuc 
1941ebfedea0SLionel Sambuc 	while (*revoke_list) {
1942ebfedea0SLionel Sambuc 	    ret = hx509_revoke_add_crl(context->hx509ctx,
1943ebfedea0SLionel Sambuc 				       id->revokectx,
1944ebfedea0SLionel Sambuc 				       *revoke_list);
1945ebfedea0SLionel Sambuc 	    if (ret) {
1946ebfedea0SLionel Sambuc 		pk_copy_error(context, context->hx509ctx, ret,
1947ebfedea0SLionel Sambuc 			      "Failed load revoke list");
1948ebfedea0SLionel Sambuc 		goto out;
1949ebfedea0SLionel Sambuc 	    }
1950ebfedea0SLionel Sambuc 	    revoke_list++;
1951ebfedea0SLionel Sambuc 	}
1952ebfedea0SLionel Sambuc     } else
1953ebfedea0SLionel Sambuc 	hx509_context_set_missing_revoke(context->hx509ctx, 1);
1954ebfedea0SLionel Sambuc 
1955ebfedea0SLionel Sambuc     ret = hx509_verify_init_ctx(context->hx509ctx, &id->verify_ctx);
1956ebfedea0SLionel Sambuc     if (ret) {
1957ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
1958ebfedea0SLionel Sambuc 		      "Failed init verify context");
1959ebfedea0SLionel Sambuc 	goto out;
1960ebfedea0SLionel Sambuc     }
1961ebfedea0SLionel Sambuc 
1962ebfedea0SLionel Sambuc     hx509_verify_attach_anchors(id->verify_ctx, id->anchors);
1963ebfedea0SLionel Sambuc     hx509_verify_attach_revoke(id->verify_ctx, id->revokectx);
1964ebfedea0SLionel Sambuc 
1965ebfedea0SLionel Sambuc  out:
1966ebfedea0SLionel Sambuc     if (ret) {
1967ebfedea0SLionel Sambuc 	hx509_verify_destroy_ctx(id->verify_ctx);
1968ebfedea0SLionel Sambuc 	hx509_certs_free(&id->certs);
1969ebfedea0SLionel Sambuc 	hx509_certs_free(&id->anchors);
1970ebfedea0SLionel Sambuc 	hx509_certs_free(&id->certpool);
1971ebfedea0SLionel Sambuc 	hx509_revoke_free(&id->revokectx);
1972ebfedea0SLionel Sambuc 	free(id);
1973ebfedea0SLionel Sambuc     } else
1974ebfedea0SLionel Sambuc 	*ret_id = id;
1975ebfedea0SLionel Sambuc 
1976ebfedea0SLionel Sambuc     return ret;
1977ebfedea0SLionel Sambuc }
1978ebfedea0SLionel Sambuc 
1979ebfedea0SLionel Sambuc /*
1980ebfedea0SLionel Sambuc  *
1981ebfedea0SLionel Sambuc  */
1982ebfedea0SLionel Sambuc 
1983ebfedea0SLionel Sambuc static void
pk_copy_error(krb5_context context,hx509_context hx509ctx,int hxret,const char * fmt,...)1984ebfedea0SLionel Sambuc pk_copy_error(krb5_context context,
1985ebfedea0SLionel Sambuc 	      hx509_context hx509ctx,
1986ebfedea0SLionel Sambuc 	      int hxret,
1987ebfedea0SLionel Sambuc 	      const char *fmt,
1988ebfedea0SLionel Sambuc 	      ...)
1989ebfedea0SLionel Sambuc {
1990ebfedea0SLionel Sambuc     va_list va;
1991ebfedea0SLionel Sambuc     char *s, *f;
1992ebfedea0SLionel Sambuc     int ret;
1993ebfedea0SLionel Sambuc 
1994ebfedea0SLionel Sambuc     va_start(va, fmt);
1995ebfedea0SLionel Sambuc     ret = vasprintf(&f, fmt, va);
1996ebfedea0SLionel Sambuc     va_end(va);
1997ebfedea0SLionel Sambuc     if (ret == -1 || f == NULL) {
1998ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
1999ebfedea0SLionel Sambuc 	return;
2000ebfedea0SLionel Sambuc     }
2001ebfedea0SLionel Sambuc 
2002ebfedea0SLionel Sambuc     s = hx509_get_error_string(hx509ctx, hxret);
2003ebfedea0SLionel Sambuc     if (s == NULL) {
2004ebfedea0SLionel Sambuc 	krb5_clear_error_message(context);
2005ebfedea0SLionel Sambuc 	free(f);
2006ebfedea0SLionel Sambuc 	return;
2007ebfedea0SLionel Sambuc     }
2008ebfedea0SLionel Sambuc     krb5_set_error_message(context, hxret, "%s: %s", f, s);
2009ebfedea0SLionel Sambuc     free(s);
2010ebfedea0SLionel Sambuc     free(f);
2011ebfedea0SLionel Sambuc }
2012ebfedea0SLionel Sambuc 
2013ebfedea0SLionel Sambuc static int
parse_integer(krb5_context context,char ** p,const char * file,int lineno,const char * name,heim_integer * integer)2014ebfedea0SLionel Sambuc parse_integer(krb5_context context, char **p, const char *file, int lineno,
2015ebfedea0SLionel Sambuc 	      const char *name, heim_integer *integer)
2016ebfedea0SLionel Sambuc {
2017ebfedea0SLionel Sambuc     int ret;
2018ebfedea0SLionel Sambuc     char *p1;
2019ebfedea0SLionel Sambuc     p1 = strsep(p, " \t");
2020ebfedea0SLionel Sambuc     if (p1 == NULL) {
2021ebfedea0SLionel Sambuc 	krb5_set_error_message(context, EINVAL,
2022ebfedea0SLionel Sambuc 			       N_("moduli file %s missing %s on line %d", ""),
2023ebfedea0SLionel Sambuc 			       file, name, lineno);
2024ebfedea0SLionel Sambuc 	return EINVAL;
2025ebfedea0SLionel Sambuc     }
2026ebfedea0SLionel Sambuc     ret = der_parse_hex_heim_integer(p1, integer);
2027ebfedea0SLionel Sambuc     if (ret) {
2028ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
2029ebfedea0SLionel Sambuc 			       N_("moduli file %s failed parsing %s "
2030ebfedea0SLionel Sambuc 				  "on line %d", ""),
2031ebfedea0SLionel Sambuc 			       file, name, lineno);
2032ebfedea0SLionel Sambuc 	return ret;
2033ebfedea0SLionel Sambuc     }
2034ebfedea0SLionel Sambuc 
2035ebfedea0SLionel Sambuc     return 0;
2036ebfedea0SLionel Sambuc }
2037ebfedea0SLionel Sambuc 
2038ebfedea0SLionel Sambuc krb5_error_code
_krb5_parse_moduli_line(krb5_context context,const char * file,int lineno,char * p,struct krb5_dh_moduli ** m)2039ebfedea0SLionel Sambuc _krb5_parse_moduli_line(krb5_context context,
2040ebfedea0SLionel Sambuc 			const char *file,
2041ebfedea0SLionel Sambuc 			int lineno,
2042ebfedea0SLionel Sambuc 			char *p,
2043ebfedea0SLionel Sambuc 			struct krb5_dh_moduli **m)
2044ebfedea0SLionel Sambuc {
2045ebfedea0SLionel Sambuc     struct krb5_dh_moduli *m1;
2046ebfedea0SLionel Sambuc     char *p1;
2047ebfedea0SLionel Sambuc     int ret;
2048ebfedea0SLionel Sambuc 
2049ebfedea0SLionel Sambuc     *m = NULL;
2050ebfedea0SLionel Sambuc 
2051ebfedea0SLionel Sambuc     m1 = calloc(1, sizeof(*m1));
2052ebfedea0SLionel Sambuc     if (m1 == NULL) {
2053ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM,
2054ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
2055ebfedea0SLionel Sambuc 	return ENOMEM;
2056ebfedea0SLionel Sambuc     }
2057ebfedea0SLionel Sambuc 
2058ebfedea0SLionel Sambuc     while (isspace((unsigned char)*p))
2059ebfedea0SLionel Sambuc 	p++;
2060ebfedea0SLionel Sambuc     if (*p  == '#') {
2061ebfedea0SLionel Sambuc         free(m1);
2062ebfedea0SLionel Sambuc 	return 0;
2063ebfedea0SLionel Sambuc     }
2064ebfedea0SLionel Sambuc     ret = EINVAL;
2065ebfedea0SLionel Sambuc 
2066ebfedea0SLionel Sambuc     p1 = strsep(&p, " \t");
2067ebfedea0SLionel Sambuc     if (p1 == NULL) {
2068ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
2069ebfedea0SLionel Sambuc 			       N_("moduli file %s missing name on line %d", ""),
2070ebfedea0SLionel Sambuc 			       file, lineno);
2071ebfedea0SLionel Sambuc 	goto out;
2072ebfedea0SLionel Sambuc     }
2073ebfedea0SLionel Sambuc     m1->name = strdup(p1);
2074ebfedea0SLionel Sambuc     if (m1->name == NULL) {
2075ebfedea0SLionel Sambuc 	ret = ENOMEM;
2076ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret, N_("malloc: out of memeory", ""));
2077ebfedea0SLionel Sambuc 	goto out;
2078ebfedea0SLionel Sambuc     }
2079ebfedea0SLionel Sambuc 
2080ebfedea0SLionel Sambuc     p1 = strsep(&p, " \t");
2081ebfedea0SLionel Sambuc     if (p1 == NULL) {
2082ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
2083ebfedea0SLionel Sambuc 			       N_("moduli file %s missing bits on line %d", ""),
2084ebfedea0SLionel Sambuc 			       file, lineno);
2085ebfedea0SLionel Sambuc 	goto out;
2086ebfedea0SLionel Sambuc     }
2087ebfedea0SLionel Sambuc 
2088ebfedea0SLionel Sambuc     m1->bits = atoi(p1);
2089ebfedea0SLionel Sambuc     if (m1->bits == 0) {
2090ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret,
2091ebfedea0SLionel Sambuc 			       N_("moduli file %s have un-parsable "
2092ebfedea0SLionel Sambuc 				  "bits on line %d", ""), file, lineno);
2093ebfedea0SLionel Sambuc 	goto out;
2094ebfedea0SLionel Sambuc     }
2095ebfedea0SLionel Sambuc 
2096ebfedea0SLionel Sambuc     ret = parse_integer(context, &p, file, lineno, "p", &m1->p);
2097ebfedea0SLionel Sambuc     if (ret)
2098ebfedea0SLionel Sambuc 	goto out;
2099ebfedea0SLionel Sambuc     ret = parse_integer(context, &p, file, lineno, "g", &m1->g);
2100ebfedea0SLionel Sambuc     if (ret)
2101ebfedea0SLionel Sambuc 	goto out;
2102ebfedea0SLionel Sambuc     ret = parse_integer(context, &p, file, lineno, "q", &m1->q);
2103ebfedea0SLionel Sambuc     if (ret)
2104ebfedea0SLionel Sambuc 	goto out;
2105ebfedea0SLionel Sambuc 
2106ebfedea0SLionel Sambuc     *m = m1;
2107ebfedea0SLionel Sambuc 
2108ebfedea0SLionel Sambuc     return 0;
2109ebfedea0SLionel Sambuc  out:
2110ebfedea0SLionel Sambuc     free(m1->name);
2111ebfedea0SLionel Sambuc     der_free_heim_integer(&m1->p);
2112ebfedea0SLionel Sambuc     der_free_heim_integer(&m1->g);
2113ebfedea0SLionel Sambuc     der_free_heim_integer(&m1->q);
2114ebfedea0SLionel Sambuc     free(m1);
2115ebfedea0SLionel Sambuc     return ret;
2116ebfedea0SLionel Sambuc }
2117ebfedea0SLionel Sambuc 
2118ebfedea0SLionel Sambuc void
_krb5_free_moduli(struct krb5_dh_moduli ** moduli)2119ebfedea0SLionel Sambuc _krb5_free_moduli(struct krb5_dh_moduli **moduli)
2120ebfedea0SLionel Sambuc {
2121ebfedea0SLionel Sambuc     int i;
2122ebfedea0SLionel Sambuc     for (i = 0; moduli[i] != NULL; i++) {
2123ebfedea0SLionel Sambuc 	free(moduli[i]->name);
2124ebfedea0SLionel Sambuc 	der_free_heim_integer(&moduli[i]->p);
2125ebfedea0SLionel Sambuc 	der_free_heim_integer(&moduli[i]->g);
2126ebfedea0SLionel Sambuc 	der_free_heim_integer(&moduli[i]->q);
2127ebfedea0SLionel Sambuc 	free(moduli[i]);
2128ebfedea0SLionel Sambuc     }
2129ebfedea0SLionel Sambuc     free(moduli);
2130ebfedea0SLionel Sambuc }
2131ebfedea0SLionel Sambuc 
2132ebfedea0SLionel Sambuc static const char *default_moduli_RFC2412_MODP_group2 =
2133ebfedea0SLionel Sambuc     /* name */
2134ebfedea0SLionel Sambuc     "RFC2412-MODP-group2 "
2135ebfedea0SLionel Sambuc     /* bits */
2136ebfedea0SLionel Sambuc     "1024 "
2137ebfedea0SLionel Sambuc     /* p */
2138ebfedea0SLionel Sambuc     "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2139ebfedea0SLionel Sambuc     "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2140ebfedea0SLionel Sambuc     "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2141ebfedea0SLionel Sambuc     "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2142ebfedea0SLionel Sambuc     "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
2143ebfedea0SLionel Sambuc     "FFFFFFFF" "FFFFFFFF "
2144ebfedea0SLionel Sambuc     /* g */
2145ebfedea0SLionel Sambuc     "02 "
2146ebfedea0SLionel Sambuc     /* q */
2147ebfedea0SLionel Sambuc     "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2148ebfedea0SLionel Sambuc     "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2149ebfedea0SLionel Sambuc     "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2150ebfedea0SLionel Sambuc     "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2151ebfedea0SLionel Sambuc     "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
2152ebfedea0SLionel Sambuc     "FFFFFFFF" "FFFFFFFF";
2153ebfedea0SLionel Sambuc 
2154ebfedea0SLionel Sambuc static const char *default_moduli_rfc3526_MODP_group14 =
2155ebfedea0SLionel Sambuc     /* name */
2156ebfedea0SLionel Sambuc     "rfc3526-MODP-group14 "
2157ebfedea0SLionel Sambuc     /* bits */
2158ebfedea0SLionel Sambuc     "1760 "
2159ebfedea0SLionel Sambuc     /* p */
2160ebfedea0SLionel Sambuc     "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2161ebfedea0SLionel Sambuc     "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2162ebfedea0SLionel Sambuc     "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2163ebfedea0SLionel Sambuc     "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2164ebfedea0SLionel Sambuc     "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
2165ebfedea0SLionel Sambuc     "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
2166ebfedea0SLionel Sambuc     "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
2167ebfedea0SLionel Sambuc     "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
2168ebfedea0SLionel Sambuc     "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
2169ebfedea0SLionel Sambuc     "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
2170ebfedea0SLionel Sambuc     "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
2171ebfedea0SLionel Sambuc     /* g */
2172ebfedea0SLionel Sambuc     "02 "
2173ebfedea0SLionel Sambuc     /* q */
2174ebfedea0SLionel Sambuc     "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2175ebfedea0SLionel Sambuc     "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2176ebfedea0SLionel Sambuc     "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2177ebfedea0SLionel Sambuc     "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2178ebfedea0SLionel Sambuc     "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
2179ebfedea0SLionel Sambuc     "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
2180ebfedea0SLionel Sambuc     "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
2181ebfedea0SLionel Sambuc     "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
2182ebfedea0SLionel Sambuc     "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
2183ebfedea0SLionel Sambuc     "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
2184ebfedea0SLionel Sambuc     "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
2185ebfedea0SLionel Sambuc 
2186ebfedea0SLionel Sambuc krb5_error_code
_krb5_parse_moduli(krb5_context context,const char * file,struct krb5_dh_moduli *** moduli)2187ebfedea0SLionel Sambuc _krb5_parse_moduli(krb5_context context, const char *file,
2188ebfedea0SLionel Sambuc 		   struct krb5_dh_moduli ***moduli)
2189ebfedea0SLionel Sambuc {
2190ebfedea0SLionel Sambuc     /* name bits P G Q */
2191ebfedea0SLionel Sambuc     krb5_error_code ret;
2192ebfedea0SLionel Sambuc     struct krb5_dh_moduli **m = NULL, **m2;
2193ebfedea0SLionel Sambuc     char buf[4096];
2194ebfedea0SLionel Sambuc     FILE *f;
2195ebfedea0SLionel Sambuc     int lineno = 0, n = 0;
2196ebfedea0SLionel Sambuc 
2197ebfedea0SLionel Sambuc     *moduli = NULL;
2198ebfedea0SLionel Sambuc 
2199ebfedea0SLionel Sambuc     m = calloc(1, sizeof(m[0]) * 3);
2200ebfedea0SLionel Sambuc     if (m == NULL) {
2201ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM,
2202ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
2203ebfedea0SLionel Sambuc 	return ENOMEM;
2204ebfedea0SLionel Sambuc     }
2205ebfedea0SLionel Sambuc 
2206ebfedea0SLionel Sambuc     strlcpy(buf, default_moduli_rfc3526_MODP_group14, sizeof(buf));
2207ebfedea0SLionel Sambuc     ret = _krb5_parse_moduli_line(context, "builtin", 1, buf,  &m[0]);
2208ebfedea0SLionel Sambuc     if (ret) {
2209ebfedea0SLionel Sambuc 	_krb5_free_moduli(m);
2210ebfedea0SLionel Sambuc 	return ret;
2211ebfedea0SLionel Sambuc     }
2212ebfedea0SLionel Sambuc     n++;
2213ebfedea0SLionel Sambuc 
2214ebfedea0SLionel Sambuc     strlcpy(buf, default_moduli_RFC2412_MODP_group2, sizeof(buf));
2215ebfedea0SLionel Sambuc     ret = _krb5_parse_moduli_line(context, "builtin", 1, buf,  &m[1]);
2216ebfedea0SLionel Sambuc     if (ret) {
2217ebfedea0SLionel Sambuc 	_krb5_free_moduli(m);
2218ebfedea0SLionel Sambuc 	return ret;
2219ebfedea0SLionel Sambuc     }
2220ebfedea0SLionel Sambuc     n++;
2221ebfedea0SLionel Sambuc 
2222ebfedea0SLionel Sambuc 
2223ebfedea0SLionel Sambuc     if (file == NULL)
2224ebfedea0SLionel Sambuc 	file = MODULI_FILE;
2225ebfedea0SLionel Sambuc 
2226ebfedea0SLionel Sambuc #ifdef KRB5_USE_PATH_TOKENS
2227ebfedea0SLionel Sambuc     {
2228ebfedea0SLionel Sambuc         char * exp_file;
2229ebfedea0SLionel Sambuc 
2230ebfedea0SLionel Sambuc         if (_krb5_expand_path_tokens(context, file, &exp_file) == 0) {
2231ebfedea0SLionel Sambuc             f = fopen(exp_file, "r");
2232ebfedea0SLionel Sambuc             krb5_xfree(exp_file);
2233ebfedea0SLionel Sambuc         } else {
2234ebfedea0SLionel Sambuc             f = NULL;
2235ebfedea0SLionel Sambuc         }
2236ebfedea0SLionel Sambuc     }
2237ebfedea0SLionel Sambuc #else
2238ebfedea0SLionel Sambuc     f = fopen(file, "r");
2239ebfedea0SLionel Sambuc #endif
2240ebfedea0SLionel Sambuc 
2241ebfedea0SLionel Sambuc     if (f == NULL) {
2242ebfedea0SLionel Sambuc 	*moduli = m;
2243ebfedea0SLionel Sambuc 	return 0;
2244ebfedea0SLionel Sambuc     }
2245ebfedea0SLionel Sambuc     rk_cloexec_file(f);
2246ebfedea0SLionel Sambuc 
2247ebfedea0SLionel Sambuc     while(fgets(buf, sizeof(buf), f) != NULL) {
2248ebfedea0SLionel Sambuc 	struct krb5_dh_moduli *element;
2249ebfedea0SLionel Sambuc 
2250ebfedea0SLionel Sambuc 	buf[strcspn(buf, "\n")] = '\0';
2251ebfedea0SLionel Sambuc 	lineno++;
2252ebfedea0SLionel Sambuc 
2253ebfedea0SLionel Sambuc 	m2 = realloc(m, (n + 2) * sizeof(m[0]));
2254ebfedea0SLionel Sambuc 	if (m2 == NULL) {
2255ebfedea0SLionel Sambuc 	    _krb5_free_moduli(m);
2256ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, ENOMEM,
2257ebfedea0SLionel Sambuc 				   N_("malloc: out of memory", ""));
2258ebfedea0SLionel Sambuc 	    return ENOMEM;
2259ebfedea0SLionel Sambuc 	}
2260ebfedea0SLionel Sambuc 	m = m2;
2261ebfedea0SLionel Sambuc 
2262ebfedea0SLionel Sambuc 	m[n] = NULL;
2263ebfedea0SLionel Sambuc 
2264ebfedea0SLionel Sambuc 	ret = _krb5_parse_moduli_line(context, file, lineno, buf,  &element);
2265ebfedea0SLionel Sambuc 	if (ret) {
2266ebfedea0SLionel Sambuc 	    _krb5_free_moduli(m);
2267ebfedea0SLionel Sambuc 	    return ret;
2268ebfedea0SLionel Sambuc 	}
2269ebfedea0SLionel Sambuc 	if (element == NULL)
2270ebfedea0SLionel Sambuc 	    continue;
2271ebfedea0SLionel Sambuc 
2272ebfedea0SLionel Sambuc 	m[n] = element;
2273ebfedea0SLionel Sambuc 	m[n + 1] = NULL;
2274ebfedea0SLionel Sambuc 	n++;
2275ebfedea0SLionel Sambuc     }
2276ebfedea0SLionel Sambuc     *moduli = m;
2277ebfedea0SLionel Sambuc     return 0;
2278ebfedea0SLionel Sambuc }
2279ebfedea0SLionel Sambuc 
2280ebfedea0SLionel Sambuc krb5_error_code
_krb5_dh_group_ok(krb5_context context,unsigned long bits,heim_integer * p,heim_integer * g,heim_integer * q,struct krb5_dh_moduli ** moduli,char ** name)2281ebfedea0SLionel Sambuc _krb5_dh_group_ok(krb5_context context, unsigned long bits,
2282ebfedea0SLionel Sambuc 		  heim_integer *p, heim_integer *g, heim_integer *q,
2283ebfedea0SLionel Sambuc 		  struct krb5_dh_moduli **moduli,
2284ebfedea0SLionel Sambuc 		  char **name)
2285ebfedea0SLionel Sambuc {
2286ebfedea0SLionel Sambuc     int i;
2287ebfedea0SLionel Sambuc 
2288ebfedea0SLionel Sambuc     if (name)
2289ebfedea0SLionel Sambuc 	*name = NULL;
2290ebfedea0SLionel Sambuc 
2291ebfedea0SLionel Sambuc     for (i = 0; moduli[i] != NULL; i++) {
2292ebfedea0SLionel Sambuc 	if (der_heim_integer_cmp(&moduli[i]->g, g) == 0 &&
2293ebfedea0SLionel Sambuc 	    der_heim_integer_cmp(&moduli[i]->p, p) == 0 &&
2294ebfedea0SLionel Sambuc 	    (q == NULL || der_heim_integer_cmp(&moduli[i]->q, q) == 0))
2295ebfedea0SLionel Sambuc 	    {
2296ebfedea0SLionel Sambuc 		if (bits && bits > moduli[i]->bits) {
2297ebfedea0SLionel Sambuc 		    krb5_set_error_message(context,
2298ebfedea0SLionel Sambuc 					   KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
2299ebfedea0SLionel Sambuc 					   N_("PKINIT: DH group parameter %s "
2300ebfedea0SLionel Sambuc 					      "no accepted, not enough bits "
2301ebfedea0SLionel Sambuc 					      "generated", ""),
2302ebfedea0SLionel Sambuc 					   moduli[i]->name);
2303ebfedea0SLionel Sambuc 		    return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2304ebfedea0SLionel Sambuc 		}
2305ebfedea0SLionel Sambuc 		if (name)
2306ebfedea0SLionel Sambuc 		    *name = strdup(moduli[i]->name);
2307ebfedea0SLionel Sambuc 		return 0;
2308ebfedea0SLionel Sambuc 	    }
2309ebfedea0SLionel Sambuc     }
2310ebfedea0SLionel Sambuc     krb5_set_error_message(context,
2311ebfedea0SLionel Sambuc 			   KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
2312ebfedea0SLionel Sambuc 			   N_("PKINIT: DH group parameter no ok", ""));
2313ebfedea0SLionel Sambuc     return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2314ebfedea0SLionel Sambuc }
2315ebfedea0SLionel Sambuc #endif /* PKINIT */
2316ebfedea0SLionel Sambuc 
2317ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION void KRB5_LIB_CALL
_krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt * opt)2318ebfedea0SLionel Sambuc _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt)
2319ebfedea0SLionel Sambuc {
2320ebfedea0SLionel Sambuc #ifdef PKINIT
2321ebfedea0SLionel Sambuc     krb5_pk_init_ctx ctx;
2322ebfedea0SLionel Sambuc 
2323ebfedea0SLionel Sambuc     if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL)
2324ebfedea0SLionel Sambuc 	return;
2325ebfedea0SLionel Sambuc     ctx = opt->opt_private->pk_init_ctx;
2326ebfedea0SLionel Sambuc     switch (ctx->keyex) {
2327ebfedea0SLionel Sambuc     case USE_DH:
2328ebfedea0SLionel Sambuc 	if (ctx->u.dh)
2329ebfedea0SLionel Sambuc 	    DH_free(ctx->u.dh);
2330ebfedea0SLionel Sambuc 	break;
2331ebfedea0SLionel Sambuc     case USE_RSA:
2332ebfedea0SLionel Sambuc 	break;
2333ebfedea0SLionel Sambuc     case USE_ECDH:
2334ebfedea0SLionel Sambuc #ifdef HAVE_OPENSSL
2335ebfedea0SLionel Sambuc 	if (ctx->u.eckey)
2336ebfedea0SLionel Sambuc 	    EC_KEY_free(ctx->u.eckey);
2337ebfedea0SLionel Sambuc #endif
2338ebfedea0SLionel Sambuc 	break;
2339ebfedea0SLionel Sambuc     }
2340ebfedea0SLionel Sambuc     if (ctx->id) {
2341ebfedea0SLionel Sambuc 	hx509_verify_destroy_ctx(ctx->id->verify_ctx);
2342ebfedea0SLionel Sambuc 	hx509_certs_free(&ctx->id->certs);
2343ebfedea0SLionel Sambuc 	hx509_cert_free(ctx->id->cert);
2344ebfedea0SLionel Sambuc 	hx509_certs_free(&ctx->id->anchors);
2345ebfedea0SLionel Sambuc 	hx509_certs_free(&ctx->id->certpool);
2346ebfedea0SLionel Sambuc 
2347ebfedea0SLionel Sambuc 	if (ctx->clientDHNonce) {
2348ebfedea0SLionel Sambuc 	    krb5_free_data(NULL, ctx->clientDHNonce);
2349ebfedea0SLionel Sambuc 	    ctx->clientDHNonce = NULL;
2350ebfedea0SLionel Sambuc 	}
2351ebfedea0SLionel Sambuc 	if (ctx->m)
2352ebfedea0SLionel Sambuc 	    _krb5_free_moduli(ctx->m);
2353ebfedea0SLionel Sambuc 	free(ctx->id);
2354ebfedea0SLionel Sambuc 	ctx->id = NULL;
2355ebfedea0SLionel Sambuc     }
2356ebfedea0SLionel Sambuc     free(opt->opt_private->pk_init_ctx);
2357ebfedea0SLionel Sambuc     opt->opt_private->pk_init_ctx = NULL;
2358ebfedea0SLionel Sambuc #endif
2359ebfedea0SLionel Sambuc }
2360ebfedea0SLionel Sambuc 
2361ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_init_creds_opt_set_pkinit(krb5_context context,krb5_get_init_creds_opt * opt,krb5_principal principal,const char * user_id,const char * x509_anchors,char * const * pool,char * const * pki_revoke,int flags,krb5_prompter_fct prompter,void * prompter_data,char * password)2362ebfedea0SLionel Sambuc krb5_get_init_creds_opt_set_pkinit(krb5_context context,
2363ebfedea0SLionel Sambuc 				   krb5_get_init_creds_opt *opt,
2364ebfedea0SLionel Sambuc 				   krb5_principal principal,
2365ebfedea0SLionel Sambuc 				   const char *user_id,
2366ebfedea0SLionel Sambuc 				   const char *x509_anchors,
2367ebfedea0SLionel Sambuc 				   char * const * pool,
2368ebfedea0SLionel Sambuc 				   char * const * pki_revoke,
2369ebfedea0SLionel Sambuc 				   int flags,
2370ebfedea0SLionel Sambuc 				   krb5_prompter_fct prompter,
2371ebfedea0SLionel Sambuc 				   void *prompter_data,
2372ebfedea0SLionel Sambuc 				   char *password)
2373ebfedea0SLionel Sambuc {
2374ebfedea0SLionel Sambuc #ifdef PKINIT
2375ebfedea0SLionel Sambuc     krb5_error_code ret;
2376ebfedea0SLionel Sambuc     char *anchors = NULL;
2377ebfedea0SLionel Sambuc 
2378ebfedea0SLionel Sambuc     if (opt->opt_private == NULL) {
2379ebfedea0SLionel Sambuc 	krb5_set_error_message(context, EINVAL,
2380ebfedea0SLionel Sambuc 			       N_("PKINIT: on non extendable opt", ""));
2381ebfedea0SLionel Sambuc 	return EINVAL;
2382ebfedea0SLionel Sambuc     }
2383ebfedea0SLionel Sambuc 
2384ebfedea0SLionel Sambuc     opt->opt_private->pk_init_ctx =
2385ebfedea0SLionel Sambuc 	calloc(1, sizeof(*opt->opt_private->pk_init_ctx));
2386ebfedea0SLionel Sambuc     if (opt->opt_private->pk_init_ctx == NULL) {
2387ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM,
2388ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
2389ebfedea0SLionel Sambuc 	return ENOMEM;
2390ebfedea0SLionel Sambuc     }
2391ebfedea0SLionel Sambuc     opt->opt_private->pk_init_ctx->require_binding = 0;
2392ebfedea0SLionel Sambuc     opt->opt_private->pk_init_ctx->require_eku = 1;
2393ebfedea0SLionel Sambuc     opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1;
2394ebfedea0SLionel Sambuc     opt->opt_private->pk_init_ctx->peer = NULL;
2395ebfedea0SLionel Sambuc 
2396ebfedea0SLionel Sambuc     /* XXX implement krb5_appdefault_strings  */
2397ebfedea0SLionel Sambuc     if (pool == NULL)
2398ebfedea0SLionel Sambuc 	pool = krb5_config_get_strings(context, NULL,
2399ebfedea0SLionel Sambuc 				       "appdefaults",
2400ebfedea0SLionel Sambuc 				       "pkinit_pool",
2401ebfedea0SLionel Sambuc 				       NULL);
2402ebfedea0SLionel Sambuc 
2403ebfedea0SLionel Sambuc     if (pki_revoke == NULL)
2404ebfedea0SLionel Sambuc 	pki_revoke = krb5_config_get_strings(context, NULL,
2405ebfedea0SLionel Sambuc 					     "appdefaults",
2406ebfedea0SLionel Sambuc 					     "pkinit_revoke",
2407ebfedea0SLionel Sambuc 					     NULL);
2408ebfedea0SLionel Sambuc 
2409ebfedea0SLionel Sambuc     if (x509_anchors == NULL) {
2410ebfedea0SLionel Sambuc 	krb5_appdefault_string(context, "kinit",
2411ebfedea0SLionel Sambuc 			       krb5_principal_get_realm(context, principal),
2412ebfedea0SLionel Sambuc 			       "pkinit_anchors", NULL, &anchors);
2413ebfedea0SLionel Sambuc 	x509_anchors = anchors;
2414ebfedea0SLionel Sambuc     }
2415ebfedea0SLionel Sambuc 
2416ebfedea0SLionel Sambuc     if (flags & 4)
2417ebfedea0SLionel Sambuc 	opt->opt_private->pk_init_ctx->anonymous = 1;
2418ebfedea0SLionel Sambuc 
2419ebfedea0SLionel Sambuc     ret = _krb5_pk_load_id(context,
2420ebfedea0SLionel Sambuc 			   &opt->opt_private->pk_init_ctx->id,
2421ebfedea0SLionel Sambuc 			   user_id,
2422ebfedea0SLionel Sambuc 			   x509_anchors,
2423ebfedea0SLionel Sambuc 			   pool,
2424ebfedea0SLionel Sambuc 			   pki_revoke,
2425ebfedea0SLionel Sambuc 			   prompter,
2426ebfedea0SLionel Sambuc 			   prompter_data,
2427ebfedea0SLionel Sambuc 			   password);
2428ebfedea0SLionel Sambuc     if (ret) {
2429ebfedea0SLionel Sambuc 	free(opt->opt_private->pk_init_ctx);
2430ebfedea0SLionel Sambuc 	opt->opt_private->pk_init_ctx = NULL;
2431ebfedea0SLionel Sambuc 	return ret;
2432ebfedea0SLionel Sambuc     }
2433ebfedea0SLionel Sambuc 
2434ebfedea0SLionel Sambuc     if (opt->opt_private->pk_init_ctx->id->certs) {
2435ebfedea0SLionel Sambuc 	_krb5_pk_set_user_id(context,
2436ebfedea0SLionel Sambuc 			     principal,
2437ebfedea0SLionel Sambuc 			     opt->opt_private->pk_init_ctx,
2438ebfedea0SLionel Sambuc 			     opt->opt_private->pk_init_ctx->id->certs);
2439ebfedea0SLionel Sambuc     } else
2440ebfedea0SLionel Sambuc 	opt->opt_private->pk_init_ctx->id->cert = NULL;
2441ebfedea0SLionel Sambuc 
2442ebfedea0SLionel Sambuc     if ((flags & 2) == 0) {
2443ebfedea0SLionel Sambuc 	hx509_context hx509ctx = context->hx509ctx;
2444ebfedea0SLionel Sambuc 	hx509_cert cert = opt->opt_private->pk_init_ctx->id->cert;
2445ebfedea0SLionel Sambuc 
2446ebfedea0SLionel Sambuc 	opt->opt_private->pk_init_ctx->keyex = USE_DH;
2447ebfedea0SLionel Sambuc 
2448ebfedea0SLionel Sambuc 	/*
2449ebfedea0SLionel Sambuc 	 * If its a ECDSA certs, lets select ECDSA as the keyex algorithm.
2450ebfedea0SLionel Sambuc 	 */
2451ebfedea0SLionel Sambuc 	if (cert) {
2452ebfedea0SLionel Sambuc 	    AlgorithmIdentifier alg;
2453ebfedea0SLionel Sambuc 
2454ebfedea0SLionel Sambuc 	    ret = hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx, cert, &alg);
2455ebfedea0SLionel Sambuc 	    if (ret == 0) {
2456ebfedea0SLionel Sambuc 		if (der_heim_oid_cmp(&alg.algorithm, &asn1_oid_id_ecPublicKey) == 0)
2457ebfedea0SLionel Sambuc 		    opt->opt_private->pk_init_ctx->keyex = USE_ECDH;
2458ebfedea0SLionel Sambuc 		free_AlgorithmIdentifier(&alg);
2459ebfedea0SLionel Sambuc 	    }
2460ebfedea0SLionel Sambuc 	}
2461ebfedea0SLionel Sambuc 
2462ebfedea0SLionel Sambuc     } else {
2463ebfedea0SLionel Sambuc 	opt->opt_private->pk_init_ctx->keyex = USE_RSA;
2464ebfedea0SLionel Sambuc 
2465ebfedea0SLionel Sambuc 	if (opt->opt_private->pk_init_ctx->id->certs == NULL) {
2466ebfedea0SLionel Sambuc 	    krb5_set_error_message(context, EINVAL,
2467ebfedea0SLionel Sambuc 				   N_("No anonymous pkinit support in RSA mode", ""));
2468ebfedea0SLionel Sambuc 	    return EINVAL;
2469ebfedea0SLionel Sambuc 	}
2470ebfedea0SLionel Sambuc     }
2471ebfedea0SLionel Sambuc 
2472ebfedea0SLionel Sambuc     return 0;
2473ebfedea0SLionel Sambuc #else
2474ebfedea0SLionel Sambuc     krb5_set_error_message(context, EINVAL,
2475ebfedea0SLionel Sambuc 			   N_("no support for PKINIT compiled in", ""));
2476ebfedea0SLionel Sambuc     return EINVAL;
2477ebfedea0SLionel Sambuc #endif
2478ebfedea0SLionel Sambuc }
2479ebfedea0SLionel Sambuc 
2480ebfedea0SLionel Sambuc krb5_error_code KRB5_LIB_FUNCTION
krb5_get_init_creds_opt_set_pkinit_user_certs(krb5_context context,krb5_get_init_creds_opt * opt,struct hx509_certs_data * certs)2481ebfedea0SLionel Sambuc krb5_get_init_creds_opt_set_pkinit_user_certs(krb5_context context,
2482ebfedea0SLionel Sambuc 					      krb5_get_init_creds_opt *opt,
2483ebfedea0SLionel Sambuc 					      struct hx509_certs_data *certs)
2484ebfedea0SLionel Sambuc {
2485ebfedea0SLionel Sambuc #ifdef PKINIT
2486ebfedea0SLionel Sambuc     if (opt->opt_private == NULL) {
2487ebfedea0SLionel Sambuc 	krb5_set_error_message(context, EINVAL,
2488ebfedea0SLionel Sambuc 			       N_("PKINIT: on non extendable opt", ""));
2489ebfedea0SLionel Sambuc 	return EINVAL;
2490ebfedea0SLionel Sambuc     }
2491ebfedea0SLionel Sambuc     if (opt->opt_private->pk_init_ctx == NULL) {
2492ebfedea0SLionel Sambuc 	krb5_set_error_message(context, EINVAL,
2493ebfedea0SLionel Sambuc 			       N_("PKINIT: on pkinit context", ""));
2494ebfedea0SLionel Sambuc 	return EINVAL;
2495ebfedea0SLionel Sambuc     }
2496ebfedea0SLionel Sambuc 
2497ebfedea0SLionel Sambuc     _krb5_pk_set_user_id(context, NULL, opt->opt_private->pk_init_ctx, certs);
2498ebfedea0SLionel Sambuc 
2499ebfedea0SLionel Sambuc     return 0;
2500ebfedea0SLionel Sambuc #else
2501ebfedea0SLionel Sambuc     krb5_set_error_message(context, EINVAL,
2502ebfedea0SLionel Sambuc 			   N_("no support for PKINIT compiled in", ""));
2503ebfedea0SLionel Sambuc     return EINVAL;
2504ebfedea0SLionel Sambuc #endif
2505ebfedea0SLionel Sambuc }
2506ebfedea0SLionel Sambuc 
2507ebfedea0SLionel Sambuc #ifdef PKINIT
2508ebfedea0SLionel Sambuc 
2509ebfedea0SLionel Sambuc static int
get_ms_san(hx509_context context,hx509_cert cert,char ** upn)2510ebfedea0SLionel Sambuc get_ms_san(hx509_context context, hx509_cert cert, char **upn)
2511ebfedea0SLionel Sambuc {
2512ebfedea0SLionel Sambuc     hx509_octet_string_list list;
2513ebfedea0SLionel Sambuc     int ret;
2514ebfedea0SLionel Sambuc 
2515ebfedea0SLionel Sambuc     *upn = NULL;
2516ebfedea0SLionel Sambuc 
2517ebfedea0SLionel Sambuc     ret = hx509_cert_find_subjectAltName_otherName(context,
2518ebfedea0SLionel Sambuc 						   cert,
2519ebfedea0SLionel Sambuc 						   &asn1_oid_id_pkinit_ms_san,
2520ebfedea0SLionel Sambuc 						   &list);
2521ebfedea0SLionel Sambuc     if (ret)
2522ebfedea0SLionel Sambuc 	return 0;
2523ebfedea0SLionel Sambuc 
2524ebfedea0SLionel Sambuc     if (list.len > 0 && list.val[0].length > 0)
2525ebfedea0SLionel Sambuc 	ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length,
2526ebfedea0SLionel Sambuc 				upn, NULL);
2527ebfedea0SLionel Sambuc     else
2528ebfedea0SLionel Sambuc 	ret = 1;
2529ebfedea0SLionel Sambuc     hx509_free_octet_string_list(&list);
2530ebfedea0SLionel Sambuc 
2531ebfedea0SLionel Sambuc     return ret;
2532ebfedea0SLionel Sambuc }
2533ebfedea0SLionel Sambuc 
2534ebfedea0SLionel Sambuc static int
find_ms_san(hx509_context context,hx509_cert cert,void * ctx)2535ebfedea0SLionel Sambuc find_ms_san(hx509_context context, hx509_cert cert, void *ctx)
2536ebfedea0SLionel Sambuc {
2537ebfedea0SLionel Sambuc     char *upn;
2538ebfedea0SLionel Sambuc     int ret;
2539ebfedea0SLionel Sambuc 
2540ebfedea0SLionel Sambuc     ret = get_ms_san(context, cert, &upn);
2541ebfedea0SLionel Sambuc     if (ret == 0)
2542ebfedea0SLionel Sambuc 	free(upn);
2543ebfedea0SLionel Sambuc     return ret;
2544ebfedea0SLionel Sambuc }
2545ebfedea0SLionel Sambuc 
2546ebfedea0SLionel Sambuc 
2547ebfedea0SLionel Sambuc 
2548ebfedea0SLionel Sambuc #endif
2549ebfedea0SLionel Sambuc 
2550ebfedea0SLionel Sambuc /*
2551ebfedea0SLionel Sambuc  * Private since it need to be redesigned using krb5_get_init_creds()
2552ebfedea0SLionel Sambuc  */
2553ebfedea0SLionel Sambuc 
2554ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code  KRB5_LIB_CALL
krb5_pk_enterprise_cert(krb5_context context,const char * user_id,krb5_const_realm realm,krb5_principal * principal,struct hx509_certs_data ** res)2555ebfedea0SLionel Sambuc krb5_pk_enterprise_cert(krb5_context context,
2556ebfedea0SLionel Sambuc 			const char *user_id,
2557ebfedea0SLionel Sambuc 			krb5_const_realm realm,
2558ebfedea0SLionel Sambuc 			krb5_principal *principal,
2559ebfedea0SLionel Sambuc 			struct hx509_certs_data **res)
2560ebfedea0SLionel Sambuc {
2561ebfedea0SLionel Sambuc #ifdef PKINIT
2562ebfedea0SLionel Sambuc     krb5_error_code ret;
2563ebfedea0SLionel Sambuc     hx509_certs certs, result;
2564*0a6a1f1dSLionel Sambuc     hx509_cert cert = NULL;
2565ebfedea0SLionel Sambuc     hx509_query *q;
2566ebfedea0SLionel Sambuc     char *name;
2567ebfedea0SLionel Sambuc 
2568ebfedea0SLionel Sambuc     *principal = NULL;
2569ebfedea0SLionel Sambuc     if (res)
2570ebfedea0SLionel Sambuc 	*res = NULL;
2571ebfedea0SLionel Sambuc 
2572ebfedea0SLionel Sambuc     if (user_id == NULL) {
2573ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOENT, "no user id");
2574ebfedea0SLionel Sambuc 	return ENOENT;
2575ebfedea0SLionel Sambuc     }
2576ebfedea0SLionel Sambuc 
2577ebfedea0SLionel Sambuc     ret = hx509_certs_init(context->hx509ctx, user_id, 0, NULL, &certs);
2578ebfedea0SLionel Sambuc     if (ret) {
2579ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
2580ebfedea0SLionel Sambuc 		      "Failed to init cert certs");
2581ebfedea0SLionel Sambuc 	goto out;
2582ebfedea0SLionel Sambuc     }
2583ebfedea0SLionel Sambuc 
2584ebfedea0SLionel Sambuc     ret = hx509_query_alloc(context->hx509ctx, &q);
2585ebfedea0SLionel Sambuc     if (ret) {
2586ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ret, "out of memory");
2587ebfedea0SLionel Sambuc 	hx509_certs_free(&certs);
2588ebfedea0SLionel Sambuc 	goto out;
2589ebfedea0SLionel Sambuc     }
2590ebfedea0SLionel Sambuc 
2591ebfedea0SLionel Sambuc     hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
2592ebfedea0SLionel Sambuc     hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
2593ebfedea0SLionel Sambuc     hx509_query_match_eku(q, &asn1_oid_id_pkinit_ms_eku);
2594ebfedea0SLionel Sambuc     hx509_query_match_cmp_func(q, find_ms_san, NULL);
2595ebfedea0SLionel Sambuc 
2596ebfedea0SLionel Sambuc     ret = hx509_certs_filter(context->hx509ctx, certs, q, &result);
2597ebfedea0SLionel Sambuc     hx509_query_free(context->hx509ctx, q);
2598ebfedea0SLionel Sambuc     hx509_certs_free(&certs);
2599ebfedea0SLionel Sambuc     if (ret) {
2600ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
2601ebfedea0SLionel Sambuc 		      "Failed to find PKINIT certificate");
2602ebfedea0SLionel Sambuc 	return ret;
2603ebfedea0SLionel Sambuc     }
2604ebfedea0SLionel Sambuc 
2605ebfedea0SLionel Sambuc     ret = hx509_get_one_cert(context->hx509ctx, result, &cert);
2606ebfedea0SLionel Sambuc     hx509_certs_free(&result);
2607ebfedea0SLionel Sambuc     if (ret) {
2608ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
2609ebfedea0SLionel Sambuc 		      "Failed to get one cert");
2610ebfedea0SLionel Sambuc 	goto out;
2611ebfedea0SLionel Sambuc     }
2612ebfedea0SLionel Sambuc 
2613ebfedea0SLionel Sambuc     ret = get_ms_san(context->hx509ctx, cert, &name);
2614ebfedea0SLionel Sambuc     if (ret) {
2615ebfedea0SLionel Sambuc 	pk_copy_error(context, context->hx509ctx, ret,
2616ebfedea0SLionel Sambuc 		      "Failed to get MS SAN");
2617ebfedea0SLionel Sambuc 	goto out;
2618ebfedea0SLionel Sambuc     }
2619ebfedea0SLionel Sambuc 
2620ebfedea0SLionel Sambuc     ret = krb5_make_principal(context, principal, realm, name, NULL);
2621ebfedea0SLionel Sambuc     free(name);
2622ebfedea0SLionel Sambuc     if (ret)
2623ebfedea0SLionel Sambuc 	goto out;
2624ebfedea0SLionel Sambuc 
2625ebfedea0SLionel Sambuc     krb5_principal_set_type(context, *principal, KRB5_NT_ENTERPRISE_PRINCIPAL);
2626ebfedea0SLionel Sambuc 
2627ebfedea0SLionel Sambuc     if (res) {
2628ebfedea0SLionel Sambuc 	ret = hx509_certs_init(context->hx509ctx, "MEMORY:", 0, NULL, res);
2629*0a6a1f1dSLionel Sambuc 	if (ret)
2630ebfedea0SLionel Sambuc 	    goto out;
2631ebfedea0SLionel Sambuc 
2632ebfedea0SLionel Sambuc 	ret = hx509_certs_add(context->hx509ctx, *res, cert);
2633ebfedea0SLionel Sambuc 	if (ret) {
2634ebfedea0SLionel Sambuc 	    hx509_certs_free(res);
2635ebfedea0SLionel Sambuc 	    goto out;
2636ebfedea0SLionel Sambuc 	}
2637ebfedea0SLionel Sambuc     }
2638ebfedea0SLionel Sambuc 
2639ebfedea0SLionel Sambuc  out:
2640ebfedea0SLionel Sambuc     hx509_cert_free(cert);
2641ebfedea0SLionel Sambuc 
2642ebfedea0SLionel Sambuc     return ret;
2643ebfedea0SLionel Sambuc #else
2644ebfedea0SLionel Sambuc     krb5_set_error_message(context, EINVAL,
2645ebfedea0SLionel Sambuc 			   N_("no support for PKINIT compiled in", ""));
2646ebfedea0SLionel Sambuc     return EINVAL;
2647ebfedea0SLionel Sambuc #endif
2648ebfedea0SLionel Sambuc }
2649