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 static krb5_error_code 1310 pk_rd_pa_reply_dh(krb5_context context, 1311 const heim_octet_string *indata, 1312 const heim_oid *dataType, 1313 const char *realm, 1314 krb5_pk_init_ctx ctx, 1315 krb5_enctype etype, 1316 const krb5_krbhst_info *hi, 1317 const DHNonce *c_n, 1318 const DHNonce *k_n, 1319 unsigned nonce, 1320 PA_DATA *pa, 1321 krb5_keyblock **key) 1322 { 1323 const unsigned char *p; 1324 unsigned char *dh_gen_key = NULL; 1325 struct krb5_pk_cert *host = NULL; 1326 BIGNUM *kdc_dh_pubkey = NULL; 1327 KDCDHKeyInfo kdc_dh_info; 1328 heim_oid contentType = { 0, NULL }; 1329 krb5_data content; 1330 krb5_error_code ret; 1331 int dh_gen_keylen = 0; 1332 size_t size; 1333 1334 krb5_data_zero(&content); 1335 memset(&kdc_dh_info, 0, sizeof(kdc_dh_info)); 1336 1337 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_signedData, dataType)) { 1338 krb5_set_error_message(context, EINVAL, 1339 N_("PKINIT: Invalid content type", "")); 1340 return EINVAL; 1341 } 1342 1343 ret = pk_verify_sign(context, 1344 indata->data, 1345 indata->length, 1346 ctx->id, 1347 &contentType, 1348 &content, 1349 &host); 1350 if (ret) 1351 goto out; 1352 1353 /* make sure that it is the kdc's certificate */ 1354 ret = pk_verify_host(context, realm, hi, ctx, host); 1355 if (ret) 1356 goto out; 1357 1358 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkdhkeydata)) { 1359 ret = KRB5KRB_AP_ERR_MSG_TYPE; 1360 krb5_set_error_message(context, ret, 1361 N_("pkinit - dh reply contains wrong oid", "")); 1362 goto out; 1363 } 1364 1365 ret = decode_KDCDHKeyInfo(content.data, 1366 content.length, 1367 &kdc_dh_info, 1368 &size); 1369 1370 if (ret) { 1371 krb5_set_error_message(context, ret, 1372 N_("pkinit - failed to decode " 1373 "KDC DH Key Info", "")); 1374 goto out; 1375 } 1376 1377 if (kdc_dh_info.nonce != nonce) { 1378 ret = KRB5KRB_AP_ERR_MODIFIED; 1379 krb5_set_error_message(context, ret, 1380 N_("PKINIT: DH nonce is wrong", "")); 1381 goto out; 1382 } 1383 1384 if (kdc_dh_info.dhKeyExpiration) { 1385 if (k_n == NULL) { 1386 ret = KRB5KRB_ERR_GENERIC; 1387 krb5_set_error_message(context, ret, 1388 N_("pkinit; got key expiration " 1389 "without server nonce", "")); 1390 goto out; 1391 } 1392 if (c_n == NULL) { 1393 ret = KRB5KRB_ERR_GENERIC; 1394 krb5_set_error_message(context, ret, 1395 N_("pkinit; got DH reuse but no " 1396 "client nonce", "")); 1397 goto out; 1398 } 1399 } else { 1400 if (k_n) { 1401 ret = KRB5KRB_ERR_GENERIC; 1402 krb5_set_error_message(context, ret, 1403 N_("pkinit: got server nonce " 1404 "without key expiration", "")); 1405 goto out; 1406 } 1407 c_n = NULL; 1408 } 1409 1410 1411 p = kdc_dh_info.subjectPublicKey.data; 1412 size = (kdc_dh_info.subjectPublicKey.length + 7) / 8; 1413 1414 if (ctx->keyex == USE_DH) { 1415 DHPublicKey k; 1416 ret = decode_DHPublicKey(p, size, &k, NULL); 1417 if (ret) { 1418 krb5_set_error_message(context, ret, 1419 N_("pkinit: can't decode " 1420 "without key expiration", "")); 1421 goto out; 1422 } 1423 1424 kdc_dh_pubkey = integer_to_BN(context, "DHPublicKey", &k); 1425 free_DHPublicKey(&k); 1426 if (kdc_dh_pubkey == NULL) { 1427 ret = ENOMEM; 1428 goto out; 1429 } 1430 1431 1432 size = DH_size(ctx->u.dh); 1433 1434 dh_gen_key = malloc(size); 1435 if (dh_gen_key == NULL) { 1436 ret = ENOMEM; 1437 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1438 goto out; 1439 } 1440 1441 dh_gen_keylen = DH_compute_key(dh_gen_key, kdc_dh_pubkey, ctx->u.dh); 1442 if (dh_gen_keylen == -1) { 1443 ret = KRB5KRB_ERR_GENERIC; 1444 dh_gen_keylen = 0; 1445 krb5_set_error_message(context, ret, 1446 N_("PKINIT: Can't compute Diffie-Hellman key", "")); 1447 goto out; 1448 } 1449 if (dh_gen_keylen < (int)size) { 1450 size -= dh_gen_keylen; 1451 memmove(dh_gen_key + size, dh_gen_key, dh_gen_keylen); 1452 memset(dh_gen_key, 0, size); 1453 } 1454 1455 } else { 1456 #ifdef HAVE_OPENSSL 1457 const EC_GROUP *group; 1458 EC_KEY *public = NULL; 1459 1460 group = EC_KEY_get0_group(ctx->u.eckey); 1461 1462 public = EC_KEY_new(); 1463 if (public == NULL) { 1464 ret = ENOMEM; 1465 goto out; 1466 } 1467 if (EC_KEY_set_group(public, group) != 1) { 1468 EC_KEY_free(public); 1469 ret = ENOMEM; 1470 goto out; 1471 } 1472 1473 if (o2i_ECPublicKey(&public, &p, size) == NULL) { 1474 EC_KEY_free(public); 1475 ret = KRB5KRB_ERR_GENERIC; 1476 krb5_set_error_message(context, ret, 1477 N_("PKINIT: Can't parse ECDH public key", "")); 1478 goto out; 1479 } 1480 1481 size = (EC_GROUP_get_degree(group) + 7) / 8; 1482 dh_gen_key = malloc(size); 1483 if (dh_gen_key == NULL) { 1484 EC_KEY_free(public); 1485 ret = ENOMEM; 1486 krb5_set_error_message(context, ret, 1487 N_("malloc: out of memory", "")); 1488 goto out; 1489 } 1490 dh_gen_keylen = ECDH_compute_key(dh_gen_key, size, 1491 EC_KEY_get0_public_key(public), ctx->u.eckey, NULL); 1492 EC_KEY_free(public); 1493 if (dh_gen_keylen == -1) { 1494 ret = KRB5KRB_ERR_GENERIC; 1495 dh_gen_keylen = 0; 1496 krb5_set_error_message(context, ret, 1497 N_("PKINIT: Can't compute ECDH public key", "")); 1498 goto out; 1499 } 1500 #else 1501 ret = EINVAL; 1502 #endif 1503 } 1504 1505 if (dh_gen_keylen <= 0) { 1506 ret = EINVAL; 1507 krb5_set_error_message(context, ret, 1508 N_("PKINIT: resulting DH key <= 0", "")); 1509 dh_gen_keylen = 0; 1510 goto out; 1511 } 1512 1513 *key = malloc (sizeof (**key)); 1514 if (*key == NULL) { 1515 ret = ENOMEM; 1516 krb5_set_error_message(context, ret, 1517 N_("malloc: out of memory", "")); 1518 goto out; 1519 } 1520 1521 ret = _krb5_pk_octetstring2key(context, 1522 etype, 1523 dh_gen_key, dh_gen_keylen, 1524 c_n, k_n, 1525 *key); 1526 if (ret) { 1527 krb5_set_error_message(context, ret, 1528 N_("PKINIT: can't create key from DH key", "")); 1529 free(*key); 1530 *key = NULL; 1531 goto out; 1532 } 1533 1534 out: 1535 if (kdc_dh_pubkey) 1536 BN_free(kdc_dh_pubkey); 1537 if (dh_gen_key) { 1538 memset(dh_gen_key, 0, dh_gen_keylen); 1539 free(dh_gen_key); 1540 } 1541 if (host) 1542 _krb5_pk_cert_free(host); 1543 if (content.data) 1544 krb5_data_free(&content); 1545 der_free_oid(&contentType); 1546 free_KDCDHKeyInfo(&kdc_dh_info); 1547 1548 return ret; 1549 } 1550 1551 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1552 _krb5_pk_rd_pa_reply(krb5_context context, 1553 const char *realm, 1554 void *c, 1555 krb5_enctype etype, 1556 const krb5_krbhst_info *hi, 1557 unsigned nonce, 1558 const krb5_data *req_buffer, 1559 PA_DATA *pa, 1560 krb5_keyblock **key) 1561 { 1562 krb5_pk_init_ctx ctx = c; 1563 krb5_error_code ret; 1564 size_t size; 1565 1566 /* Check for IETF PK-INIT first */ 1567 if (ctx->type == PKINIT_27) { 1568 PA_PK_AS_REP rep; 1569 heim_octet_string os, data; 1570 heim_oid oid; 1571 1572 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) { 1573 krb5_set_error_message(context, EINVAL, 1574 N_("PKINIT: wrong padata recv", "")); 1575 return EINVAL; 1576 } 1577 1578 ret = decode_PA_PK_AS_REP(pa->padata_value.data, 1579 pa->padata_value.length, 1580 &rep, 1581 &size); 1582 if (ret) { 1583 krb5_set_error_message(context, ret, 1584 N_("Failed to decode pkinit AS rep", "")); 1585 return ret; 1586 } 1587 1588 switch (rep.element) { 1589 case choice_PA_PK_AS_REP_dhInfo: 1590 _krb5_debug(context, 5, "krb5_get_init_creds: using pkinit dh"); 1591 os = rep.u.dhInfo.dhSignedData; 1592 break; 1593 case choice_PA_PK_AS_REP_encKeyPack: 1594 _krb5_debug(context, 5, "krb5_get_init_creds: using kinit enc reply key"); 1595 os = rep.u.encKeyPack; 1596 break; 1597 default: { 1598 PA_PK_AS_REP_BTMM btmm; 1599 free_PA_PK_AS_REP(&rep); 1600 memset(&rep, 0, sizeof(rep)); 1601 1602 _krb5_debug(context, 5, "krb5_get_init_creds: using BTMM kinit enc reply key"); 1603 1604 ret = decode_PA_PK_AS_REP_BTMM(pa->padata_value.data, 1605 pa->padata_value.length, 1606 &btmm, 1607 &size); 1608 if (ret) { 1609 krb5_set_error_message(context, EINVAL, 1610 N_("PKINIT: -27 reply " 1611 "invalid content type", "")); 1612 return EINVAL; 1613 } 1614 1615 if (btmm.dhSignedData || btmm.encKeyPack == NULL) { 1616 free_PA_PK_AS_REP_BTMM(&btmm); 1617 ret = EINVAL; 1618 krb5_set_error_message(context, ret, 1619 N_("DH mode not supported for BTMM mode", "")); 1620 return ret; 1621 } 1622 1623 /* 1624 * Transform to IETF style PK-INIT reply so that free works below 1625 */ 1626 1627 rep.element = choice_PA_PK_AS_REP_encKeyPack; 1628 rep.u.encKeyPack.data = btmm.encKeyPack->data; 1629 rep.u.encKeyPack.length = btmm.encKeyPack->length; 1630 btmm.encKeyPack->data = NULL; 1631 btmm.encKeyPack->length = 0; 1632 free_PA_PK_AS_REP_BTMM(&btmm); 1633 os = rep.u.encKeyPack; 1634 } 1635 } 1636 1637 ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL); 1638 if (ret) { 1639 free_PA_PK_AS_REP(&rep); 1640 krb5_set_error_message(context, ret, 1641 N_("PKINIT: failed to unwrap CI", "")); 1642 return ret; 1643 } 1644 1645 switch (rep.element) { 1646 case choice_PA_PK_AS_REP_dhInfo: 1647 ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi, 1648 ctx->clientDHNonce, 1649 rep.u.dhInfo.serverDHNonce, 1650 nonce, pa, key); 1651 break; 1652 case choice_PA_PK_AS_REP_encKeyPack: 1653 ret = pk_rd_pa_reply_enckey(context, PKINIT_27, &data, &oid, realm, 1654 ctx, etype, hi, nonce, req_buffer, pa, key); 1655 break; 1656 default: 1657 krb5_abortx(context, "pk-init as-rep case not possible to happen"); 1658 } 1659 der_free_octet_string(&data); 1660 der_free_oid(&oid); 1661 free_PA_PK_AS_REP(&rep); 1662 1663 } else if (ctx->type == PKINIT_WIN2K) { 1664 PA_PK_AS_REP_Win2k w2krep; 1665 1666 /* Check for Windows encoding of the AS-REP pa data */ 1667 1668 #if 0 /* should this be ? */ 1669 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) { 1670 krb5_set_error_message(context, EINVAL, 1671 "PKINIT: wrong padata recv"); 1672 return EINVAL; 1673 } 1674 #endif 1675 1676 memset(&w2krep, 0, sizeof(w2krep)); 1677 1678 ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data, 1679 pa->padata_value.length, 1680 &w2krep, 1681 &size); 1682 if (ret) { 1683 krb5_set_error_message(context, ret, 1684 N_("PKINIT: Failed decoding windows " 1685 "pkinit reply %d", ""), (int)ret); 1686 return ret; 1687 } 1688 1689 krb5_clear_error_message(context); 1690 1691 switch (w2krep.element) { 1692 case choice_PA_PK_AS_REP_Win2k_encKeyPack: { 1693 heim_octet_string data; 1694 heim_oid oid; 1695 1696 ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack, 1697 &oid, &data, NULL); 1698 free_PA_PK_AS_REP_Win2k(&w2krep); 1699 if (ret) { 1700 krb5_set_error_message(context, ret, 1701 N_("PKINIT: failed to unwrap CI", "")); 1702 return ret; 1703 } 1704 1705 ret = pk_rd_pa_reply_enckey(context, PKINIT_WIN2K, &data, &oid, realm, 1706 ctx, etype, hi, nonce, req_buffer, pa, key); 1707 der_free_octet_string(&data); 1708 der_free_oid(&oid); 1709 1710 break; 1711 } 1712 default: 1713 free_PA_PK_AS_REP_Win2k(&w2krep); 1714 ret = EINVAL; 1715 krb5_set_error_message(context, ret, 1716 N_("PKINIT: win2k reply invalid " 1717 "content type", "")); 1718 break; 1719 } 1720 1721 } else { 1722 ret = EINVAL; 1723 krb5_set_error_message(context, ret, 1724 N_("PKINIT: unknown reply type", "")); 1725 } 1726 1727 return ret; 1728 } 1729 1730 struct prompter { 1731 krb5_context context; 1732 krb5_prompter_fct prompter; 1733 void *prompter_data; 1734 }; 1735 1736 static int 1737 hx_pass_prompter(void *data, const hx509_prompt *prompter) 1738 { 1739 krb5_error_code ret; 1740 krb5_prompt prompt; 1741 krb5_data password_data; 1742 struct prompter *p = data; 1743 1744 password_data.data = prompter->reply.data; 1745 password_data.length = prompter->reply.length; 1746 1747 prompt.prompt = prompter->prompt; 1748 prompt.hidden = hx509_prompt_hidden(prompter->type); 1749 prompt.reply = &password_data; 1750 1751 switch (prompter->type) { 1752 case HX509_PROMPT_TYPE_INFO: 1753 prompt.type = KRB5_PROMPT_TYPE_INFO; 1754 break; 1755 case HX509_PROMPT_TYPE_PASSWORD: 1756 case HX509_PROMPT_TYPE_QUESTION: 1757 default: 1758 prompt.type = KRB5_PROMPT_TYPE_PASSWORD; 1759 break; 1760 } 1761 1762 ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt); 1763 if (ret) { 1764 memset (prompter->reply.data, 0, prompter->reply.length); 1765 return 1; 1766 } 1767 return 0; 1768 } 1769 1770 static krb5_error_code 1771 _krb5_pk_set_user_id(krb5_context context, 1772 krb5_principal principal, 1773 krb5_pk_init_ctx ctx, 1774 struct hx509_certs_data *certs) 1775 { 1776 hx509_certs c = hx509_certs_ref(certs); 1777 hx509_query *q = NULL; 1778 int ret; 1779 1780 if (ctx->id->certs) 1781 hx509_certs_free(&ctx->id->certs); 1782 if (ctx->id->cert) { 1783 hx509_cert_free(ctx->id->cert); 1784 ctx->id->cert = NULL; 1785 } 1786 1787 ctx->id->certs = c; 1788 ctx->anonymous = 0; 1789 1790 ret = hx509_query_alloc(context->hx509ctx, &q); 1791 if (ret) { 1792 pk_copy_error(context, context->hx509ctx, ret, 1793 "Allocate query to find signing certificate"); 1794 return ret; 1795 } 1796 1797 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); 1798 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); 1799 1800 if (principal && strncmp("LKDC:SHA1.", krb5_principal_get_realm(context, principal), 9) == 0) { 1801 ctx->id->flags |= PKINIT_BTMM; 1802 } 1803 1804 ret = find_cert(context, ctx->id, q, &ctx->id->cert); 1805 hx509_query_free(context->hx509ctx, q); 1806 1807 if (ret == 0 && _krb5_have_debug(context, 2)) { 1808 hx509_name name; 1809 char *str, *sn; 1810 heim_integer i; 1811 1812 ret = hx509_cert_get_subject(ctx->id->cert, &name); 1813 if (ret) 1814 goto out; 1815 1816 ret = hx509_name_to_string(name, &str); 1817 hx509_name_free(&name); 1818 if (ret) 1819 goto out; 1820 1821 ret = hx509_cert_get_serialnumber(ctx->id->cert, &i); 1822 if (ret) { 1823 free(str); 1824 goto out; 1825 } 1826 1827 ret = der_print_hex_heim_integer(&i, &sn); 1828 der_free_heim_integer(&i); 1829 if (ret) { 1830 free(name); 1831 goto out; 1832 } 1833 1834 _krb5_debug(context, 2, "using cert: subject: %s sn: %s", str, sn); 1835 free(str); 1836 free(sn); 1837 } 1838 out: 1839 1840 return ret; 1841 } 1842 1843 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1844 _krb5_pk_load_id(krb5_context context, 1845 struct krb5_pk_identity **ret_id, 1846 const char *user_id, 1847 const char *anchor_id, 1848 char * const *chain_list, 1849 char * const *revoke_list, 1850 krb5_prompter_fct prompter, 1851 void *prompter_data, 1852 char *password) 1853 { 1854 struct krb5_pk_identity *id = NULL; 1855 struct prompter p; 1856 int ret; 1857 1858 *ret_id = NULL; 1859 1860 if (anchor_id == NULL) { 1861 krb5_set_error_message(context, HEIM_PKINIT_NO_VALID_CA, 1862 N_("PKINIT: No anchor given", "")); 1863 return HEIM_PKINIT_NO_VALID_CA; 1864 } 1865 1866 /* load cert */ 1867 1868 id = calloc(1, sizeof(*id)); 1869 if (id == NULL) { 1870 krb5_set_error_message(context, ENOMEM, 1871 N_("malloc: out of memory", "")); 1872 return ENOMEM; 1873 } 1874 1875 if (user_id) { 1876 hx509_lock lock; 1877 1878 ret = hx509_lock_init(context->hx509ctx, &lock); 1879 if (ret) { 1880 pk_copy_error(context, context->hx509ctx, ret, "Failed init lock"); 1881 goto out; 1882 } 1883 1884 if (password && password[0]) 1885 hx509_lock_add_password(lock, password); 1886 1887 if (prompter) { 1888 p.context = context; 1889 p.prompter = prompter; 1890 p.prompter_data = prompter_data; 1891 1892 ret = hx509_lock_set_prompter(lock, hx_pass_prompter, &p); 1893 if (ret) { 1894 hx509_lock_free(lock); 1895 goto out; 1896 } 1897 } 1898 1899 ret = hx509_certs_init(context->hx509ctx, user_id, 0, lock, &id->certs); 1900 hx509_lock_free(lock); 1901 if (ret) { 1902 pk_copy_error(context, context->hx509ctx, ret, 1903 "Failed to init cert certs"); 1904 goto out; 1905 } 1906 } else { 1907 id->certs = NULL; 1908 } 1909 1910 ret = hx509_certs_init(context->hx509ctx, anchor_id, 0, NULL, &id->anchors); 1911 if (ret) { 1912 pk_copy_error(context, context->hx509ctx, ret, 1913 "Failed to init anchors"); 1914 goto out; 1915 } 1916 1917 ret = hx509_certs_init(context->hx509ctx, "MEMORY:pkinit-cert-chain", 1918 0, NULL, &id->certpool); 1919 if (ret) { 1920 pk_copy_error(context, context->hx509ctx, ret, 1921 "Failed to init chain"); 1922 goto out; 1923 } 1924 1925 while (chain_list && *chain_list) { 1926 ret = hx509_certs_append(context->hx509ctx, id->certpool, 1927 NULL, *chain_list); 1928 if (ret) { 1929 pk_copy_error(context, context->hx509ctx, ret, 1930 "Failed to laod chain %s", 1931 *chain_list); 1932 goto out; 1933 } 1934 chain_list++; 1935 } 1936 1937 if (revoke_list) { 1938 ret = hx509_revoke_init(context->hx509ctx, &id->revokectx); 1939 if (ret) { 1940 pk_copy_error(context, context->hx509ctx, ret, 1941 "Failed init revoke list"); 1942 goto out; 1943 } 1944 1945 while (*revoke_list) { 1946 ret = hx509_revoke_add_crl(context->hx509ctx, 1947 id->revokectx, 1948 *revoke_list); 1949 if (ret) { 1950 pk_copy_error(context, context->hx509ctx, ret, 1951 "Failed load revoke list"); 1952 goto out; 1953 } 1954 revoke_list++; 1955 } 1956 } else 1957 hx509_context_set_missing_revoke(context->hx509ctx, 1); 1958 1959 ret = hx509_verify_init_ctx(context->hx509ctx, &id->verify_ctx); 1960 if (ret) { 1961 pk_copy_error(context, context->hx509ctx, ret, 1962 "Failed init verify context"); 1963 goto out; 1964 } 1965 1966 hx509_verify_attach_anchors(id->verify_ctx, id->anchors); 1967 hx509_verify_attach_revoke(id->verify_ctx, id->revokectx); 1968 1969 out: 1970 if (ret) { 1971 hx509_verify_destroy_ctx(id->verify_ctx); 1972 hx509_certs_free(&id->certs); 1973 hx509_certs_free(&id->anchors); 1974 hx509_certs_free(&id->certpool); 1975 hx509_revoke_free(&id->revokectx); 1976 free(id); 1977 } else 1978 *ret_id = id; 1979 1980 return ret; 1981 } 1982 1983 /* 1984 * 1985 */ 1986 1987 static void 1988 pk_copy_error(krb5_context context, 1989 hx509_context hx509ctx, 1990 int hxret, 1991 const char *fmt, 1992 ...) 1993 { 1994 va_list va; 1995 char *s, *f; 1996 int ret; 1997 1998 va_start(va, fmt); 1999 ret = vasprintf(&f, fmt, va); 2000 va_end(va); 2001 if (ret == -1 || f == NULL) { 2002 krb5_clear_error_message(context); 2003 return; 2004 } 2005 2006 s = hx509_get_error_string(hx509ctx, hxret); 2007 if (s == NULL) { 2008 krb5_clear_error_message(context); 2009 free(f); 2010 return; 2011 } 2012 krb5_set_error_message(context, hxret, "%s: %s", f, s); 2013 free(s); 2014 free(f); 2015 } 2016 2017 static int 2018 parse_integer(krb5_context context, char **p, const char *file, int lineno, 2019 const char *name, heim_integer *integer) 2020 { 2021 int ret; 2022 char *p1; 2023 p1 = strsep(p, " \t"); 2024 if (p1 == NULL) { 2025 krb5_set_error_message(context, EINVAL, 2026 N_("moduli file %s missing %s on line %d", ""), 2027 file, name, lineno); 2028 return EINVAL; 2029 } 2030 ret = der_parse_hex_heim_integer(p1, integer); 2031 if (ret) { 2032 krb5_set_error_message(context, ret, 2033 N_("moduli file %s failed parsing %s " 2034 "on line %d", ""), 2035 file, name, lineno); 2036 return ret; 2037 } 2038 2039 return 0; 2040 } 2041 2042 krb5_error_code 2043 _krb5_parse_moduli_line(krb5_context context, 2044 const char *file, 2045 int lineno, 2046 char *p, 2047 struct krb5_dh_moduli **m) 2048 { 2049 struct krb5_dh_moduli *m1; 2050 char *p1; 2051 int ret; 2052 2053 *m = NULL; 2054 2055 m1 = calloc(1, sizeof(*m1)); 2056 if (m1 == NULL) { 2057 krb5_set_error_message(context, ENOMEM, 2058 N_("malloc: out of memory", "")); 2059 return ENOMEM; 2060 } 2061 2062 while (isspace((unsigned char)*p)) 2063 p++; 2064 if (*p == '#') { 2065 free(m1); 2066 return 0; 2067 } 2068 ret = EINVAL; 2069 2070 p1 = strsep(&p, " \t"); 2071 if (p1 == NULL) { 2072 krb5_set_error_message(context, ret, 2073 N_("moduli file %s missing name on line %d", ""), 2074 file, lineno); 2075 goto out; 2076 } 2077 m1->name = strdup(p1); 2078 if (m1->name == NULL) { 2079 ret = ENOMEM; 2080 krb5_set_error_message(context, ret, N_("malloc: out of memeory", "")); 2081 goto out; 2082 } 2083 2084 p1 = strsep(&p, " \t"); 2085 if (p1 == NULL) { 2086 krb5_set_error_message(context, ret, 2087 N_("moduli file %s missing bits on line %d", ""), 2088 file, lineno); 2089 goto out; 2090 } 2091 2092 m1->bits = atoi(p1); 2093 if (m1->bits == 0) { 2094 krb5_set_error_message(context, ret, 2095 N_("moduli file %s have un-parsable " 2096 "bits on line %d", ""), file, lineno); 2097 goto out; 2098 } 2099 2100 ret = parse_integer(context, &p, file, lineno, "p", &m1->p); 2101 if (ret) 2102 goto out; 2103 ret = parse_integer(context, &p, file, lineno, "g", &m1->g); 2104 if (ret) 2105 goto out; 2106 ret = parse_integer(context, &p, file, lineno, "q", &m1->q); 2107 if (ret) 2108 goto out; 2109 2110 *m = m1; 2111 2112 return 0; 2113 out: 2114 free(m1->name); 2115 der_free_heim_integer(&m1->p); 2116 der_free_heim_integer(&m1->g); 2117 der_free_heim_integer(&m1->q); 2118 free(m1); 2119 return ret; 2120 } 2121 2122 void 2123 _krb5_free_moduli(struct krb5_dh_moduli **moduli) 2124 { 2125 int i; 2126 for (i = 0; moduli[i] != NULL; i++) { 2127 free(moduli[i]->name); 2128 der_free_heim_integer(&moduli[i]->p); 2129 der_free_heim_integer(&moduli[i]->g); 2130 der_free_heim_integer(&moduli[i]->q); 2131 free(moduli[i]); 2132 } 2133 free(moduli); 2134 } 2135 2136 static const char *default_moduli_RFC2412_MODP_group2 = 2137 /* name */ 2138 "RFC2412-MODP-group2 " 2139 /* bits */ 2140 "1024 " 2141 /* p */ 2142 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" 2143 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" 2144 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" 2145 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" 2146 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" 2147 "FFFFFFFF" "FFFFFFFF " 2148 /* g */ 2149 "02 " 2150 /* q */ 2151 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68" 2152 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E" 2153 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122" 2154 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6" 2155 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0" 2156 "FFFFFFFF" "FFFFFFFF"; 2157 2158 static const char *default_moduli_rfc3526_MODP_group14 = 2159 /* name */ 2160 "rfc3526-MODP-group14 " 2161 /* bits */ 2162 "1760 " 2163 /* p */ 2164 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" 2165 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" 2166 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" 2167 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" 2168 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D" 2169 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F" 2170 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D" 2171 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B" 2172 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9" 2173 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510" 2174 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF " 2175 /* g */ 2176 "02 " 2177 /* q */ 2178 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68" 2179 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E" 2180 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122" 2181 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6" 2182 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E" 2183 "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF" 2184 "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36" 2185 "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D" 2186 "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964" 2187 "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288" 2188 "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF"; 2189 2190 krb5_error_code 2191 _krb5_parse_moduli(krb5_context context, const char *file, 2192 struct krb5_dh_moduli ***moduli) 2193 { 2194 /* name bits P G Q */ 2195 krb5_error_code ret; 2196 struct krb5_dh_moduli **m = NULL, **m2; 2197 char buf[4096]; 2198 FILE *f; 2199 int lineno = 0, n = 0; 2200 2201 *moduli = NULL; 2202 2203 m = calloc(1, sizeof(m[0]) * 3); 2204 if (m == NULL) { 2205 krb5_set_error_message(context, ENOMEM, 2206 N_("malloc: out of memory", "")); 2207 return ENOMEM; 2208 } 2209 2210 strlcpy(buf, default_moduli_rfc3526_MODP_group14, sizeof(buf)); 2211 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[0]); 2212 if (ret) { 2213 _krb5_free_moduli(m); 2214 return ret; 2215 } 2216 n++; 2217 2218 strlcpy(buf, default_moduli_RFC2412_MODP_group2, sizeof(buf)); 2219 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[1]); 2220 if (ret) { 2221 _krb5_free_moduli(m); 2222 return ret; 2223 } 2224 n++; 2225 2226 2227 if (file == NULL) 2228 file = MODULI_FILE; 2229 2230 #ifdef KRB5_USE_PATH_TOKENS 2231 { 2232 char * exp_file; 2233 2234 if (_krb5_expand_path_tokens(context, file, &exp_file) == 0) { 2235 f = fopen(exp_file, "r"); 2236 krb5_xfree(exp_file); 2237 } else { 2238 f = NULL; 2239 } 2240 } 2241 #else 2242 f = fopen(file, "r"); 2243 #endif 2244 2245 if (f == NULL) { 2246 *moduli = m; 2247 return 0; 2248 } 2249 rk_cloexec_file(f); 2250 2251 while(fgets(buf, sizeof(buf), f) != NULL) { 2252 struct krb5_dh_moduli *element; 2253 2254 buf[strcspn(buf, "\n")] = '\0'; 2255 lineno++; 2256 2257 m2 = realloc(m, (n + 2) * sizeof(m[0])); 2258 if (m2 == NULL) { 2259 _krb5_free_moduli(m); 2260 krb5_set_error_message(context, ENOMEM, 2261 N_("malloc: out of memory", "")); 2262 return ENOMEM; 2263 } 2264 m = m2; 2265 2266 m[n] = NULL; 2267 2268 ret = _krb5_parse_moduli_line(context, file, lineno, buf, &element); 2269 if (ret) { 2270 _krb5_free_moduli(m); 2271 return ret; 2272 } 2273 if (element == NULL) 2274 continue; 2275 2276 m[n] = element; 2277 m[n + 1] = NULL; 2278 n++; 2279 } 2280 *moduli = m; 2281 return 0; 2282 } 2283 2284 krb5_error_code 2285 _krb5_dh_group_ok(krb5_context context, unsigned long bits, 2286 heim_integer *p, heim_integer *g, heim_integer *q, 2287 struct krb5_dh_moduli **moduli, 2288 char **name) 2289 { 2290 int i; 2291 2292 if (name) 2293 *name = NULL; 2294 2295 for (i = 0; moduli[i] != NULL; i++) { 2296 if (der_heim_integer_cmp(&moduli[i]->g, g) == 0 && 2297 der_heim_integer_cmp(&moduli[i]->p, p) == 0 && 2298 (q == NULL || der_heim_integer_cmp(&moduli[i]->q, q) == 0)) 2299 { 2300 if (bits && bits > moduli[i]->bits) { 2301 krb5_set_error_message(context, 2302 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED, 2303 N_("PKINIT: DH group parameter %s " 2304 "no accepted, not enough bits " 2305 "generated", ""), 2306 moduli[i]->name); 2307 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED; 2308 } 2309 if (name) 2310 *name = strdup(moduli[i]->name); 2311 return 0; 2312 } 2313 } 2314 krb5_set_error_message(context, 2315 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED, 2316 N_("PKINIT: DH group parameter no ok", "")); 2317 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED; 2318 } 2319 #endif /* PKINIT */ 2320 2321 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 2322 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt) 2323 { 2324 #ifdef PKINIT 2325 krb5_pk_init_ctx ctx; 2326 2327 if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL) 2328 return; 2329 ctx = opt->opt_private->pk_init_ctx; 2330 switch (ctx->keyex) { 2331 case USE_DH: 2332 if (ctx->u.dh) 2333 DH_free(ctx->u.dh); 2334 break; 2335 case USE_RSA: 2336 break; 2337 case USE_ECDH: 2338 #ifdef HAVE_OPENSSL 2339 if (ctx->u.eckey) 2340 EC_KEY_free(ctx->u.eckey); 2341 #endif 2342 break; 2343 } 2344 if (ctx->id) { 2345 hx509_verify_destroy_ctx(ctx->id->verify_ctx); 2346 hx509_certs_free(&ctx->id->certs); 2347 hx509_cert_free(ctx->id->cert); 2348 hx509_certs_free(&ctx->id->anchors); 2349 hx509_certs_free(&ctx->id->certpool); 2350 2351 if (ctx->clientDHNonce) { 2352 krb5_free_data(NULL, ctx->clientDHNonce); 2353 ctx->clientDHNonce = NULL; 2354 } 2355 if (ctx->m) 2356 _krb5_free_moduli(ctx->m); 2357 free(ctx->id); 2358 ctx->id = NULL; 2359 } 2360 free(opt->opt_private->pk_init_ctx); 2361 opt->opt_private->pk_init_ctx = NULL; 2362 #endif 2363 } 2364 2365 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2366 krb5_get_init_creds_opt_set_pkinit(krb5_context context, 2367 krb5_get_init_creds_opt *opt, 2368 krb5_principal principal, 2369 const char *user_id, 2370 const char *x509_anchors, 2371 char * const * pool, 2372 char * const * pki_revoke, 2373 int flags, 2374 krb5_prompter_fct prompter, 2375 void *prompter_data, 2376 char *password) 2377 { 2378 #ifdef PKINIT 2379 krb5_error_code ret; 2380 char *anchors = NULL; 2381 2382 if (opt->opt_private == NULL) { 2383 krb5_set_error_message(context, EINVAL, 2384 N_("PKINIT: on non extendable opt", "")); 2385 return EINVAL; 2386 } 2387 2388 opt->opt_private->pk_init_ctx = 2389 calloc(1, sizeof(*opt->opt_private->pk_init_ctx)); 2390 if (opt->opt_private->pk_init_ctx == NULL) { 2391 krb5_set_error_message(context, ENOMEM, 2392 N_("malloc: out of memory", "")); 2393 return ENOMEM; 2394 } 2395 opt->opt_private->pk_init_ctx->require_binding = 0; 2396 opt->opt_private->pk_init_ctx->require_eku = 1; 2397 opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1; 2398 opt->opt_private->pk_init_ctx->peer = NULL; 2399 2400 /* XXX implement krb5_appdefault_strings */ 2401 if (pool == NULL) 2402 pool = krb5_config_get_strings(context, NULL, 2403 "appdefaults", 2404 "pkinit_pool", 2405 NULL); 2406 2407 if (pki_revoke == NULL) 2408 pki_revoke = krb5_config_get_strings(context, NULL, 2409 "appdefaults", 2410 "pkinit_revoke", 2411 NULL); 2412 2413 if (x509_anchors == NULL) { 2414 krb5_appdefault_string(context, "kinit", 2415 krb5_principal_get_realm(context, principal), 2416 "pkinit_anchors", NULL, &anchors); 2417 x509_anchors = anchors; 2418 } 2419 2420 if (flags & 4) 2421 opt->opt_private->pk_init_ctx->anonymous = 1; 2422 2423 ret = _krb5_pk_load_id(context, 2424 &opt->opt_private->pk_init_ctx->id, 2425 user_id, 2426 x509_anchors, 2427 pool, 2428 pki_revoke, 2429 prompter, 2430 prompter_data, 2431 password); 2432 if (ret) { 2433 free(opt->opt_private->pk_init_ctx); 2434 opt->opt_private->pk_init_ctx = NULL; 2435 return ret; 2436 } 2437 2438 if (opt->opt_private->pk_init_ctx->id->certs) { 2439 _krb5_pk_set_user_id(context, 2440 principal, 2441 opt->opt_private->pk_init_ctx, 2442 opt->opt_private->pk_init_ctx->id->certs); 2443 } else 2444 opt->opt_private->pk_init_ctx->id->cert = NULL; 2445 2446 if ((flags & 2) == 0) { 2447 hx509_context hx509ctx = context->hx509ctx; 2448 hx509_cert cert = opt->opt_private->pk_init_ctx->id->cert; 2449 2450 opt->opt_private->pk_init_ctx->keyex = USE_DH; 2451 2452 /* 2453 * If its a ECDSA certs, lets select ECDSA as the keyex algorithm. 2454 */ 2455 if (cert) { 2456 AlgorithmIdentifier alg; 2457 2458 ret = hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx, cert, &alg); 2459 if (ret == 0) { 2460 if (der_heim_oid_cmp(&alg.algorithm, &asn1_oid_id_ecPublicKey) == 0) 2461 opt->opt_private->pk_init_ctx->keyex = USE_ECDH; 2462 free_AlgorithmIdentifier(&alg); 2463 } 2464 } 2465 2466 } else { 2467 opt->opt_private->pk_init_ctx->keyex = USE_RSA; 2468 2469 if (opt->opt_private->pk_init_ctx->id->certs == NULL) { 2470 krb5_set_error_message(context, EINVAL, 2471 N_("No anonymous pkinit support in RSA mode", "")); 2472 return EINVAL; 2473 } 2474 } 2475 2476 return 0; 2477 #else 2478 krb5_set_error_message(context, EINVAL, 2479 N_("no support for PKINIT compiled in", "")); 2480 return EINVAL; 2481 #endif 2482 } 2483 2484 krb5_error_code KRB5_LIB_FUNCTION 2485 krb5_get_init_creds_opt_set_pkinit_user_certs(krb5_context context, 2486 krb5_get_init_creds_opt *opt, 2487 struct hx509_certs_data *certs) 2488 { 2489 #ifdef PKINIT 2490 if (opt->opt_private == NULL) { 2491 krb5_set_error_message(context, EINVAL, 2492 N_("PKINIT: on non extendable opt", "")); 2493 return EINVAL; 2494 } 2495 if (opt->opt_private->pk_init_ctx == NULL) { 2496 krb5_set_error_message(context, EINVAL, 2497 N_("PKINIT: on pkinit context", "")); 2498 return EINVAL; 2499 } 2500 2501 _krb5_pk_set_user_id(context, NULL, opt->opt_private->pk_init_ctx, certs); 2502 2503 return 0; 2504 #else 2505 krb5_set_error_message(context, EINVAL, 2506 N_("no support for PKINIT compiled in", "")); 2507 return EINVAL; 2508 #endif 2509 } 2510 2511 #ifdef PKINIT 2512 2513 static int 2514 get_ms_san(hx509_context context, hx509_cert cert, char **upn) 2515 { 2516 hx509_octet_string_list list; 2517 int ret; 2518 2519 *upn = NULL; 2520 2521 ret = hx509_cert_find_subjectAltName_otherName(context, 2522 cert, 2523 &asn1_oid_id_pkinit_ms_san, 2524 &list); 2525 if (ret) 2526 return 0; 2527 2528 if (list.len > 0 && list.val[0].length > 0) 2529 ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length, 2530 upn, NULL); 2531 else 2532 ret = 1; 2533 hx509_free_octet_string_list(&list); 2534 2535 return ret; 2536 } 2537 2538 static int 2539 find_ms_san(hx509_context context, hx509_cert cert, void *ctx) 2540 { 2541 char *upn; 2542 int ret; 2543 2544 ret = get_ms_san(context, cert, &upn); 2545 if (ret == 0) 2546 free(upn); 2547 return ret; 2548 } 2549 2550 2551 2552 #endif 2553 2554 /* 2555 * Private since it need to be redesigned using krb5_get_init_creds() 2556 */ 2557 2558 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2559 krb5_pk_enterprise_cert(krb5_context context, 2560 const char *user_id, 2561 krb5_const_realm realm, 2562 krb5_principal *principal, 2563 struct hx509_certs_data **res) 2564 { 2565 #ifdef PKINIT 2566 krb5_error_code ret; 2567 hx509_certs certs, result; 2568 hx509_cert cert = NULL; 2569 hx509_query *q; 2570 char *name; 2571 2572 *principal = NULL; 2573 if (res) 2574 *res = NULL; 2575 2576 if (user_id == NULL) { 2577 krb5_set_error_message(context, ENOENT, "no user id"); 2578 return ENOENT; 2579 } 2580 2581 ret = hx509_certs_init(context->hx509ctx, user_id, 0, NULL, &certs); 2582 if (ret) { 2583 pk_copy_error(context, context->hx509ctx, ret, 2584 "Failed to init cert certs"); 2585 goto out; 2586 } 2587 2588 ret = hx509_query_alloc(context->hx509ctx, &q); 2589 if (ret) { 2590 krb5_set_error_message(context, ret, "out of memory"); 2591 hx509_certs_free(&certs); 2592 goto out; 2593 } 2594 2595 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); 2596 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); 2597 hx509_query_match_eku(q, &asn1_oid_id_pkinit_ms_eku); 2598 hx509_query_match_cmp_func(q, find_ms_san, NULL); 2599 2600 ret = hx509_certs_filter(context->hx509ctx, certs, q, &result); 2601 hx509_query_free(context->hx509ctx, q); 2602 hx509_certs_free(&certs); 2603 if (ret) { 2604 pk_copy_error(context, context->hx509ctx, ret, 2605 "Failed to find PKINIT certificate"); 2606 return ret; 2607 } 2608 2609 ret = hx509_get_one_cert(context->hx509ctx, result, &cert); 2610 hx509_certs_free(&result); 2611 if (ret) { 2612 pk_copy_error(context, context->hx509ctx, ret, 2613 "Failed to get one cert"); 2614 goto out; 2615 } 2616 2617 ret = get_ms_san(context->hx509ctx, cert, &name); 2618 if (ret) { 2619 pk_copy_error(context, context->hx509ctx, ret, 2620 "Failed to get MS SAN"); 2621 goto out; 2622 } 2623 2624 ret = krb5_make_principal(context, principal, realm, name, NULL); 2625 free(name); 2626 if (ret) 2627 goto out; 2628 2629 krb5_principal_set_type(context, *principal, KRB5_NT_ENTERPRISE_PRINCIPAL); 2630 2631 if (res) { 2632 ret = hx509_certs_init(context->hx509ctx, "MEMORY:", 0, NULL, res); 2633 if (ret) 2634 goto out; 2635 2636 ret = hx509_certs_add(context->hx509ctx, *res, cert); 2637 if (ret) { 2638 hx509_certs_free(res); 2639 goto out; 2640 } 2641 } 2642 2643 out: 2644 hx509_cert_free(cert); 2645 2646 return ret; 2647 #else 2648 krb5_set_error_message(context, EINVAL, 2649 N_("no support for PKINIT compiled in", "")); 2650 return EINVAL; 2651 #endif 2652 } 2653