1c19800e8SDoug Rabson /*
2ae771770SStanislav Sedov * Copyright (c) 2003 - 2008 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 "kdc_locl.h"
37c19800e8SDoug Rabson
38c19800e8SDoug Rabson #ifdef PKINIT
39c19800e8SDoug Rabson
40c19800e8SDoug Rabson #include <heim_asn1.h>
41c19800e8SDoug Rabson #include <rfc2459_asn1.h>
42c19800e8SDoug Rabson #include <cms_asn1.h>
43c19800e8SDoug Rabson #include <pkinit_asn1.h>
44c19800e8SDoug Rabson
45c19800e8SDoug Rabson #include <hx509.h>
46c19800e8SDoug Rabson #include "crypto-headers.h"
47c19800e8SDoug Rabson
48c19800e8SDoug Rabson struct pk_client_params {
49ae771770SStanislav Sedov enum krb5_pk_type type;
50ae771770SStanislav Sedov enum { USE_RSA, USE_DH, USE_ECDH } keyex;
51ae771770SStanislav Sedov union {
52ae771770SStanislav Sedov struct {
53ae771770SStanislav Sedov BIGNUM *public_key;
54ae771770SStanislav Sedov DH *key;
55ae771770SStanislav Sedov } dh;
56ae771770SStanislav Sedov #ifdef HAVE_OPENSSL
57ae771770SStanislav Sedov struct {
58ae771770SStanislav Sedov EC_KEY *public_key;
59ae771770SStanislav Sedov EC_KEY *key;
60ae771770SStanislav Sedov } ecdh;
61ae771770SStanislav Sedov #endif
62ae771770SStanislav Sedov } u;
63c19800e8SDoug Rabson hx509_cert cert;
64c19800e8SDoug Rabson unsigned nonce;
65c19800e8SDoug Rabson EncryptionKey reply_key;
66c19800e8SDoug Rabson char *dh_group_name;
67c19800e8SDoug Rabson hx509_peer_info peer;
68c19800e8SDoug Rabson hx509_certs client_anchors;
69ae771770SStanislav Sedov hx509_verify_ctx verify_ctx;
70c19800e8SDoug Rabson };
71c19800e8SDoug Rabson
72c19800e8SDoug Rabson struct pk_principal_mapping {
73c19800e8SDoug Rabson unsigned int len;
74c19800e8SDoug Rabson struct pk_allowed_princ {
75c19800e8SDoug Rabson krb5_principal principal;
76c19800e8SDoug Rabson char *subject;
77c19800e8SDoug Rabson } *val;
78c19800e8SDoug Rabson };
79c19800e8SDoug Rabson
80c19800e8SDoug Rabson static struct krb5_pk_identity *kdc_identity;
81c19800e8SDoug Rabson static struct pk_principal_mapping principal_mappings;
82c19800e8SDoug Rabson static struct krb5_dh_moduli **moduli;
83c19800e8SDoug Rabson
84c19800e8SDoug Rabson static struct {
85c19800e8SDoug Rabson krb5_data data;
86c19800e8SDoug Rabson time_t expire;
87c19800e8SDoug Rabson time_t next_update;
88c19800e8SDoug Rabson } ocsp;
89c19800e8SDoug Rabson
90c19800e8SDoug Rabson /*
91c19800e8SDoug Rabson *
92c19800e8SDoug Rabson */
93c19800e8SDoug Rabson
94c19800e8SDoug Rabson static krb5_error_code
pk_check_pkauthenticator_win2k(krb5_context context,PKAuthenticator_Win2k * a,const KDC_REQ * req)95c19800e8SDoug Rabson pk_check_pkauthenticator_win2k(krb5_context context,
96c19800e8SDoug Rabson PKAuthenticator_Win2k *a,
97c19800e8SDoug Rabson const KDC_REQ *req)
98c19800e8SDoug Rabson {
99c19800e8SDoug Rabson krb5_timestamp now;
100c19800e8SDoug Rabson
101c19800e8SDoug Rabson krb5_timeofday (context, &now);
102c19800e8SDoug Rabson
103c19800e8SDoug Rabson /* XXX cusec */
104c19800e8SDoug Rabson if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) {
105ae771770SStanislav Sedov krb5_clear_error_message(context);
106c19800e8SDoug Rabson return KRB5KRB_AP_ERR_SKEW;
107c19800e8SDoug Rabson }
108c19800e8SDoug Rabson return 0;
109c19800e8SDoug Rabson }
110c19800e8SDoug Rabson
111c19800e8SDoug Rabson static krb5_error_code
pk_check_pkauthenticator(krb5_context context,PKAuthenticator * a,const KDC_REQ * req)112c19800e8SDoug Rabson pk_check_pkauthenticator(krb5_context context,
113c19800e8SDoug Rabson PKAuthenticator *a,
114c19800e8SDoug Rabson const KDC_REQ *req)
115c19800e8SDoug Rabson {
116c19800e8SDoug Rabson u_char *buf = NULL;
117c19800e8SDoug Rabson size_t buf_size;
118c19800e8SDoug Rabson krb5_error_code ret;
119ae771770SStanislav Sedov size_t len = 0;
120c19800e8SDoug Rabson krb5_timestamp now;
121c19800e8SDoug Rabson Checksum checksum;
122c19800e8SDoug Rabson
123c19800e8SDoug Rabson krb5_timeofday (context, &now);
124c19800e8SDoug Rabson
125c19800e8SDoug Rabson /* XXX cusec */
126c19800e8SDoug Rabson if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) {
127ae771770SStanislav Sedov krb5_clear_error_message(context);
128c19800e8SDoug Rabson return KRB5KRB_AP_ERR_SKEW;
129c19800e8SDoug Rabson }
130c19800e8SDoug Rabson
131c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, &req->req_body, &len, ret);
132c19800e8SDoug Rabson if (ret) {
133ae771770SStanislav Sedov krb5_clear_error_message(context);
134c19800e8SDoug Rabson return ret;
135c19800e8SDoug Rabson }
136c19800e8SDoug Rabson if (buf_size != len)
137c19800e8SDoug Rabson krb5_abortx(context, "Internal error in ASN.1 encoder");
138c19800e8SDoug Rabson
139c19800e8SDoug Rabson ret = krb5_create_checksum(context,
140c19800e8SDoug Rabson NULL,
141c19800e8SDoug Rabson 0,
142c19800e8SDoug Rabson CKSUMTYPE_SHA1,
143c19800e8SDoug Rabson buf,
144c19800e8SDoug Rabson len,
145c19800e8SDoug Rabson &checksum);
146c19800e8SDoug Rabson free(buf);
147c19800e8SDoug Rabson if (ret) {
148ae771770SStanislav Sedov krb5_clear_error_message(context);
149c19800e8SDoug Rabson return ret;
150c19800e8SDoug Rabson }
151c19800e8SDoug Rabson
152c19800e8SDoug Rabson if (a->paChecksum == NULL) {
153ae771770SStanislav Sedov krb5_clear_error_message(context);
154c19800e8SDoug Rabson ret = KRB5_KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
155c19800e8SDoug Rabson goto out;
156c19800e8SDoug Rabson }
157c19800e8SDoug Rabson
158c19800e8SDoug Rabson if (der_heim_octet_string_cmp(a->paChecksum, &checksum.checksum) != 0) {
159ae771770SStanislav Sedov krb5_clear_error_message(context);
160c19800e8SDoug Rabson ret = KRB5KRB_ERR_GENERIC;
161c19800e8SDoug Rabson }
162c19800e8SDoug Rabson
163c19800e8SDoug Rabson out:
164c19800e8SDoug Rabson free_Checksum(&checksum);
165c19800e8SDoug Rabson
166c19800e8SDoug Rabson return ret;
167c19800e8SDoug Rabson }
168c19800e8SDoug Rabson
169c19800e8SDoug Rabson void
_kdc_pk_free_client_param(krb5_context context,pk_client_params * cp)170ae771770SStanislav Sedov _kdc_pk_free_client_param(krb5_context context, pk_client_params *cp)
171c19800e8SDoug Rabson {
172ae771770SStanislav Sedov if (cp == NULL)
173ae771770SStanislav Sedov return;
174ae771770SStanislav Sedov if (cp->cert)
175ae771770SStanislav Sedov hx509_cert_free(cp->cert);
176ae771770SStanislav Sedov if (cp->verify_ctx)
177ae771770SStanislav Sedov hx509_verify_destroy_ctx(cp->verify_ctx);
178ae771770SStanislav Sedov if (cp->keyex == USE_DH) {
179ae771770SStanislav Sedov if (cp->u.dh.key)
180ae771770SStanislav Sedov DH_free(cp->u.dh.key);
181ae771770SStanislav Sedov if (cp->u.dh.public_key)
182ae771770SStanislav Sedov BN_free(cp->u.dh.public_key);
183ae771770SStanislav Sedov }
184ae771770SStanislav Sedov #ifdef HAVE_OPENSSL
185ae771770SStanislav Sedov if (cp->keyex == USE_ECDH) {
186ae771770SStanislav Sedov if (cp->u.ecdh.key)
187ae771770SStanislav Sedov EC_KEY_free(cp->u.ecdh.key);
188ae771770SStanislav Sedov if (cp->u.ecdh.public_key)
189ae771770SStanislav Sedov EC_KEY_free(cp->u.ecdh.public_key);
190ae771770SStanislav Sedov }
191ae771770SStanislav Sedov #endif
192ae771770SStanislav Sedov krb5_free_keyblock_contents(context, &cp->reply_key);
193ae771770SStanislav Sedov if (cp->dh_group_name)
194ae771770SStanislav Sedov free(cp->dh_group_name);
195ae771770SStanislav Sedov if (cp->peer)
196ae771770SStanislav Sedov hx509_peer_info_free(cp->peer);
197ae771770SStanislav Sedov if (cp->client_anchors)
198ae771770SStanislav Sedov hx509_certs_free(&cp->client_anchors);
199ae771770SStanislav Sedov memset(cp, 0, sizeof(*cp));
200ae771770SStanislav Sedov free(cp);
201c19800e8SDoug Rabson }
202c19800e8SDoug Rabson
203c19800e8SDoug Rabson static krb5_error_code
generate_dh_keyblock(krb5_context context,pk_client_params * client_params,krb5_enctype enctype)204ae771770SStanislav Sedov generate_dh_keyblock(krb5_context context,
205ae771770SStanislav Sedov pk_client_params *client_params,
206ae771770SStanislav Sedov krb5_enctype enctype)
207c19800e8SDoug Rabson {
208c19800e8SDoug Rabson unsigned char *dh_gen_key = NULL;
209c19800e8SDoug Rabson krb5_keyblock key;
210c19800e8SDoug Rabson krb5_error_code ret;
211c19800e8SDoug Rabson size_t dh_gen_keylen, size;
212c19800e8SDoug Rabson
213c19800e8SDoug Rabson memset(&key, 0, sizeof(key));
214c19800e8SDoug Rabson
215ae771770SStanislav Sedov if (client_params->keyex == USE_DH) {
216ae771770SStanislav Sedov
217ae771770SStanislav Sedov if (client_params->u.dh.public_key == NULL) {
218c19800e8SDoug Rabson ret = KRB5KRB_ERR_GENERIC;
219ae771770SStanislav Sedov krb5_set_error_message(context, ret, "public_key");
220c19800e8SDoug Rabson goto out;
221c19800e8SDoug Rabson }
222c19800e8SDoug Rabson
223ae771770SStanislav Sedov if (!DH_generate_key(client_params->u.dh.key)) {
224ae771770SStanislav Sedov ret = KRB5KRB_ERR_GENERIC;
225ae771770SStanislav Sedov krb5_set_error_message(context, ret,
226ae771770SStanislav Sedov "Can't generate Diffie-Hellman keys");
227ae771770SStanislav Sedov goto out;
228ae771770SStanislav Sedov }
229ae771770SStanislav Sedov
230ae771770SStanislav Sedov size = DH_size(client_params->u.dh.key);
231c19800e8SDoug Rabson
232c19800e8SDoug Rabson dh_gen_key = malloc(size);
233c19800e8SDoug Rabson if (dh_gen_key == NULL) {
234ae771770SStanislav Sedov ret = ENOMEM;
235ae771770SStanislav Sedov krb5_set_error_message(context, ret, "malloc: out of memory");
236ae771770SStanislav Sedov goto out;
237ae771770SStanislav Sedov }
238ae771770SStanislav Sedov
239ae771770SStanislav Sedov dh_gen_keylen = DH_compute_key(dh_gen_key,client_params->u.dh.public_key, client_params->u.dh.key);
240ae771770SStanislav Sedov if (dh_gen_keylen == (size_t)-1) {
241ae771770SStanislav Sedov ret = KRB5KRB_ERR_GENERIC;
242ae771770SStanislav Sedov krb5_set_error_message(context, ret,
243ae771770SStanislav Sedov "Can't compute Diffie-Hellman key");
244ae771770SStanislav Sedov goto out;
245ae771770SStanislav Sedov }
246ae771770SStanislav Sedov if (dh_gen_keylen < size) {
247ae771770SStanislav Sedov size -= dh_gen_keylen;
248ae771770SStanislav Sedov memmove(dh_gen_key + size, dh_gen_key, dh_gen_keylen);
249ae771770SStanislav Sedov memset(dh_gen_key, 0, size);
250ae771770SStanislav Sedov }
251ae771770SStanislav Sedov
252ae771770SStanislav Sedov #ifdef HAVE_OPENSSL
253ae771770SStanislav Sedov } else if (client_params->keyex == USE_ECDH) {
254ae771770SStanislav Sedov
255ae771770SStanislav Sedov if (client_params->u.ecdh.public_key == NULL) {
256ae771770SStanislav Sedov ret = KRB5KRB_ERR_GENERIC;
257ae771770SStanislav Sedov krb5_set_error_message(context, ret, "public_key");
258ae771770SStanislav Sedov goto out;
259ae771770SStanislav Sedov }
260ae771770SStanislav Sedov
261ae771770SStanislav Sedov client_params->u.ecdh.key = EC_KEY_new();
262ae771770SStanislav Sedov if (client_params->u.ecdh.key == NULL) {
263c19800e8SDoug Rabson ret = ENOMEM;
264c19800e8SDoug Rabson goto out;
265c19800e8SDoug Rabson }
266ae771770SStanislav Sedov EC_KEY_set_group(client_params->u.ecdh.key,
267ae771770SStanislav Sedov EC_KEY_get0_group(client_params->u.ecdh.public_key));
268c19800e8SDoug Rabson
269ae771770SStanislav Sedov if (EC_KEY_generate_key(client_params->u.ecdh.key) != 1) {
270ae771770SStanislav Sedov ret = ENOMEM;
271ae771770SStanislav Sedov goto out;
272ae771770SStanislav Sedov }
273ae771770SStanislav Sedov
274ae771770SStanislav Sedov size = (EC_GROUP_get_degree(EC_KEY_get0_group(client_params->u.ecdh.key)) + 7) / 8;
275ae771770SStanislav Sedov dh_gen_key = malloc(size);
276ae771770SStanislav Sedov if (dh_gen_key == NULL) {
277ae771770SStanislav Sedov ret = ENOMEM;
278ae771770SStanislav Sedov krb5_set_error_message(context, ret,
279ae771770SStanislav Sedov N_("malloc: out of memory", ""));
280ae771770SStanislav Sedov goto out;
281ae771770SStanislav Sedov }
282ae771770SStanislav Sedov
283ae771770SStanislav Sedov dh_gen_keylen = ECDH_compute_key(dh_gen_key, size,
284ae771770SStanislav Sedov EC_KEY_get0_public_key(client_params->u.ecdh.public_key),
285ae771770SStanislav Sedov client_params->u.ecdh.key, NULL);
286ae771770SStanislav Sedov
287ae771770SStanislav Sedov #endif /* HAVE_OPENSSL */
288ae771770SStanislav Sedov } else {
289c19800e8SDoug Rabson ret = KRB5KRB_ERR_GENERIC;
290ae771770SStanislav Sedov krb5_set_error_message(context, ret,
291ae771770SStanislav Sedov "Diffie-Hellman not selected keys");
292c19800e8SDoug Rabson goto out;
293c19800e8SDoug Rabson }
294c19800e8SDoug Rabson
295c19800e8SDoug Rabson ret = _krb5_pk_octetstring2key(context,
296c19800e8SDoug Rabson enctype,
297c19800e8SDoug Rabson dh_gen_key, dh_gen_keylen,
298c19800e8SDoug Rabson NULL, NULL,
299ae771770SStanislav Sedov &client_params->reply_key);
300c19800e8SDoug Rabson
301c19800e8SDoug Rabson out:
302c19800e8SDoug Rabson if (dh_gen_key)
303c19800e8SDoug Rabson free(dh_gen_key);
304c19800e8SDoug Rabson if (key.keyvalue.data)
305c19800e8SDoug Rabson krb5_free_keyblock_contents(context, &key);
306c19800e8SDoug Rabson
307c19800e8SDoug Rabson return ret;
308c19800e8SDoug Rabson }
309c19800e8SDoug Rabson
310c19800e8SDoug Rabson static BIGNUM *
integer_to_BN(krb5_context context,const char * field,heim_integer * f)311c19800e8SDoug Rabson integer_to_BN(krb5_context context, const char *field, heim_integer *f)
312c19800e8SDoug Rabson {
313c19800e8SDoug Rabson BIGNUM *bn;
314c19800e8SDoug Rabson
315c19800e8SDoug Rabson bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL);
316c19800e8SDoug Rabson if (bn == NULL) {
317ae771770SStanislav Sedov krb5_set_error_message(context, KRB5_BADMSGTYPE,
318ae771770SStanislav Sedov "PKINIT: parsing BN failed %s", field);
319c19800e8SDoug Rabson return NULL;
320c19800e8SDoug Rabson }
321c19800e8SDoug Rabson BN_set_negative(bn, f->negative);
322c19800e8SDoug Rabson return bn;
323c19800e8SDoug Rabson }
324c19800e8SDoug Rabson
325c19800e8SDoug Rabson static krb5_error_code
get_dh_param(krb5_context context,krb5_kdc_configuration * config,SubjectPublicKeyInfo * dh_key_info,pk_client_params * client_params)326c19800e8SDoug Rabson get_dh_param(krb5_context context,
327c19800e8SDoug Rabson krb5_kdc_configuration *config,
328c19800e8SDoug Rabson SubjectPublicKeyInfo *dh_key_info,
329c19800e8SDoug Rabson pk_client_params *client_params)
330c19800e8SDoug Rabson {
331c19800e8SDoug Rabson DomainParameters dhparam;
332c19800e8SDoug Rabson DH *dh = NULL;
333*e4456411SJohn Baldwin BIGNUM *p, *q, *g;
334c19800e8SDoug Rabson krb5_error_code ret;
335c19800e8SDoug Rabson
336c19800e8SDoug Rabson memset(&dhparam, 0, sizeof(dhparam));
337c19800e8SDoug Rabson
338ae771770SStanislav Sedov if ((dh_key_info->subjectPublicKey.length % 8) != 0) {
339ae771770SStanislav Sedov ret = KRB5_BADMSGTYPE;
340ae771770SStanislav Sedov krb5_set_error_message(context, ret,
341ae771770SStanislav Sedov "PKINIT: subjectPublicKey not aligned "
342ae771770SStanislav Sedov "to 8 bit boundary");
343ae771770SStanislav Sedov goto out;
344c19800e8SDoug Rabson }
345c19800e8SDoug Rabson
346c19800e8SDoug Rabson if (dh_key_info->algorithm.parameters == NULL) {
347ae771770SStanislav Sedov krb5_set_error_message(context, KRB5_BADMSGTYPE,
348ae771770SStanislav Sedov "PKINIT missing algorithm parameter "
349c19800e8SDoug Rabson "in clientPublicValue");
350c19800e8SDoug Rabson return KRB5_BADMSGTYPE;
351c19800e8SDoug Rabson }
352c19800e8SDoug Rabson
353c19800e8SDoug Rabson ret = decode_DomainParameters(dh_key_info->algorithm.parameters->data,
354c19800e8SDoug Rabson dh_key_info->algorithm.parameters->length,
355c19800e8SDoug Rabson &dhparam,
356c19800e8SDoug Rabson NULL);
357c19800e8SDoug Rabson if (ret) {
358ae771770SStanislav Sedov krb5_set_error_message(context, ret, "Can't decode algorithm "
359c19800e8SDoug Rabson "parameters in clientPublicValue");
360c19800e8SDoug Rabson goto out;
361c19800e8SDoug Rabson }
362c19800e8SDoug Rabson
363c19800e8SDoug Rabson ret = _krb5_dh_group_ok(context, config->pkinit_dh_min_bits,
364c19800e8SDoug Rabson &dhparam.p, &dhparam.g, &dhparam.q, moduli,
365c19800e8SDoug Rabson &client_params->dh_group_name);
366c19800e8SDoug Rabson if (ret) {
367c19800e8SDoug Rabson /* XXX send back proposal of better group */
368c19800e8SDoug Rabson goto out;
369c19800e8SDoug Rabson }
370c19800e8SDoug Rabson
371c19800e8SDoug Rabson dh = DH_new();
372c19800e8SDoug Rabson if (dh == NULL) {
373c19800e8SDoug Rabson ret = ENOMEM;
374ae771770SStanislav Sedov krb5_set_error_message(context, ret, "Cannot create DH structure");
375c19800e8SDoug Rabson goto out;
376c19800e8SDoug Rabson }
377c19800e8SDoug Rabson ret = KRB5_BADMSGTYPE;
378*e4456411SJohn Baldwin p = integer_to_BN(context, "DH prime", &dhparam.p);
379*e4456411SJohn Baldwin g = integer_to_BN(context, "DH base", &dhparam.g);
380*e4456411SJohn Baldwin q = integer_to_BN(context, "DH p-1 factor", &dhparam.q);
381*e4456411SJohn Baldwin if (p == NULL || g == NULL || q == NULL) {
382*e4456411SJohn Baldwin BN_free(p);
383*e4456411SJohn Baldwin BN_free(g);
384*e4456411SJohn Baldwin BN_free(q);
385c19800e8SDoug Rabson goto out;
386*e4456411SJohn Baldwin }
387*e4456411SJohn Baldwin if (DH_set0_pqg(dh, p, g, q) != 1) {
388*e4456411SJohn Baldwin BN_free(p);
389*e4456411SJohn Baldwin BN_free(g);
390*e4456411SJohn Baldwin BN_free(q);
391c19800e8SDoug Rabson goto out;
392*e4456411SJohn Baldwin }
393c19800e8SDoug Rabson
394c19800e8SDoug Rabson {
395c19800e8SDoug Rabson heim_integer glue;
396c19800e8SDoug Rabson size_t size;
397c19800e8SDoug Rabson
398c19800e8SDoug Rabson ret = decode_DHPublicKey(dh_key_info->subjectPublicKey.data,
399c19800e8SDoug Rabson dh_key_info->subjectPublicKey.length / 8,
400c19800e8SDoug Rabson &glue,
401c19800e8SDoug Rabson &size);
402c19800e8SDoug Rabson if (ret) {
403ae771770SStanislav Sedov krb5_clear_error_message(context);
404c19800e8SDoug Rabson return ret;
405c19800e8SDoug Rabson }
406c19800e8SDoug Rabson
407ae771770SStanislav Sedov client_params->u.dh.public_key = integer_to_BN(context,
408c19800e8SDoug Rabson "subjectPublicKey",
409c19800e8SDoug Rabson &glue);
410c19800e8SDoug Rabson der_free_heim_integer(&glue);
411ae771770SStanislav Sedov if (client_params->u.dh.public_key == NULL) {
412ae771770SStanislav Sedov ret = KRB5_BADMSGTYPE;
413c19800e8SDoug Rabson goto out;
414c19800e8SDoug Rabson }
415ae771770SStanislav Sedov }
416c19800e8SDoug Rabson
417ae771770SStanislav Sedov client_params->u.dh.key = dh;
418c19800e8SDoug Rabson dh = NULL;
419c19800e8SDoug Rabson ret = 0;
420c19800e8SDoug Rabson
421c19800e8SDoug Rabson out:
422c19800e8SDoug Rabson if (dh)
423c19800e8SDoug Rabson DH_free(dh);
424c19800e8SDoug Rabson free_DomainParameters(&dhparam);
425c19800e8SDoug Rabson return ret;
426c19800e8SDoug Rabson }
427c19800e8SDoug Rabson
428ae771770SStanislav Sedov #ifdef HAVE_OPENSSL
429ae771770SStanislav Sedov
430ae771770SStanislav Sedov static krb5_error_code
get_ecdh_param(krb5_context context,krb5_kdc_configuration * config,SubjectPublicKeyInfo * dh_key_info,pk_client_params * client_params)431ae771770SStanislav Sedov get_ecdh_param(krb5_context context,
432ae771770SStanislav Sedov krb5_kdc_configuration *config,
433ae771770SStanislav Sedov SubjectPublicKeyInfo *dh_key_info,
434ae771770SStanislav Sedov pk_client_params *client_params)
435ae771770SStanislav Sedov {
436ae771770SStanislav Sedov ECParameters ecp;
437ae771770SStanislav Sedov EC_KEY *public = NULL;
438ae771770SStanislav Sedov krb5_error_code ret;
439ae771770SStanislav Sedov const unsigned char *p;
440ae771770SStanislav Sedov size_t len;
441ae771770SStanislav Sedov int nid;
442ae771770SStanislav Sedov
443ae771770SStanislav Sedov if (dh_key_info->algorithm.parameters == NULL) {
444ae771770SStanislav Sedov krb5_set_error_message(context, KRB5_BADMSGTYPE,
445ae771770SStanislav Sedov "PKINIT missing algorithm parameter "
446ae771770SStanislav Sedov "in clientPublicValue");
447ae771770SStanislav Sedov return KRB5_BADMSGTYPE;
448ae771770SStanislav Sedov }
449ae771770SStanislav Sedov
450ae771770SStanislav Sedov memset(&ecp, 0, sizeof(ecp));
451ae771770SStanislav Sedov
452ae771770SStanislav Sedov ret = decode_ECParameters(dh_key_info->algorithm.parameters->data,
453ae771770SStanislav Sedov dh_key_info->algorithm.parameters->length, &ecp, &len);
454ae771770SStanislav Sedov if (ret)
455ae771770SStanislav Sedov goto out;
456ae771770SStanislav Sedov
457ae771770SStanislav Sedov if (ecp.element != choice_ECParameters_namedCurve) {
458ae771770SStanislav Sedov ret = KRB5_BADMSGTYPE;
459ae771770SStanislav Sedov goto out;
460ae771770SStanislav Sedov }
461ae771770SStanislav Sedov
462ae771770SStanislav Sedov if (der_heim_oid_cmp(&ecp.u.namedCurve, &asn1_oid_id_ec_group_secp256r1) == 0)
463ae771770SStanislav Sedov nid = NID_X9_62_prime256v1;
464ae771770SStanislav Sedov else {
465ae771770SStanislav Sedov ret = KRB5_BADMSGTYPE;
466ae771770SStanislav Sedov goto out;
467ae771770SStanislav Sedov }
468ae771770SStanislav Sedov
469ae771770SStanislav Sedov /* XXX verify group is ok */
470ae771770SStanislav Sedov
471ae771770SStanislav Sedov public = EC_KEY_new_by_curve_name(nid);
472ae771770SStanislav Sedov
473ae771770SStanislav Sedov p = dh_key_info->subjectPublicKey.data;
474ae771770SStanislav Sedov len = dh_key_info->subjectPublicKey.length / 8;
475ae771770SStanislav Sedov if (o2i_ECPublicKey(&public, &p, len) == NULL) {
476ae771770SStanislav Sedov ret = KRB5_BADMSGTYPE;
477ae771770SStanislav Sedov krb5_set_error_message(context, ret,
478ae771770SStanislav Sedov "PKINIT failed to decode ECDH key");
479ae771770SStanislav Sedov goto out;
480ae771770SStanislav Sedov }
481ae771770SStanislav Sedov client_params->u.ecdh.public_key = public;
482ae771770SStanislav Sedov public = NULL;
483ae771770SStanislav Sedov
484ae771770SStanislav Sedov out:
485ae771770SStanislav Sedov if (public)
486ae771770SStanislav Sedov EC_KEY_free(public);
487ae771770SStanislav Sedov free_ECParameters(&ecp);
488ae771770SStanislav Sedov return ret;
489ae771770SStanislav Sedov }
490ae771770SStanislav Sedov
491ae771770SStanislav Sedov #endif /* HAVE_OPENSSL */
492ae771770SStanislav Sedov
493c19800e8SDoug Rabson krb5_error_code
_kdc_pk_rd_padata(krb5_context context,krb5_kdc_configuration * config,const KDC_REQ * req,const PA_DATA * pa,hdb_entry_ex * client,pk_client_params ** ret_params)494c19800e8SDoug Rabson _kdc_pk_rd_padata(krb5_context context,
495c19800e8SDoug Rabson krb5_kdc_configuration *config,
496c19800e8SDoug Rabson const KDC_REQ *req,
497c19800e8SDoug Rabson const PA_DATA *pa,
498ae771770SStanislav Sedov hdb_entry_ex *client,
499c19800e8SDoug Rabson pk_client_params **ret_params)
500c19800e8SDoug Rabson {
501ae771770SStanislav Sedov pk_client_params *cp;
502c19800e8SDoug Rabson krb5_error_code ret;
503c19800e8SDoug Rabson heim_oid eContentType = { 0, NULL }, contentInfoOid = { 0, NULL };
504c19800e8SDoug Rabson krb5_data eContent = { 0, NULL };
505c19800e8SDoug Rabson krb5_data signed_content = { 0, NULL };
506c19800e8SDoug Rabson const char *type = "unknown type";
507ae771770SStanislav Sedov hx509_certs trust_anchors;
508c19800e8SDoug Rabson int have_data = 0;
509ae771770SStanislav Sedov const HDB_Ext_PKINIT_cert *pc;
510c19800e8SDoug Rabson
511c19800e8SDoug Rabson *ret_params = NULL;
512c19800e8SDoug Rabson
513c19800e8SDoug Rabson if (!config->enable_pkinit) {
514c19800e8SDoug Rabson kdc_log(context, config, 0, "PK-INIT request but PK-INIT not enabled");
515ae771770SStanislav Sedov krb5_clear_error_message(context);
516c19800e8SDoug Rabson return 0;
517c19800e8SDoug Rabson }
518c19800e8SDoug Rabson
519ae771770SStanislav Sedov cp = calloc(1, sizeof(*cp));
520ae771770SStanislav Sedov if (cp == NULL) {
521ae771770SStanislav Sedov krb5_clear_error_message(context);
522c19800e8SDoug Rabson ret = ENOMEM;
523c19800e8SDoug Rabson goto out;
524c19800e8SDoug Rabson }
525c19800e8SDoug Rabson
526ae771770SStanislav Sedov ret = hx509_certs_init(context->hx509ctx,
527ae771770SStanislav Sedov "MEMORY:trust-anchors",
528ae771770SStanislav Sedov 0, NULL, &trust_anchors);
529ae771770SStanislav Sedov if (ret) {
530ae771770SStanislav Sedov krb5_set_error_message(context, ret, "failed to create trust anchors");
531ae771770SStanislav Sedov goto out;
532ae771770SStanislav Sedov }
533ae771770SStanislav Sedov
534ae771770SStanislav Sedov ret = hx509_certs_merge(context->hx509ctx, trust_anchors,
535ae771770SStanislav Sedov kdc_identity->anchors);
536ae771770SStanislav Sedov if (ret) {
537ae771770SStanislav Sedov hx509_certs_free(&trust_anchors);
538ae771770SStanislav Sedov krb5_set_error_message(context, ret, "failed to create verify context");
539ae771770SStanislav Sedov goto out;
540ae771770SStanislav Sedov }
541ae771770SStanislav Sedov
542ae771770SStanislav Sedov /* Add any registered certificates for this client as trust anchors */
543ae771770SStanislav Sedov ret = hdb_entry_get_pkinit_cert(&client->entry, &pc);
544ae771770SStanislav Sedov if (ret == 0 && pc != NULL) {
545ae771770SStanislav Sedov hx509_cert cert;
546ae771770SStanislav Sedov unsigned int i;
547ae771770SStanislav Sedov
548ae771770SStanislav Sedov for (i = 0; i < pc->len; i++) {
549ae771770SStanislav Sedov ret = hx509_cert_init_data(context->hx509ctx,
550ae771770SStanislav Sedov pc->val[i].cert.data,
551ae771770SStanislav Sedov pc->val[i].cert.length,
552ae771770SStanislav Sedov &cert);
553ae771770SStanislav Sedov if (ret)
554ae771770SStanislav Sedov continue;
555ae771770SStanislav Sedov hx509_certs_add(context->hx509ctx, trust_anchors, cert);
556ae771770SStanislav Sedov hx509_cert_free(cert);
557ae771770SStanislav Sedov }
558ae771770SStanislav Sedov }
559ae771770SStanislav Sedov
560ae771770SStanislav Sedov ret = hx509_verify_init_ctx(context->hx509ctx, &cp->verify_ctx);
561ae771770SStanislav Sedov if (ret) {
562ae771770SStanislav Sedov hx509_certs_free(&trust_anchors);
563ae771770SStanislav Sedov krb5_set_error_message(context, ret, "failed to create verify context");
564ae771770SStanislav Sedov goto out;
565ae771770SStanislav Sedov }
566ae771770SStanislav Sedov
567ae771770SStanislav Sedov hx509_verify_set_time(cp->verify_ctx, kdc_time);
568ae771770SStanislav Sedov hx509_verify_attach_anchors(cp->verify_ctx, trust_anchors);
569ae771770SStanislav Sedov hx509_certs_free(&trust_anchors);
570ae771770SStanislav Sedov
571ae771770SStanislav Sedov if (config->pkinit_allow_proxy_certs)
572ae771770SStanislav Sedov hx509_verify_set_proxy_certificate(cp->verify_ctx, 1);
573ae771770SStanislav Sedov
574c19800e8SDoug Rabson if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
575c19800e8SDoug Rabson PA_PK_AS_REQ_Win2k r;
576c19800e8SDoug Rabson
577c19800e8SDoug Rabson type = "PK-INIT-Win2k";
578c19800e8SDoug Rabson
579ae771770SStanislav Sedov if (req->req_body.kdc_options.request_anonymous) {
580ae771770SStanislav Sedov ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED;
581ae771770SStanislav Sedov krb5_set_error_message(context, ret,
582ae771770SStanislav Sedov "Anon not supported in RSA mode");
583ae771770SStanislav Sedov goto out;
584ae771770SStanislav Sedov }
585ae771770SStanislav Sedov
586c19800e8SDoug Rabson ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data,
587c19800e8SDoug Rabson pa->padata_value.length,
588c19800e8SDoug Rabson &r,
589c19800e8SDoug Rabson NULL);
590c19800e8SDoug Rabson if (ret) {
591ae771770SStanislav Sedov krb5_set_error_message(context, ret, "Can't decode "
592c19800e8SDoug Rabson "PK-AS-REQ-Win2k: %d", ret);
593c19800e8SDoug Rabson goto out;
594c19800e8SDoug Rabson }
595c19800e8SDoug Rabson
596c19800e8SDoug Rabson ret = hx509_cms_unwrap_ContentInfo(&r.signed_auth_pack,
597c19800e8SDoug Rabson &contentInfoOid,
598c19800e8SDoug Rabson &signed_content,
599c19800e8SDoug Rabson &have_data);
600c19800e8SDoug Rabson free_PA_PK_AS_REQ_Win2k(&r);
601c19800e8SDoug Rabson if (ret) {
602ae771770SStanislav Sedov krb5_set_error_message(context, ret,
603ae771770SStanislav Sedov "Can't unwrap ContentInfo(win): %d", ret);
604c19800e8SDoug Rabson goto out;
605c19800e8SDoug Rabson }
606c19800e8SDoug Rabson
607c19800e8SDoug Rabson } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
608c19800e8SDoug Rabson PA_PK_AS_REQ r;
609c19800e8SDoug Rabson
610c19800e8SDoug Rabson type = "PK-INIT-IETF";
611c19800e8SDoug Rabson
612c19800e8SDoug Rabson ret = decode_PA_PK_AS_REQ(pa->padata_value.data,
613c19800e8SDoug Rabson pa->padata_value.length,
614c19800e8SDoug Rabson &r,
615c19800e8SDoug Rabson NULL);
616c19800e8SDoug Rabson if (ret) {
617ae771770SStanislav Sedov krb5_set_error_message(context, ret,
618ae771770SStanislav Sedov "Can't decode PK-AS-REQ: %d", ret);
619c19800e8SDoug Rabson goto out;
620c19800e8SDoug Rabson }
621c19800e8SDoug Rabson
622c19800e8SDoug Rabson /* XXX look at r.kdcPkId */
623c19800e8SDoug Rabson if (r.trustedCertifiers) {
624c19800e8SDoug Rabson ExternalPrincipalIdentifiers *edi = r.trustedCertifiers;
625ae771770SStanislav Sedov unsigned int i, maxedi;
626c19800e8SDoug Rabson
627ae771770SStanislav Sedov ret = hx509_certs_init(context->hx509ctx,
628c19800e8SDoug Rabson "MEMORY:client-anchors",
629c19800e8SDoug Rabson 0, NULL,
630ae771770SStanislav Sedov &cp->client_anchors);
631c19800e8SDoug Rabson if (ret) {
632ae771770SStanislav Sedov krb5_set_error_message(context, ret,
633ae771770SStanislav Sedov "Can't allocate client anchors: %d",
634ae771770SStanislav Sedov ret);
635c19800e8SDoug Rabson goto out;
636c19800e8SDoug Rabson
637c19800e8SDoug Rabson }
638ae771770SStanislav Sedov /*
639ae771770SStanislav Sedov * If the client sent more then 10 EDI, don't bother
640ae771770SStanislav Sedov * looking more then 10 of performance reasons.
641ae771770SStanislav Sedov */
642ae771770SStanislav Sedov maxedi = edi->len;
643ae771770SStanislav Sedov if (maxedi > 10)
644ae771770SStanislav Sedov maxedi = 10;
645ae771770SStanislav Sedov for (i = 0; i < maxedi; i++) {
646c19800e8SDoug Rabson IssuerAndSerialNumber iasn;
647c19800e8SDoug Rabson hx509_query *q;
648c19800e8SDoug Rabson hx509_cert cert;
649c19800e8SDoug Rabson size_t size;
650c19800e8SDoug Rabson
651c19800e8SDoug Rabson if (edi->val[i].issuerAndSerialNumber == NULL)
652c19800e8SDoug Rabson continue;
653c19800e8SDoug Rabson
654ae771770SStanislav Sedov ret = hx509_query_alloc(context->hx509ctx, &q);
655c19800e8SDoug Rabson if (ret) {
656ae771770SStanislav Sedov krb5_set_error_message(context, ret,
657c19800e8SDoug Rabson "Failed to allocate hx509_query");
658c19800e8SDoug Rabson goto out;
659c19800e8SDoug Rabson }
660c19800e8SDoug Rabson
661c19800e8SDoug Rabson ret = decode_IssuerAndSerialNumber(edi->val[i].issuerAndSerialNumber->data,
662c19800e8SDoug Rabson edi->val[i].issuerAndSerialNumber->length,
663c19800e8SDoug Rabson &iasn,
664c19800e8SDoug Rabson &size);
665c19800e8SDoug Rabson if (ret) {
666ae771770SStanislav Sedov hx509_query_free(context->hx509ctx, q);
667c19800e8SDoug Rabson continue;
668c19800e8SDoug Rabson }
669c19800e8SDoug Rabson ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber);
670c19800e8SDoug Rabson free_IssuerAndSerialNumber(&iasn);
671ae771770SStanislav Sedov if (ret) {
672ae771770SStanislav Sedov hx509_query_free(context->hx509ctx, q);
673c19800e8SDoug Rabson continue;
674ae771770SStanislav Sedov }
675c19800e8SDoug Rabson
676ae771770SStanislav Sedov ret = hx509_certs_find(context->hx509ctx,
677c19800e8SDoug Rabson kdc_identity->certs,
678c19800e8SDoug Rabson q,
679c19800e8SDoug Rabson &cert);
680ae771770SStanislav Sedov hx509_query_free(context->hx509ctx, q);
681c19800e8SDoug Rabson if (ret)
682c19800e8SDoug Rabson continue;
683ae771770SStanislav Sedov hx509_certs_add(context->hx509ctx,
684ae771770SStanislav Sedov cp->client_anchors, cert);
685c19800e8SDoug Rabson hx509_cert_free(cert);
686c19800e8SDoug Rabson }
687c19800e8SDoug Rabson }
688c19800e8SDoug Rabson
689c19800e8SDoug Rabson ret = hx509_cms_unwrap_ContentInfo(&r.signedAuthPack,
690c19800e8SDoug Rabson &contentInfoOid,
691c19800e8SDoug Rabson &signed_content,
692c19800e8SDoug Rabson &have_data);
693c19800e8SDoug Rabson free_PA_PK_AS_REQ(&r);
694c19800e8SDoug Rabson if (ret) {
695ae771770SStanislav Sedov krb5_set_error_message(context, ret,
696ae771770SStanislav Sedov "Can't unwrap ContentInfo: %d", ret);
697c19800e8SDoug Rabson goto out;
698c19800e8SDoug Rabson }
699c19800e8SDoug Rabson
700c19800e8SDoug Rabson } else {
701ae771770SStanislav Sedov krb5_clear_error_message(context);
702c19800e8SDoug Rabson ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
703c19800e8SDoug Rabson goto out;
704c19800e8SDoug Rabson }
705c19800e8SDoug Rabson
706ae771770SStanislav Sedov ret = der_heim_oid_cmp(&contentInfoOid, &asn1_oid_id_pkcs7_signedData);
707c19800e8SDoug Rabson if (ret != 0) {
708c19800e8SDoug Rabson ret = KRB5KRB_ERR_GENERIC;
709ae771770SStanislav Sedov krb5_set_error_message(context, ret,
710ae771770SStanislav Sedov "PK-AS-REQ-Win2k invalid content type oid");
711c19800e8SDoug Rabson goto out;
712c19800e8SDoug Rabson }
713c19800e8SDoug Rabson
714c19800e8SDoug Rabson if (!have_data) {
715c19800e8SDoug Rabson ret = KRB5KRB_ERR_GENERIC;
716ae771770SStanislav Sedov krb5_set_error_message(context, ret,
717ae771770SStanislav Sedov "PK-AS-REQ-Win2k no signed auth pack");
718c19800e8SDoug Rabson goto out;
719c19800e8SDoug Rabson }
720c19800e8SDoug Rabson
721c19800e8SDoug Rabson {
722c19800e8SDoug Rabson hx509_certs signer_certs;
723ae771770SStanislav Sedov int flags = HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; /* BTMM */
724c19800e8SDoug Rabson
725ae771770SStanislav Sedov if (req->req_body.kdc_options.request_anonymous)
726ae771770SStanislav Sedov flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER;
727ae771770SStanislav Sedov
728ae771770SStanislav Sedov ret = hx509_cms_verify_signed(context->hx509ctx,
729ae771770SStanislav Sedov cp->verify_ctx,
730ae771770SStanislav Sedov flags,
731c19800e8SDoug Rabson signed_content.data,
732c19800e8SDoug Rabson signed_content.length,
733c19800e8SDoug Rabson NULL,
734c19800e8SDoug Rabson kdc_identity->certpool,
735c19800e8SDoug Rabson &eContentType,
736c19800e8SDoug Rabson &eContent,
737c19800e8SDoug Rabson &signer_certs);
738c19800e8SDoug Rabson if (ret) {
739ae771770SStanislav Sedov char *s = hx509_get_error_string(context->hx509ctx, ret);
740c19800e8SDoug Rabson krb5_warnx(context, "PKINIT: failed to verify signature: %s: %d",
741c19800e8SDoug Rabson s, ret);
742c19800e8SDoug Rabson free(s);
743c19800e8SDoug Rabson goto out;
744c19800e8SDoug Rabson }
745c19800e8SDoug Rabson
746ae771770SStanislav Sedov if (signer_certs) {
747ae771770SStanislav Sedov ret = hx509_get_one_cert(context->hx509ctx, signer_certs,
748ae771770SStanislav Sedov &cp->cert);
749c19800e8SDoug Rabson hx509_certs_free(&signer_certs);
750ae771770SStanislav Sedov }
751c19800e8SDoug Rabson if (ret)
752c19800e8SDoug Rabson goto out;
753c19800e8SDoug Rabson }
754c19800e8SDoug Rabson
755c19800e8SDoug Rabson /* Signature is correct, now verify the signed message */
756ae771770SStanislav Sedov if (der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkcs7_data) != 0 &&
757ae771770SStanislav Sedov der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkauthdata) != 0)
758c19800e8SDoug Rabson {
759c19800e8SDoug Rabson ret = KRB5_BADMSGTYPE;
760ae771770SStanislav Sedov krb5_set_error_message(context, ret, "got wrong oid for pkauthdata");
761c19800e8SDoug Rabson goto out;
762c19800e8SDoug Rabson }
763c19800e8SDoug Rabson
764c19800e8SDoug Rabson if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
765c19800e8SDoug Rabson AuthPack_Win2k ap;
766c19800e8SDoug Rabson
767c19800e8SDoug Rabson ret = decode_AuthPack_Win2k(eContent.data,
768c19800e8SDoug Rabson eContent.length,
769c19800e8SDoug Rabson &ap,
770c19800e8SDoug Rabson NULL);
771c19800e8SDoug Rabson if (ret) {
772ae771770SStanislav Sedov krb5_set_error_message(context, ret,
773ae771770SStanislav Sedov "Can't decode AuthPack: %d", ret);
774c19800e8SDoug Rabson goto out;
775c19800e8SDoug Rabson }
776c19800e8SDoug Rabson
777c19800e8SDoug Rabson ret = pk_check_pkauthenticator_win2k(context,
778c19800e8SDoug Rabson &ap.pkAuthenticator,
779c19800e8SDoug Rabson req);
780c19800e8SDoug Rabson if (ret) {
781c19800e8SDoug Rabson free_AuthPack_Win2k(&ap);
782c19800e8SDoug Rabson goto out;
783c19800e8SDoug Rabson }
784c19800e8SDoug Rabson
785ae771770SStanislav Sedov cp->type = PKINIT_WIN2K;
786ae771770SStanislav Sedov cp->nonce = ap.pkAuthenticator.nonce;
787c19800e8SDoug Rabson
788c19800e8SDoug Rabson if (ap.clientPublicValue) {
789c19800e8SDoug Rabson ret = KRB5KRB_ERR_GENERIC;
790ae771770SStanislav Sedov krb5_set_error_message(context, ret,
791ae771770SStanislav Sedov "DH not supported for windows");
792c19800e8SDoug Rabson goto out;
793c19800e8SDoug Rabson }
794c19800e8SDoug Rabson free_AuthPack_Win2k(&ap);
795c19800e8SDoug Rabson
796c19800e8SDoug Rabson } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
797c19800e8SDoug Rabson AuthPack ap;
798c19800e8SDoug Rabson
799c19800e8SDoug Rabson ret = decode_AuthPack(eContent.data,
800c19800e8SDoug Rabson eContent.length,
801c19800e8SDoug Rabson &ap,
802c19800e8SDoug Rabson NULL);
803c19800e8SDoug Rabson if (ret) {
804ae771770SStanislav Sedov krb5_set_error_message(context, ret,
805ae771770SStanislav Sedov "Can't decode AuthPack: %d", ret);
806c19800e8SDoug Rabson free_AuthPack(&ap);
807c19800e8SDoug Rabson goto out;
808c19800e8SDoug Rabson }
809c19800e8SDoug Rabson
810ae771770SStanislav Sedov if (req->req_body.kdc_options.request_anonymous &&
811ae771770SStanislav Sedov ap.clientPublicValue == NULL) {
812ae771770SStanislav Sedov free_AuthPack(&ap);
813ae771770SStanislav Sedov ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED;
814ae771770SStanislav Sedov krb5_set_error_message(context, ret,
815ae771770SStanislav Sedov "Anon not supported in RSA mode");
816ae771770SStanislav Sedov goto out;
817ae771770SStanislav Sedov }
818ae771770SStanislav Sedov
819c19800e8SDoug Rabson ret = pk_check_pkauthenticator(context,
820c19800e8SDoug Rabson &ap.pkAuthenticator,
821c19800e8SDoug Rabson req);
822c19800e8SDoug Rabson if (ret) {
823c19800e8SDoug Rabson free_AuthPack(&ap);
824c19800e8SDoug Rabson goto out;
825c19800e8SDoug Rabson }
826c19800e8SDoug Rabson
827ae771770SStanislav Sedov cp->type = PKINIT_27;
828ae771770SStanislav Sedov cp->nonce = ap.pkAuthenticator.nonce;
829c19800e8SDoug Rabson
830c19800e8SDoug Rabson if (ap.clientPublicValue) {
831ae771770SStanislav Sedov if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_dhpublicnumber) == 0) {
832ae771770SStanislav Sedov cp->keyex = USE_DH;
833c19800e8SDoug Rabson ret = get_dh_param(context, config,
834ae771770SStanislav Sedov ap.clientPublicValue, cp);
835ae771770SStanislav Sedov #ifdef HAVE_OPENSSL
836ae771770SStanislav Sedov } else if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_ecPublicKey) == 0) {
837ae771770SStanislav Sedov cp->keyex = USE_ECDH;
838ae771770SStanislav Sedov ret = get_ecdh_param(context, config,
839ae771770SStanislav Sedov ap.clientPublicValue, cp);
840ae771770SStanislav Sedov #endif /* HAVE_OPENSSL */
841ae771770SStanislav Sedov } else {
842ae771770SStanislav Sedov ret = KRB5_BADMSGTYPE;
843ae771770SStanislav Sedov krb5_set_error_message(context, ret, "PKINIT unknown DH mechanism");
844ae771770SStanislav Sedov }
845c19800e8SDoug Rabson if (ret) {
846c19800e8SDoug Rabson free_AuthPack(&ap);
847c19800e8SDoug Rabson goto out;
848c19800e8SDoug Rabson }
849ae771770SStanislav Sedov } else
850ae771770SStanislav Sedov cp->keyex = USE_RSA;
851ae771770SStanislav Sedov
852ae771770SStanislav Sedov ret = hx509_peer_info_alloc(context->hx509ctx,
853ae771770SStanislav Sedov &cp->peer);
854ae771770SStanislav Sedov if (ret) {
855ae771770SStanislav Sedov free_AuthPack(&ap);
856ae771770SStanislav Sedov goto out;
857c19800e8SDoug Rabson }
858c19800e8SDoug Rabson
859c19800e8SDoug Rabson if (ap.supportedCMSTypes) {
860ae771770SStanislav Sedov ret = hx509_peer_info_set_cms_algs(context->hx509ctx,
861ae771770SStanislav Sedov cp->peer,
862c19800e8SDoug Rabson ap.supportedCMSTypes->val,
863c19800e8SDoug Rabson ap.supportedCMSTypes->len);
864c19800e8SDoug Rabson if (ret) {
865c19800e8SDoug Rabson free_AuthPack(&ap);
866c19800e8SDoug Rabson goto out;
867c19800e8SDoug Rabson }
868ae771770SStanislav Sedov } else {
869ae771770SStanislav Sedov /* assume old client */
870ae771770SStanislav Sedov hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer,
871ae771770SStanislav Sedov hx509_crypto_des_rsdi_ede3_cbc());
872ae771770SStanislav Sedov hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer,
873ae771770SStanislav Sedov hx509_signature_rsa_with_sha1());
874ae771770SStanislav Sedov hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer,
875ae771770SStanislav Sedov hx509_signature_sha1());
876c19800e8SDoug Rabson }
877c19800e8SDoug Rabson free_AuthPack(&ap);
878c19800e8SDoug Rabson } else
879c19800e8SDoug Rabson krb5_abortx(context, "internal pkinit error");
880c19800e8SDoug Rabson
881c19800e8SDoug Rabson kdc_log(context, config, 0, "PK-INIT request of type %s", type);
882c19800e8SDoug Rabson
883c19800e8SDoug Rabson out:
884c19800e8SDoug Rabson if (ret)
885c19800e8SDoug Rabson krb5_warn(context, ret, "PKINIT");
886c19800e8SDoug Rabson
887c19800e8SDoug Rabson if (signed_content.data)
888c19800e8SDoug Rabson free(signed_content.data);
889c19800e8SDoug Rabson krb5_data_free(&eContent);
890c19800e8SDoug Rabson der_free_oid(&eContentType);
891c19800e8SDoug Rabson der_free_oid(&contentInfoOid);
892ae771770SStanislav Sedov if (ret) {
893ae771770SStanislav Sedov _kdc_pk_free_client_param(context, cp);
894ae771770SStanislav Sedov } else
895ae771770SStanislav Sedov *ret_params = cp;
896c19800e8SDoug Rabson return ret;
897c19800e8SDoug Rabson }
898c19800e8SDoug Rabson
899c19800e8SDoug Rabson /*
900c19800e8SDoug Rabson *
901c19800e8SDoug Rabson */
902c19800e8SDoug Rabson
903c19800e8SDoug Rabson static krb5_error_code
BN_to_integer(krb5_context context,const BIGNUM * bn,heim_integer * integer)904*e4456411SJohn Baldwin BN_to_integer(krb5_context context, const BIGNUM *bn, heim_integer *integer)
905c19800e8SDoug Rabson {
906c19800e8SDoug Rabson integer->length = BN_num_bytes(bn);
907c19800e8SDoug Rabson integer->data = malloc(integer->length);
908c19800e8SDoug Rabson if (integer->data == NULL) {
909ae771770SStanislav Sedov krb5_clear_error_message(context);
910c19800e8SDoug Rabson return ENOMEM;
911c19800e8SDoug Rabson }
912c19800e8SDoug Rabson BN_bn2bin(bn, integer->data);
913c19800e8SDoug Rabson integer->negative = BN_is_negative(bn);
914c19800e8SDoug Rabson return 0;
915c19800e8SDoug Rabson }
916c19800e8SDoug Rabson
917c19800e8SDoug Rabson static krb5_error_code
pk_mk_pa_reply_enckey(krb5_context context,krb5_kdc_configuration * config,pk_client_params * cp,const KDC_REQ * req,const krb5_data * req_buffer,krb5_keyblock * reply_key,ContentInfo * content_info,hx509_cert * kdc_cert)918c19800e8SDoug Rabson pk_mk_pa_reply_enckey(krb5_context context,
919c19800e8SDoug Rabson krb5_kdc_configuration *config,
920ae771770SStanislav Sedov pk_client_params *cp,
921c19800e8SDoug Rabson const KDC_REQ *req,
922c19800e8SDoug Rabson const krb5_data *req_buffer,
923c19800e8SDoug Rabson krb5_keyblock *reply_key,
924ae771770SStanislav Sedov ContentInfo *content_info,
925ae771770SStanislav Sedov hx509_cert *kdc_cert)
926c19800e8SDoug Rabson {
927ae771770SStanislav Sedov const heim_oid *envelopedAlg = NULL, *sdAlg = NULL, *evAlg = NULL;
928c19800e8SDoug Rabson krb5_error_code ret;
929c19800e8SDoug Rabson krb5_data buf, signed_data;
930ae771770SStanislav Sedov size_t size = 0;
931c19800e8SDoug Rabson int do_win2k = 0;
932c19800e8SDoug Rabson
933c19800e8SDoug Rabson krb5_data_zero(&buf);
934c19800e8SDoug Rabson krb5_data_zero(&signed_data);
935c19800e8SDoug Rabson
936ae771770SStanislav Sedov *kdc_cert = NULL;
937ae771770SStanislav Sedov
938c19800e8SDoug Rabson /*
939c19800e8SDoug Rabson * If the message client is a win2k-type but it send pa data
940c19800e8SDoug Rabson * 09-binding it expects a IETF (checksum) reply so there can be
941c19800e8SDoug Rabson * no replay attacks.
942c19800e8SDoug Rabson */
943c19800e8SDoug Rabson
944ae771770SStanislav Sedov switch (cp->type) {
945ae771770SStanislav Sedov case PKINIT_WIN2K: {
946c19800e8SDoug Rabson int i = 0;
947c19800e8SDoug Rabson if (_kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_09_BINDING) == NULL
948c19800e8SDoug Rabson && config->pkinit_require_binding == 0)
949c19800e8SDoug Rabson {
950c19800e8SDoug Rabson do_win2k = 1;
951c19800e8SDoug Rabson }
952ae771770SStanislav Sedov sdAlg = &asn1_oid_id_pkcs7_data;
953ae771770SStanislav Sedov evAlg = &asn1_oid_id_pkcs7_data;
954ae771770SStanislav Sedov envelopedAlg = &asn1_oid_id_rsadsi_des_ede3_cbc;
955c19800e8SDoug Rabson break;
956c19800e8SDoug Rabson }
957ae771770SStanislav Sedov case PKINIT_27:
958ae771770SStanislav Sedov sdAlg = &asn1_oid_id_pkrkeydata;
959ae771770SStanislav Sedov evAlg = &asn1_oid_id_pkcs7_signedData;
960c19800e8SDoug Rabson break;
961c19800e8SDoug Rabson default:
962c19800e8SDoug Rabson krb5_abortx(context, "internal pkinit error");
963c19800e8SDoug Rabson }
964c19800e8SDoug Rabson
965c19800e8SDoug Rabson if (do_win2k) {
966c19800e8SDoug Rabson ReplyKeyPack_Win2k kp;
967c19800e8SDoug Rabson memset(&kp, 0, sizeof(kp));
968c19800e8SDoug Rabson
969c19800e8SDoug Rabson ret = copy_EncryptionKey(reply_key, &kp.replyKey);
970c19800e8SDoug Rabson if (ret) {
971ae771770SStanislav Sedov krb5_clear_error_message(context);
972c19800e8SDoug Rabson goto out;
973c19800e8SDoug Rabson }
974ae771770SStanislav Sedov kp.nonce = cp->nonce;
975c19800e8SDoug Rabson
976c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(ReplyKeyPack_Win2k,
977c19800e8SDoug Rabson buf.data, buf.length,
978c19800e8SDoug Rabson &kp, &size,ret);
979c19800e8SDoug Rabson free_ReplyKeyPack_Win2k(&kp);
980c19800e8SDoug Rabson } else {
981c19800e8SDoug Rabson krb5_crypto ascrypto;
982c19800e8SDoug Rabson ReplyKeyPack kp;
983c19800e8SDoug Rabson memset(&kp, 0, sizeof(kp));
984c19800e8SDoug Rabson
985c19800e8SDoug Rabson ret = copy_EncryptionKey(reply_key, &kp.replyKey);
986c19800e8SDoug Rabson if (ret) {
987ae771770SStanislav Sedov krb5_clear_error_message(context);
988c19800e8SDoug Rabson goto out;
989c19800e8SDoug Rabson }
990c19800e8SDoug Rabson
991c19800e8SDoug Rabson ret = krb5_crypto_init(context, reply_key, 0, &ascrypto);
992c19800e8SDoug Rabson if (ret) {
993ae771770SStanislav Sedov krb5_clear_error_message(context);
994c19800e8SDoug Rabson goto out;
995c19800e8SDoug Rabson }
996c19800e8SDoug Rabson
997c19800e8SDoug Rabson ret = krb5_create_checksum(context, ascrypto, 6, 0,
998c19800e8SDoug Rabson req_buffer->data, req_buffer->length,
999c19800e8SDoug Rabson &kp.asChecksum);
1000c19800e8SDoug Rabson if (ret) {
1001ae771770SStanislav Sedov krb5_clear_error_message(context);
1002c19800e8SDoug Rabson goto out;
1003c19800e8SDoug Rabson }
1004c19800e8SDoug Rabson
1005c19800e8SDoug Rabson ret = krb5_crypto_destroy(context, ascrypto);
1006c19800e8SDoug Rabson if (ret) {
1007ae771770SStanislav Sedov krb5_clear_error_message(context);
1008c19800e8SDoug Rabson goto out;
1009c19800e8SDoug Rabson }
1010c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(ReplyKeyPack, buf.data, buf.length, &kp, &size,ret);
1011c19800e8SDoug Rabson free_ReplyKeyPack(&kp);
1012c19800e8SDoug Rabson }
1013c19800e8SDoug Rabson if (ret) {
1014ae771770SStanislav Sedov krb5_set_error_message(context, ret, "ASN.1 encoding of ReplyKeyPack "
1015c19800e8SDoug Rabson "failed (%d)", ret);
1016c19800e8SDoug Rabson goto out;
1017c19800e8SDoug Rabson }
1018c19800e8SDoug Rabson if (buf.length != size)
1019c19800e8SDoug Rabson krb5_abortx(context, "Internal ASN.1 encoder error");
1020c19800e8SDoug Rabson
1021c19800e8SDoug Rabson {
1022c19800e8SDoug Rabson hx509_query *q;
1023c19800e8SDoug Rabson hx509_cert cert;
1024c19800e8SDoug Rabson
1025ae771770SStanislav Sedov ret = hx509_query_alloc(context->hx509ctx, &q);
1026c19800e8SDoug Rabson if (ret)
1027c19800e8SDoug Rabson goto out;
1028c19800e8SDoug Rabson
1029c19800e8SDoug Rabson hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
1030ae771770SStanislav Sedov if (config->pkinit_kdc_friendly_name)
1031ae771770SStanislav Sedov hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);
1032c19800e8SDoug Rabson
1033ae771770SStanislav Sedov ret = hx509_certs_find(context->hx509ctx,
1034c19800e8SDoug Rabson kdc_identity->certs,
1035c19800e8SDoug Rabson q,
1036c19800e8SDoug Rabson &cert);
1037ae771770SStanislav Sedov hx509_query_free(context->hx509ctx, q);
1038c19800e8SDoug Rabson if (ret)
1039c19800e8SDoug Rabson goto out;
1040c19800e8SDoug Rabson
1041ae771770SStanislav Sedov ret = hx509_cms_create_signed_1(context->hx509ctx,
1042c19800e8SDoug Rabson 0,
1043c19800e8SDoug Rabson sdAlg,
1044c19800e8SDoug Rabson buf.data,
1045c19800e8SDoug Rabson buf.length,
1046c19800e8SDoug Rabson NULL,
1047c19800e8SDoug Rabson cert,
1048ae771770SStanislav Sedov cp->peer,
1049ae771770SStanislav Sedov cp->client_anchors,
1050c19800e8SDoug Rabson kdc_identity->certpool,
1051c19800e8SDoug Rabson &signed_data);
1052ae771770SStanislav Sedov *kdc_cert = cert;
1053c19800e8SDoug Rabson }
1054c19800e8SDoug Rabson
1055c19800e8SDoug Rabson krb5_data_free(&buf);
1056c19800e8SDoug Rabson if (ret)
1057c19800e8SDoug Rabson goto out;
1058c19800e8SDoug Rabson
1059ae771770SStanislav Sedov if (cp->type == PKINIT_WIN2K) {
1060ae771770SStanislav Sedov ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData,
1061c19800e8SDoug Rabson &signed_data,
1062c19800e8SDoug Rabson &buf);
1063c19800e8SDoug Rabson if (ret)
1064c19800e8SDoug Rabson goto out;
1065c19800e8SDoug Rabson krb5_data_free(&signed_data);
1066c19800e8SDoug Rabson signed_data = buf;
1067c19800e8SDoug Rabson }
1068c19800e8SDoug Rabson
1069ae771770SStanislav Sedov ret = hx509_cms_envelope_1(context->hx509ctx,
1070ae771770SStanislav Sedov HX509_CMS_EV_NO_KU_CHECK,
1071ae771770SStanislav Sedov cp->cert,
1072c19800e8SDoug Rabson signed_data.data, signed_data.length,
1073c19800e8SDoug Rabson envelopedAlg,
1074ae771770SStanislav Sedov evAlg, &buf);
1075c19800e8SDoug Rabson if (ret)
1076c19800e8SDoug Rabson goto out;
1077c19800e8SDoug Rabson
1078c19800e8SDoug Rabson ret = _krb5_pk_mk_ContentInfo(context,
1079c19800e8SDoug Rabson &buf,
1080ae771770SStanislav Sedov &asn1_oid_id_pkcs7_envelopedData,
1081c19800e8SDoug Rabson content_info);
1082c19800e8SDoug Rabson out:
1083ae771770SStanislav Sedov if (ret && *kdc_cert) {
1084ae771770SStanislav Sedov hx509_cert_free(*kdc_cert);
1085ae771770SStanislav Sedov *kdc_cert = NULL;
1086ae771770SStanislav Sedov }
1087ae771770SStanislav Sedov
1088c19800e8SDoug Rabson krb5_data_free(&buf);
1089c19800e8SDoug Rabson krb5_data_free(&signed_data);
1090c19800e8SDoug Rabson return ret;
1091c19800e8SDoug Rabson }
1092c19800e8SDoug Rabson
1093c19800e8SDoug Rabson /*
1094c19800e8SDoug Rabson *
1095c19800e8SDoug Rabson */
1096c19800e8SDoug Rabson
1097c19800e8SDoug Rabson static krb5_error_code
pk_mk_pa_reply_dh(krb5_context context,krb5_kdc_configuration * config,pk_client_params * cp,ContentInfo * content_info,hx509_cert * kdc_cert)1098c19800e8SDoug Rabson pk_mk_pa_reply_dh(krb5_context context,
1099ae771770SStanislav Sedov krb5_kdc_configuration *config,
1100ae771770SStanislav Sedov pk_client_params *cp,
1101c19800e8SDoug Rabson ContentInfo *content_info,
1102c19800e8SDoug Rabson hx509_cert *kdc_cert)
1103c19800e8SDoug Rabson {
1104c19800e8SDoug Rabson KDCDHKeyInfo dh_info;
1105c19800e8SDoug Rabson krb5_data signed_data, buf;
1106c19800e8SDoug Rabson ContentInfo contentinfo;
1107c19800e8SDoug Rabson krb5_error_code ret;
1108ae771770SStanislav Sedov hx509_cert cert;
1109ae771770SStanislav Sedov hx509_query *q;
1110ae771770SStanislav Sedov size_t size = 0;
1111c19800e8SDoug Rabson
1112c19800e8SDoug Rabson memset(&contentinfo, 0, sizeof(contentinfo));
1113c19800e8SDoug Rabson memset(&dh_info, 0, sizeof(dh_info));
1114c19800e8SDoug Rabson krb5_data_zero(&signed_data);
1115ae771770SStanislav Sedov krb5_data_zero(&buf);
1116c19800e8SDoug Rabson
1117c19800e8SDoug Rabson *kdc_cert = NULL;
1118c19800e8SDoug Rabson
1119ae771770SStanislav Sedov if (cp->keyex == USE_DH) {
1120ae771770SStanislav Sedov DH *kdc_dh = cp->u.dh.key;
1121*e4456411SJohn Baldwin const BIGNUM *pub_key;
1122ae771770SStanislav Sedov heim_integer i;
1123ae771770SStanislav Sedov
1124*e4456411SJohn Baldwin DH_get0_key(kdc_dh, &pub_key, NULL);
1125*e4456411SJohn Baldwin ret = BN_to_integer(context, pub_key, &i);
1126c19800e8SDoug Rabson if (ret)
1127c19800e8SDoug Rabson return ret;
1128c19800e8SDoug Rabson
1129c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(DHPublicKey, buf.data, buf.length, &i, &size, ret);
1130ae771770SStanislav Sedov der_free_heim_integer(&i);
1131c19800e8SDoug Rabson if (ret) {
1132ae771770SStanislav Sedov krb5_set_error_message(context, ret, "ASN.1 encoding of "
1133c19800e8SDoug Rabson "DHPublicKey failed (%d)", ret);
1134c19800e8SDoug Rabson return ret;
1135c19800e8SDoug Rabson }
1136c19800e8SDoug Rabson if (buf.length != size)
1137c19800e8SDoug Rabson krb5_abortx(context, "Internal ASN.1 encoder error");
1138c19800e8SDoug Rabson
1139c19800e8SDoug Rabson dh_info.subjectPublicKey.length = buf.length * 8;
1140c19800e8SDoug Rabson dh_info.subjectPublicKey.data = buf.data;
1141ae771770SStanislav Sedov krb5_data_zero(&buf);
1142ae771770SStanislav Sedov #ifdef HAVE_OPENSSL
1143ae771770SStanislav Sedov } else if (cp->keyex == USE_ECDH) {
1144ae771770SStanislav Sedov unsigned char *p;
1145ae771770SStanislav Sedov int len;
1146c19800e8SDoug Rabson
1147ae771770SStanislav Sedov len = i2o_ECPublicKey(cp->u.ecdh.key, NULL);
1148ae771770SStanislav Sedov if (len <= 0)
1149ae771770SStanislav Sedov abort();
1150ae771770SStanislav Sedov
1151ae771770SStanislav Sedov p = malloc(len);
1152ae771770SStanislav Sedov if (p == NULL)
1153ae771770SStanislav Sedov abort();
1154ae771770SStanislav Sedov
1155ae771770SStanislav Sedov dh_info.subjectPublicKey.length = len * 8;
1156ae771770SStanislav Sedov dh_info.subjectPublicKey.data = p;
1157ae771770SStanislav Sedov
1158ae771770SStanislav Sedov len = i2o_ECPublicKey(cp->u.ecdh.key, &p);
1159ae771770SStanislav Sedov if (len <= 0)
1160ae771770SStanislav Sedov abort();
1161ae771770SStanislav Sedov #endif
1162ae771770SStanislav Sedov } else
1163ae771770SStanislav Sedov krb5_abortx(context, "no keyex selected ?");
1164ae771770SStanislav Sedov
1165ae771770SStanislav Sedov
1166ae771770SStanislav Sedov dh_info.nonce = cp->nonce;
1167c19800e8SDoug Rabson
1168c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(KDCDHKeyInfo, buf.data, buf.length, &dh_info, &size,
1169c19800e8SDoug Rabson ret);
1170c19800e8SDoug Rabson if (ret) {
1171ae771770SStanislav Sedov krb5_set_error_message(context, ret, "ASN.1 encoding of "
1172c19800e8SDoug Rabson "KdcDHKeyInfo failed (%d)", ret);
1173c19800e8SDoug Rabson goto out;
1174c19800e8SDoug Rabson }
1175c19800e8SDoug Rabson if (buf.length != size)
1176c19800e8SDoug Rabson krb5_abortx(context, "Internal ASN.1 encoder error");
1177c19800e8SDoug Rabson
1178c19800e8SDoug Rabson /*
1179c19800e8SDoug Rabson * Create the SignedData structure and sign the KdcDHKeyInfo
1180c19800e8SDoug Rabson * filled in above
1181c19800e8SDoug Rabson */
1182c19800e8SDoug Rabson
1183ae771770SStanislav Sedov ret = hx509_query_alloc(context->hx509ctx, &q);
1184c19800e8SDoug Rabson if (ret)
1185c19800e8SDoug Rabson goto out;
1186c19800e8SDoug Rabson
1187c19800e8SDoug Rabson hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
1188ae771770SStanislav Sedov if (config->pkinit_kdc_friendly_name)
1189ae771770SStanislav Sedov hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);
1190c19800e8SDoug Rabson
1191ae771770SStanislav Sedov ret = hx509_certs_find(context->hx509ctx,
1192c19800e8SDoug Rabson kdc_identity->certs,
1193c19800e8SDoug Rabson q,
1194c19800e8SDoug Rabson &cert);
1195ae771770SStanislav Sedov hx509_query_free(context->hx509ctx, q);
1196c19800e8SDoug Rabson if (ret)
1197c19800e8SDoug Rabson goto out;
1198c19800e8SDoug Rabson
1199ae771770SStanislav Sedov ret = hx509_cms_create_signed_1(context->hx509ctx,
1200c19800e8SDoug Rabson 0,
1201ae771770SStanislav Sedov &asn1_oid_id_pkdhkeydata,
1202c19800e8SDoug Rabson buf.data,
1203c19800e8SDoug Rabson buf.length,
1204c19800e8SDoug Rabson NULL,
1205c19800e8SDoug Rabson cert,
1206ae771770SStanislav Sedov cp->peer,
1207ae771770SStanislav Sedov cp->client_anchors,
1208c19800e8SDoug Rabson kdc_identity->certpool,
1209c19800e8SDoug Rabson &signed_data);
1210ae771770SStanislav Sedov if (ret) {
1211ae771770SStanislav Sedov kdc_log(context, config, 0, "Failed signing the DH* reply: %d", ret);
1212c19800e8SDoug Rabson goto out;
1213ae771770SStanislav Sedov }
1214ae771770SStanislav Sedov *kdc_cert = cert;
1215c19800e8SDoug Rabson
1216c19800e8SDoug Rabson ret = _krb5_pk_mk_ContentInfo(context,
1217c19800e8SDoug Rabson &signed_data,
1218ae771770SStanislav Sedov &asn1_oid_id_pkcs7_signedData,
1219c19800e8SDoug Rabson content_info);
1220c19800e8SDoug Rabson if (ret)
1221c19800e8SDoug Rabson goto out;
1222c19800e8SDoug Rabson
1223c19800e8SDoug Rabson out:
1224c19800e8SDoug Rabson if (ret && *kdc_cert) {
1225c19800e8SDoug Rabson hx509_cert_free(*kdc_cert);
1226c19800e8SDoug Rabson *kdc_cert = NULL;
1227c19800e8SDoug Rabson }
1228c19800e8SDoug Rabson
1229c19800e8SDoug Rabson krb5_data_free(&buf);
1230c19800e8SDoug Rabson krb5_data_free(&signed_data);
1231c19800e8SDoug Rabson free_KDCDHKeyInfo(&dh_info);
1232c19800e8SDoug Rabson
1233c19800e8SDoug Rabson return ret;
1234c19800e8SDoug Rabson }
1235c19800e8SDoug Rabson
1236c19800e8SDoug Rabson /*
1237c19800e8SDoug Rabson *
1238c19800e8SDoug Rabson */
1239c19800e8SDoug Rabson
1240c19800e8SDoug Rabson krb5_error_code
_kdc_pk_mk_pa_reply(krb5_context context,krb5_kdc_configuration * config,pk_client_params * cp,const hdb_entry_ex * client,krb5_enctype sessionetype,const KDC_REQ * req,const krb5_data * req_buffer,krb5_keyblock ** reply_key,krb5_keyblock * sessionkey,METHOD_DATA * md)1241c19800e8SDoug Rabson _kdc_pk_mk_pa_reply(krb5_context context,
1242c19800e8SDoug Rabson krb5_kdc_configuration *config,
1243ae771770SStanislav Sedov pk_client_params *cp,
1244c19800e8SDoug Rabson const hdb_entry_ex *client,
1245ae771770SStanislav Sedov krb5_enctype sessionetype,
1246c19800e8SDoug Rabson const KDC_REQ *req,
1247c19800e8SDoug Rabson const krb5_data *req_buffer,
1248c19800e8SDoug Rabson krb5_keyblock **reply_key,
1249ae771770SStanislav Sedov krb5_keyblock *sessionkey,
1250c19800e8SDoug Rabson METHOD_DATA *md)
1251c19800e8SDoug Rabson {
1252c19800e8SDoug Rabson krb5_error_code ret;
1253ae771770SStanislav Sedov void *buf = NULL;
1254ae771770SStanislav Sedov size_t len = 0, size = 0;
1255c19800e8SDoug Rabson krb5_enctype enctype;
1256c19800e8SDoug Rabson int pa_type;
1257c19800e8SDoug Rabson hx509_cert kdc_cert = NULL;
1258ae771770SStanislav Sedov size_t i;
1259c19800e8SDoug Rabson
1260c19800e8SDoug Rabson if (!config->enable_pkinit) {
1261ae771770SStanislav Sedov krb5_clear_error_message(context);
1262c19800e8SDoug Rabson return 0;
1263c19800e8SDoug Rabson }
1264c19800e8SDoug Rabson
1265c19800e8SDoug Rabson if (req->req_body.etype.len > 0) {
1266c19800e8SDoug Rabson for (i = 0; i < req->req_body.etype.len; i++)
1267c19800e8SDoug Rabson if (krb5_enctype_valid(context, req->req_body.etype.val[i]) == 0)
1268c19800e8SDoug Rabson break;
1269c19800e8SDoug Rabson if (req->req_body.etype.len <= i) {
1270c19800e8SDoug Rabson ret = KRB5KRB_ERR_GENERIC;
1271ae771770SStanislav Sedov krb5_set_error_message(context, ret,
1272c19800e8SDoug Rabson "No valid enctype available from client");
1273c19800e8SDoug Rabson goto out;
1274c19800e8SDoug Rabson }
1275c19800e8SDoug Rabson enctype = req->req_body.etype.val[i];
1276c19800e8SDoug Rabson } else
1277c19800e8SDoug Rabson enctype = ETYPE_DES3_CBC_SHA1;
1278c19800e8SDoug Rabson
1279ae771770SStanislav Sedov if (cp->type == PKINIT_27) {
1280c19800e8SDoug Rabson PA_PK_AS_REP rep;
1281c19800e8SDoug Rabson const char *type, *other = "";
1282c19800e8SDoug Rabson
1283c19800e8SDoug Rabson memset(&rep, 0, sizeof(rep));
1284c19800e8SDoug Rabson
1285c19800e8SDoug Rabson pa_type = KRB5_PADATA_PK_AS_REP;
1286c19800e8SDoug Rabson
1287ae771770SStanislav Sedov if (cp->keyex == USE_RSA) {
1288c19800e8SDoug Rabson ContentInfo info;
1289c19800e8SDoug Rabson
1290c19800e8SDoug Rabson type = "enckey";
1291c19800e8SDoug Rabson
1292c19800e8SDoug Rabson rep.element = choice_PA_PK_AS_REP_encKeyPack;
1293c19800e8SDoug Rabson
1294c19800e8SDoug Rabson ret = krb5_generate_random_keyblock(context, enctype,
1295ae771770SStanislav Sedov &cp->reply_key);
1296c19800e8SDoug Rabson if (ret) {
1297c19800e8SDoug Rabson free_PA_PK_AS_REP(&rep);
1298c19800e8SDoug Rabson goto out;
1299c19800e8SDoug Rabson }
1300c19800e8SDoug Rabson ret = pk_mk_pa_reply_enckey(context,
1301c19800e8SDoug Rabson config,
1302ae771770SStanislav Sedov cp,
1303c19800e8SDoug Rabson req,
1304c19800e8SDoug Rabson req_buffer,
1305ae771770SStanislav Sedov &cp->reply_key,
1306ae771770SStanislav Sedov &info,
1307ae771770SStanislav Sedov &kdc_cert);
1308c19800e8SDoug Rabson if (ret) {
1309c19800e8SDoug Rabson free_PA_PK_AS_REP(&rep);
1310c19800e8SDoug Rabson goto out;
1311c19800e8SDoug Rabson }
1312c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data,
1313c19800e8SDoug Rabson rep.u.encKeyPack.length, &info, &size,
1314c19800e8SDoug Rabson ret);
1315c19800e8SDoug Rabson free_ContentInfo(&info);
1316c19800e8SDoug Rabson if (ret) {
1317ae771770SStanislav Sedov krb5_set_error_message(context, ret, "encoding of Key ContentInfo "
1318c19800e8SDoug Rabson "failed %d", ret);
1319c19800e8SDoug Rabson free_PA_PK_AS_REP(&rep);
1320c19800e8SDoug Rabson goto out;
1321c19800e8SDoug Rabson }
1322c19800e8SDoug Rabson if (rep.u.encKeyPack.length != size)
1323c19800e8SDoug Rabson krb5_abortx(context, "Internal ASN.1 encoder error");
1324c19800e8SDoug Rabson
1325ae771770SStanislav Sedov ret = krb5_generate_random_keyblock(context, sessionetype,
1326ae771770SStanislav Sedov sessionkey);
1327ae771770SStanislav Sedov if (ret) {
1328ae771770SStanislav Sedov free_PA_PK_AS_REP(&rep);
1329ae771770SStanislav Sedov goto out;
1330ae771770SStanislav Sedov }
1331ae771770SStanislav Sedov
1332c19800e8SDoug Rabson } else {
1333c19800e8SDoug Rabson ContentInfo info;
1334c19800e8SDoug Rabson
1335ae771770SStanislav Sedov switch (cp->keyex) {
1336ae771770SStanislav Sedov case USE_DH: type = "dh"; break;
1337ae771770SStanislav Sedov #ifdef HAVE_OPENSSL
1338ae771770SStanislav Sedov case USE_ECDH: type = "ecdh"; break;
1339ae771770SStanislav Sedov #endif
1340ae771770SStanislav Sedov default: krb5_abortx(context, "unknown keyex"); break;
1341ae771770SStanislav Sedov }
1342ae771770SStanislav Sedov
1343ae771770SStanislav Sedov if (cp->dh_group_name)
1344ae771770SStanislav Sedov other = cp->dh_group_name;
1345c19800e8SDoug Rabson
1346c19800e8SDoug Rabson rep.element = choice_PA_PK_AS_REP_dhInfo;
1347c19800e8SDoug Rabson
1348ae771770SStanislav Sedov ret = generate_dh_keyblock(context, cp, enctype);
1349c19800e8SDoug Rabson if (ret)
1350c19800e8SDoug Rabson return ret;
1351c19800e8SDoug Rabson
1352ae771770SStanislav Sedov ret = pk_mk_pa_reply_dh(context, config,
1353ae771770SStanislav Sedov cp,
1354c19800e8SDoug Rabson &info,
1355c19800e8SDoug Rabson &kdc_cert);
1356ae771770SStanislav Sedov if (ret) {
1357ae771770SStanislav Sedov free_PA_PK_AS_REP(&rep);
1358ae771770SStanislav Sedov krb5_set_error_message(context, ret,
1359ae771770SStanislav Sedov "create pa-reply-dh "
1360ae771770SStanislav Sedov "failed %d", ret);
1361ae771770SStanislav Sedov goto out;
1362ae771770SStanislav Sedov }
1363c19800e8SDoug Rabson
1364c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(ContentInfo, rep.u.dhInfo.dhSignedData.data,
1365c19800e8SDoug Rabson rep.u.dhInfo.dhSignedData.length, &info, &size,
1366c19800e8SDoug Rabson ret);
1367c19800e8SDoug Rabson free_ContentInfo(&info);
1368c19800e8SDoug Rabson if (ret) {
1369ae771770SStanislav Sedov krb5_set_error_message(context, ret,
1370ae771770SStanislav Sedov "encoding of Key ContentInfo "
1371c19800e8SDoug Rabson "failed %d", ret);
1372c19800e8SDoug Rabson free_PA_PK_AS_REP(&rep);
1373c19800e8SDoug Rabson goto out;
1374c19800e8SDoug Rabson }
1375c19800e8SDoug Rabson if (rep.u.encKeyPack.length != size)
1376c19800e8SDoug Rabson krb5_abortx(context, "Internal ASN.1 encoder error");
1377c19800e8SDoug Rabson
1378ae771770SStanislav Sedov /* XXX KRB-FX-CF2 */
1379ae771770SStanislav Sedov ret = krb5_generate_random_keyblock(context, sessionetype,
1380ae771770SStanislav Sedov sessionkey);
1381c19800e8SDoug Rabson if (ret) {
1382c19800e8SDoug Rabson free_PA_PK_AS_REP(&rep);
1383c19800e8SDoug Rabson goto out;
1384c19800e8SDoug Rabson }
1385c19800e8SDoug Rabson
1386ae771770SStanislav Sedov /* XXX Add PA-PKINIT-KX */
1387ae771770SStanislav Sedov
1388ae771770SStanislav Sedov }
1389ae771770SStanislav Sedov
1390ae771770SStanislav Sedov #define use_btmm_with_enckey 0
1391ae771770SStanislav Sedov if (use_btmm_with_enckey && rep.element == choice_PA_PK_AS_REP_encKeyPack) {
1392ae771770SStanislav Sedov PA_PK_AS_REP_BTMM btmm;
1393ae771770SStanislav Sedov heim_any any;
1394ae771770SStanislav Sedov
1395ae771770SStanislav Sedov any.data = rep.u.encKeyPack.data;
1396ae771770SStanislav Sedov any.length = rep.u.encKeyPack.length;
1397ae771770SStanislav Sedov
1398ae771770SStanislav Sedov btmm.dhSignedData = NULL;
1399ae771770SStanislav Sedov btmm.encKeyPack = &any;
1400ae771770SStanislav Sedov
1401ae771770SStanislav Sedov ASN1_MALLOC_ENCODE(PA_PK_AS_REP_BTMM, buf, len, &btmm, &size, ret);
1402ae771770SStanislav Sedov } else {
1403c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret);
1404ae771770SStanislav Sedov }
1405ae771770SStanislav Sedov
1406c19800e8SDoug Rabson free_PA_PK_AS_REP(&rep);
1407c19800e8SDoug Rabson if (ret) {
1408ae771770SStanislav Sedov krb5_set_error_message(context, ret,
1409ae771770SStanislav Sedov "encode PA-PK-AS-REP failed %d", ret);
1410c19800e8SDoug Rabson goto out;
1411c19800e8SDoug Rabson }
1412c19800e8SDoug Rabson if (len != size)
1413c19800e8SDoug Rabson krb5_abortx(context, "Internal ASN.1 encoder error");
1414c19800e8SDoug Rabson
1415c19800e8SDoug Rabson kdc_log(context, config, 0, "PK-INIT using %s %s", type, other);
1416c19800e8SDoug Rabson
1417ae771770SStanislav Sedov } else if (cp->type == PKINIT_WIN2K) {
1418c19800e8SDoug Rabson PA_PK_AS_REP_Win2k rep;
1419c19800e8SDoug Rabson ContentInfo info;
1420c19800e8SDoug Rabson
1421ae771770SStanislav Sedov if (cp->keyex != USE_RSA) {
1422c19800e8SDoug Rabson ret = KRB5KRB_ERR_GENERIC;
1423ae771770SStanislav Sedov krb5_set_error_message(context, ret,
1424ae771770SStanislav Sedov "Windows PK-INIT doesn't support DH");
1425c19800e8SDoug Rabson goto out;
1426c19800e8SDoug Rabson }
1427c19800e8SDoug Rabson
1428c19800e8SDoug Rabson memset(&rep, 0, sizeof(rep));
1429c19800e8SDoug Rabson
1430c19800e8SDoug Rabson pa_type = KRB5_PADATA_PK_AS_REP_19;
1431ae771770SStanislav Sedov rep.element = choice_PA_PK_AS_REP_Win2k_encKeyPack;
1432c19800e8SDoug Rabson
1433c19800e8SDoug Rabson ret = krb5_generate_random_keyblock(context, enctype,
1434ae771770SStanislav Sedov &cp->reply_key);
1435c19800e8SDoug Rabson if (ret) {
1436c19800e8SDoug Rabson free_PA_PK_AS_REP_Win2k(&rep);
1437c19800e8SDoug Rabson goto out;
1438c19800e8SDoug Rabson }
1439c19800e8SDoug Rabson ret = pk_mk_pa_reply_enckey(context,
1440c19800e8SDoug Rabson config,
1441ae771770SStanislav Sedov cp,
1442c19800e8SDoug Rabson req,
1443c19800e8SDoug Rabson req_buffer,
1444ae771770SStanislav Sedov &cp->reply_key,
1445ae771770SStanislav Sedov &info,
1446ae771770SStanislav Sedov &kdc_cert);
1447c19800e8SDoug Rabson if (ret) {
1448c19800e8SDoug Rabson free_PA_PK_AS_REP_Win2k(&rep);
1449c19800e8SDoug Rabson goto out;
1450c19800e8SDoug Rabson }
1451c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data,
1452c19800e8SDoug Rabson rep.u.encKeyPack.length, &info, &size,
1453c19800e8SDoug Rabson ret);
1454c19800e8SDoug Rabson free_ContentInfo(&info);
1455c19800e8SDoug Rabson if (ret) {
1456ae771770SStanislav Sedov krb5_set_error_message(context, ret, "encoding of Key ContentInfo "
1457c19800e8SDoug Rabson "failed %d", ret);
1458c19800e8SDoug Rabson free_PA_PK_AS_REP_Win2k(&rep);
1459c19800e8SDoug Rabson goto out;
1460c19800e8SDoug Rabson }
1461c19800e8SDoug Rabson if (rep.u.encKeyPack.length != size)
1462c19800e8SDoug Rabson krb5_abortx(context, "Internal ASN.1 encoder error");
1463c19800e8SDoug Rabson
1464c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(PA_PK_AS_REP_Win2k, buf, len, &rep, &size, ret);
1465c19800e8SDoug Rabson free_PA_PK_AS_REP_Win2k(&rep);
1466c19800e8SDoug Rabson if (ret) {
1467ae771770SStanislav Sedov krb5_set_error_message(context, ret,
1468c19800e8SDoug Rabson "encode PA-PK-AS-REP-Win2k failed %d", ret);
1469c19800e8SDoug Rabson goto out;
1470c19800e8SDoug Rabson }
1471c19800e8SDoug Rabson if (len != size)
1472c19800e8SDoug Rabson krb5_abortx(context, "Internal ASN.1 encoder error");
1473c19800e8SDoug Rabson
1474ae771770SStanislav Sedov ret = krb5_generate_random_keyblock(context, sessionetype,
1475ae771770SStanislav Sedov sessionkey);
1476ae771770SStanislav Sedov if (ret) {
1477ae771770SStanislav Sedov free(buf);
1478ae771770SStanislav Sedov goto out;
1479ae771770SStanislav Sedov }
1480ae771770SStanislav Sedov
1481c19800e8SDoug Rabson } else
1482c19800e8SDoug Rabson krb5_abortx(context, "PK-INIT internal error");
1483c19800e8SDoug Rabson
1484c19800e8SDoug Rabson
1485c19800e8SDoug Rabson ret = krb5_padata_add(context, md, pa_type, buf, len);
1486c19800e8SDoug Rabson if (ret) {
1487ae771770SStanislav Sedov krb5_set_error_message(context, ret,
1488ae771770SStanislav Sedov "Failed adding PA-PK-AS-REP %d", ret);
1489c19800e8SDoug Rabson free(buf);
1490c19800e8SDoug Rabson goto out;
1491c19800e8SDoug Rabson }
1492c19800e8SDoug Rabson
1493c19800e8SDoug Rabson if (config->pkinit_kdc_ocsp_file) {
1494c19800e8SDoug Rabson
1495c19800e8SDoug Rabson if (ocsp.expire == 0 && ocsp.next_update > kdc_time) {
1496c19800e8SDoug Rabson struct stat sb;
1497c19800e8SDoug Rabson int fd;
1498c19800e8SDoug Rabson
1499c19800e8SDoug Rabson krb5_data_free(&ocsp.data);
1500c19800e8SDoug Rabson
1501c19800e8SDoug Rabson ocsp.expire = 0;
1502c19800e8SDoug Rabson ocsp.next_update = kdc_time + 60 * 5;
1503c19800e8SDoug Rabson
1504c19800e8SDoug Rabson fd = open(config->pkinit_kdc_ocsp_file, O_RDONLY);
1505c19800e8SDoug Rabson if (fd < 0) {
1506c19800e8SDoug Rabson kdc_log(context, config, 0,
1507c19800e8SDoug Rabson "PK-INIT failed to open ocsp data file %d", errno);
1508c19800e8SDoug Rabson goto out_ocsp;
1509c19800e8SDoug Rabson }
1510c19800e8SDoug Rabson ret = fstat(fd, &sb);
1511c19800e8SDoug Rabson if (ret) {
1512c19800e8SDoug Rabson ret = errno;
1513c19800e8SDoug Rabson close(fd);
1514c19800e8SDoug Rabson kdc_log(context, config, 0,
1515c19800e8SDoug Rabson "PK-INIT failed to stat ocsp data %d", ret);
1516c19800e8SDoug Rabson goto out_ocsp;
1517c19800e8SDoug Rabson }
1518c19800e8SDoug Rabson
1519c19800e8SDoug Rabson ret = krb5_data_alloc(&ocsp.data, sb.st_size);
1520c19800e8SDoug Rabson if (ret) {
1521c19800e8SDoug Rabson close(fd);
1522c19800e8SDoug Rabson kdc_log(context, config, 0,
1523c19800e8SDoug Rabson "PK-INIT failed to stat ocsp data %d", ret);
1524c19800e8SDoug Rabson goto out_ocsp;
1525c19800e8SDoug Rabson }
1526c19800e8SDoug Rabson ocsp.data.length = sb.st_size;
1527c19800e8SDoug Rabson ret = read(fd, ocsp.data.data, sb.st_size);
1528c19800e8SDoug Rabson close(fd);
1529c19800e8SDoug Rabson if (ret != sb.st_size) {
1530c19800e8SDoug Rabson kdc_log(context, config, 0,
1531c19800e8SDoug Rabson "PK-INIT failed to read ocsp data %d", errno);
1532c19800e8SDoug Rabson goto out_ocsp;
1533c19800e8SDoug Rabson }
1534c19800e8SDoug Rabson
1535ae771770SStanislav Sedov ret = hx509_ocsp_verify(context->hx509ctx,
1536c19800e8SDoug Rabson kdc_time,
1537c19800e8SDoug Rabson kdc_cert,
1538c19800e8SDoug Rabson 0,
1539c19800e8SDoug Rabson ocsp.data.data, ocsp.data.length,
1540c19800e8SDoug Rabson &ocsp.expire);
1541c19800e8SDoug Rabson if (ret) {
1542c19800e8SDoug Rabson kdc_log(context, config, 0,
1543c19800e8SDoug Rabson "PK-INIT failed to verify ocsp data %d", ret);
1544c19800e8SDoug Rabson krb5_data_free(&ocsp.data);
1545c19800e8SDoug Rabson ocsp.expire = 0;
1546c19800e8SDoug Rabson } else if (ocsp.expire > 180) {
1547c19800e8SDoug Rabson ocsp.expire -= 180; /* refetch the ocsp before it expire */
1548c19800e8SDoug Rabson ocsp.next_update = ocsp.expire;
1549c19800e8SDoug Rabson } else {
1550c19800e8SDoug Rabson ocsp.next_update = kdc_time;
1551c19800e8SDoug Rabson }
1552c19800e8SDoug Rabson out_ocsp:
1553c19800e8SDoug Rabson ret = 0;
1554c19800e8SDoug Rabson }
1555c19800e8SDoug Rabson
1556c19800e8SDoug Rabson if (ocsp.expire != 0 && ocsp.expire > kdc_time) {
1557c19800e8SDoug Rabson
1558c19800e8SDoug Rabson ret = krb5_padata_add(context, md,
1559c19800e8SDoug Rabson KRB5_PADATA_PA_PK_OCSP_RESPONSE,
1560c19800e8SDoug Rabson ocsp.data.data, ocsp.data.length);
1561c19800e8SDoug Rabson if (ret) {
1562ae771770SStanislav Sedov krb5_set_error_message(context, ret,
1563c19800e8SDoug Rabson "Failed adding OCSP response %d", ret);
1564c19800e8SDoug Rabson goto out;
1565c19800e8SDoug Rabson }
1566c19800e8SDoug Rabson }
1567c19800e8SDoug Rabson }
1568c19800e8SDoug Rabson
1569c19800e8SDoug Rabson out:
1570c19800e8SDoug Rabson if (kdc_cert)
1571c19800e8SDoug Rabson hx509_cert_free(kdc_cert);
1572c19800e8SDoug Rabson
1573c19800e8SDoug Rabson if (ret == 0)
1574ae771770SStanislav Sedov *reply_key = &cp->reply_key;
1575c19800e8SDoug Rabson return ret;
1576c19800e8SDoug Rabson }
1577c19800e8SDoug Rabson
1578c19800e8SDoug Rabson static int
match_rfc_san(krb5_context context,krb5_kdc_configuration * config,hx509_context hx509ctx,hx509_cert client_cert,krb5_const_principal match)1579c19800e8SDoug Rabson match_rfc_san(krb5_context context,
1580c19800e8SDoug Rabson krb5_kdc_configuration *config,
1581c19800e8SDoug Rabson hx509_context hx509ctx,
1582c19800e8SDoug Rabson hx509_cert client_cert,
1583c19800e8SDoug Rabson krb5_const_principal match)
1584c19800e8SDoug Rabson {
1585c19800e8SDoug Rabson hx509_octet_string_list list;
1586ae771770SStanislav Sedov int ret, found = 0;
1587ae771770SStanislav Sedov size_t i;
1588c19800e8SDoug Rabson
1589c19800e8SDoug Rabson memset(&list, 0 , sizeof(list));
1590c19800e8SDoug Rabson
1591c19800e8SDoug Rabson ret = hx509_cert_find_subjectAltName_otherName(hx509ctx,
1592c19800e8SDoug Rabson client_cert,
1593ae771770SStanislav Sedov &asn1_oid_id_pkinit_san,
1594c19800e8SDoug Rabson &list);
1595c19800e8SDoug Rabson if (ret)
1596c19800e8SDoug Rabson goto out;
1597c19800e8SDoug Rabson
1598c19800e8SDoug Rabson for (i = 0; !found && i < list.len; i++) {
1599c19800e8SDoug Rabson krb5_principal_data principal;
1600c19800e8SDoug Rabson KRB5PrincipalName kn;
1601c19800e8SDoug Rabson size_t size;
1602c19800e8SDoug Rabson
1603c19800e8SDoug Rabson ret = decode_KRB5PrincipalName(list.val[i].data,
1604c19800e8SDoug Rabson list.val[i].length,
1605c19800e8SDoug Rabson &kn, &size);
1606c19800e8SDoug Rabson if (ret) {
1607ae771770SStanislav Sedov const char *msg = krb5_get_error_message(context, ret);
1608c19800e8SDoug Rabson kdc_log(context, config, 0,
1609ae771770SStanislav Sedov "Decoding kerberos name in certificate failed: %s", msg);
1610ae771770SStanislav Sedov krb5_free_error_message(context, msg);
1611c19800e8SDoug Rabson break;
1612c19800e8SDoug Rabson }
1613c19800e8SDoug Rabson if (size != list.val[i].length) {
1614c19800e8SDoug Rabson kdc_log(context, config, 0,
1615c19800e8SDoug Rabson "Decoding kerberos name have extra bits on the end");
1616c19800e8SDoug Rabson return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1617c19800e8SDoug Rabson }
1618c19800e8SDoug Rabson
1619c19800e8SDoug Rabson principal.name = kn.principalName;
1620c19800e8SDoug Rabson principal.realm = kn.realm;
1621c19800e8SDoug Rabson
1622c19800e8SDoug Rabson if (krb5_principal_compare(context, &principal, match) == TRUE)
1623c19800e8SDoug Rabson found = 1;
1624c19800e8SDoug Rabson free_KRB5PrincipalName(&kn);
1625c19800e8SDoug Rabson }
1626c19800e8SDoug Rabson
1627c19800e8SDoug Rabson out:
1628c19800e8SDoug Rabson hx509_free_octet_string_list(&list);
1629c19800e8SDoug Rabson if (ret)
1630c19800e8SDoug Rabson return ret;
1631c19800e8SDoug Rabson
1632c19800e8SDoug Rabson if (!found)
1633c19800e8SDoug Rabson return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1634c19800e8SDoug Rabson
1635c19800e8SDoug Rabson return 0;
1636c19800e8SDoug Rabson }
1637c19800e8SDoug Rabson
1638c19800e8SDoug Rabson static int
match_ms_upn_san(krb5_context context,krb5_kdc_configuration * config,hx509_context hx509ctx,hx509_cert client_cert,HDB * clientdb,hdb_entry_ex * client)1639c19800e8SDoug Rabson match_ms_upn_san(krb5_context context,
1640c19800e8SDoug Rabson krb5_kdc_configuration *config,
1641c19800e8SDoug Rabson hx509_context hx509ctx,
1642c19800e8SDoug Rabson hx509_cert client_cert,
1643ae771770SStanislav Sedov HDB *clientdb,
1644ae771770SStanislav Sedov hdb_entry_ex *client)
1645c19800e8SDoug Rabson {
1646c19800e8SDoug Rabson hx509_octet_string_list list;
1647c19800e8SDoug Rabson krb5_principal principal = NULL;
1648ae771770SStanislav Sedov int ret;
1649c19800e8SDoug Rabson MS_UPN_SAN upn;
1650c19800e8SDoug Rabson size_t size;
1651c19800e8SDoug Rabson
1652c19800e8SDoug Rabson memset(&list, 0 , sizeof(list));
1653c19800e8SDoug Rabson
1654c19800e8SDoug Rabson ret = hx509_cert_find_subjectAltName_otherName(hx509ctx,
1655c19800e8SDoug Rabson client_cert,
1656ae771770SStanislav Sedov &asn1_oid_id_pkinit_ms_san,
1657c19800e8SDoug Rabson &list);
1658c19800e8SDoug Rabson if (ret)
1659c19800e8SDoug Rabson goto out;
1660c19800e8SDoug Rabson
1661c19800e8SDoug Rabson if (list.len != 1) {
1662c19800e8SDoug Rabson kdc_log(context, config, 0,
1663c19800e8SDoug Rabson "More then one PK-INIT MS UPN SAN");
1664c19800e8SDoug Rabson goto out;
1665c19800e8SDoug Rabson }
1666c19800e8SDoug Rabson
1667c19800e8SDoug Rabson ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length, &upn, &size);
1668c19800e8SDoug Rabson if (ret) {
1669c19800e8SDoug Rabson kdc_log(context, config, 0, "Decode of MS-UPN-SAN failed");
1670c19800e8SDoug Rabson goto out;
1671c19800e8SDoug Rabson }
1672ae771770SStanislav Sedov if (size != list.val[0].length) {
1673ae771770SStanislav Sedov free_MS_UPN_SAN(&upn);
1674ae771770SStanislav Sedov kdc_log(context, config, 0, "Trailing data in ");
1675ae771770SStanislav Sedov ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1676ae771770SStanislav Sedov goto out;
1677ae771770SStanislav Sedov }
1678c19800e8SDoug Rabson
1679c19800e8SDoug Rabson kdc_log(context, config, 0, "found MS UPN SAN: %s", upn);
1680c19800e8SDoug Rabson
1681c19800e8SDoug Rabson ret = krb5_parse_name(context, upn, &principal);
1682c19800e8SDoug Rabson free_MS_UPN_SAN(&upn);
1683c19800e8SDoug Rabson if (ret) {
1684c19800e8SDoug Rabson kdc_log(context, config, 0, "Failed to parse principal in MS UPN SAN");
1685c19800e8SDoug Rabson goto out;
1686c19800e8SDoug Rabson }
1687c19800e8SDoug Rabson
1688ae771770SStanislav Sedov if (clientdb->hdb_check_pkinit_ms_upn_match) {
1689ae771770SStanislav Sedov ret = clientdb->hdb_check_pkinit_ms_upn_match(context, clientdb, client, principal);
1690ae771770SStanislav Sedov } else {
1691ae771770SStanislav Sedov
1692c19800e8SDoug Rabson /*
1693ae771770SStanislav Sedov * This is very wrong, but will do for a fallback
1694c19800e8SDoug Rabson */
1695c19800e8SDoug Rabson strupr(principal->realm);
1696c19800e8SDoug Rabson
1697ae771770SStanislav Sedov if (krb5_principal_compare(context, principal, client->entry.principal) == FALSE)
1698ae771770SStanislav Sedov ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1699ae771770SStanislav Sedov }
1700c19800e8SDoug Rabson
1701c19800e8SDoug Rabson out:
1702c19800e8SDoug Rabson if (principal)
1703c19800e8SDoug Rabson krb5_free_principal(context, principal);
1704c19800e8SDoug Rabson hx509_free_octet_string_list(&list);
1705ae771770SStanislav Sedov
1706c19800e8SDoug Rabson return ret;
1707c19800e8SDoug Rabson }
1708c19800e8SDoug Rabson
1709c19800e8SDoug Rabson krb5_error_code
_kdc_pk_check_client(krb5_context context,krb5_kdc_configuration * config,HDB * clientdb,hdb_entry_ex * client,pk_client_params * cp,char ** subject_name)1710c19800e8SDoug Rabson _kdc_pk_check_client(krb5_context context,
1711c19800e8SDoug Rabson krb5_kdc_configuration *config,
1712ae771770SStanislav Sedov HDB *clientdb,
1713ae771770SStanislav Sedov hdb_entry_ex *client,
1714ae771770SStanislav Sedov pk_client_params *cp,
1715c19800e8SDoug Rabson char **subject_name)
1716c19800e8SDoug Rabson {
1717c19800e8SDoug Rabson const HDB_Ext_PKINIT_acl *acl;
1718ae771770SStanislav Sedov const HDB_Ext_PKINIT_cert *pc;
1719c19800e8SDoug Rabson krb5_error_code ret;
1720c19800e8SDoug Rabson hx509_name name;
1721ae771770SStanislav Sedov size_t i;
1722c19800e8SDoug Rabson
1723ae771770SStanislav Sedov if (cp->cert == NULL) {
1724ae771770SStanislav Sedov
1725ae771770SStanislav Sedov *subject_name = strdup("anonymous client client");
1726ae771770SStanislav Sedov if (*subject_name == NULL)
1727ae771770SStanislav Sedov return ENOMEM;
1728ae771770SStanislav Sedov return 0;
1729ae771770SStanislav Sedov }
1730ae771770SStanislav Sedov
1731ae771770SStanislav Sedov ret = hx509_cert_get_base_subject(context->hx509ctx,
1732ae771770SStanislav Sedov cp->cert,
1733c19800e8SDoug Rabson &name);
1734c19800e8SDoug Rabson if (ret)
1735c19800e8SDoug Rabson return ret;
1736c19800e8SDoug Rabson
1737c19800e8SDoug Rabson ret = hx509_name_to_string(name, subject_name);
1738c19800e8SDoug Rabson hx509_name_free(&name);
1739c19800e8SDoug Rabson if (ret)
1740c19800e8SDoug Rabson return ret;
1741c19800e8SDoug Rabson
1742c19800e8SDoug Rabson kdc_log(context, config, 0,
1743c19800e8SDoug Rabson "Trying to authorize PK-INIT subject DN %s",
1744c19800e8SDoug Rabson *subject_name);
1745c19800e8SDoug Rabson
1746ae771770SStanislav Sedov ret = hdb_entry_get_pkinit_cert(&client->entry, &pc);
1747ae771770SStanislav Sedov if (ret == 0 && pc) {
1748ae771770SStanislav Sedov hx509_cert cert;
1749ae771770SStanislav Sedov size_t j;
1750ae771770SStanislav Sedov
1751ae771770SStanislav Sedov for (j = 0; j < pc->len; j++) {
1752ae771770SStanislav Sedov ret = hx509_cert_init_data(context->hx509ctx,
1753ae771770SStanislav Sedov pc->val[j].cert.data,
1754ae771770SStanislav Sedov pc->val[j].cert.length,
1755ae771770SStanislav Sedov &cert);
1756ae771770SStanislav Sedov if (ret)
1757ae771770SStanislav Sedov continue;
1758ae771770SStanislav Sedov ret = hx509_cert_cmp(cert, cp->cert);
1759ae771770SStanislav Sedov hx509_cert_free(cert);
1760ae771770SStanislav Sedov if (ret == 0) {
1761ae771770SStanislav Sedov kdc_log(context, config, 5,
1762ae771770SStanislav Sedov "Found matching PK-INIT cert in hdb");
1763ae771770SStanislav Sedov return 0;
1764ae771770SStanislav Sedov }
1765ae771770SStanislav Sedov }
1766ae771770SStanislav Sedov }
1767ae771770SStanislav Sedov
1768ae771770SStanislav Sedov
1769c19800e8SDoug Rabson if (config->pkinit_princ_in_cert) {
1770c19800e8SDoug Rabson ret = match_rfc_san(context, config,
1771ae771770SStanislav Sedov context->hx509ctx,
1772ae771770SStanislav Sedov cp->cert,
1773c19800e8SDoug Rabson client->entry.principal);
1774c19800e8SDoug Rabson if (ret == 0) {
1775c19800e8SDoug Rabson kdc_log(context, config, 5,
1776c19800e8SDoug Rabson "Found matching PK-INIT SAN in certificate");
1777c19800e8SDoug Rabson return 0;
1778c19800e8SDoug Rabson }
1779c19800e8SDoug Rabson ret = match_ms_upn_san(context, config,
1780ae771770SStanislav Sedov context->hx509ctx,
1781ae771770SStanislav Sedov cp->cert,
1782ae771770SStanislav Sedov clientdb,
1783ae771770SStanislav Sedov client);
1784c19800e8SDoug Rabson if (ret == 0) {
1785c19800e8SDoug Rabson kdc_log(context, config, 5,
1786c19800e8SDoug Rabson "Found matching MS UPN SAN in certificate");
1787c19800e8SDoug Rabson return 0;
1788c19800e8SDoug Rabson }
1789c19800e8SDoug Rabson }
1790c19800e8SDoug Rabson
1791c19800e8SDoug Rabson ret = hdb_entry_get_pkinit_acl(&client->entry, &acl);
1792c19800e8SDoug Rabson if (ret == 0 && acl != NULL) {
1793c19800e8SDoug Rabson /*
1794c19800e8SDoug Rabson * Cheat here and compare the generated name with the string
1795c19800e8SDoug Rabson * and not the reverse.
1796c19800e8SDoug Rabson */
1797c19800e8SDoug Rabson for (i = 0; i < acl->len; i++) {
1798c19800e8SDoug Rabson if (strcmp(*subject_name, acl->val[0].subject) != 0)
1799c19800e8SDoug Rabson continue;
1800c19800e8SDoug Rabson
1801c19800e8SDoug Rabson /* Don't support isser and anchor checking right now */
1802c19800e8SDoug Rabson if (acl->val[0].issuer)
1803c19800e8SDoug Rabson continue;
1804c19800e8SDoug Rabson if (acl->val[0].anchor)
1805c19800e8SDoug Rabson continue;
1806c19800e8SDoug Rabson
1807c19800e8SDoug Rabson kdc_log(context, config, 5,
1808c19800e8SDoug Rabson "Found matching PK-INIT database ACL");
1809c19800e8SDoug Rabson return 0;
1810c19800e8SDoug Rabson }
1811c19800e8SDoug Rabson }
1812c19800e8SDoug Rabson
1813c19800e8SDoug Rabson for (i = 0; i < principal_mappings.len; i++) {
1814c19800e8SDoug Rabson krb5_boolean b;
1815c19800e8SDoug Rabson
1816c19800e8SDoug Rabson b = krb5_principal_compare(context,
1817c19800e8SDoug Rabson client->entry.principal,
1818c19800e8SDoug Rabson principal_mappings.val[i].principal);
1819c19800e8SDoug Rabson if (b == FALSE)
1820c19800e8SDoug Rabson continue;
1821c19800e8SDoug Rabson if (strcmp(principal_mappings.val[i].subject, *subject_name) != 0)
1822c19800e8SDoug Rabson continue;
1823c19800e8SDoug Rabson kdc_log(context, config, 5,
1824c19800e8SDoug Rabson "Found matching PK-INIT FILE ACL");
1825c19800e8SDoug Rabson return 0;
1826c19800e8SDoug Rabson }
1827c19800e8SDoug Rabson
1828ae771770SStanislav Sedov ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1829ae771770SStanislav Sedov krb5_set_error_message(context, ret,
1830c19800e8SDoug Rabson "PKINIT no matching principals for %s",
1831c19800e8SDoug Rabson *subject_name);
1832c19800e8SDoug Rabson
1833c19800e8SDoug Rabson kdc_log(context, config, 5,
1834c19800e8SDoug Rabson "PKINIT no matching principals for %s",
1835c19800e8SDoug Rabson *subject_name);
1836c19800e8SDoug Rabson
1837c19800e8SDoug Rabson free(*subject_name);
1838c19800e8SDoug Rabson *subject_name = NULL;
1839c19800e8SDoug Rabson
1840ae771770SStanislav Sedov return ret;
1841c19800e8SDoug Rabson }
1842c19800e8SDoug Rabson
1843c19800e8SDoug Rabson static krb5_error_code
add_principal_mapping(krb5_context context,const char * principal_name,const char * subject)1844c19800e8SDoug Rabson add_principal_mapping(krb5_context context,
1845c19800e8SDoug Rabson const char *principal_name,
1846c19800e8SDoug Rabson const char * subject)
1847c19800e8SDoug Rabson {
1848c19800e8SDoug Rabson struct pk_allowed_princ *tmp;
1849c19800e8SDoug Rabson krb5_principal principal;
1850c19800e8SDoug Rabson krb5_error_code ret;
1851c19800e8SDoug Rabson
1852c19800e8SDoug Rabson tmp = realloc(principal_mappings.val,
1853c19800e8SDoug Rabson (principal_mappings.len + 1) * sizeof(*tmp));
1854c19800e8SDoug Rabson if (tmp == NULL)
1855c19800e8SDoug Rabson return ENOMEM;
1856c19800e8SDoug Rabson principal_mappings.val = tmp;
1857c19800e8SDoug Rabson
1858c19800e8SDoug Rabson ret = krb5_parse_name(context, principal_name, &principal);
1859c19800e8SDoug Rabson if (ret)
1860c19800e8SDoug Rabson return ret;
1861c19800e8SDoug Rabson
1862c19800e8SDoug Rabson principal_mappings.val[principal_mappings.len].principal = principal;
1863c19800e8SDoug Rabson
1864c19800e8SDoug Rabson principal_mappings.val[principal_mappings.len].subject = strdup(subject);
1865c19800e8SDoug Rabson if (principal_mappings.val[principal_mappings.len].subject == NULL) {
1866c19800e8SDoug Rabson krb5_free_principal(context, principal);
1867c19800e8SDoug Rabson return ENOMEM;
1868c19800e8SDoug Rabson }
1869c19800e8SDoug Rabson principal_mappings.len++;
1870c19800e8SDoug Rabson
1871c19800e8SDoug Rabson return 0;
1872c19800e8SDoug Rabson }
1873c19800e8SDoug Rabson
1874c19800e8SDoug Rabson krb5_error_code
_kdc_add_inital_verified_cas(krb5_context context,krb5_kdc_configuration * config,pk_client_params * cp,EncTicketPart * tkt)1875c19800e8SDoug Rabson _kdc_add_inital_verified_cas(krb5_context context,
1876c19800e8SDoug Rabson krb5_kdc_configuration *config,
1877ae771770SStanislav Sedov pk_client_params *cp,
1878c19800e8SDoug Rabson EncTicketPart *tkt)
1879c19800e8SDoug Rabson {
1880c19800e8SDoug Rabson AD_INITIAL_VERIFIED_CAS cas;
1881c19800e8SDoug Rabson krb5_error_code ret;
1882c19800e8SDoug Rabson krb5_data data;
1883ae771770SStanislav Sedov size_t size = 0;
1884c19800e8SDoug Rabson
1885c19800e8SDoug Rabson memset(&cas, 0, sizeof(cas));
1886c19800e8SDoug Rabson
1887c19800e8SDoug Rabson /* XXX add CAs to cas here */
1888c19800e8SDoug Rabson
1889c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(AD_INITIAL_VERIFIED_CAS, data.data, data.length,
1890c19800e8SDoug Rabson &cas, &size, ret);
1891c19800e8SDoug Rabson if (ret)
1892c19800e8SDoug Rabson return ret;
1893c19800e8SDoug Rabson if (data.length != size)
1894c19800e8SDoug Rabson krb5_abortx(context, "internal asn.1 encoder error");
1895c19800e8SDoug Rabson
1896c19800e8SDoug Rabson ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
1897c19800e8SDoug Rabson KRB5_AUTHDATA_INITIAL_VERIFIED_CAS,
1898c19800e8SDoug Rabson &data);
1899c19800e8SDoug Rabson krb5_data_free(&data);
1900c19800e8SDoug Rabson return ret;
1901c19800e8SDoug Rabson }
1902c19800e8SDoug Rabson
1903c19800e8SDoug Rabson /*
1904c19800e8SDoug Rabson *
1905c19800e8SDoug Rabson */
1906c19800e8SDoug Rabson
1907c19800e8SDoug Rabson static void
load_mappings(krb5_context context,const char * fn)1908c19800e8SDoug Rabson load_mappings(krb5_context context, const char *fn)
1909c19800e8SDoug Rabson {
1910c19800e8SDoug Rabson krb5_error_code ret;
1911c19800e8SDoug Rabson char buf[1024];
1912c19800e8SDoug Rabson unsigned long lineno = 0;
1913c19800e8SDoug Rabson FILE *f;
1914c19800e8SDoug Rabson
1915c19800e8SDoug Rabson f = fopen(fn, "r");
1916c19800e8SDoug Rabson if (f == NULL)
1917c19800e8SDoug Rabson return;
1918c19800e8SDoug Rabson
1919c19800e8SDoug Rabson while (fgets(buf, sizeof(buf), f) != NULL) {
1920c19800e8SDoug Rabson char *subject_name, *p;
1921c19800e8SDoug Rabson
1922c19800e8SDoug Rabson buf[strcspn(buf, "\n")] = '\0';
1923c19800e8SDoug Rabson lineno++;
1924c19800e8SDoug Rabson
1925c19800e8SDoug Rabson p = buf + strspn(buf, " \t");
1926c19800e8SDoug Rabson
1927c19800e8SDoug Rabson if (*p == '#' || *p == '\0')
1928c19800e8SDoug Rabson continue;
1929c19800e8SDoug Rabson
1930c19800e8SDoug Rabson subject_name = strchr(p, ':');
1931c19800e8SDoug Rabson if (subject_name == NULL) {
1932c19800e8SDoug Rabson krb5_warnx(context, "pkinit mapping file line %lu "
1933c19800e8SDoug Rabson "missing \":\" :%s",
1934c19800e8SDoug Rabson lineno, buf);
1935c19800e8SDoug Rabson continue;
1936c19800e8SDoug Rabson }
1937c19800e8SDoug Rabson *subject_name++ = '\0';
1938c19800e8SDoug Rabson
1939c19800e8SDoug Rabson ret = add_principal_mapping(context, p, subject_name);
1940c19800e8SDoug Rabson if (ret) {
1941c19800e8SDoug Rabson krb5_warn(context, ret, "failed to add line %lu \":\" :%s\n",
1942c19800e8SDoug Rabson lineno, buf);
1943c19800e8SDoug Rabson continue;
1944c19800e8SDoug Rabson }
1945c19800e8SDoug Rabson }
1946c19800e8SDoug Rabson
1947c19800e8SDoug Rabson fclose(f);
1948c19800e8SDoug Rabson }
1949c19800e8SDoug Rabson
1950c19800e8SDoug Rabson /*
1951c19800e8SDoug Rabson *
1952c19800e8SDoug Rabson */
1953c19800e8SDoug Rabson
1954c19800e8SDoug Rabson krb5_error_code
krb5_kdc_pk_initialize(krb5_context context,krb5_kdc_configuration * config,const char * user_id,const char * anchors,char ** pool,char ** revoke_list)1955ae771770SStanislav Sedov krb5_kdc_pk_initialize(krb5_context context,
1956c19800e8SDoug Rabson krb5_kdc_configuration *config,
1957c19800e8SDoug Rabson const char *user_id,
1958c19800e8SDoug Rabson const char *anchors,
1959c19800e8SDoug Rabson char **pool,
1960c19800e8SDoug Rabson char **revoke_list)
1961c19800e8SDoug Rabson {
1962c19800e8SDoug Rabson const char *file;
1963c19800e8SDoug Rabson char *fn = NULL;
1964c19800e8SDoug Rabson krb5_error_code ret;
1965c19800e8SDoug Rabson
1966c19800e8SDoug Rabson file = krb5_config_get_string(context, NULL,
1967c19800e8SDoug Rabson "libdefaults", "moduli", NULL);
1968c19800e8SDoug Rabson
1969c19800e8SDoug Rabson ret = _krb5_parse_moduli(context, file, &moduli);
1970c19800e8SDoug Rabson if (ret)
1971c19800e8SDoug Rabson krb5_err(context, 1, ret, "PKINIT: failed to load modidi file");
1972c19800e8SDoug Rabson
1973c19800e8SDoug Rabson principal_mappings.len = 0;
1974c19800e8SDoug Rabson principal_mappings.val = NULL;
1975c19800e8SDoug Rabson
1976c19800e8SDoug Rabson ret = _krb5_pk_load_id(context,
1977c19800e8SDoug Rabson &kdc_identity,
1978c19800e8SDoug Rabson user_id,
1979c19800e8SDoug Rabson anchors,
1980c19800e8SDoug Rabson pool,
1981c19800e8SDoug Rabson revoke_list,
1982c19800e8SDoug Rabson NULL,
1983c19800e8SDoug Rabson NULL,
1984c19800e8SDoug Rabson NULL);
1985c19800e8SDoug Rabson if (ret) {
1986c19800e8SDoug Rabson krb5_warn(context, ret, "PKINIT: ");
1987c19800e8SDoug Rabson config->enable_pkinit = 0;
1988c19800e8SDoug Rabson return ret;
1989c19800e8SDoug Rabson }
1990c19800e8SDoug Rabson
1991c19800e8SDoug Rabson {
1992c19800e8SDoug Rabson hx509_query *q;
1993c19800e8SDoug Rabson hx509_cert cert;
1994c19800e8SDoug Rabson
1995ae771770SStanislav Sedov ret = hx509_query_alloc(context->hx509ctx, &q);
1996c19800e8SDoug Rabson if (ret) {
1997c19800e8SDoug Rabson krb5_warnx(context, "PKINIT: out of memory");
1998c19800e8SDoug Rabson return ENOMEM;
1999c19800e8SDoug Rabson }
2000c19800e8SDoug Rabson
2001c19800e8SDoug Rabson hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
2002ae771770SStanislav Sedov if (config->pkinit_kdc_friendly_name)
2003ae771770SStanislav Sedov hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);
2004c19800e8SDoug Rabson
2005ae771770SStanislav Sedov ret = hx509_certs_find(context->hx509ctx,
2006c19800e8SDoug Rabson kdc_identity->certs,
2007c19800e8SDoug Rabson q,
2008c19800e8SDoug Rabson &cert);
2009ae771770SStanislav Sedov hx509_query_free(context->hx509ctx, q);
2010c19800e8SDoug Rabson if (ret == 0) {
2011ae771770SStanislav Sedov if (hx509_cert_check_eku(context->hx509ctx, cert,
2012ae771770SStanislav Sedov &asn1_oid_id_pkkdcekuoid, 0)) {
2013ae771770SStanislav Sedov hx509_name name;
2014ae771770SStanislav Sedov char *str;
2015ae771770SStanislav Sedov ret = hx509_cert_get_subject(cert, &name);
2016ae771770SStanislav Sedov if (ret == 0) {
2017ae771770SStanislav Sedov hx509_name_to_string(name, &str);
2018ae771770SStanislav Sedov krb5_warnx(context, "WARNING Found KDC certificate (%s)"
2019c19800e8SDoug Rabson "is missing the PK-INIT KDC EKU, this is bad for "
2020ae771770SStanislav Sedov "interoperability.", str);
2021ae771770SStanislav Sedov hx509_name_free(&name);
2022ae771770SStanislav Sedov free(str);
2023ae771770SStanislav Sedov }
2024ae771770SStanislav Sedov }
2025c19800e8SDoug Rabson hx509_cert_free(cert);
2026c19800e8SDoug Rabson } else
2027c19800e8SDoug Rabson krb5_warnx(context, "PKINIT: failed to find a signing "
2028c19800e8SDoug Rabson "certifiate with a public key");
2029c19800e8SDoug Rabson }
2030c19800e8SDoug Rabson
2031ae771770SStanislav Sedov if (krb5_config_get_bool_default(context,
2032c19800e8SDoug Rabson NULL,
2033c19800e8SDoug Rabson FALSE,
2034c19800e8SDoug Rabson "kdc",
2035c19800e8SDoug Rabson "pkinit_allow_proxy_certificate",
2036ae771770SStanislav Sedov NULL))
2037ae771770SStanislav Sedov config->pkinit_allow_proxy_certs = 1;
2038c19800e8SDoug Rabson
2039c19800e8SDoug Rabson file = krb5_config_get_string(context,
2040c19800e8SDoug Rabson NULL,
2041c19800e8SDoug Rabson "kdc",
2042c19800e8SDoug Rabson "pkinit_mappings_file",
2043c19800e8SDoug Rabson NULL);
2044c19800e8SDoug Rabson if (file == NULL) {
2045c19800e8SDoug Rabson asprintf(&fn, "%s/pki-mapping", hdb_db_dir(context));
2046c19800e8SDoug Rabson file = fn;
2047c19800e8SDoug Rabson }
2048c19800e8SDoug Rabson
2049c19800e8SDoug Rabson load_mappings(context, file);
2050c19800e8SDoug Rabson if (fn)
2051c19800e8SDoug Rabson free(fn);
2052c19800e8SDoug Rabson
2053c19800e8SDoug Rabson return 0;
2054c19800e8SDoug Rabson }
2055c19800e8SDoug Rabson
2056c19800e8SDoug Rabson #endif /* PKINIT */
2057