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