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