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