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