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