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