x
[heimdal.git] / kdc / pkinit.c
blobe26d7b8fc589cce0a8e9b70e45773a53fac06cf8
1 /*
2 * Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "kdc_locl.h"
36 RCSID("$Id$");
38 #ifdef PKINIT
40 #include <heim_asn1.h>
41 #include <rfc2459_asn1.h>
42 #include <cms_asn1.h>
43 #include <pkinit_asn1.h>
45 #include <hx509.h>
46 #include "crypto-headers.h"
48 struct pk_client_params {
49 enum krb5_pk_type type;
50 BIGNUM *dh_public_key;
51 hx509_cert cert;
52 unsigned nonce;
53 DH *dh;
54 EncryptionKey reply_key;
55 char *dh_group_name;
56 hx509_peer_info peer;
57 hx509_certs client_anchors;
60 struct pk_principal_mapping {
61 unsigned int len;
62 struct pk_allowed_princ {
63 krb5_principal principal;
64 char *subject;
65 } *val;
68 static struct krb5_pk_identity *kdc_identity;
69 static struct pk_principal_mapping principal_mappings;
70 static struct krb5_dh_moduli **moduli;
72 static struct {
73 krb5_data data;
74 time_t expire;
75 time_t next_update;
76 } ocsp;
82 static krb5_error_code
83 pk_check_pkauthenticator_win2k(krb5_context context,
84 PKAuthenticator_Win2k *a,
85 const KDC_REQ *req)
87 krb5_timestamp now;
89 krb5_timeofday (context, &now);
91 /* XXX cusec */
92 if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) {
93 krb5_clear_error_string(context);
94 return KRB5KRB_AP_ERR_SKEW;
96 return 0;
99 static krb5_error_code
100 pk_check_pkauthenticator(krb5_context context,
101 PKAuthenticator *a,
102 const KDC_REQ *req)
104 u_char *buf = NULL;
105 size_t buf_size;
106 krb5_error_code ret;
107 size_t len;
108 krb5_timestamp now;
109 Checksum checksum;
111 krb5_timeofday (context, &now);
113 /* XXX cusec */
114 if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) {
115 krb5_clear_error_string(context);
116 return KRB5KRB_AP_ERR_SKEW;
119 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, &req->req_body, &len, ret);
120 if (ret) {
121 krb5_clear_error_string(context);
122 return ret;
124 if (buf_size != len)
125 krb5_abortx(context, "Internal error in ASN.1 encoder");
127 ret = krb5_create_checksum(context,
128 NULL,
130 CKSUMTYPE_SHA1,
131 buf,
132 len,
133 &checksum);
134 free(buf);
135 if (ret) {
136 krb5_clear_error_string(context);
137 return ret;
140 if (a->paChecksum == NULL) {
141 krb5_clear_error_string(context);
142 ret = KRB5_KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
143 goto out;
146 if (der_heim_octet_string_cmp(a->paChecksum, &checksum.checksum) != 0) {
147 krb5_clear_error_string(context);
148 ret = KRB5KRB_ERR_GENERIC;
151 out:
152 free_Checksum(&checksum);
154 return ret;
157 void
158 _kdc_pk_free_client_param(krb5_context context,
159 pk_client_params *client_params)
161 if (client_params->cert)
162 hx509_cert_free(client_params->cert);
163 if (client_params->dh)
164 DH_free(client_params->dh);
165 if (client_params->dh_public_key)
166 BN_free(client_params->dh_public_key);
167 krb5_free_keyblock_contents(context, &client_params->reply_key);
168 if (client_params->dh_group_name)
169 free(client_params->dh_group_name);
170 if (client_params->peer)
171 hx509_peer_info_free(client_params->peer);
172 if (client_params->client_anchors)
173 hx509_certs_free(&client_params->client_anchors);
174 memset(client_params, 0, sizeof(*client_params));
175 free(client_params);
178 static krb5_error_code
179 generate_dh_keyblock(krb5_context context, pk_client_params *client_params,
180 krb5_enctype enctype, krb5_keyblock *reply_key)
182 unsigned char *dh_gen_key = NULL;
183 krb5_keyblock key;
184 krb5_error_code ret;
185 size_t dh_gen_keylen, size;
187 memset(&key, 0, sizeof(key));
189 if (!DH_generate_key(client_params->dh)) {
190 krb5_set_error_string(context, "Can't generate Diffie-Hellman keys");
191 ret = KRB5KRB_ERR_GENERIC;
192 goto out;
194 if (client_params->dh_public_key == NULL) {
195 krb5_set_error_string(context, "dh_public_key");
196 ret = KRB5KRB_ERR_GENERIC;
197 goto out;
200 dh_gen_keylen = DH_size(client_params->dh);
201 size = BN_num_bytes(client_params->dh->p);
202 if (size < dh_gen_keylen)
203 size = dh_gen_keylen;
205 dh_gen_key = malloc(size);
206 if (dh_gen_key == NULL) {
207 krb5_set_error_string(context, "malloc: out of memory");
208 ret = ENOMEM;
209 goto out;
211 memset(dh_gen_key, 0, size - dh_gen_keylen);
213 dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen),
214 client_params->dh_public_key,
215 client_params->dh);
216 if (dh_gen_keylen == -1) {
217 krb5_set_error_string(context, "Can't compute Diffie-Hellman key");
218 ret = KRB5KRB_ERR_GENERIC;
219 goto out;
222 ret = _krb5_pk_octetstring2key(context,
223 enctype,
224 dh_gen_key, dh_gen_keylen,
225 NULL, NULL,
226 reply_key);
228 out:
229 if (dh_gen_key)
230 free(dh_gen_key);
231 if (key.keyvalue.data)
232 krb5_free_keyblock_contents(context, &key);
234 return ret;
237 static BIGNUM *
238 integer_to_BN(krb5_context context, const char *field, heim_integer *f)
240 BIGNUM *bn;
242 bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL);
243 if (bn == NULL) {
244 krb5_set_error_string(context, "PKINIT: parsing BN failed %s", field);
245 return NULL;
247 BN_set_negative(bn, f->negative);
248 return bn;
251 static krb5_error_code
252 get_dh_param(krb5_context context,
253 krb5_kdc_configuration *config,
254 SubjectPublicKeyInfo *dh_key_info,
255 pk_client_params *client_params)
257 DomainParameters dhparam;
258 DH *dh = NULL;
259 krb5_error_code ret;
261 memset(&dhparam, 0, sizeof(dhparam));
263 if (der_heim_oid_cmp(&dh_key_info->algorithm.algorithm, oid_id_dhpublicnumber())) {
264 krb5_set_error_string(context,
265 "PKINIT invalid oid in clientPublicValue");
266 return KRB5_BADMSGTYPE;
269 if (dh_key_info->algorithm.parameters == NULL) {
270 krb5_set_error_string(context, "PKINIT missing algorithm parameter "
271 "in clientPublicValue");
272 return KRB5_BADMSGTYPE;
275 ret = decode_DomainParameters(dh_key_info->algorithm.parameters->data,
276 dh_key_info->algorithm.parameters->length,
277 &dhparam,
278 NULL);
279 if (ret) {
280 krb5_set_error_string(context, "Can't decode algorithm "
281 "parameters in clientPublicValue");
282 goto out;
285 if ((dh_key_info->subjectPublicKey.length % 8) != 0) {
286 ret = KRB5_BADMSGTYPE;
287 krb5_set_error_string(context, "PKINIT: subjectPublicKey not aligned "
288 "to 8 bit boundary");
289 goto out;
293 ret = _krb5_dh_group_ok(context, config->pkinit_dh_min_bits,
294 &dhparam.p, &dhparam.g, &dhparam.q, moduli,
295 &client_params->dh_group_name);
296 if (ret) {
297 /* XXX send back proposal of better group */
298 goto out;
301 dh = DH_new();
302 if (dh == NULL) {
303 krb5_set_error_string(context, "Cannot create DH structure");
304 ret = ENOMEM;
305 goto out;
307 ret = KRB5_BADMSGTYPE;
308 dh->p = integer_to_BN(context, "DH prime", &dhparam.p);
309 if (dh->p == NULL)
310 goto out;
311 dh->g = integer_to_BN(context, "DH base", &dhparam.g);
312 if (dh->g == NULL)
313 goto out;
314 dh->q = integer_to_BN(context, "DH p-1 factor", &dhparam.q);
315 if (dh->g == NULL)
316 goto out;
319 heim_integer glue;
320 size_t size;
322 ret = decode_DHPublicKey(dh_key_info->subjectPublicKey.data,
323 dh_key_info->subjectPublicKey.length / 8,
324 &glue,
325 &size);
326 if (ret) {
327 krb5_clear_error_string(context);
328 return ret;
331 client_params->dh_public_key = integer_to_BN(context,
332 "subjectPublicKey",
333 &glue);
334 der_free_heim_integer(&glue);
335 if (client_params->dh_public_key == NULL)
336 goto out;
339 client_params->dh = dh;
340 dh = NULL;
341 ret = 0;
343 out:
344 if (dh)
345 DH_free(dh);
346 free_DomainParameters(&dhparam);
347 return ret;
350 krb5_error_code
351 _kdc_pk_rd_padata(krb5_context context,
352 krb5_kdc_configuration *config,
353 const KDC_REQ *req,
354 const PA_DATA *pa,
355 pk_client_params **ret_params)
357 pk_client_params *client_params;
358 krb5_error_code ret;
359 heim_oid eContentType = { 0, NULL }, contentInfoOid = { 0, NULL };
360 krb5_data eContent = { 0, NULL };
361 krb5_data signed_content = { 0, NULL };
362 const char *type = "unknown type";
363 int have_data = 0;
365 *ret_params = NULL;
367 if (!config->enable_pkinit) {
368 kdc_log(context, config, 0, "PK-INIT request but PK-INIT not enabled");
369 krb5_clear_error_string(context);
370 return 0;
373 hx509_verify_set_time(kdc_identity->verify_ctx, _kdc_now.tv_sec);
375 client_params = calloc(1, sizeof(*client_params));
376 if (client_params == NULL) {
377 krb5_clear_error_string(context);
378 ret = ENOMEM;
379 goto out;
382 if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
383 PA_PK_AS_REQ_Win2k r;
385 type = "PK-INIT-Win2k";
387 ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data,
388 pa->padata_value.length,
390 NULL);
391 if (ret) {
392 krb5_set_error_string(context, "Can't decode "
393 "PK-AS-REQ-Win2k: %d", ret);
394 goto out;
397 ret = hx509_cms_unwrap_ContentInfo(&r.signed_auth_pack,
398 &contentInfoOid,
399 &signed_content,
400 &have_data);
401 free_PA_PK_AS_REQ_Win2k(&r);
402 if (ret) {
403 krb5_set_error_string(context, "Can't decode PK-AS-REQ: %d", ret);
404 goto out;
407 } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
408 PA_PK_AS_REQ r;
410 type = "PK-INIT-IETF";
412 ret = decode_PA_PK_AS_REQ(pa->padata_value.data,
413 pa->padata_value.length,
415 NULL);
416 if (ret) {
417 krb5_set_error_string(context, "Can't decode PK-AS-REQ: %d", ret);
418 goto out;
421 /* XXX look at r.kdcPkId */
422 if (r.trustedCertifiers) {
423 ExternalPrincipalIdentifiers *edi = r.trustedCertifiers;
424 unsigned int i;
426 ret = hx509_certs_init(kdc_identity->hx509ctx,
427 "MEMORY:client-anchors",
428 0, NULL,
429 &client_params->client_anchors);
430 if (ret) {
431 krb5_set_error_string(context, "Can't allocate client anchors: %d", ret);
432 goto out;
435 for (i = 0; i < edi->len; i++) {
436 IssuerAndSerialNumber iasn;
437 hx509_query *q;
438 hx509_cert cert;
439 size_t size;
441 if (edi->val[i].issuerAndSerialNumber == NULL)
442 continue;
444 ret = hx509_query_alloc(kdc_identity->hx509ctx, &q);
445 if (ret) {
446 krb5_set_error_string(context,
447 "Failed to allocate hx509_query");
448 goto out;
451 ret = decode_IssuerAndSerialNumber(edi->val[i].issuerAndSerialNumber->data,
452 edi->val[i].issuerAndSerialNumber->length,
453 &iasn,
454 &size);
455 if (ret) {
456 hx509_query_free(kdc_identity->hx509ctx, q);
457 continue;
459 ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber);
460 free_IssuerAndSerialNumber(&iasn);
461 if (ret)
462 continue;
464 ret = hx509_certs_find(kdc_identity->hx509ctx,
465 kdc_identity->certs,
467 &cert);
468 hx509_query_free(kdc_identity->hx509ctx, q);
469 if (ret)
470 continue;
471 hx509_certs_add(kdc_identity->hx509ctx,
472 client_params->client_anchors, cert);
473 hx509_cert_free(cert);
477 ret = hx509_cms_unwrap_ContentInfo(&r.signedAuthPack,
478 &contentInfoOid,
479 &signed_content,
480 &have_data);
481 free_PA_PK_AS_REQ(&r);
482 if (ret) {
483 krb5_set_error_string(context, "Can't unwrap ContentInfo: %d", ret);
484 goto out;
487 } else {
488 krb5_clear_error_string(context);
489 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
490 goto out;
493 ret = der_heim_oid_cmp(&contentInfoOid, oid_id_pkcs7_signedData());
494 if (ret != 0) {
495 krb5_set_error_string(context, "PK-AS-REQ-Win2k invalid content "
496 "type oid");
497 ret = KRB5KRB_ERR_GENERIC;
498 goto out;
501 if (!have_data) {
502 krb5_set_error_string(context,
503 "PK-AS-REQ-Win2k no signed auth pack");
504 ret = KRB5KRB_ERR_GENERIC;
505 goto out;
509 hx509_certs signer_certs;
511 ret = hx509_cms_verify_signed(kdc_identity->hx509ctx,
512 kdc_identity->verify_ctx,
513 signed_content.data,
514 signed_content.length,
515 NULL,
516 kdc_identity->certpool,
517 &eContentType,
518 &eContent,
519 &signer_certs);
520 if (ret) {
521 char *s = hx509_get_error_string(kdc_identity->hx509ctx, ret);
522 krb5_warnx(context, "PKINIT: failed to verify signature: %s: %d",
523 s, ret);
524 free(s);
525 goto out;
528 ret = hx509_get_one_cert(kdc_identity->hx509ctx, signer_certs,
529 &client_params->cert);
530 hx509_certs_free(&signer_certs);
531 if (ret)
532 goto out;
535 /* Signature is correct, now verify the signed message */
536 if (der_heim_oid_cmp(&eContentType, oid_id_pkcs7_data()) != 0 &&
537 der_heim_oid_cmp(&eContentType, oid_id_pkauthdata()) != 0)
539 krb5_set_error_string(context, "got wrong oid for pkauthdata");
540 ret = KRB5_BADMSGTYPE;
541 goto out;
544 if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
545 AuthPack_Win2k ap;
547 ret = decode_AuthPack_Win2k(eContent.data,
548 eContent.length,
549 &ap,
550 NULL);
551 if (ret) {
552 krb5_set_error_string(context, "can't decode AuthPack: %d", ret);
553 goto out;
556 ret = pk_check_pkauthenticator_win2k(context,
557 &ap.pkAuthenticator,
558 req);
559 if (ret) {
560 free_AuthPack_Win2k(&ap);
561 goto out;
564 client_params->type = PKINIT_WIN2K;
565 client_params->nonce = ap.pkAuthenticator.nonce;
567 if (ap.clientPublicValue) {
568 krb5_set_error_string(context, "DH not supported for windows");
569 ret = KRB5KRB_ERR_GENERIC;
570 goto out;
572 free_AuthPack_Win2k(&ap);
574 } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
575 AuthPack ap;
577 ret = decode_AuthPack(eContent.data,
578 eContent.length,
579 &ap,
580 NULL);
581 if (ret) {
582 krb5_set_error_string(context, "can't decode AuthPack: %d", ret);
583 free_AuthPack(&ap);
584 goto out;
587 ret = pk_check_pkauthenticator(context,
588 &ap.pkAuthenticator,
589 req);
590 if (ret) {
591 free_AuthPack(&ap);
592 goto out;
595 client_params->type = PKINIT_27;
596 client_params->nonce = ap.pkAuthenticator.nonce;
598 if (ap.clientPublicValue) {
599 ret = get_dh_param(context, config,
600 ap.clientPublicValue, client_params);
601 if (ret) {
602 free_AuthPack(&ap);
603 goto out;
607 if (ap.supportedCMSTypes) {
608 ret = hx509_peer_info_alloc(kdc_identity->hx509ctx,
609 &client_params->peer);
610 if (ret) {
611 free_AuthPack(&ap);
612 goto out;
614 ret = hx509_peer_info_set_cms_algs(kdc_identity->hx509ctx,
615 client_params->peer,
616 ap.supportedCMSTypes->val,
617 ap.supportedCMSTypes->len);
618 if (ret) {
619 free_AuthPack(&ap);
620 goto out;
623 free_AuthPack(&ap);
624 } else
625 krb5_abortx(context, "internal pkinit error");
627 kdc_log(context, config, 0, "PK-INIT request of type %s", type);
629 out:
630 if (ret)
631 krb5_warn(context, ret, "PKINIT");
633 if (signed_content.data)
634 free(signed_content.data);
635 krb5_data_free(&eContent);
636 der_free_oid(&eContentType);
637 der_free_oid(&contentInfoOid);
638 if (ret)
639 _kdc_pk_free_client_param(context, client_params);
640 else
641 *ret_params = client_params;
642 return ret;
649 static krb5_error_code
650 BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer)
652 integer->length = BN_num_bytes(bn);
653 integer->data = malloc(integer->length);
654 if (integer->data == NULL) {
655 krb5_clear_error_string(context);
656 return ENOMEM;
658 BN_bn2bin(bn, integer->data);
659 integer->negative = BN_is_negative(bn);
660 return 0;
663 static krb5_error_code
664 pk_mk_pa_reply_enckey(krb5_context context,
665 krb5_kdc_configuration *config,
666 pk_client_params *client_params,
667 const KDC_REQ *req,
668 const krb5_data *req_buffer,
669 krb5_keyblock *reply_key,
670 ContentInfo *content_info)
672 const heim_oid *envelopedAlg = NULL, *sdAlg = NULL;
673 krb5_error_code ret;
674 krb5_data buf, signed_data;
675 size_t size;
676 int do_win2k = 0;
678 krb5_data_zero(&buf);
679 krb5_data_zero(&signed_data);
682 * If the message client is a win2k-type but it send pa data
683 * 09-binding it expects a IETF (checksum) reply so there can be
684 * no replay attacks.
687 switch (client_params->type) {
688 case PKINIT_WIN2K: {
689 int i = 0;
690 if (_kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_09_BINDING) == NULL
691 && config->pkinit_require_binding == 0)
693 do_win2k = 1;
695 break;
697 case PKINIT_27:
698 break;
699 default:
700 krb5_abortx(context, "internal pkinit error");
703 if (do_win2k) {
704 ReplyKeyPack_Win2k kp;
705 memset(&kp, 0, sizeof(kp));
707 envelopedAlg = oid_id_rsadsi_des_ede3_cbc();
708 sdAlg = oid_id_pkcs7_data();
710 ret = copy_EncryptionKey(reply_key, &kp.replyKey);
711 if (ret) {
712 krb5_clear_error_string(context);
713 goto out;
715 kp.nonce = client_params->nonce;
717 ASN1_MALLOC_ENCODE(ReplyKeyPack_Win2k,
718 buf.data, buf.length,
719 &kp, &size,ret);
720 free_ReplyKeyPack_Win2k(&kp);
721 } else {
722 krb5_crypto ascrypto;
723 ReplyKeyPack kp;
724 memset(&kp, 0, sizeof(kp));
726 sdAlg = oid_id_pkrkeydata();
728 ret = copy_EncryptionKey(reply_key, &kp.replyKey);
729 if (ret) {
730 krb5_clear_error_string(context);
731 goto out;
734 ret = krb5_crypto_init(context, reply_key, 0, &ascrypto);
735 if (ret) {
736 krb5_clear_error_string(context);
737 goto out;
740 ret = krb5_create_checksum(context, ascrypto, 6, 0,
741 req_buffer->data, req_buffer->length,
742 &kp.asChecksum);
743 if (ret) {
744 krb5_clear_error_string(context);
745 goto out;
748 ret = krb5_crypto_destroy(context, ascrypto);
749 if (ret) {
750 krb5_clear_error_string(context);
751 goto out;
753 ASN1_MALLOC_ENCODE(ReplyKeyPack, buf.data, buf.length, &kp, &size,ret);
754 free_ReplyKeyPack(&kp);
756 if (ret) {
757 krb5_set_error_string(context, "ASN.1 encoding of ReplyKeyPack "
758 "failed (%d)", ret);
759 goto out;
761 if (buf.length != size)
762 krb5_abortx(context, "Internal ASN.1 encoder error");
765 hx509_query *q;
766 hx509_cert cert;
768 ret = hx509_query_alloc(kdc_identity->hx509ctx, &q);
769 if (ret)
770 goto out;
772 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
773 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
775 ret = hx509_certs_find(kdc_identity->hx509ctx,
776 kdc_identity->certs,
778 &cert);
779 hx509_query_free(kdc_identity->hx509ctx, q);
780 if (ret)
781 goto out;
783 ret = hx509_cms_create_signed_1(kdc_identity->hx509ctx,
785 sdAlg,
786 buf.data,
787 buf.length,
788 NULL,
789 cert,
790 client_params->peer,
791 client_params->client_anchors,
792 kdc_identity->certpool,
793 &signed_data);
794 hx509_cert_free(cert);
797 krb5_data_free(&buf);
798 if (ret)
799 goto out;
801 if (client_params->type == PKINIT_WIN2K) {
802 ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(),
803 &signed_data,
804 &buf);
805 if (ret)
806 goto out;
807 krb5_data_free(&signed_data);
808 signed_data = buf;
811 ret = hx509_cms_envelope_1(kdc_identity->hx509ctx,
813 client_params->cert,
814 signed_data.data, signed_data.length,
815 envelopedAlg,
816 oid_id_pkcs7_signedData(), &buf);
817 if (ret)
818 goto out;
820 ret = _krb5_pk_mk_ContentInfo(context,
821 &buf,
822 oid_id_pkcs7_envelopedData(),
823 content_info);
824 out:
825 krb5_data_free(&buf);
826 krb5_data_free(&signed_data);
827 return ret;
834 static krb5_error_code
835 pk_mk_pa_reply_dh(krb5_context context,
836 DH *kdc_dh,
837 pk_client_params *client_params,
838 krb5_keyblock *reply_key,
839 ContentInfo *content_info,
840 hx509_cert *kdc_cert)
842 KDCDHKeyInfo dh_info;
843 krb5_data signed_data, buf;
844 ContentInfo contentinfo;
845 krb5_error_code ret;
846 size_t size;
847 heim_integer i;
849 memset(&contentinfo, 0, sizeof(contentinfo));
850 memset(&dh_info, 0, sizeof(dh_info));
851 krb5_data_zero(&buf);
852 krb5_data_zero(&signed_data);
854 *kdc_cert = NULL;
856 ret = BN_to_integer(context, kdc_dh->pub_key, &i);
857 if (ret)
858 return ret;
860 ASN1_MALLOC_ENCODE(DHPublicKey, buf.data, buf.length, &i, &size, ret);
861 if (ret) {
862 krb5_set_error_string(context, "ASN.1 encoding of "
863 "DHPublicKey failed (%d)", ret);
864 krb5_clear_error_string(context);
865 return ret;
867 if (buf.length != size)
868 krb5_abortx(context, "Internal ASN.1 encoder error");
870 dh_info.subjectPublicKey.length = buf.length * 8;
871 dh_info.subjectPublicKey.data = buf.data;
873 dh_info.nonce = client_params->nonce;
875 ASN1_MALLOC_ENCODE(KDCDHKeyInfo, buf.data, buf.length, &dh_info, &size,
876 ret);
877 if (ret) {
878 krb5_set_error_string(context, "ASN.1 encoding of "
879 "KdcDHKeyInfo failed (%d)", ret);
880 goto out;
882 if (buf.length != size)
883 krb5_abortx(context, "Internal ASN.1 encoder error");
886 * Create the SignedData structure and sign the KdcDHKeyInfo
887 * filled in above
891 hx509_query *q;
892 hx509_cert cert;
894 ret = hx509_query_alloc(kdc_identity->hx509ctx, &q);
895 if (ret)
896 goto out;
898 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
899 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
901 ret = hx509_certs_find(kdc_identity->hx509ctx,
902 kdc_identity->certs,
904 &cert);
905 hx509_query_free(kdc_identity->hx509ctx, q);
906 if (ret)
907 goto out;
909 ret = hx509_cms_create_signed_1(kdc_identity->hx509ctx,
911 oid_id_pkdhkeydata(),
912 buf.data,
913 buf.length,
914 NULL,
915 cert,
916 client_params->peer,
917 client_params->client_anchors,
918 kdc_identity->certpool,
919 &signed_data);
920 *kdc_cert = cert;
922 if (ret)
923 goto out;
925 ret = _krb5_pk_mk_ContentInfo(context,
926 &signed_data,
927 oid_id_pkcs7_signedData(),
928 content_info);
929 if (ret)
930 goto out;
932 out:
933 if (ret && *kdc_cert) {
934 hx509_cert_free(*kdc_cert);
935 *kdc_cert = NULL;
938 krb5_data_free(&buf);
939 krb5_data_free(&signed_data);
940 free_KDCDHKeyInfo(&dh_info);
942 return ret;
949 krb5_error_code
950 _kdc_pk_mk_pa_reply(krb5_context context,
951 krb5_kdc_configuration *config,
952 pk_client_params *client_params,
953 const hdb_entry_ex *client,
954 const KDC_REQ *req,
955 const krb5_data *req_buffer,
956 krb5_keyblock **reply_key,
957 METHOD_DATA *md)
959 krb5_error_code ret;
960 void *buf;
961 size_t len, size;
962 krb5_enctype enctype;
963 int pa_type;
964 hx509_cert kdc_cert = NULL;
965 int i;
967 if (!config->enable_pkinit) {
968 krb5_clear_error_string(context);
969 return 0;
972 if (req->req_body.etype.len > 0) {
973 for (i = 0; i < req->req_body.etype.len; i++)
974 if (krb5_enctype_valid(context, req->req_body.etype.val[i]) == 0)
975 break;
976 if (req->req_body.etype.len <= i) {
977 ret = KRB5KRB_ERR_GENERIC;
978 krb5_set_error_string(context,
979 "No valid enctype available from client");
980 goto out;
982 enctype = req->req_body.etype.val[i];
983 } else
984 enctype = ETYPE_DES3_CBC_SHA1;
986 if (client_params->type == PKINIT_27) {
987 PA_PK_AS_REP rep;
988 const char *type, *other = "";
990 memset(&rep, 0, sizeof(rep));
992 pa_type = KRB5_PADATA_PK_AS_REP;
994 if (client_params->dh == NULL) {
995 ContentInfo info;
997 type = "enckey";
999 rep.element = choice_PA_PK_AS_REP_encKeyPack;
1001 ret = krb5_generate_random_keyblock(context, enctype,
1002 &client_params->reply_key);
1003 if (ret) {
1004 free_PA_PK_AS_REP(&rep);
1005 goto out;
1007 ret = pk_mk_pa_reply_enckey(context,
1008 config,
1009 client_params,
1010 req,
1011 req_buffer,
1012 &client_params->reply_key,
1013 &info);
1014 if (ret) {
1015 free_PA_PK_AS_REP(&rep);
1016 goto out;
1018 ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data,
1019 rep.u.encKeyPack.length, &info, &size,
1020 ret);
1021 free_ContentInfo(&info);
1022 if (ret) {
1023 krb5_set_error_string(context, "encoding of Key ContentInfo "
1024 "failed %d", ret);
1025 free_PA_PK_AS_REP(&rep);
1026 goto out;
1028 if (rep.u.encKeyPack.length != size)
1029 krb5_abortx(context, "Internal ASN.1 encoder error");
1031 } else {
1032 ContentInfo info;
1034 type = "dh";
1035 if (client_params->dh_group_name)
1036 other = client_params->dh_group_name;
1038 rep.element = choice_PA_PK_AS_REP_dhInfo;
1040 ret = generate_dh_keyblock(context, client_params, enctype,
1041 &client_params->reply_key);
1042 if (ret)
1043 return ret;
1045 ret = pk_mk_pa_reply_dh(context, client_params->dh,
1046 client_params,
1047 &client_params->reply_key,
1048 &info,
1049 &kdc_cert);
1051 ASN1_MALLOC_ENCODE(ContentInfo, rep.u.dhInfo.dhSignedData.data,
1052 rep.u.dhInfo.dhSignedData.length, &info, &size,
1053 ret);
1054 free_ContentInfo(&info);
1055 if (ret) {
1056 krb5_set_error_string(context, "encoding of Key ContentInfo "
1057 "failed %d", ret);
1058 free_PA_PK_AS_REP(&rep);
1059 goto out;
1061 if (rep.u.encKeyPack.length != size)
1062 krb5_abortx(context, "Internal ASN.1 encoder error");
1065 if (ret) {
1066 free_PA_PK_AS_REP(&rep);
1067 goto out;
1070 ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret);
1071 free_PA_PK_AS_REP(&rep);
1072 if (ret) {
1073 krb5_set_error_string(context, "encode PA-PK-AS-REP failed %d",
1074 ret);
1075 goto out;
1077 if (len != size)
1078 krb5_abortx(context, "Internal ASN.1 encoder error");
1080 kdc_log(context, config, 0, "PK-INIT using %s %s", type, other);
1082 } else if (client_params->type == PKINIT_WIN2K) {
1083 PA_PK_AS_REP_Win2k rep;
1084 ContentInfo info;
1086 if (client_params->dh) {
1087 krb5_set_error_string(context, "Windows PK-INIT doesn't support DH");
1088 ret = KRB5KRB_ERR_GENERIC;
1089 goto out;
1092 memset(&rep, 0, sizeof(rep));
1094 pa_type = KRB5_PADATA_PK_AS_REP_19;
1095 rep.element = choice_PA_PK_AS_REP_encKeyPack;
1097 ret = krb5_generate_random_keyblock(context, enctype,
1098 &client_params->reply_key);
1099 if (ret) {
1100 free_PA_PK_AS_REP_Win2k(&rep);
1101 goto out;
1103 ret = pk_mk_pa_reply_enckey(context,
1104 config,
1105 client_params,
1106 req,
1107 req_buffer,
1108 &client_params->reply_key,
1109 &info);
1110 if (ret) {
1111 free_PA_PK_AS_REP_Win2k(&rep);
1112 goto out;
1114 ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data,
1115 rep.u.encKeyPack.length, &info, &size,
1116 ret);
1117 free_ContentInfo(&info);
1118 if (ret) {
1119 krb5_set_error_string(context, "encoding of Key ContentInfo "
1120 "failed %d", ret);
1121 free_PA_PK_AS_REP_Win2k(&rep);
1122 goto out;
1124 if (rep.u.encKeyPack.length != size)
1125 krb5_abortx(context, "Internal ASN.1 encoder error");
1127 ASN1_MALLOC_ENCODE(PA_PK_AS_REP_Win2k, buf, len, &rep, &size, ret);
1128 free_PA_PK_AS_REP_Win2k(&rep);
1129 if (ret) {
1130 krb5_set_error_string(context,
1131 "encode PA-PK-AS-REP-Win2k failed %d", ret);
1132 goto out;
1134 if (len != size)
1135 krb5_abortx(context, "Internal ASN.1 encoder error");
1137 } else
1138 krb5_abortx(context, "PK-INIT internal error");
1141 ret = krb5_padata_add(context, md, pa_type, buf, len);
1142 if (ret) {
1143 krb5_set_error_string(context, "failed adding PA-PK-AS-REP %d", ret);
1144 free(buf);
1145 goto out;
1148 if (config->pkinit_kdc_ocsp_file) {
1150 if (ocsp.expire == 0 && ocsp.next_update > kdc_time) {
1151 struct stat sb;
1152 int fd;
1154 krb5_data_free(&ocsp.data);
1156 ocsp.expire = 0;
1157 ocsp.next_update = kdc_time + 60 * 5;
1159 fd = open(config->pkinit_kdc_ocsp_file, O_RDONLY);
1160 if (fd < 0) {
1161 kdc_log(context, config, 0,
1162 "PK-INIT failed to open ocsp data file %d", errno);
1163 goto out_ocsp;
1165 ret = fstat(fd, &sb);
1166 if (ret) {
1167 ret = errno;
1168 close(fd);
1169 kdc_log(context, config, 0,
1170 "PK-INIT failed to stat ocsp data %d", ret);
1171 goto out_ocsp;
1174 ret = krb5_data_alloc(&ocsp.data, sb.st_size);
1175 if (ret) {
1176 close(fd);
1177 kdc_log(context, config, 0,
1178 "PK-INIT failed to stat ocsp data %d", ret);
1179 goto out_ocsp;
1181 ocsp.data.length = sb.st_size;
1182 ret = read(fd, ocsp.data.data, sb.st_size);
1183 close(fd);
1184 if (ret != sb.st_size) {
1185 kdc_log(context, config, 0,
1186 "PK-INIT failed to read ocsp data %d", errno);
1187 goto out_ocsp;
1190 ret = hx509_ocsp_verify(kdc_identity->hx509ctx,
1191 kdc_time,
1192 kdc_cert,
1194 ocsp.data.data, ocsp.data.length,
1195 &ocsp.expire);
1196 if (ret) {
1197 kdc_log(context, config, 0,
1198 "PK-INIT failed to verify ocsp data %d", ret);
1199 krb5_data_free(&ocsp.data);
1200 ocsp.expire = 0;
1201 } else if (ocsp.expire > 180) {
1202 ocsp.expire -= 180; /* refetch the ocsp before it expire */
1203 ocsp.next_update = ocsp.expire;
1204 } else {
1205 ocsp.next_update = kdc_time;
1207 out_ocsp:
1208 ret = 0;
1211 if (ocsp.expire != 0 && ocsp.expire > kdc_time) {
1213 ret = krb5_padata_add(context, md,
1214 KRB5_PADATA_PA_PK_OCSP_RESPONSE,
1215 ocsp.data.data, ocsp.data.length);
1216 if (ret) {
1217 krb5_set_error_string(context,
1218 "Failed adding OCSP response %d", ret);
1219 goto out;
1224 out:
1225 if (kdc_cert)
1226 hx509_cert_free(kdc_cert);
1228 if (ret == 0)
1229 *reply_key = &client_params->reply_key;
1230 return ret;
1233 static int
1234 match_rfc_san(krb5_context context,
1235 krb5_kdc_configuration *config,
1236 hx509_context hx509ctx,
1237 hx509_cert client_cert,
1238 krb5_const_principal match)
1240 hx509_octet_string_list list;
1241 int ret, i, found = 0;
1243 memset(&list, 0 , sizeof(list));
1245 ret = hx509_cert_find_subjectAltName_otherName(hx509ctx,
1246 client_cert,
1247 oid_id_pkinit_san(),
1248 &list);
1249 if (ret)
1250 goto out;
1252 for (i = 0; !found && i < list.len; i++) {
1253 krb5_principal_data principal;
1254 KRB5PrincipalName kn;
1255 size_t size;
1257 ret = decode_KRB5PrincipalName(list.val[i].data,
1258 list.val[i].length,
1259 &kn, &size);
1260 if (ret) {
1261 kdc_log(context, config, 0,
1262 "Decoding kerberos name in certificate failed: %s",
1263 krb5_get_err_text(context, ret));
1264 break;
1266 if (size != list.val[i].length) {
1267 kdc_log(context, config, 0,
1268 "Decoding kerberos name have extra bits on the end");
1269 return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1272 principal.name = kn.principalName;
1273 principal.realm = kn.realm;
1275 if (krb5_principal_compare(context, &principal, match) == TRUE)
1276 found = 1;
1277 free_KRB5PrincipalName(&kn);
1280 out:
1281 hx509_free_octet_string_list(&list);
1282 if (ret)
1283 return ret;
1285 if (!found)
1286 return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1288 return 0;
1291 static int
1292 match_ms_upn_san(krb5_context context,
1293 krb5_kdc_configuration *config,
1294 hx509_context hx509ctx,
1295 hx509_cert client_cert,
1296 krb5_const_principal match)
1298 hx509_octet_string_list list;
1299 krb5_principal principal = NULL;
1300 int ret, found = 0;
1301 MS_UPN_SAN upn;
1302 size_t size;
1304 memset(&list, 0 , sizeof(list));
1306 ret = hx509_cert_find_subjectAltName_otherName(hx509ctx,
1307 client_cert,
1308 oid_id_pkinit_ms_san(),
1309 &list);
1310 if (ret)
1311 goto out;
1313 if (list.len != 1) {
1314 kdc_log(context, config, 0,
1315 "More then one PK-INIT MS UPN SAN");
1316 goto out;
1319 ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length, &upn, &size);
1320 if (ret) {
1321 kdc_log(context, config, 0, "Decode of MS-UPN-SAN failed");
1322 goto out;
1325 kdc_log(context, config, 0, "found MS UPN SAN: %s", upn);
1327 ret = krb5_parse_name(context, upn, &principal);
1328 free_MS_UPN_SAN(&upn);
1329 if (ret) {
1330 kdc_log(context, config, 0, "Failed to parse principal in MS UPN SAN");
1331 goto out;
1335 * This is very wrong, but will do for now, should really and a
1336 * plugin to the windc layer to very this ACL.
1338 strupr(principal->realm);
1340 if (krb5_principal_compare(context, principal, match) == TRUE)
1341 found = 1;
1343 out:
1344 if (principal)
1345 krb5_free_principal(context, principal);
1346 hx509_free_octet_string_list(&list);
1347 if (ret)
1348 return ret;
1350 if (!found)
1351 return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1353 return 0;
1356 krb5_error_code
1357 _kdc_pk_check_client(krb5_context context,
1358 krb5_kdc_configuration *config,
1359 const hdb_entry_ex *client,
1360 pk_client_params *client_params,
1361 char **subject_name)
1363 const HDB_Ext_PKINIT_acl *acl;
1364 krb5_error_code ret;
1365 hx509_name name;
1366 int i;
1368 ret = hx509_cert_get_base_subject(kdc_identity->hx509ctx,
1369 client_params->cert,
1370 &name);
1371 if (ret)
1372 return ret;
1374 ret = hx509_name_to_string(name, subject_name);
1375 hx509_name_free(&name);
1376 if (ret)
1377 return ret;
1379 kdc_log(context, config, 0,
1380 "Trying to authorize PK-INIT subject DN %s",
1381 *subject_name);
1383 if (config->pkinit_princ_in_cert) {
1384 ret = match_rfc_san(context, config,
1385 kdc_identity->hx509ctx,
1386 client_params->cert,
1387 client->entry.principal);
1388 if (ret == 0) {
1389 kdc_log(context, config, 5,
1390 "Found matching PK-INIT SAN in certificate");
1391 return 0;
1393 ret = match_ms_upn_san(context, config,
1394 kdc_identity->hx509ctx,
1395 client_params->cert,
1396 client->entry.principal);
1397 if (ret == 0) {
1398 kdc_log(context, config, 5,
1399 "Found matching MS UPN SAN in certificate");
1400 return 0;
1404 ret = hdb_entry_get_pkinit_acl(&client->entry, &acl);
1405 if (ret == 0 && acl != NULL) {
1407 * Cheat here and compare the generated name with the string
1408 * and not the reverse.
1410 for (i = 0; i < acl->len; i++) {
1411 if (strcmp(*subject_name, acl->val[0].subject) != 0)
1412 continue;
1414 /* Don't support isser and anchor checking right now */
1415 if (acl->val[0].issuer)
1416 continue;
1417 if (acl->val[0].anchor)
1418 continue;
1420 kdc_log(context, config, 5,
1421 "Found matching PK-INIT database ACL");
1422 return 0;
1426 for (i = 0; i < principal_mappings.len; i++) {
1427 krb5_boolean b;
1429 b = krb5_principal_compare(context,
1430 client->entry.principal,
1431 principal_mappings.val[i].principal);
1432 if (b == FALSE)
1433 continue;
1434 if (strcmp(principal_mappings.val[i].subject, *subject_name) != 0)
1435 continue;
1436 kdc_log(context, config, 5,
1437 "Found matching PK-INIT FILE ACL");
1438 return 0;
1441 krb5_set_error_string(context,
1442 "PKINIT no matching principals for %s",
1443 *subject_name);
1445 kdc_log(context, config, 5,
1446 "PKINIT no matching principals for %s",
1447 *subject_name);
1449 free(*subject_name);
1450 *subject_name = NULL;
1452 return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1455 static krb5_error_code
1456 add_principal_mapping(krb5_context context,
1457 const char *principal_name,
1458 const char * subject)
1460 struct pk_allowed_princ *tmp;
1461 krb5_principal principal;
1462 krb5_error_code ret;
1464 tmp = realloc(principal_mappings.val,
1465 (principal_mappings.len + 1) * sizeof(*tmp));
1466 if (tmp == NULL)
1467 return ENOMEM;
1468 principal_mappings.val = tmp;
1470 ret = krb5_parse_name(context, principal_name, &principal);
1471 if (ret)
1472 return ret;
1474 principal_mappings.val[principal_mappings.len].principal = principal;
1476 principal_mappings.val[principal_mappings.len].subject = strdup(subject);
1477 if (principal_mappings.val[principal_mappings.len].subject == NULL) {
1478 krb5_free_principal(context, principal);
1479 return ENOMEM;
1481 principal_mappings.len++;
1483 return 0;
1486 krb5_error_code
1487 _kdc_add_inital_verified_cas(krb5_context context,
1488 krb5_kdc_configuration *config,
1489 pk_client_params *params,
1490 EncTicketPart *tkt)
1492 AD_INITIAL_VERIFIED_CAS cas;
1493 krb5_error_code ret;
1494 krb5_data data;
1495 size_t size;
1497 memset(&cas, 0, sizeof(cas));
1499 /* XXX add CAs to cas here */
1501 ASN1_MALLOC_ENCODE(AD_INITIAL_VERIFIED_CAS, data.data, data.length,
1502 &cas, &size, ret);
1503 if (ret)
1504 return ret;
1505 if (data.length != size)
1506 krb5_abortx(context, "internal asn.1 encoder error");
1508 ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
1509 KRB5_AUTHDATA_INITIAL_VERIFIED_CAS,
1510 &data);
1511 krb5_data_free(&data);
1512 return ret;
1519 static void
1520 load_mappings(krb5_context context, const char *fn)
1522 krb5_error_code ret;
1523 char buf[1024];
1524 unsigned long lineno = 0;
1525 FILE *f;
1527 f = fopen(fn, "r");
1528 if (f == NULL)
1529 return;
1531 while (fgets(buf, sizeof(buf), f) != NULL) {
1532 char *subject_name, *p;
1534 buf[strcspn(buf, "\n")] = '\0';
1535 lineno++;
1537 p = buf + strspn(buf, " \t");
1539 if (*p == '#' || *p == '\0')
1540 continue;
1542 subject_name = strchr(p, ':');
1543 if (subject_name == NULL) {
1544 krb5_warnx(context, "pkinit mapping file line %lu "
1545 "missing \":\" :%s",
1546 lineno, buf);
1547 continue;
1549 *subject_name++ = '\0';
1551 ret = add_principal_mapping(context, p, subject_name);
1552 if (ret) {
1553 krb5_warn(context, ret, "failed to add line %lu \":\" :%s\n",
1554 lineno, buf);
1555 continue;
1559 fclose(f);
1566 krb5_error_code
1567 _kdc_pk_initialize(krb5_context context,
1568 krb5_kdc_configuration *config,
1569 const char *user_id,
1570 const char *anchors,
1571 char **pool,
1572 char **revoke_list)
1574 const char *file;
1575 char *fn = NULL;
1576 krb5_error_code ret;
1578 file = krb5_config_get_string(context, NULL,
1579 "libdefaults", "moduli", NULL);
1581 ret = _krb5_parse_moduli(context, file, &moduli);
1582 if (ret)
1583 krb5_err(context, 1, ret, "PKINIT: failed to load modidi file");
1585 principal_mappings.len = 0;
1586 principal_mappings.val = NULL;
1588 ret = _krb5_pk_load_id(context,
1589 &kdc_identity,
1590 user_id,
1591 anchors,
1592 pool,
1593 revoke_list,
1594 NULL,
1595 NULL,
1596 NULL);
1597 if (ret) {
1598 krb5_warn(context, ret, "PKINIT: ");
1599 config->enable_pkinit = 0;
1600 return ret;
1604 hx509_query *q;
1605 hx509_cert cert;
1607 ret = hx509_query_alloc(kdc_identity->hx509ctx, &q);
1608 if (ret) {
1609 krb5_warnx(context, "PKINIT: out of memory");
1610 return ENOMEM;
1613 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
1614 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
1616 ret = hx509_certs_find(kdc_identity->hx509ctx,
1617 kdc_identity->certs,
1619 &cert);
1620 hx509_query_free(kdc_identity->hx509ctx, q);
1621 if (ret == 0) {
1622 if (hx509_cert_check_eku(kdc_identity->hx509ctx, cert,
1623 oid_id_pkkdcekuoid(), 0))
1624 krb5_warnx(context, "WARNING Found KDC certificate "
1625 "is missing the PK-INIT KDC EKU, this is bad for "
1626 "interoperability.");
1627 hx509_cert_free(cert);
1628 } else
1629 krb5_warnx(context, "PKINIT: failed to find a signing "
1630 "certifiate with a public key");
1633 ret = krb5_config_get_bool_default(context,
1634 NULL,
1635 FALSE,
1636 "kdc",
1637 "pkinit_allow_proxy_certificate",
1638 NULL);
1639 _krb5_pk_allow_proxy_certificate(kdc_identity, ret);
1641 file = krb5_config_get_string(context,
1642 NULL,
1643 "kdc",
1644 "pkinit_mappings_file",
1645 NULL);
1646 if (file == NULL) {
1647 asprintf(&fn, "%s/pki-mapping", hdb_db_dir(context));
1648 file = fn;
1651 load_mappings(context, file);
1652 if (fn)
1653 free(fn);
1655 return 0;
1658 #endif /* PKINIT */