1178825Sdfr/* 2233294Sstas * Copyright (c) 2003 - 2007 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 5178825Sdfr * 6233294Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 7178825Sdfr * 8233294Sstas * Redistribution and use in source and binary forms, with or without 9233294Sstas * modification, are permitted provided that the following conditions 10233294Sstas * are met: 11178825Sdfr * 12233294Sstas * 1. Redistributions of source code must retain the above copyright 13233294Sstas * notice, this list of conditions and the following disclaimer. 14178825Sdfr * 15233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 16233294Sstas * notice, this list of conditions and the following disclaimer in the 17233294Sstas * documentation and/or other materials provided with the distribution. 18178825Sdfr * 19233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 20233294Sstas * may be used to endorse or promote products derived from this software 21233294Sstas * without specific prior written permission. 22233294Sstas * 23233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33233294Sstas * SUCH DAMAGE. 34178825Sdfr */ 35178825Sdfr 36178825Sdfr#include "krb5_locl.h" 37178825Sdfr 38178825Sdfrstruct krb5_dh_moduli { 39178825Sdfr char *name; 40178825Sdfr unsigned long bits; 41178825Sdfr heim_integer p; 42178825Sdfr heim_integer g; 43178825Sdfr heim_integer q; 44178825Sdfr}; 45178825Sdfr 46178825Sdfr#ifdef PKINIT 47178825Sdfr 48178825Sdfr#include <cms_asn1.h> 49178825Sdfr#include <pkcs8_asn1.h> 50178825Sdfr#include <pkcs9_asn1.h> 51178825Sdfr#include <pkcs12_asn1.h> 52178825Sdfr#include <pkinit_asn1.h> 53178825Sdfr#include <asn1_err.h> 54178825Sdfr 55178825Sdfr#include <der.h> 56178825Sdfr 57178825Sdfrstruct krb5_pk_cert { 58178825Sdfr hx509_cert cert; 59178825Sdfr}; 60178825Sdfr 61178825Sdfrstruct krb5_pk_init_ctx_data { 62178825Sdfr struct krb5_pk_identity *id; 63233294Sstas enum { USE_RSA, USE_DH, USE_ECDH } keyex; 64233294Sstas union { 65233294Sstas DH *dh; 66233294Sstas#ifdef HAVE_OPENSSL 67233294Sstas EC_KEY *eckey; 68233294Sstas#endif 69233294Sstas } u; 70178825Sdfr krb5_data *clientDHNonce; 71178825Sdfr struct krb5_dh_moduli **m; 72178825Sdfr hx509_peer_info peer; 73233294Sstas enum krb5_pk_type type; 74178825Sdfr unsigned int require_binding:1; 75178825Sdfr unsigned int require_eku:1; 76178825Sdfr unsigned int require_krbtgt_otherName:1; 77178825Sdfr unsigned int require_hostname_match:1; 78178825Sdfr unsigned int trustedCertifiers:1; 79233294Sstas unsigned int anonymous:1; 80178825Sdfr}; 81178825Sdfr 82178825Sdfrstatic void 83233294Sstaspk_copy_error(krb5_context context, 84233294Sstas hx509_context hx509ctx, 85233294Sstas int hxret, 86233294Sstas const char *fmt, 87233294Sstas ...) 88178825Sdfr __attribute__ ((format (printf, 4, 5))); 89178825Sdfr 90178825Sdfr/* 91178825Sdfr * 92178825Sdfr */ 93178825Sdfr 94233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL 95178825Sdfr_krb5_pk_cert_free(struct krb5_pk_cert *cert) 96178825Sdfr{ 97178825Sdfr if (cert->cert) { 98178825Sdfr hx509_cert_free(cert->cert); 99178825Sdfr } 100178825Sdfr free(cert); 101178825Sdfr} 102178825Sdfr 103178825Sdfrstatic krb5_error_code 104178825SdfrBN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer) 105178825Sdfr{ 106178825Sdfr integer->length = BN_num_bytes(bn); 107178825Sdfr integer->data = malloc(integer->length); 108178825Sdfr if (integer->data == NULL) { 109233294Sstas krb5_clear_error_message(context); 110178825Sdfr return ENOMEM; 111178825Sdfr } 112178825Sdfr BN_bn2bin(bn, integer->data); 113178825Sdfr integer->negative = BN_is_negative(bn); 114178825Sdfr return 0; 115178825Sdfr} 116178825Sdfr 117178825Sdfrstatic BIGNUM * 118178825Sdfrinteger_to_BN(krb5_context context, const char *field, const heim_integer *f) 119178825Sdfr{ 120178825Sdfr BIGNUM *bn; 121178825Sdfr 122178825Sdfr bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL); 123178825Sdfr if (bn == NULL) { 124233294Sstas krb5_set_error_message(context, ENOMEM, 125233294Sstas N_("PKINIT: parsing BN failed %s", ""), field); 126178825Sdfr return NULL; 127178825Sdfr } 128178825Sdfr BN_set_negative(bn, f->negative); 129178825Sdfr return bn; 130178825Sdfr} 131178825Sdfr 132178825Sdfrstatic krb5_error_code 133233294Sstasselect_dh_group(krb5_context context, DH *dh, unsigned long bits, 134233294Sstas struct krb5_dh_moduli **moduli) 135178825Sdfr{ 136233294Sstas const struct krb5_dh_moduli *m; 137178825Sdfr 138233294Sstas if (bits == 0) { 139233294Sstas m = moduli[1]; /* XXX */ 140233294Sstas if (m == NULL) 141233294Sstas m = moduli[0]; /* XXX */ 142233294Sstas } else { 143233294Sstas int i; 144233294Sstas for (i = 0; moduli[i] != NULL; i++) { 145233294Sstas if (bits < moduli[i]->bits) 146233294Sstas break; 147233294Sstas } 148233294Sstas if (moduli[i] == NULL) { 149233294Sstas krb5_set_error_message(context, EINVAL, 150233294Sstas N_("Did not find a DH group parameter " 151233294Sstas "matching requirement of %lu bits", ""), 152233294Sstas bits); 153233294Sstas return EINVAL; 154233294Sstas } 155233294Sstas m = moduli[i]; 156178825Sdfr } 157178825Sdfr 158233294Sstas dh->p = integer_to_BN(context, "p", &m->p); 159233294Sstas if (dh->p == NULL) 160233294Sstas return ENOMEM; 161233294Sstas dh->g = integer_to_BN(context, "g", &m->g); 162233294Sstas if (dh->g == NULL) 163233294Sstas return ENOMEM; 164233294Sstas dh->q = integer_to_BN(context, "q", &m->q); 165233294Sstas if (dh->q == NULL) 166233294Sstas return ENOMEM; 167178825Sdfr 168233294Sstas return 0; 169233294Sstas} 170233294Sstas 171233294Sstasstruct certfind { 172233294Sstas const char *type; 173233294Sstas const heim_oid *oid; 174233294Sstas}; 175233294Sstas 176233294Sstas/* 177233294Sstas * Try searchin the key by to use by first looking for for PK-INIT 178233294Sstas * EKU, then the Microsoft smart card EKU and last, no special EKU at all. 179233294Sstas */ 180233294Sstas 181233294Sstasstatic krb5_error_code 182233294Sstasfind_cert(krb5_context context, struct krb5_pk_identity *id, 183233294Sstas hx509_query *q, hx509_cert *cert) 184233294Sstas{ 185233294Sstas struct certfind cf[4] = { 186233294Sstas { "MobileMe EKU" }, 187233294Sstas { "PKINIT EKU" }, 188233294Sstas { "MS EKU" }, 189233294Sstas { "any (or no)" } 190233294Sstas }; 191233294Sstas int ret = HX509_CERT_NOT_FOUND; 192233294Sstas size_t i, start = 1; 193233294Sstas unsigned oids[] = { 1, 2, 840, 113635, 100, 3, 2, 1 }; 194233294Sstas const heim_oid mobileMe = { sizeof(oids)/sizeof(oids[0]), oids }; 195233294Sstas 196233294Sstas 197233294Sstas if (id->flags & PKINIT_BTMM) 198233294Sstas start = 0; 199233294Sstas 200233294Sstas cf[0].oid = &mobileMe; 201233294Sstas cf[1].oid = &asn1_oid_id_pkekuoid; 202233294Sstas cf[2].oid = &asn1_oid_id_pkinit_ms_eku; 203233294Sstas cf[3].oid = NULL; 204233294Sstas 205233294Sstas for (i = start; i < sizeof(cf)/sizeof(cf[0]); i++) { 206233294Sstas ret = hx509_query_match_eku(q, cf[i].oid); 207233294Sstas if (ret) { 208233294Sstas pk_copy_error(context, context->hx509ctx, ret, 209233294Sstas "Failed setting %s OID", cf[i].type); 210233294Sstas return ret; 211233294Sstas } 212233294Sstas 213233294Sstas ret = hx509_certs_find(context->hx509ctx, id->certs, q, cert); 214233294Sstas if (ret == 0) 215233294Sstas break; 216233294Sstas pk_copy_error(context, context->hx509ctx, ret, 217233294Sstas "Failed finding certificate with %s OID", cf[i].type); 218178825Sdfr } 219233294Sstas return ret; 220233294Sstas} 221178825Sdfr 222233294Sstas 223233294Sstasstatic krb5_error_code 224233294Sstascreate_signature(krb5_context context, 225233294Sstas const heim_oid *eContentType, 226233294Sstas krb5_data *eContent, 227233294Sstas struct krb5_pk_identity *id, 228233294Sstas hx509_peer_info peer, 229233294Sstas krb5_data *sd_data) 230233294Sstas{ 231233294Sstas int ret, flags = 0; 232233294Sstas 233233294Sstas if (id->cert == NULL) 234233294Sstas flags |= HX509_CMS_SIGNATURE_NO_SIGNER; 235233294Sstas 236233294Sstas ret = hx509_cms_create_signed_1(context->hx509ctx, 237233294Sstas flags, 238178825Sdfr eContentType, 239178825Sdfr eContent->data, 240178825Sdfr eContent->length, 241178825Sdfr NULL, 242233294Sstas id->cert, 243178825Sdfr peer, 244178825Sdfr NULL, 245178825Sdfr id->certs, 246178825Sdfr sd_data); 247233294Sstas if (ret) { 248233294Sstas pk_copy_error(context, context->hx509ctx, ret, 249233294Sstas "Create CMS signedData"); 250233294Sstas return ret; 251233294Sstas } 252178825Sdfr 253233294Sstas return 0; 254178825Sdfr} 255178825Sdfr 256178825Sdfrstatic int 257178825Sdfrcert2epi(hx509_context context, void *ctx, hx509_cert c) 258178825Sdfr{ 259178825Sdfr ExternalPrincipalIdentifiers *ids = ctx; 260178825Sdfr ExternalPrincipalIdentifier id; 261178825Sdfr hx509_name subject = NULL; 262178825Sdfr void *p; 263178825Sdfr int ret; 264178825Sdfr 265233294Sstas if (ids->len > 10) 266233294Sstas return 0; 267233294Sstas 268178825Sdfr memset(&id, 0, sizeof(id)); 269178825Sdfr 270178825Sdfr ret = hx509_cert_get_subject(c, &subject); 271178825Sdfr if (ret) 272178825Sdfr return ret; 273178825Sdfr 274178825Sdfr if (hx509_name_is_null_p(subject) != 0) { 275178825Sdfr 276178825Sdfr id.subjectName = calloc(1, sizeof(*id.subjectName)); 277178825Sdfr if (id.subjectName == NULL) { 278178825Sdfr hx509_name_free(&subject); 279178825Sdfr free_ExternalPrincipalIdentifier(&id); 280178825Sdfr return ENOMEM; 281178825Sdfr } 282233294Sstas 283178825Sdfr ret = hx509_name_binary(subject, id.subjectName); 284178825Sdfr if (ret) { 285178825Sdfr hx509_name_free(&subject); 286178825Sdfr free_ExternalPrincipalIdentifier(&id); 287178825Sdfr return ret; 288178825Sdfr } 289178825Sdfr } 290178825Sdfr hx509_name_free(&subject); 291178825Sdfr 292178825Sdfr 293178825Sdfr id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber)); 294178825Sdfr if (id.issuerAndSerialNumber == NULL) { 295178825Sdfr free_ExternalPrincipalIdentifier(&id); 296178825Sdfr return ENOMEM; 297178825Sdfr } 298178825Sdfr 299178825Sdfr { 300178825Sdfr IssuerAndSerialNumber iasn; 301178825Sdfr hx509_name issuer; 302233294Sstas size_t size = 0; 303233294Sstas 304178825Sdfr memset(&iasn, 0, sizeof(iasn)); 305178825Sdfr 306178825Sdfr ret = hx509_cert_get_issuer(c, &issuer); 307178825Sdfr if (ret) { 308178825Sdfr free_ExternalPrincipalIdentifier(&id); 309178825Sdfr return ret; 310178825Sdfr } 311178825Sdfr 312178825Sdfr ret = hx509_name_to_Name(issuer, &iasn.issuer); 313178825Sdfr hx509_name_free(&issuer); 314178825Sdfr if (ret) { 315178825Sdfr free_ExternalPrincipalIdentifier(&id); 316178825Sdfr return ret; 317178825Sdfr } 318233294Sstas 319178825Sdfr ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber); 320178825Sdfr if (ret) { 321178825Sdfr free_IssuerAndSerialNumber(&iasn); 322178825Sdfr free_ExternalPrincipalIdentifier(&id); 323178825Sdfr return ret; 324178825Sdfr } 325178825Sdfr 326178825Sdfr ASN1_MALLOC_ENCODE(IssuerAndSerialNumber, 327233294Sstas id.issuerAndSerialNumber->data, 328178825Sdfr id.issuerAndSerialNumber->length, 329178825Sdfr &iasn, &size, ret); 330178825Sdfr free_IssuerAndSerialNumber(&iasn); 331178825Sdfr if (ret) 332178825Sdfr return ret; 333178825Sdfr if (id.issuerAndSerialNumber->length != size) 334178825Sdfr abort(); 335178825Sdfr } 336178825Sdfr 337178825Sdfr id.subjectKeyIdentifier = NULL; 338178825Sdfr 339233294Sstas p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1)); 340178825Sdfr if (p == NULL) { 341178825Sdfr free_ExternalPrincipalIdentifier(&id); 342178825Sdfr return ENOMEM; 343178825Sdfr } 344178825Sdfr 345178825Sdfr ids->val = p; 346178825Sdfr ids->val[ids->len] = id; 347178825Sdfr ids->len++; 348178825Sdfr 349178825Sdfr return 0; 350178825Sdfr} 351178825Sdfr 352178825Sdfrstatic krb5_error_code 353178825Sdfrbuild_edi(krb5_context context, 354178825Sdfr hx509_context hx509ctx, 355178825Sdfr hx509_certs certs, 356178825Sdfr ExternalPrincipalIdentifiers *ids) 357178825Sdfr{ 358233294Sstas return hx509_certs_iter_f(hx509ctx, certs, cert2epi, ids); 359178825Sdfr} 360178825Sdfr 361178825Sdfrstatic krb5_error_code 362178825Sdfrbuild_auth_pack(krb5_context context, 363178825Sdfr unsigned nonce, 364178825Sdfr krb5_pk_init_ctx ctx, 365178825Sdfr const KDC_REQ_BODY *body, 366178825Sdfr AuthPack *a) 367178825Sdfr{ 368233294Sstas size_t buf_size, len = 0; 369178825Sdfr krb5_error_code ret; 370178825Sdfr void *buf; 371178825Sdfr krb5_timestamp sec; 372178825Sdfr int32_t usec; 373178825Sdfr Checksum checksum; 374178825Sdfr 375233294Sstas krb5_clear_error_message(context); 376178825Sdfr 377178825Sdfr memset(&checksum, 0, sizeof(checksum)); 378178825Sdfr 379178825Sdfr krb5_us_timeofday(context, &sec, &usec); 380178825Sdfr a->pkAuthenticator.ctime = sec; 381178825Sdfr a->pkAuthenticator.nonce = nonce; 382178825Sdfr 383178825Sdfr ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret); 384178825Sdfr if (ret) 385178825Sdfr return ret; 386178825Sdfr if (buf_size != len) 387178825Sdfr krb5_abortx(context, "internal error in ASN.1 encoder"); 388178825Sdfr 389178825Sdfr ret = krb5_create_checksum(context, 390178825Sdfr NULL, 391178825Sdfr 0, 392178825Sdfr CKSUMTYPE_SHA1, 393178825Sdfr buf, 394178825Sdfr len, 395178825Sdfr &checksum); 396178825Sdfr free(buf); 397233294Sstas if (ret) 398178825Sdfr return ret; 399178825Sdfr 400178825Sdfr ALLOC(a->pkAuthenticator.paChecksum, 1); 401178825Sdfr if (a->pkAuthenticator.paChecksum == NULL) { 402233294Sstas krb5_set_error_message(context, ENOMEM, 403233294Sstas N_("malloc: out of memory", "")); 404178825Sdfr return ENOMEM; 405178825Sdfr } 406178825Sdfr 407178825Sdfr ret = krb5_data_copy(a->pkAuthenticator.paChecksum, 408178825Sdfr checksum.checksum.data, checksum.checksum.length); 409178825Sdfr free_Checksum(&checksum); 410178825Sdfr if (ret) 411178825Sdfr return ret; 412178825Sdfr 413233294Sstas if (ctx->keyex == USE_DH || ctx->keyex == USE_ECDH) { 414233294Sstas const char *moduli_file; 415233294Sstas unsigned long dh_min_bits; 416178825Sdfr krb5_data dhbuf; 417233294Sstas size_t size = 0; 418178825Sdfr 419233294Sstas krb5_data_zero(&dhbuf); 420233294Sstas 421233294Sstas 422233294Sstas 423233294Sstas moduli_file = krb5_config_get_string(context, NULL, 424233294Sstas "libdefaults", 425233294Sstas "moduli", 426233294Sstas NULL); 427233294Sstas 428233294Sstas dh_min_bits = 429233294Sstas krb5_config_get_int_default(context, NULL, 0, 430233294Sstas "libdefaults", 431233294Sstas "pkinit_dh_min_bits", 432233294Sstas NULL); 433233294Sstas 434233294Sstas ret = _krb5_parse_moduli(context, moduli_file, &ctx->m); 435233294Sstas if (ret) 436233294Sstas return ret; 437233294Sstas 438233294Sstas ctx->u.dh = DH_new(); 439233294Sstas if (ctx->u.dh == NULL) { 440233294Sstas krb5_set_error_message(context, ENOMEM, 441233294Sstas N_("malloc: out of memory", "")); 442233294Sstas return ENOMEM; 443233294Sstas } 444233294Sstas 445233294Sstas ret = select_dh_group(context, ctx->u.dh, dh_min_bits, ctx->m); 446233294Sstas if (ret) 447233294Sstas return ret; 448233294Sstas 449233294Sstas if (DH_generate_key(ctx->u.dh) != 1) { 450233294Sstas krb5_set_error_message(context, ENOMEM, 451233294Sstas N_("pkinit: failed to generate DH key", "")); 452233294Sstas return ENOMEM; 453233294Sstas } 454233294Sstas 455233294Sstas 456178825Sdfr if (1 /* support_cached_dh */) { 457178825Sdfr ALLOC(a->clientDHNonce, 1); 458178825Sdfr if (a->clientDHNonce == NULL) { 459233294Sstas krb5_clear_error_message(context); 460178825Sdfr return ENOMEM; 461178825Sdfr } 462178825Sdfr ret = krb5_data_alloc(a->clientDHNonce, 40); 463178825Sdfr if (a->clientDHNonce == NULL) { 464233294Sstas krb5_clear_error_message(context); 465233294Sstas return ret; 466178825Sdfr } 467233294Sstas RAND_bytes(a->clientDHNonce->data, a->clientDHNonce->length); 468233294Sstas ret = krb5_copy_data(context, a->clientDHNonce, 469178825Sdfr &ctx->clientDHNonce); 470178825Sdfr if (ret) 471178825Sdfr return ret; 472178825Sdfr } 473178825Sdfr 474178825Sdfr ALLOC(a->clientPublicValue, 1); 475178825Sdfr if (a->clientPublicValue == NULL) 476178825Sdfr return ENOMEM; 477178825Sdfr 478233294Sstas if (ctx->keyex == USE_DH) { 479233294Sstas DH *dh = ctx->u.dh; 480233294Sstas DomainParameters dp; 481233294Sstas heim_integer dh_pub_key; 482178825Sdfr 483233294Sstas ret = der_copy_oid(&asn1_oid_id_dhpublicnumber, 484233294Sstas &a->clientPublicValue->algorithm.algorithm); 485233294Sstas if (ret) 486233294Sstas return ret; 487233294Sstas 488233294Sstas memset(&dp, 0, sizeof(dp)); 489233294Sstas 490233294Sstas ret = BN_to_integer(context, dh->p, &dp.p); 491233294Sstas if (ret) { 492233294Sstas free_DomainParameters(&dp); 493233294Sstas return ret; 494233294Sstas } 495233294Sstas ret = BN_to_integer(context, dh->g, &dp.g); 496233294Sstas if (ret) { 497233294Sstas free_DomainParameters(&dp); 498233294Sstas return ret; 499233294Sstas } 500233294Sstas ret = BN_to_integer(context, dh->q, &dp.q); 501233294Sstas if (ret) { 502233294Sstas free_DomainParameters(&dp); 503233294Sstas return ret; 504233294Sstas } 505233294Sstas dp.j = NULL; 506233294Sstas dp.validationParms = NULL; 507233294Sstas 508233294Sstas a->clientPublicValue->algorithm.parameters = 509233294Sstas malloc(sizeof(*a->clientPublicValue->algorithm.parameters)); 510233294Sstas if (a->clientPublicValue->algorithm.parameters == NULL) { 511233294Sstas free_DomainParameters(&dp); 512233294Sstas return ret; 513233294Sstas } 514233294Sstas 515233294Sstas ASN1_MALLOC_ENCODE(DomainParameters, 516233294Sstas a->clientPublicValue->algorithm.parameters->data, 517233294Sstas a->clientPublicValue->algorithm.parameters->length, 518233294Sstas &dp, &size, ret); 519178825Sdfr free_DomainParameters(&dp); 520233294Sstas if (ret) 521233294Sstas return ret; 522233294Sstas if (size != a->clientPublicValue->algorithm.parameters->length) 523233294Sstas krb5_abortx(context, "Internal ASN1 encoder error"); 524178825Sdfr 525233294Sstas ret = BN_to_integer(context, dh->pub_key, &dh_pub_key); 526233294Sstas if (ret) 527233294Sstas return ret; 528178825Sdfr 529233294Sstas ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length, 530233294Sstas &dh_pub_key, &size, ret); 531233294Sstas der_free_heim_integer(&dh_pub_key); 532233294Sstas if (ret) 533233294Sstas return ret; 534233294Sstas if (size != dhbuf.length) 535233294Sstas krb5_abortx(context, "asn1 internal error"); 536233294Sstas } else if (ctx->keyex == USE_ECDH) { 537233294Sstas#ifdef HAVE_OPENSSL 538233294Sstas ECParameters ecp; 539233294Sstas unsigned char *p; 540233294Sstas int xlen; 541178825Sdfr 542233294Sstas /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */ 543178825Sdfr 544233294Sstas ecp.element = choice_ECParameters_namedCurve; 545233294Sstas ret = der_copy_oid(&asn1_oid_id_ec_group_secp256r1, 546233294Sstas &ecp.u.namedCurve); 547233294Sstas if (ret) 548233294Sstas return ret; 549233294Sstas 550233294Sstas ALLOC(a->clientPublicValue->algorithm.parameters, 1); 551233294Sstas if (a->clientPublicValue->algorithm.parameters == NULL) { 552233294Sstas free_ECParameters(&ecp); 553233294Sstas return ENOMEM; 554233294Sstas } 555233294Sstas ASN1_MALLOC_ENCODE(ECParameters, p, xlen, &ecp, &size, ret); 556233294Sstas free_ECParameters(&ecp); 557233294Sstas if (ret) 558233294Sstas return ret; 559233294Sstas if ((int)size != xlen) 560233294Sstas krb5_abortx(context, "asn1 internal error"); 561233294Sstas 562233294Sstas a->clientPublicValue->algorithm.parameters->data = p; 563233294Sstas a->clientPublicValue->algorithm.parameters->length = size; 564233294Sstas 565233294Sstas /* copy in public key */ 566233294Sstas 567233294Sstas ret = der_copy_oid(&asn1_oid_id_ecPublicKey, 568233294Sstas &a->clientPublicValue->algorithm.algorithm); 569233294Sstas if (ret) 570233294Sstas return ret; 571233294Sstas 572233294Sstas ctx->u.eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); 573233294Sstas if (ctx->u.eckey == NULL) 574233294Sstas return ENOMEM; 575233294Sstas 576233294Sstas ret = EC_KEY_generate_key(ctx->u.eckey); 577233294Sstas if (ret != 1) 578233294Sstas return EINVAL; 579233294Sstas 580233294Sstas /* encode onto dhkey */ 581233294Sstas 582233294Sstas xlen = i2o_ECPublicKey(ctx->u.eckey, NULL); 583233294Sstas if (xlen <= 0) 584233294Sstas abort(); 585233294Sstas 586233294Sstas dhbuf.data = malloc(xlen); 587233294Sstas if (dhbuf.data == NULL) 588233294Sstas abort(); 589233294Sstas dhbuf.length = xlen; 590233294Sstas p = dhbuf.data; 591233294Sstas 592233294Sstas xlen = i2o_ECPublicKey(ctx->u.eckey, &p); 593233294Sstas if (xlen <= 0) 594233294Sstas abort(); 595233294Sstas 596233294Sstas /* XXX verify that this is right with RFC3279 */ 597233294Sstas#else 598233294Sstas return EINVAL; 599233294Sstas#endif 600233294Sstas } else 601233294Sstas krb5_abortx(context, "internal error"); 602178825Sdfr a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8; 603178825Sdfr a->clientPublicValue->subjectPublicKey.data = dhbuf.data; 604178825Sdfr } 605178825Sdfr 606178825Sdfr { 607178825Sdfr a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes)); 608178825Sdfr if (a->supportedCMSTypes == NULL) 609178825Sdfr return ENOMEM; 610178825Sdfr 611233294Sstas ret = hx509_crypto_available(context->hx509ctx, HX509_SELECT_ALL, 612233294Sstas ctx->id->cert, 613178825Sdfr &a->supportedCMSTypes->val, 614178825Sdfr &a->supportedCMSTypes->len); 615178825Sdfr if (ret) 616178825Sdfr return ret; 617178825Sdfr } 618178825Sdfr 619178825Sdfr return ret; 620178825Sdfr} 621178825Sdfr 622233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 623178825Sdfr_krb5_pk_mk_ContentInfo(krb5_context context, 624233294Sstas const krb5_data *buf, 625178825Sdfr const heim_oid *oid, 626178825Sdfr struct ContentInfo *content_info) 627178825Sdfr{ 628178825Sdfr krb5_error_code ret; 629178825Sdfr 630178825Sdfr ret = der_copy_oid(oid, &content_info->contentType); 631178825Sdfr if (ret) 632178825Sdfr return ret; 633178825Sdfr ALLOC(content_info->content, 1); 634178825Sdfr if (content_info->content == NULL) 635178825Sdfr return ENOMEM; 636178825Sdfr content_info->content->data = malloc(buf->length); 637178825Sdfr if (content_info->content->data == NULL) 638178825Sdfr return ENOMEM; 639178825Sdfr memcpy(content_info->content->data, buf->data, buf->length); 640178825Sdfr content_info->content->length = buf->length; 641178825Sdfr return 0; 642178825Sdfr} 643178825Sdfr 644178825Sdfrstatic krb5_error_code 645178825Sdfrpk_mk_padata(krb5_context context, 646178825Sdfr krb5_pk_init_ctx ctx, 647178825Sdfr const KDC_REQ_BODY *req_body, 648178825Sdfr unsigned nonce, 649178825Sdfr METHOD_DATA *md) 650178825Sdfr{ 651178825Sdfr struct ContentInfo content_info; 652178825Sdfr krb5_error_code ret; 653233294Sstas const heim_oid *oid = NULL; 654233294Sstas size_t size = 0; 655178825Sdfr krb5_data buf, sd_buf; 656233294Sstas int pa_type = -1; 657178825Sdfr 658178825Sdfr krb5_data_zero(&buf); 659178825Sdfr krb5_data_zero(&sd_buf); 660178825Sdfr memset(&content_info, 0, sizeof(content_info)); 661178825Sdfr 662233294Sstas if (ctx->type == PKINIT_WIN2K) { 663178825Sdfr AuthPack_Win2k ap; 664178825Sdfr krb5_timestamp sec; 665178825Sdfr int32_t usec; 666178825Sdfr 667178825Sdfr memset(&ap, 0, sizeof(ap)); 668178825Sdfr 669178825Sdfr /* fill in PKAuthenticator */ 670178825Sdfr ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName); 671178825Sdfr if (ret) { 672178825Sdfr free_AuthPack_Win2k(&ap); 673233294Sstas krb5_clear_error_message(context); 674178825Sdfr goto out; 675178825Sdfr } 676178825Sdfr ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm); 677178825Sdfr if (ret) { 678178825Sdfr free_AuthPack_Win2k(&ap); 679233294Sstas krb5_clear_error_message(context); 680178825Sdfr goto out; 681178825Sdfr } 682178825Sdfr 683178825Sdfr krb5_us_timeofday(context, &sec, &usec); 684178825Sdfr ap.pkAuthenticator.ctime = sec; 685178825Sdfr ap.pkAuthenticator.cusec = usec; 686178825Sdfr ap.pkAuthenticator.nonce = nonce; 687178825Sdfr 688178825Sdfr ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length, 689178825Sdfr &ap, &size, ret); 690178825Sdfr free_AuthPack_Win2k(&ap); 691178825Sdfr if (ret) { 692233294Sstas krb5_set_error_message(context, ret, 693233294Sstas N_("Failed encoding AuthPackWin: %d", ""), 694233294Sstas (int)ret); 695178825Sdfr goto out; 696178825Sdfr } 697178825Sdfr if (buf.length != size) 698178825Sdfr krb5_abortx(context, "internal ASN1 encoder error"); 699178825Sdfr 700233294Sstas oid = &asn1_oid_id_pkcs7_data; 701233294Sstas } else if (ctx->type == PKINIT_27) { 702178825Sdfr AuthPack ap; 703233294Sstas 704178825Sdfr memset(&ap, 0, sizeof(ap)); 705178825Sdfr 706233294Sstas ret = build_auth_pack(context, nonce, ctx, req_body, &ap); 707178825Sdfr if (ret) { 708178825Sdfr free_AuthPack(&ap); 709178825Sdfr goto out; 710178825Sdfr } 711178825Sdfr 712178825Sdfr ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret); 713178825Sdfr free_AuthPack(&ap); 714178825Sdfr if (ret) { 715233294Sstas krb5_set_error_message(context, ret, 716233294Sstas N_("Failed encoding AuthPack: %d", ""), 717233294Sstas (int)ret); 718178825Sdfr goto out; 719178825Sdfr } 720178825Sdfr if (buf.length != size) 721178825Sdfr krb5_abortx(context, "internal ASN1 encoder error"); 722178825Sdfr 723233294Sstas oid = &asn1_oid_id_pkauthdata; 724178825Sdfr } else 725178825Sdfr krb5_abortx(context, "internal pkinit error"); 726178825Sdfr 727233294Sstas ret = create_signature(context, oid, &buf, ctx->id, 728233294Sstas ctx->peer, &sd_buf); 729178825Sdfr krb5_data_free(&buf); 730178825Sdfr if (ret) 731178825Sdfr goto out; 732178825Sdfr 733233294Sstas ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData, &sd_buf, &buf); 734178825Sdfr krb5_data_free(&sd_buf); 735178825Sdfr if (ret) { 736233294Sstas krb5_set_error_message(context, ret, 737233294Sstas N_("ContentInfo wrapping of signedData failed","")); 738178825Sdfr goto out; 739178825Sdfr } 740178825Sdfr 741233294Sstas if (ctx->type == PKINIT_WIN2K) { 742178825Sdfr PA_PK_AS_REQ_Win2k winreq; 743178825Sdfr 744178825Sdfr pa_type = KRB5_PADATA_PK_AS_REQ_WIN; 745178825Sdfr 746178825Sdfr memset(&winreq, 0, sizeof(winreq)); 747178825Sdfr 748178825Sdfr winreq.signed_auth_pack = buf; 749178825Sdfr 750178825Sdfr ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length, 751178825Sdfr &winreq, &size, ret); 752178825Sdfr free_PA_PK_AS_REQ_Win2k(&winreq); 753178825Sdfr 754233294Sstas } else if (ctx->type == PKINIT_27) { 755178825Sdfr PA_PK_AS_REQ req; 756178825Sdfr 757178825Sdfr pa_type = KRB5_PADATA_PK_AS_REQ; 758178825Sdfr 759178825Sdfr memset(&req, 0, sizeof(req)); 760233294Sstas req.signedAuthPack = buf; 761178825Sdfr 762178825Sdfr if (ctx->trustedCertifiers) { 763178825Sdfr 764178825Sdfr req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers)); 765178825Sdfr if (req.trustedCertifiers == NULL) { 766233294Sstas ret = ENOMEM; 767233294Sstas krb5_set_error_message(context, ret, 768233294Sstas N_("malloc: out of memory", "")); 769178825Sdfr free_PA_PK_AS_REQ(&req); 770178825Sdfr goto out; 771178825Sdfr } 772233294Sstas ret = build_edi(context, context->hx509ctx, 773178825Sdfr ctx->id->anchors, req.trustedCertifiers); 774178825Sdfr if (ret) { 775233294Sstas krb5_set_error_message(context, ret, 776233294Sstas N_("pk-init: failed to build " 777233294Sstas "trustedCertifiers", "")); 778178825Sdfr free_PA_PK_AS_REQ(&req); 779178825Sdfr goto out; 780178825Sdfr } 781178825Sdfr } 782178825Sdfr req.kdcPkId = NULL; 783178825Sdfr 784178825Sdfr ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length, 785178825Sdfr &req, &size, ret); 786178825Sdfr 787178825Sdfr free_PA_PK_AS_REQ(&req); 788178825Sdfr 789178825Sdfr } else 790178825Sdfr krb5_abortx(context, "internal pkinit error"); 791178825Sdfr if (ret) { 792233294Sstas krb5_set_error_message(context, ret, "PA-PK-AS-REQ %d", (int)ret); 793178825Sdfr goto out; 794178825Sdfr } 795178825Sdfr if (buf.length != size) 796178825Sdfr krb5_abortx(context, "Internal ASN1 encoder error"); 797178825Sdfr 798178825Sdfr ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length); 799178825Sdfr if (ret) 800178825Sdfr free(buf.data); 801178825Sdfr 802233294Sstas if (ret == 0) 803233294Sstas krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0); 804178825Sdfr 805233294Sstas out: 806178825Sdfr free_ContentInfo(&content_info); 807178825Sdfr 808178825Sdfr return ret; 809178825Sdfr} 810178825Sdfr 811178825Sdfr 812233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 813178825Sdfr_krb5_pk_mk_padata(krb5_context context, 814178825Sdfr void *c, 815233294Sstas int ic_flags, 816233294Sstas int win2k, 817178825Sdfr const KDC_REQ_BODY *req_body, 818178825Sdfr unsigned nonce, 819178825Sdfr METHOD_DATA *md) 820178825Sdfr{ 821178825Sdfr krb5_pk_init_ctx ctx = c; 822178825Sdfr int win2k_compat; 823178825Sdfr 824233294Sstas if (ctx->id->certs == NULL && ctx->anonymous == 0) { 825233294Sstas krb5_set_error_message(context, HEIM_PKINIT_NO_PRIVATE_KEY, 826233294Sstas N_("PKINIT: No user certificate given", "")); 827233294Sstas return HEIM_PKINIT_NO_PRIVATE_KEY; 828233294Sstas } 829233294Sstas 830178825Sdfr win2k_compat = krb5_config_get_bool_default(context, NULL, 831233294Sstas win2k, 832178825Sdfr "realms", 833178825Sdfr req_body->realm, 834178825Sdfr "pkinit_win2k", 835178825Sdfr NULL); 836178825Sdfr 837178825Sdfr if (win2k_compat) { 838233294Sstas ctx->require_binding = 839178825Sdfr krb5_config_get_bool_default(context, NULL, 840233294Sstas TRUE, 841178825Sdfr "realms", 842178825Sdfr req_body->realm, 843178825Sdfr "pkinit_win2k_require_binding", 844178825Sdfr NULL); 845233294Sstas ctx->type = PKINIT_WIN2K; 846178825Sdfr } else 847233294Sstas ctx->type = PKINIT_27; 848178825Sdfr 849233294Sstas ctx->require_eku = 850178825Sdfr krb5_config_get_bool_default(context, NULL, 851178825Sdfr TRUE, 852178825Sdfr "realms", 853178825Sdfr req_body->realm, 854178825Sdfr "pkinit_require_eku", 855178825Sdfr NULL); 856233294Sstas if (ic_flags & KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK) 857233294Sstas ctx->require_eku = 0; 858233294Sstas if (ctx->id->flags & PKINIT_BTMM) 859233294Sstas ctx->require_eku = 0; 860233294Sstas 861233294Sstas ctx->require_krbtgt_otherName = 862178825Sdfr krb5_config_get_bool_default(context, NULL, 863178825Sdfr TRUE, 864178825Sdfr "realms", 865178825Sdfr req_body->realm, 866178825Sdfr "pkinit_require_krbtgt_otherName", 867178825Sdfr NULL); 868178825Sdfr 869233294Sstas ctx->require_hostname_match = 870178825Sdfr krb5_config_get_bool_default(context, NULL, 871178825Sdfr FALSE, 872178825Sdfr "realms", 873178825Sdfr req_body->realm, 874178825Sdfr "pkinit_require_hostname_match", 875178825Sdfr NULL); 876178825Sdfr 877233294Sstas ctx->trustedCertifiers = 878178825Sdfr krb5_config_get_bool_default(context, NULL, 879178825Sdfr TRUE, 880178825Sdfr "realms", 881178825Sdfr req_body->realm, 882178825Sdfr "pkinit_trustedCertifiers", 883178825Sdfr NULL); 884178825Sdfr 885178825Sdfr return pk_mk_padata(context, ctx, req_body, nonce, md); 886178825Sdfr} 887178825Sdfr 888233294Sstasstatic krb5_error_code 889233294Sstaspk_verify_sign(krb5_context context, 890233294Sstas const void *data, 891233294Sstas size_t length, 892233294Sstas struct krb5_pk_identity *id, 893233294Sstas heim_oid *contentType, 894233294Sstas krb5_data *content, 895233294Sstas struct krb5_pk_cert **signer) 896178825Sdfr{ 897178825Sdfr hx509_certs signer_certs; 898233294Sstas int ret, flags = 0; 899178825Sdfr 900233294Sstas /* BTMM is broken in Leo and SnowLeo */ 901233294Sstas if (id->flags & PKINIT_BTMM) { 902233294Sstas flags |= HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; 903233294Sstas flags |= HX509_CMS_VS_NO_KU_CHECK; 904233294Sstas flags |= HX509_CMS_VS_NO_VALIDATE; 905233294Sstas } 906233294Sstas 907178825Sdfr *signer = NULL; 908178825Sdfr 909233294Sstas ret = hx509_cms_verify_signed(context->hx509ctx, 910178825Sdfr id->verify_ctx, 911233294Sstas flags, 912178825Sdfr data, 913178825Sdfr length, 914178825Sdfr NULL, 915178825Sdfr id->certpool, 916178825Sdfr contentType, 917178825Sdfr content, 918178825Sdfr &signer_certs); 919178825Sdfr if (ret) { 920233294Sstas pk_copy_error(context, context->hx509ctx, ret, 921233294Sstas "CMS verify signed failed"); 922178825Sdfr return ret; 923178825Sdfr } 924178825Sdfr 925178825Sdfr *signer = calloc(1, sizeof(**signer)); 926178825Sdfr if (*signer == NULL) { 927233294Sstas krb5_clear_error_message(context); 928178825Sdfr ret = ENOMEM; 929178825Sdfr goto out; 930178825Sdfr } 931233294Sstas 932233294Sstas ret = hx509_get_one_cert(context->hx509ctx, signer_certs, &(*signer)->cert); 933178825Sdfr if (ret) { 934233294Sstas pk_copy_error(context, context->hx509ctx, ret, 935233294Sstas "Failed to get on of the signer certs"); 936178825Sdfr goto out; 937178825Sdfr } 938178825Sdfr 939233294Sstas out: 940178825Sdfr hx509_certs_free(&signer_certs); 941178825Sdfr if (ret) { 942178825Sdfr if (*signer) { 943178825Sdfr hx509_cert_free((*signer)->cert); 944178825Sdfr free(*signer); 945178825Sdfr *signer = NULL; 946178825Sdfr } 947178825Sdfr } 948178825Sdfr 949178825Sdfr return ret; 950178825Sdfr} 951178825Sdfr 952178825Sdfrstatic krb5_error_code 953178825Sdfrget_reply_key_win(krb5_context context, 954178825Sdfr const krb5_data *content, 955178825Sdfr unsigned nonce, 956178825Sdfr krb5_keyblock **key) 957178825Sdfr{ 958178825Sdfr ReplyKeyPack_Win2k key_pack; 959178825Sdfr krb5_error_code ret; 960178825Sdfr size_t size; 961178825Sdfr 962178825Sdfr ret = decode_ReplyKeyPack_Win2k(content->data, 963178825Sdfr content->length, 964178825Sdfr &key_pack, 965178825Sdfr &size); 966178825Sdfr if (ret) { 967233294Sstas krb5_set_error_message(context, ret, 968233294Sstas N_("PKINIT decoding reply key failed", "")); 969178825Sdfr free_ReplyKeyPack_Win2k(&key_pack); 970178825Sdfr return ret; 971178825Sdfr } 972233294Sstas 973233294Sstas if ((unsigned)key_pack.nonce != nonce) { 974233294Sstas krb5_set_error_message(context, ret, 975233294Sstas N_("PKINIT enckey nonce is wrong", "")); 976178825Sdfr free_ReplyKeyPack_Win2k(&key_pack); 977178825Sdfr return KRB5KRB_AP_ERR_MODIFIED; 978178825Sdfr } 979178825Sdfr 980178825Sdfr *key = malloc (sizeof (**key)); 981178825Sdfr if (*key == NULL) { 982178825Sdfr free_ReplyKeyPack_Win2k(&key_pack); 983233294Sstas krb5_set_error_message(context, ENOMEM, 984233294Sstas N_("malloc: out of memory", "")); 985178825Sdfr return ENOMEM; 986178825Sdfr } 987178825Sdfr 988178825Sdfr ret = copy_EncryptionKey(&key_pack.replyKey, *key); 989178825Sdfr free_ReplyKeyPack_Win2k(&key_pack); 990178825Sdfr if (ret) { 991233294Sstas krb5_set_error_message(context, ret, 992233294Sstas N_("PKINIT failed copying reply key", "")); 993178825Sdfr free(*key); 994178825Sdfr *key = NULL; 995178825Sdfr } 996178825Sdfr 997178825Sdfr return ret; 998178825Sdfr} 999178825Sdfr 1000178825Sdfrstatic krb5_error_code 1001178825Sdfrget_reply_key(krb5_context context, 1002178825Sdfr const krb5_data *content, 1003178825Sdfr const krb5_data *req_buffer, 1004178825Sdfr krb5_keyblock **key) 1005178825Sdfr{ 1006178825Sdfr ReplyKeyPack key_pack; 1007178825Sdfr krb5_error_code ret; 1008178825Sdfr size_t size; 1009178825Sdfr 1010178825Sdfr ret = decode_ReplyKeyPack(content->data, 1011178825Sdfr content->length, 1012178825Sdfr &key_pack, 1013178825Sdfr &size); 1014178825Sdfr if (ret) { 1015233294Sstas krb5_set_error_message(context, ret, 1016233294Sstas N_("PKINIT decoding reply key failed", "")); 1017178825Sdfr free_ReplyKeyPack(&key_pack); 1018178825Sdfr return ret; 1019178825Sdfr } 1020233294Sstas 1021178825Sdfr { 1022178825Sdfr krb5_crypto crypto; 1023178825Sdfr 1024233294Sstas /* 1025178825Sdfr * XXX Verify kp.replyKey is a allowed enctype in the 1026178825Sdfr * configuration file 1027178825Sdfr */ 1028178825Sdfr 1029178825Sdfr ret = krb5_crypto_init(context, &key_pack.replyKey, 0, &crypto); 1030178825Sdfr if (ret) { 1031178825Sdfr free_ReplyKeyPack(&key_pack); 1032178825Sdfr return ret; 1033178825Sdfr } 1034178825Sdfr 1035178825Sdfr ret = krb5_verify_checksum(context, crypto, 6, 1036178825Sdfr req_buffer->data, req_buffer->length, 1037178825Sdfr &key_pack.asChecksum); 1038178825Sdfr krb5_crypto_destroy(context, crypto); 1039178825Sdfr if (ret) { 1040178825Sdfr free_ReplyKeyPack(&key_pack); 1041178825Sdfr return ret; 1042178825Sdfr } 1043178825Sdfr } 1044178825Sdfr 1045178825Sdfr *key = malloc (sizeof (**key)); 1046178825Sdfr if (*key == NULL) { 1047178825Sdfr free_ReplyKeyPack(&key_pack); 1048233294Sstas krb5_set_error_message(context, ENOMEM, 1049233294Sstas N_("malloc: out of memory", "")); 1050178825Sdfr return ENOMEM; 1051178825Sdfr } 1052178825Sdfr 1053178825Sdfr ret = copy_EncryptionKey(&key_pack.replyKey, *key); 1054178825Sdfr free_ReplyKeyPack(&key_pack); 1055178825Sdfr if (ret) { 1056233294Sstas krb5_set_error_message(context, ret, 1057233294Sstas N_("PKINIT failed copying reply key", "")); 1058178825Sdfr free(*key); 1059178825Sdfr *key = NULL; 1060178825Sdfr } 1061178825Sdfr 1062178825Sdfr return ret; 1063178825Sdfr} 1064178825Sdfr 1065178825Sdfr 1066178825Sdfrstatic krb5_error_code 1067178825Sdfrpk_verify_host(krb5_context context, 1068178825Sdfr const char *realm, 1069178825Sdfr const krb5_krbhst_info *hi, 1070178825Sdfr struct krb5_pk_init_ctx_data *ctx, 1071178825Sdfr struct krb5_pk_cert *host) 1072178825Sdfr{ 1073178825Sdfr krb5_error_code ret = 0; 1074178825Sdfr 1075178825Sdfr if (ctx->require_eku) { 1076233294Sstas ret = hx509_cert_check_eku(context->hx509ctx, host->cert, 1077233294Sstas &asn1_oid_id_pkkdcekuoid, 0); 1078178825Sdfr if (ret) { 1079233294Sstas krb5_set_error_message(context, ret, 1080233294Sstas N_("No PK-INIT KDC EKU in kdc certificate", "")); 1081178825Sdfr return ret; 1082178825Sdfr } 1083178825Sdfr } 1084178825Sdfr if (ctx->require_krbtgt_otherName) { 1085178825Sdfr hx509_octet_string_list list; 1086233294Sstas size_t i; 1087178825Sdfr 1088233294Sstas ret = hx509_cert_find_subjectAltName_otherName(context->hx509ctx, 1089178825Sdfr host->cert, 1090233294Sstas &asn1_oid_id_pkinit_san, 1091178825Sdfr &list); 1092178825Sdfr if (ret) { 1093233294Sstas krb5_set_error_message(context, ret, 1094233294Sstas N_("Failed to find the PK-INIT " 1095233294Sstas "subjectAltName in the KDC " 1096233294Sstas "certificate", "")); 1097178825Sdfr 1098178825Sdfr return ret; 1099178825Sdfr } 1100178825Sdfr 1101178825Sdfr for (i = 0; i < list.len; i++) { 1102178825Sdfr KRB5PrincipalName r; 1103178825Sdfr 1104178825Sdfr ret = decode_KRB5PrincipalName(list.val[i].data, 1105178825Sdfr list.val[i].length, 1106178825Sdfr &r, 1107178825Sdfr NULL); 1108178825Sdfr if (ret) { 1109233294Sstas krb5_set_error_message(context, ret, 1110233294Sstas N_("Failed to decode the PK-INIT " 1111233294Sstas "subjectAltName in the " 1112233294Sstas "KDC certificate", "")); 1113178825Sdfr 1114178825Sdfr break; 1115178825Sdfr } 1116178825Sdfr 1117178825Sdfr if (r.principalName.name_string.len != 2 || 1118178825Sdfr strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) != 0 || 1119178825Sdfr strcmp(r.principalName.name_string.val[1], realm) != 0 || 1120178825Sdfr strcmp(r.realm, realm) != 0) 1121233294Sstas { 1122233294Sstas ret = KRB5_KDC_ERR_INVALID_CERTIFICATE; 1123233294Sstas krb5_set_error_message(context, ret, 1124233294Sstas N_("KDC have wrong realm name in " 1125233294Sstas "the certificate", "")); 1126233294Sstas } 1127178825Sdfr 1128178825Sdfr free_KRB5PrincipalName(&r); 1129178825Sdfr if (ret) 1130178825Sdfr break; 1131178825Sdfr } 1132178825Sdfr hx509_free_octet_string_list(&list); 1133178825Sdfr } 1134178825Sdfr if (ret) 1135178825Sdfr return ret; 1136233294Sstas 1137178825Sdfr if (hi) { 1138233294Sstas ret = hx509_verify_hostname(context->hx509ctx, host->cert, 1139178825Sdfr ctx->require_hostname_match, 1140178825Sdfr HX509_HN_HOSTNAME, 1141178825Sdfr hi->hostname, 1142178825Sdfr hi->ai->ai_addr, hi->ai->ai_addrlen); 1143178825Sdfr 1144178825Sdfr if (ret) 1145233294Sstas krb5_set_error_message(context, ret, 1146233294Sstas N_("Address mismatch in " 1147233294Sstas "the KDC certificate", "")); 1148178825Sdfr } 1149178825Sdfr return ret; 1150178825Sdfr} 1151178825Sdfr 1152178825Sdfrstatic krb5_error_code 1153178825Sdfrpk_rd_pa_reply_enckey(krb5_context context, 1154178825Sdfr int type, 1155178825Sdfr const heim_octet_string *indata, 1156178825Sdfr const heim_oid *dataType, 1157178825Sdfr const char *realm, 1158178825Sdfr krb5_pk_init_ctx ctx, 1159178825Sdfr krb5_enctype etype, 1160178825Sdfr const krb5_krbhst_info *hi, 1161178825Sdfr unsigned nonce, 1162178825Sdfr const krb5_data *req_buffer, 1163178825Sdfr PA_DATA *pa, 1164233294Sstas krb5_keyblock **key) 1165178825Sdfr{ 1166178825Sdfr krb5_error_code ret; 1167178825Sdfr struct krb5_pk_cert *host = NULL; 1168178825Sdfr krb5_data content; 1169178825Sdfr heim_oid contentType = { 0, NULL }; 1170233294Sstas int flags = HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT; 1171178825Sdfr 1172233294Sstas if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_envelopedData, dataType)) { 1173233294Sstas krb5_set_error_message(context, EINVAL, 1174233294Sstas N_("PKINIT: Invalid content type", "")); 1175178825Sdfr return EINVAL; 1176178825Sdfr } 1177178825Sdfr 1178233294Sstas if (ctx->type == PKINIT_WIN2K) 1179233294Sstas flags |= HX509_CMS_UE_ALLOW_WEAK; 1180233294Sstas 1181233294Sstas ret = hx509_cms_unenvelope(context->hx509ctx, 1182178825Sdfr ctx->id->certs, 1183233294Sstas flags, 1184178825Sdfr indata->data, 1185178825Sdfr indata->length, 1186178825Sdfr NULL, 1187233294Sstas 0, 1188178825Sdfr &contentType, 1189178825Sdfr &content); 1190178825Sdfr if (ret) { 1191233294Sstas pk_copy_error(context, context->hx509ctx, ret, 1192233294Sstas "Failed to unenvelope CMS data in PK-INIT reply"); 1193178825Sdfr return ret; 1194178825Sdfr } 1195178825Sdfr der_free_oid(&contentType); 1196178825Sdfr 1197233294Sstas /* win2k uses ContentInfo */ 1198233294Sstas if (type == PKINIT_WIN2K) { 1199233294Sstas heim_oid type2; 1200233294Sstas heim_octet_string out; 1201178825Sdfr 1202233294Sstas ret = hx509_cms_unwrap_ContentInfo(&content, &type2, &out, NULL); 1203233294Sstas if (ret) { 1204233294Sstas /* windows LH with interesting CMS packets */ 1205233294Sstas size_t ph = 1 + der_length_len(content.length); 1206233294Sstas unsigned char *ptr = malloc(content.length + ph); 1207233294Sstas size_t l; 1208178825Sdfr 1209233294Sstas memcpy(ptr + ph, content.data, content.length); 1210178825Sdfr 1211233294Sstas ret = der_put_length_and_tag (ptr + ph - 1, ph, content.length, 1212233294Sstas ASN1_C_UNIV, CONS, UT_Sequence, &l); 1213233294Sstas if (ret) 1214233294Sstas return ret; 1215233294Sstas free(content.data); 1216233294Sstas content.data = ptr; 1217233294Sstas content.length += ph; 1218178825Sdfr 1219233294Sstas ret = hx509_cms_unwrap_ContentInfo(&content, &type2, &out, NULL); 1220233294Sstas if (ret) 1221233294Sstas goto out; 1222233294Sstas } 1223233294Sstas if (der_heim_oid_cmp(&type2, &asn1_oid_id_pkcs7_signedData)) { 1224178825Sdfr ret = EINVAL; /* XXX */ 1225233294Sstas krb5_set_error_message(context, ret, 1226233294Sstas N_("PKINIT: Invalid content type", "")); 1227233294Sstas der_free_oid(&type2); 1228178825Sdfr der_free_octet_string(&out); 1229178825Sdfr goto out; 1230178825Sdfr } 1231233294Sstas der_free_oid(&type2); 1232178825Sdfr krb5_data_free(&content); 1233178825Sdfr ret = krb5_data_copy(&content, out.data, out.length); 1234178825Sdfr der_free_octet_string(&out); 1235178825Sdfr if (ret) { 1236233294Sstas krb5_set_error_message(context, ret, 1237233294Sstas N_("malloc: out of memory", "")); 1238178825Sdfr goto out; 1239178825Sdfr } 1240178825Sdfr } 1241178825Sdfr 1242233294Sstas ret = pk_verify_sign(context, 1243233294Sstas content.data, 1244233294Sstas content.length, 1245233294Sstas ctx->id, 1246233294Sstas &contentType, 1247233294Sstas &content, 1248233294Sstas &host); 1249178825Sdfr if (ret) 1250178825Sdfr goto out; 1251178825Sdfr 1252178825Sdfr /* make sure that it is the kdc's certificate */ 1253178825Sdfr ret = pk_verify_host(context, realm, hi, ctx, host); 1254178825Sdfr if (ret) { 1255178825Sdfr goto out; 1256178825Sdfr } 1257178825Sdfr 1258178825Sdfr#if 0 1259233294Sstas if (type == PKINIT_WIN2K) { 1260233294Sstas if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) != 0) { 1261178825Sdfr ret = KRB5KRB_AP_ERR_MSG_TYPE; 1262233294Sstas krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid"); 1263178825Sdfr goto out; 1264178825Sdfr } 1265178825Sdfr } else { 1266233294Sstas if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkrkeydata) != 0) { 1267178825Sdfr ret = KRB5KRB_AP_ERR_MSG_TYPE; 1268233294Sstas krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid"); 1269178825Sdfr goto out; 1270178825Sdfr } 1271178825Sdfr } 1272178825Sdfr#endif 1273178825Sdfr 1274178825Sdfr switch(type) { 1275233294Sstas case PKINIT_WIN2K: 1276178825Sdfr ret = get_reply_key(context, &content, req_buffer, key); 1277178825Sdfr if (ret != 0 && ctx->require_binding == 0) 1278178825Sdfr ret = get_reply_key_win(context, &content, nonce, key); 1279178825Sdfr break; 1280233294Sstas case PKINIT_27: 1281178825Sdfr ret = get_reply_key(context, &content, req_buffer, key); 1282178825Sdfr break; 1283178825Sdfr } 1284178825Sdfr if (ret) 1285178825Sdfr goto out; 1286178825Sdfr 1287178825Sdfr /* XXX compare given etype with key->etype */ 1288178825Sdfr 1289178825Sdfr out: 1290178825Sdfr if (host) 1291178825Sdfr _krb5_pk_cert_free(host); 1292178825Sdfr der_free_oid(&contentType); 1293178825Sdfr krb5_data_free(&content); 1294178825Sdfr 1295178825Sdfr return ret; 1296178825Sdfr} 1297178825Sdfr 1298178825Sdfrstatic krb5_error_code 1299178825Sdfrpk_rd_pa_reply_dh(krb5_context context, 1300178825Sdfr const heim_octet_string *indata, 1301178825Sdfr const heim_oid *dataType, 1302178825Sdfr const char *realm, 1303178825Sdfr krb5_pk_init_ctx ctx, 1304178825Sdfr krb5_enctype etype, 1305178825Sdfr const krb5_krbhst_info *hi, 1306178825Sdfr const DHNonce *c_n, 1307178825Sdfr const DHNonce *k_n, 1308178825Sdfr unsigned nonce, 1309178825Sdfr PA_DATA *pa, 1310178825Sdfr krb5_keyblock **key) 1311178825Sdfr{ 1312233294Sstas const unsigned char *p; 1313233294Sstas unsigned char *dh_gen_key = NULL; 1314178825Sdfr struct krb5_pk_cert *host = NULL; 1315178825Sdfr BIGNUM *kdc_dh_pubkey = NULL; 1316178825Sdfr KDCDHKeyInfo kdc_dh_info; 1317178825Sdfr heim_oid contentType = { 0, NULL }; 1318178825Sdfr krb5_data content; 1319178825Sdfr krb5_error_code ret; 1320233294Sstas int dh_gen_keylen = 0; 1321178825Sdfr size_t size; 1322178825Sdfr 1323178825Sdfr krb5_data_zero(&content); 1324178825Sdfr memset(&kdc_dh_info, 0, sizeof(kdc_dh_info)); 1325178825Sdfr 1326233294Sstas if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_signedData, dataType)) { 1327233294Sstas krb5_set_error_message(context, EINVAL, 1328233294Sstas N_("PKINIT: Invalid content type", "")); 1329178825Sdfr return EINVAL; 1330178825Sdfr } 1331178825Sdfr 1332233294Sstas ret = pk_verify_sign(context, 1333233294Sstas indata->data, 1334233294Sstas indata->length, 1335233294Sstas ctx->id, 1336233294Sstas &contentType, 1337233294Sstas &content, 1338233294Sstas &host); 1339178825Sdfr if (ret) 1340178825Sdfr goto out; 1341178825Sdfr 1342178825Sdfr /* make sure that it is the kdc's certificate */ 1343178825Sdfr ret = pk_verify_host(context, realm, hi, ctx, host); 1344178825Sdfr if (ret) 1345178825Sdfr goto out; 1346178825Sdfr 1347233294Sstas if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkdhkeydata)) { 1348178825Sdfr ret = KRB5KRB_AP_ERR_MSG_TYPE; 1349233294Sstas krb5_set_error_message(context, ret, 1350233294Sstas N_("pkinit - dh reply contains wrong oid", "")); 1351178825Sdfr goto out; 1352178825Sdfr } 1353178825Sdfr 1354178825Sdfr ret = decode_KDCDHKeyInfo(content.data, 1355178825Sdfr content.length, 1356178825Sdfr &kdc_dh_info, 1357178825Sdfr &size); 1358178825Sdfr 1359178825Sdfr if (ret) { 1360233294Sstas krb5_set_error_message(context, ret, 1361233294Sstas N_("pkinit - failed to decode " 1362233294Sstas "KDC DH Key Info", "")); 1363178825Sdfr goto out; 1364178825Sdfr } 1365178825Sdfr 1366178825Sdfr if (kdc_dh_info.nonce != nonce) { 1367178825Sdfr ret = KRB5KRB_AP_ERR_MODIFIED; 1368233294Sstas krb5_set_error_message(context, ret, 1369233294Sstas N_("PKINIT: DH nonce is wrong", "")); 1370178825Sdfr goto out; 1371178825Sdfr } 1372178825Sdfr 1373178825Sdfr if (kdc_dh_info.dhKeyExpiration) { 1374178825Sdfr if (k_n == NULL) { 1375178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1376233294Sstas krb5_set_error_message(context, ret, 1377233294Sstas N_("pkinit; got key expiration " 1378233294Sstas "without server nonce", "")); 1379178825Sdfr goto out; 1380178825Sdfr } 1381178825Sdfr if (c_n == NULL) { 1382178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1383233294Sstas krb5_set_error_message(context, ret, 1384233294Sstas N_("pkinit; got DH reuse but no " 1385233294Sstas "client nonce", "")); 1386178825Sdfr goto out; 1387178825Sdfr } 1388178825Sdfr } else { 1389178825Sdfr if (k_n) { 1390178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1391233294Sstas krb5_set_error_message(context, ret, 1392233294Sstas N_("pkinit: got server nonce " 1393233294Sstas "without key expiration", "")); 1394178825Sdfr goto out; 1395178825Sdfr } 1396178825Sdfr c_n = NULL; 1397178825Sdfr } 1398178825Sdfr 1399178825Sdfr 1400178825Sdfr p = kdc_dh_info.subjectPublicKey.data; 1401178825Sdfr size = (kdc_dh_info.subjectPublicKey.length + 7) / 8; 1402178825Sdfr 1403233294Sstas if (ctx->keyex == USE_DH) { 1404178825Sdfr DHPublicKey k; 1405178825Sdfr ret = decode_DHPublicKey(p, size, &k, NULL); 1406178825Sdfr if (ret) { 1407233294Sstas krb5_set_error_message(context, ret, 1408233294Sstas N_("pkinit: can't decode " 1409233294Sstas "without key expiration", "")); 1410178825Sdfr goto out; 1411178825Sdfr } 1412178825Sdfr 1413178825Sdfr kdc_dh_pubkey = integer_to_BN(context, "DHPublicKey", &k); 1414178825Sdfr free_DHPublicKey(&k); 1415178825Sdfr if (kdc_dh_pubkey == NULL) { 1416233294Sstas ret = ENOMEM; 1417233294Sstas goto out; 1418233294Sstas } 1419233294Sstas 1420233294Sstas 1421233294Sstas size = DH_size(ctx->u.dh); 1422233294Sstas 1423233294Sstas dh_gen_key = malloc(size); 1424233294Sstas if (dh_gen_key == NULL) { 1425233294Sstas ret = ENOMEM; 1426233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1427233294Sstas goto out; 1428233294Sstas } 1429233294Sstas 1430233294Sstas dh_gen_keylen = DH_compute_key(dh_gen_key, kdc_dh_pubkey, ctx->u.dh); 1431233294Sstas if (dh_gen_keylen == -1) { 1432178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1433233294Sstas dh_gen_keylen = 0; 1434233294Sstas krb5_set_error_message(context, ret, 1435233294Sstas N_("PKINIT: Can't compute Diffie-Hellman key", "")); 1436178825Sdfr goto out; 1437178825Sdfr } 1438233294Sstas if (dh_gen_keylen < (int)size) { 1439233294Sstas size -= dh_gen_keylen; 1440233294Sstas memmove(dh_gen_key + size, dh_gen_key, dh_gen_keylen); 1441233294Sstas memset(dh_gen_key, 0, size); 1442233294Sstas } 1443178825Sdfr 1444233294Sstas } else { 1445233294Sstas#ifdef HAVE_OPENSSL 1446233294Sstas const EC_GROUP *group; 1447233294Sstas EC_KEY *public = NULL; 1448233294Sstas 1449233294Sstas group = EC_KEY_get0_group(ctx->u.eckey); 1450233294Sstas 1451233294Sstas public = EC_KEY_new(); 1452233294Sstas if (public == NULL) { 1453233294Sstas ret = ENOMEM; 1454233294Sstas goto out; 1455233294Sstas } 1456233294Sstas if (EC_KEY_set_group(public, group) != 1) { 1457233294Sstas EC_KEY_free(public); 1458233294Sstas ret = ENOMEM; 1459233294Sstas goto out; 1460233294Sstas } 1461233294Sstas 1462233294Sstas if (o2i_ECPublicKey(&public, &p, size) == NULL) { 1463233294Sstas EC_KEY_free(public); 1464233294Sstas ret = KRB5KRB_ERR_GENERIC; 1465233294Sstas krb5_set_error_message(context, ret, 1466233294Sstas N_("PKINIT: Can't parse ECDH public key", "")); 1467233294Sstas goto out; 1468233294Sstas } 1469233294Sstas 1470233294Sstas size = (EC_GROUP_get_degree(group) + 7) / 8; 1471233294Sstas dh_gen_key = malloc(size); 1472233294Sstas if (dh_gen_key == NULL) { 1473233294Sstas EC_KEY_free(public); 1474233294Sstas ret = ENOMEM; 1475233294Sstas krb5_set_error_message(context, ret, 1476233294Sstas N_("malloc: out of memory", "")); 1477233294Sstas goto out; 1478233294Sstas } 1479233294Sstas dh_gen_keylen = ECDH_compute_key(dh_gen_key, size, 1480233294Sstas EC_KEY_get0_public_key(public), ctx->u.eckey, NULL); 1481233294Sstas EC_KEY_free(public); 1482233294Sstas if (dh_gen_keylen == -1) { 1483233294Sstas ret = KRB5KRB_ERR_GENERIC; 1484233294Sstas dh_gen_keylen = 0; 1485233294Sstas krb5_set_error_message(context, ret, 1486233294Sstas N_("PKINIT: Can't compute ECDH public key", "")); 1487233294Sstas goto out; 1488233294Sstas } 1489233294Sstas#else 1490233294Sstas ret = EINVAL; 1491233294Sstas#endif 1492178825Sdfr } 1493178825Sdfr 1494233294Sstas if (dh_gen_keylen <= 0) { 1495233294Sstas ret = EINVAL; 1496233294Sstas krb5_set_error_message(context, ret, 1497233294Sstas N_("PKINIT: resulting DH key <= 0", "")); 1498233294Sstas dh_gen_keylen = 0; 1499178825Sdfr goto out; 1500178825Sdfr } 1501178825Sdfr 1502178825Sdfr *key = malloc (sizeof (**key)); 1503178825Sdfr if (*key == NULL) { 1504178825Sdfr ret = ENOMEM; 1505233294Sstas krb5_set_error_message(context, ret, 1506233294Sstas N_("malloc: out of memory", "")); 1507178825Sdfr goto out; 1508178825Sdfr } 1509178825Sdfr 1510178825Sdfr ret = _krb5_pk_octetstring2key(context, 1511178825Sdfr etype, 1512178825Sdfr dh_gen_key, dh_gen_keylen, 1513178825Sdfr c_n, k_n, 1514178825Sdfr *key); 1515178825Sdfr if (ret) { 1516233294Sstas krb5_set_error_message(context, ret, 1517233294Sstas N_("PKINIT: can't create key from DH key", "")); 1518178825Sdfr free(*key); 1519178825Sdfr *key = NULL; 1520178825Sdfr goto out; 1521178825Sdfr } 1522178825Sdfr 1523178825Sdfr out: 1524178825Sdfr if (kdc_dh_pubkey) 1525178825Sdfr BN_free(kdc_dh_pubkey); 1526178825Sdfr if (dh_gen_key) { 1527233294Sstas memset(dh_gen_key, 0, dh_gen_keylen); 1528178825Sdfr free(dh_gen_key); 1529178825Sdfr } 1530178825Sdfr if (host) 1531178825Sdfr _krb5_pk_cert_free(host); 1532178825Sdfr if (content.data) 1533178825Sdfr krb5_data_free(&content); 1534178825Sdfr der_free_oid(&contentType); 1535178825Sdfr free_KDCDHKeyInfo(&kdc_dh_info); 1536178825Sdfr 1537178825Sdfr return ret; 1538178825Sdfr} 1539178825Sdfr 1540233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1541178825Sdfr_krb5_pk_rd_pa_reply(krb5_context context, 1542178825Sdfr const char *realm, 1543178825Sdfr void *c, 1544178825Sdfr krb5_enctype etype, 1545178825Sdfr const krb5_krbhst_info *hi, 1546178825Sdfr unsigned nonce, 1547178825Sdfr const krb5_data *req_buffer, 1548178825Sdfr PA_DATA *pa, 1549178825Sdfr krb5_keyblock **key) 1550178825Sdfr{ 1551178825Sdfr krb5_pk_init_ctx ctx = c; 1552178825Sdfr krb5_error_code ret; 1553178825Sdfr size_t size; 1554178825Sdfr 1555178825Sdfr /* Check for IETF PK-INIT first */ 1556233294Sstas if (ctx->type == PKINIT_27) { 1557178825Sdfr PA_PK_AS_REP rep; 1558178825Sdfr heim_octet_string os, data; 1559178825Sdfr heim_oid oid; 1560233294Sstas 1561178825Sdfr if (pa->padata_type != KRB5_PADATA_PK_AS_REP) { 1562233294Sstas krb5_set_error_message(context, EINVAL, 1563233294Sstas N_("PKINIT: wrong padata recv", "")); 1564178825Sdfr return EINVAL; 1565178825Sdfr } 1566178825Sdfr 1567178825Sdfr ret = decode_PA_PK_AS_REP(pa->padata_value.data, 1568178825Sdfr pa->padata_value.length, 1569178825Sdfr &rep, 1570178825Sdfr &size); 1571178825Sdfr if (ret) { 1572233294Sstas krb5_set_error_message(context, ret, 1573233294Sstas N_("Failed to decode pkinit AS rep", "")); 1574178825Sdfr return ret; 1575178825Sdfr } 1576178825Sdfr 1577178825Sdfr switch (rep.element) { 1578178825Sdfr case choice_PA_PK_AS_REP_dhInfo: 1579233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: using pkinit dh"); 1580178825Sdfr os = rep.u.dhInfo.dhSignedData; 1581178825Sdfr break; 1582178825Sdfr case choice_PA_PK_AS_REP_encKeyPack: 1583233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: using kinit enc reply key"); 1584178825Sdfr os = rep.u.encKeyPack; 1585178825Sdfr break; 1586233294Sstas default: { 1587233294Sstas PA_PK_AS_REP_BTMM btmm; 1588178825Sdfr free_PA_PK_AS_REP(&rep); 1589233294Sstas memset(&rep, 0, sizeof(rep)); 1590233294Sstas 1591233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: using BTMM kinit enc reply key"); 1592233294Sstas 1593233294Sstas ret = decode_PA_PK_AS_REP_BTMM(pa->padata_value.data, 1594233294Sstas pa->padata_value.length, 1595233294Sstas &btmm, 1596233294Sstas &size); 1597233294Sstas if (ret) { 1598233294Sstas krb5_set_error_message(context, EINVAL, 1599233294Sstas N_("PKINIT: -27 reply " 1600233294Sstas "invalid content type", "")); 1601233294Sstas return EINVAL; 1602233294Sstas } 1603233294Sstas 1604233294Sstas if (btmm.dhSignedData || btmm.encKeyPack == NULL) { 1605233294Sstas free_PA_PK_AS_REP_BTMM(&btmm); 1606233294Sstas ret = EINVAL; 1607233294Sstas krb5_set_error_message(context, ret, 1608233294Sstas N_("DH mode not supported for BTMM mode", "")); 1609233294Sstas return ret; 1610233294Sstas } 1611233294Sstas 1612233294Sstas /* 1613233294Sstas * Transform to IETF style PK-INIT reply so that free works below 1614233294Sstas */ 1615233294Sstas 1616233294Sstas rep.element = choice_PA_PK_AS_REP_encKeyPack; 1617233294Sstas rep.u.encKeyPack.data = btmm.encKeyPack->data; 1618233294Sstas rep.u.encKeyPack.length = btmm.encKeyPack->length; 1619233294Sstas btmm.encKeyPack->data = NULL; 1620233294Sstas btmm.encKeyPack->length = 0; 1621233294Sstas free_PA_PK_AS_REP_BTMM(&btmm); 1622233294Sstas os = rep.u.encKeyPack; 1623178825Sdfr } 1624233294Sstas } 1625178825Sdfr 1626178825Sdfr ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL); 1627178825Sdfr if (ret) { 1628178825Sdfr free_PA_PK_AS_REP(&rep); 1629233294Sstas krb5_set_error_message(context, ret, 1630233294Sstas N_("PKINIT: failed to unwrap CI", "")); 1631178825Sdfr return ret; 1632178825Sdfr } 1633178825Sdfr 1634178825Sdfr switch (rep.element) { 1635178825Sdfr case choice_PA_PK_AS_REP_dhInfo: 1636178825Sdfr ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi, 1637178825Sdfr ctx->clientDHNonce, 1638178825Sdfr rep.u.dhInfo.serverDHNonce, 1639178825Sdfr nonce, pa, key); 1640178825Sdfr break; 1641178825Sdfr case choice_PA_PK_AS_REP_encKeyPack: 1642233294Sstas ret = pk_rd_pa_reply_enckey(context, PKINIT_27, &data, &oid, realm, 1643178825Sdfr ctx, etype, hi, nonce, req_buffer, pa, key); 1644178825Sdfr break; 1645178825Sdfr default: 1646178825Sdfr krb5_abortx(context, "pk-init as-rep case not possible to happen"); 1647178825Sdfr } 1648178825Sdfr der_free_octet_string(&data); 1649178825Sdfr der_free_oid(&oid); 1650178825Sdfr free_PA_PK_AS_REP(&rep); 1651178825Sdfr 1652233294Sstas } else if (ctx->type == PKINIT_WIN2K) { 1653178825Sdfr PA_PK_AS_REP_Win2k w2krep; 1654178825Sdfr 1655233294Sstas /* Check for Windows encoding of the AS-REP pa data */ 1656178825Sdfr 1657178825Sdfr#if 0 /* should this be ? */ 1658178825Sdfr if (pa->padata_type != KRB5_PADATA_PK_AS_REP) { 1659233294Sstas krb5_set_error_message(context, EINVAL, 1660233294Sstas "PKINIT: wrong padata recv"); 1661178825Sdfr return EINVAL; 1662178825Sdfr } 1663178825Sdfr#endif 1664178825Sdfr 1665178825Sdfr memset(&w2krep, 0, sizeof(w2krep)); 1666233294Sstas 1667178825Sdfr ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data, 1668178825Sdfr pa->padata_value.length, 1669178825Sdfr &w2krep, 1670178825Sdfr &size); 1671178825Sdfr if (ret) { 1672233294Sstas krb5_set_error_message(context, ret, 1673233294Sstas N_("PKINIT: Failed decoding windows " 1674233294Sstas "pkinit reply %d", ""), (int)ret); 1675178825Sdfr return ret; 1676178825Sdfr } 1677178825Sdfr 1678233294Sstas krb5_clear_error_message(context); 1679233294Sstas 1680178825Sdfr switch (w2krep.element) { 1681178825Sdfr case choice_PA_PK_AS_REP_Win2k_encKeyPack: { 1682178825Sdfr heim_octet_string data; 1683178825Sdfr heim_oid oid; 1684233294Sstas 1685233294Sstas ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack, 1686178825Sdfr &oid, &data, NULL); 1687178825Sdfr free_PA_PK_AS_REP_Win2k(&w2krep); 1688178825Sdfr if (ret) { 1689233294Sstas krb5_set_error_message(context, ret, 1690233294Sstas N_("PKINIT: failed to unwrap CI", "")); 1691178825Sdfr return ret; 1692178825Sdfr } 1693178825Sdfr 1694233294Sstas ret = pk_rd_pa_reply_enckey(context, PKINIT_WIN2K, &data, &oid, realm, 1695178825Sdfr ctx, etype, hi, nonce, req_buffer, pa, key); 1696178825Sdfr der_free_octet_string(&data); 1697178825Sdfr der_free_oid(&oid); 1698178825Sdfr 1699178825Sdfr break; 1700178825Sdfr } 1701178825Sdfr default: 1702178825Sdfr free_PA_PK_AS_REP_Win2k(&w2krep); 1703178825Sdfr ret = EINVAL; 1704233294Sstas krb5_set_error_message(context, ret, 1705233294Sstas N_("PKINIT: win2k reply invalid " 1706233294Sstas "content type", "")); 1707178825Sdfr break; 1708178825Sdfr } 1709233294Sstas 1710178825Sdfr } else { 1711178825Sdfr ret = EINVAL; 1712233294Sstas krb5_set_error_message(context, ret, 1713233294Sstas N_("PKINIT: unknown reply type", "")); 1714178825Sdfr } 1715178825Sdfr 1716178825Sdfr return ret; 1717178825Sdfr} 1718178825Sdfr 1719178825Sdfrstruct prompter { 1720178825Sdfr krb5_context context; 1721178825Sdfr krb5_prompter_fct prompter; 1722178825Sdfr void *prompter_data; 1723178825Sdfr}; 1724178825Sdfr 1725233294Sstasstatic int 1726178825Sdfrhx_pass_prompter(void *data, const hx509_prompt *prompter) 1727178825Sdfr{ 1728178825Sdfr krb5_error_code ret; 1729178825Sdfr krb5_prompt prompt; 1730178825Sdfr krb5_data password_data; 1731178825Sdfr struct prompter *p = data; 1732233294Sstas 1733178825Sdfr password_data.data = prompter->reply.data; 1734178825Sdfr password_data.length = prompter->reply.length; 1735178825Sdfr 1736178825Sdfr prompt.prompt = prompter->prompt; 1737178825Sdfr prompt.hidden = hx509_prompt_hidden(prompter->type); 1738178825Sdfr prompt.reply = &password_data; 1739178825Sdfr 1740178825Sdfr switch (prompter->type) { 1741178825Sdfr case HX509_PROMPT_TYPE_INFO: 1742178825Sdfr prompt.type = KRB5_PROMPT_TYPE_INFO; 1743178825Sdfr break; 1744178825Sdfr case HX509_PROMPT_TYPE_PASSWORD: 1745178825Sdfr case HX509_PROMPT_TYPE_QUESTION: 1746178825Sdfr default: 1747178825Sdfr prompt.type = KRB5_PROMPT_TYPE_PASSWORD; 1748178825Sdfr break; 1749233294Sstas } 1750233294Sstas 1751178825Sdfr ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt); 1752178825Sdfr if (ret) { 1753178825Sdfr memset (prompter->reply.data, 0, prompter->reply.length); 1754178825Sdfr return 1; 1755178825Sdfr } 1756178825Sdfr return 0; 1757178825Sdfr} 1758178825Sdfr 1759233294Sstasstatic krb5_error_code 1760233294Sstas_krb5_pk_set_user_id(krb5_context context, 1761233294Sstas krb5_principal principal, 1762233294Sstas krb5_pk_init_ctx ctx, 1763233294Sstas struct hx509_certs_data *certs) 1764233294Sstas{ 1765233294Sstas hx509_certs c = hx509_certs_ref(certs); 1766233294Sstas hx509_query *q = NULL; 1767233294Sstas int ret; 1768178825Sdfr 1769233294Sstas if (ctx->id->certs) 1770233294Sstas hx509_certs_free(&ctx->id->certs); 1771233294Sstas if (ctx->id->cert) { 1772233294Sstas hx509_cert_free(ctx->id->cert); 1773233294Sstas ctx->id->cert = NULL; 1774233294Sstas } 1775233294Sstas 1776233294Sstas ctx->id->certs = c; 1777233294Sstas ctx->anonymous = 0; 1778233294Sstas 1779233294Sstas ret = hx509_query_alloc(context->hx509ctx, &q); 1780233294Sstas if (ret) { 1781233294Sstas pk_copy_error(context, context->hx509ctx, ret, 1782233294Sstas "Allocate query to find signing certificate"); 1783233294Sstas return ret; 1784233294Sstas } 1785233294Sstas 1786233294Sstas hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); 1787233294Sstas hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); 1788233294Sstas 1789233294Sstas if (principal && strncmp("LKDC:SHA1.", krb5_principal_get_realm(context, principal), 9) == 0) { 1790233294Sstas ctx->id->flags |= PKINIT_BTMM; 1791233294Sstas } 1792233294Sstas 1793233294Sstas ret = find_cert(context, ctx->id, q, &ctx->id->cert); 1794233294Sstas hx509_query_free(context->hx509ctx, q); 1795233294Sstas 1796233294Sstas if (ret == 0 && _krb5_have_debug(context, 2)) { 1797233294Sstas hx509_name name; 1798233294Sstas char *str, *sn; 1799233294Sstas heim_integer i; 1800233294Sstas 1801233294Sstas ret = hx509_cert_get_subject(ctx->id->cert, &name); 1802233294Sstas if (ret) 1803233294Sstas goto out; 1804233294Sstas 1805233294Sstas ret = hx509_name_to_string(name, &str); 1806233294Sstas hx509_name_free(&name); 1807233294Sstas if (ret) 1808233294Sstas goto out; 1809233294Sstas 1810233294Sstas ret = hx509_cert_get_serialnumber(ctx->id->cert, &i); 1811233294Sstas if (ret) { 1812233294Sstas free(str); 1813233294Sstas goto out; 1814233294Sstas } 1815233294Sstas 1816233294Sstas ret = der_print_hex_heim_integer(&i, &sn); 1817233294Sstas der_free_heim_integer(&i); 1818233294Sstas if (ret) { 1819233294Sstas free(name); 1820233294Sstas goto out; 1821233294Sstas } 1822233294Sstas 1823233294Sstas _krb5_debug(context, 2, "using cert: subject: %s sn: %s", str, sn); 1824233294Sstas free(str); 1825233294Sstas free(sn); 1826233294Sstas } 1827233294Sstas out: 1828233294Sstas 1829233294Sstas return ret; 1830178825Sdfr} 1831178825Sdfr 1832233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1833178825Sdfr_krb5_pk_load_id(krb5_context context, 1834178825Sdfr struct krb5_pk_identity **ret_id, 1835178825Sdfr const char *user_id, 1836178825Sdfr const char *anchor_id, 1837178825Sdfr char * const *chain_list, 1838178825Sdfr char * const *revoke_list, 1839178825Sdfr krb5_prompter_fct prompter, 1840178825Sdfr void *prompter_data, 1841178825Sdfr char *password) 1842178825Sdfr{ 1843178825Sdfr struct krb5_pk_identity *id = NULL; 1844178825Sdfr struct prompter p; 1845178825Sdfr int ret; 1846178825Sdfr 1847178825Sdfr *ret_id = NULL; 1848178825Sdfr 1849178825Sdfr if (anchor_id == NULL) { 1850233294Sstas krb5_set_error_message(context, HEIM_PKINIT_NO_VALID_CA, 1851233294Sstas N_("PKINIT: No anchor given", "")); 1852178825Sdfr return HEIM_PKINIT_NO_VALID_CA; 1853178825Sdfr } 1854178825Sdfr 1855178825Sdfr /* load cert */ 1856178825Sdfr 1857178825Sdfr id = calloc(1, sizeof(*id)); 1858178825Sdfr if (id == NULL) { 1859233294Sstas krb5_set_error_message(context, ENOMEM, 1860233294Sstas N_("malloc: out of memory", "")); 1861178825Sdfr return ENOMEM; 1862233294Sstas } 1863178825Sdfr 1864233294Sstas if (user_id) { 1865233294Sstas hx509_lock lock; 1866178825Sdfr 1867233294Sstas ret = hx509_lock_init(context->hx509ctx, &lock); 1868233294Sstas if (ret) { 1869233294Sstas pk_copy_error(context, context->hx509ctx, ret, "Failed init lock"); 1870233294Sstas goto out; 1871233294Sstas } 1872178825Sdfr 1873233294Sstas if (password && password[0]) 1874233294Sstas hx509_lock_add_password(lock, password); 1875178825Sdfr 1876233294Sstas if (prompter) { 1877233294Sstas p.context = context; 1878233294Sstas p.prompter = prompter; 1879233294Sstas p.prompter_data = prompter_data; 1880233294Sstas 1881233294Sstas ret = hx509_lock_set_prompter(lock, hx_pass_prompter, &p); 1882233294Sstas if (ret) { 1883233294Sstas hx509_lock_free(lock); 1884233294Sstas goto out; 1885233294Sstas } 1886233294Sstas } 1887233294Sstas 1888233294Sstas ret = hx509_certs_init(context->hx509ctx, user_id, 0, lock, &id->certs); 1889233294Sstas hx509_lock_free(lock); 1890233294Sstas if (ret) { 1891233294Sstas pk_copy_error(context, context->hx509ctx, ret, 1892233294Sstas "Failed to init cert certs"); 1893178825Sdfr goto out; 1894233294Sstas } 1895233294Sstas } else { 1896233294Sstas id->certs = NULL; 1897178825Sdfr } 1898178825Sdfr 1899233294Sstas ret = hx509_certs_init(context->hx509ctx, anchor_id, 0, NULL, &id->anchors); 1900178825Sdfr if (ret) { 1901233294Sstas pk_copy_error(context, context->hx509ctx, ret, 1902233294Sstas "Failed to init anchors"); 1903178825Sdfr goto out; 1904178825Sdfr } 1905178825Sdfr 1906233294Sstas ret = hx509_certs_init(context->hx509ctx, "MEMORY:pkinit-cert-chain", 1907178825Sdfr 0, NULL, &id->certpool); 1908178825Sdfr if (ret) { 1909233294Sstas pk_copy_error(context, context->hx509ctx, ret, 1910233294Sstas "Failed to init chain"); 1911178825Sdfr goto out; 1912178825Sdfr } 1913178825Sdfr 1914178825Sdfr while (chain_list && *chain_list) { 1915233294Sstas ret = hx509_certs_append(context->hx509ctx, id->certpool, 1916178825Sdfr NULL, *chain_list); 1917178825Sdfr if (ret) { 1918233294Sstas pk_copy_error(context, context->hx509ctx, ret, 1919233294Sstas "Failed to laod chain %s", 1920233294Sstas *chain_list); 1921178825Sdfr goto out; 1922178825Sdfr } 1923178825Sdfr chain_list++; 1924178825Sdfr } 1925178825Sdfr 1926178825Sdfr if (revoke_list) { 1927233294Sstas ret = hx509_revoke_init(context->hx509ctx, &id->revokectx); 1928178825Sdfr if (ret) { 1929233294Sstas pk_copy_error(context, context->hx509ctx, ret, 1930233294Sstas "Failed init revoke list"); 1931178825Sdfr goto out; 1932178825Sdfr } 1933178825Sdfr 1934178825Sdfr while (*revoke_list) { 1935233294Sstas ret = hx509_revoke_add_crl(context->hx509ctx, 1936178825Sdfr id->revokectx, 1937178825Sdfr *revoke_list); 1938178825Sdfr if (ret) { 1939233294Sstas pk_copy_error(context, context->hx509ctx, ret, 1940233294Sstas "Failed load revoke list"); 1941178825Sdfr goto out; 1942178825Sdfr } 1943178825Sdfr revoke_list++; 1944178825Sdfr } 1945178825Sdfr } else 1946233294Sstas hx509_context_set_missing_revoke(context->hx509ctx, 1); 1947178825Sdfr 1948233294Sstas ret = hx509_verify_init_ctx(context->hx509ctx, &id->verify_ctx); 1949178825Sdfr if (ret) { 1950233294Sstas pk_copy_error(context, context->hx509ctx, ret, 1951233294Sstas "Failed init verify context"); 1952178825Sdfr goto out; 1953178825Sdfr } 1954178825Sdfr 1955178825Sdfr hx509_verify_attach_anchors(id->verify_ctx, id->anchors); 1956178825Sdfr hx509_verify_attach_revoke(id->verify_ctx, id->revokectx); 1957178825Sdfr 1958233294Sstas out: 1959178825Sdfr if (ret) { 1960178825Sdfr hx509_verify_destroy_ctx(id->verify_ctx); 1961178825Sdfr hx509_certs_free(&id->certs); 1962178825Sdfr hx509_certs_free(&id->anchors); 1963178825Sdfr hx509_certs_free(&id->certpool); 1964178825Sdfr hx509_revoke_free(&id->revokectx); 1965178825Sdfr free(id); 1966178825Sdfr } else 1967178825Sdfr *ret_id = id; 1968178825Sdfr 1969178825Sdfr return ret; 1970178825Sdfr} 1971178825Sdfr 1972233294Sstas/* 1973233294Sstas * 1974233294Sstas */ 1975233294Sstas 1976233294Sstasstatic void 1977233294Sstaspk_copy_error(krb5_context context, 1978233294Sstas hx509_context hx509ctx, 1979233294Sstas int hxret, 1980233294Sstas const char *fmt, 1981233294Sstas ...) 1982178825Sdfr{ 1983233294Sstas va_list va; 1984233294Sstas char *s, *f; 1985233294Sstas int ret; 1986178825Sdfr 1987233294Sstas va_start(va, fmt); 1988233294Sstas ret = vasprintf(&f, fmt, va); 1989233294Sstas va_end(va); 1990233294Sstas if (ret == -1 || f == NULL) { 1991233294Sstas krb5_clear_error_message(context); 1992233294Sstas return; 1993178825Sdfr } 1994178825Sdfr 1995233294Sstas s = hx509_get_error_string(hx509ctx, hxret); 1996233294Sstas if (s == NULL) { 1997233294Sstas krb5_clear_error_message(context); 1998233294Sstas free(f); 1999233294Sstas return; 2000233294Sstas } 2001233294Sstas krb5_set_error_message(context, hxret, "%s: %s", f, s); 2002233294Sstas free(s); 2003233294Sstas free(f); 2004178825Sdfr} 2005178825Sdfr 2006178825Sdfrstatic int 2007233294Sstasparse_integer(krb5_context context, char **p, const char *file, int lineno, 2008178825Sdfr const char *name, heim_integer *integer) 2009178825Sdfr{ 2010178825Sdfr int ret; 2011178825Sdfr char *p1; 2012178825Sdfr p1 = strsep(p, " \t"); 2013178825Sdfr if (p1 == NULL) { 2014233294Sstas krb5_set_error_message(context, EINVAL, 2015233294Sstas N_("moduli file %s missing %s on line %d", ""), 2016233294Sstas file, name, lineno); 2017178825Sdfr return EINVAL; 2018178825Sdfr } 2019178825Sdfr ret = der_parse_hex_heim_integer(p1, integer); 2020178825Sdfr if (ret) { 2021233294Sstas krb5_set_error_message(context, ret, 2022233294Sstas N_("moduli file %s failed parsing %s " 2023233294Sstas "on line %d", ""), 2024233294Sstas file, name, lineno); 2025178825Sdfr return ret; 2026178825Sdfr } 2027178825Sdfr 2028178825Sdfr return 0; 2029178825Sdfr} 2030178825Sdfr 2031178825Sdfrkrb5_error_code 2032233294Sstas_krb5_parse_moduli_line(krb5_context context, 2033178825Sdfr const char *file, 2034178825Sdfr int lineno, 2035178825Sdfr char *p, 2036178825Sdfr struct krb5_dh_moduli **m) 2037178825Sdfr{ 2038178825Sdfr struct krb5_dh_moduli *m1; 2039178825Sdfr char *p1; 2040178825Sdfr int ret; 2041178825Sdfr 2042178825Sdfr *m = NULL; 2043178825Sdfr 2044178825Sdfr m1 = calloc(1, sizeof(*m1)); 2045178825Sdfr if (m1 == NULL) { 2046233294Sstas krb5_set_error_message(context, ENOMEM, 2047233294Sstas N_("malloc: out of memory", "")); 2048178825Sdfr return ENOMEM; 2049178825Sdfr } 2050178825Sdfr 2051178825Sdfr while (isspace((unsigned char)*p)) 2052178825Sdfr p++; 2053233294Sstas if (*p == '#') { 2054233294Sstas free(m1); 2055178825Sdfr return 0; 2056233294Sstas } 2057178825Sdfr ret = EINVAL; 2058178825Sdfr 2059178825Sdfr p1 = strsep(&p, " \t"); 2060178825Sdfr if (p1 == NULL) { 2061233294Sstas krb5_set_error_message(context, ret, 2062233294Sstas N_("moduli file %s missing name on line %d", ""), 2063233294Sstas file, lineno); 2064178825Sdfr goto out; 2065178825Sdfr } 2066178825Sdfr m1->name = strdup(p1); 2067233294Sstas if (m1->name == NULL) { 2068178825Sdfr ret = ENOMEM; 2069233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memeory", "")); 2070178825Sdfr goto out; 2071178825Sdfr } 2072178825Sdfr 2073178825Sdfr p1 = strsep(&p, " \t"); 2074178825Sdfr if (p1 == NULL) { 2075233294Sstas krb5_set_error_message(context, ret, 2076233294Sstas N_("moduli file %s missing bits on line %d", ""), 2077233294Sstas file, lineno); 2078178825Sdfr goto out; 2079178825Sdfr } 2080178825Sdfr 2081178825Sdfr m1->bits = atoi(p1); 2082178825Sdfr if (m1->bits == 0) { 2083233294Sstas krb5_set_error_message(context, ret, 2084233294Sstas N_("moduli file %s have un-parsable " 2085233294Sstas "bits on line %d", ""), file, lineno); 2086178825Sdfr goto out; 2087178825Sdfr } 2088233294Sstas 2089178825Sdfr ret = parse_integer(context, &p, file, lineno, "p", &m1->p); 2090178825Sdfr if (ret) 2091178825Sdfr goto out; 2092178825Sdfr ret = parse_integer(context, &p, file, lineno, "g", &m1->g); 2093178825Sdfr if (ret) 2094178825Sdfr goto out; 2095178825Sdfr ret = parse_integer(context, &p, file, lineno, "q", &m1->q); 2096178825Sdfr if (ret) 2097178825Sdfr goto out; 2098178825Sdfr 2099178825Sdfr *m = m1; 2100178825Sdfr 2101178825Sdfr return 0; 2102233294Sstas out: 2103178825Sdfr free(m1->name); 2104178825Sdfr der_free_heim_integer(&m1->p); 2105178825Sdfr der_free_heim_integer(&m1->g); 2106178825Sdfr der_free_heim_integer(&m1->q); 2107178825Sdfr free(m1); 2108178825Sdfr return ret; 2109178825Sdfr} 2110178825Sdfr 2111178825Sdfrvoid 2112178825Sdfr_krb5_free_moduli(struct krb5_dh_moduli **moduli) 2113178825Sdfr{ 2114178825Sdfr int i; 2115178825Sdfr for (i = 0; moduli[i] != NULL; i++) { 2116178825Sdfr free(moduli[i]->name); 2117178825Sdfr der_free_heim_integer(&moduli[i]->p); 2118178825Sdfr der_free_heim_integer(&moduli[i]->g); 2119178825Sdfr der_free_heim_integer(&moduli[i]->q); 2120178825Sdfr free(moduli[i]); 2121178825Sdfr } 2122178825Sdfr free(moduli); 2123178825Sdfr} 2124178825Sdfr 2125178825Sdfrstatic const char *default_moduli_RFC2412_MODP_group2 = 2126178825Sdfr /* name */ 2127178825Sdfr "RFC2412-MODP-group2 " 2128178825Sdfr /* bits */ 2129178825Sdfr "1024 " 2130178825Sdfr /* p */ 2131178825Sdfr "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" 2132178825Sdfr "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" 2133178825Sdfr "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" 2134178825Sdfr "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" 2135178825Sdfr "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" 2136178825Sdfr "FFFFFFFF" "FFFFFFFF " 2137178825Sdfr /* g */ 2138178825Sdfr "02 " 2139178825Sdfr /* q */ 2140178825Sdfr "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68" 2141178825Sdfr "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E" 2142178825Sdfr "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122" 2143178825Sdfr "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6" 2144178825Sdfr "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0" 2145178825Sdfr "FFFFFFFF" "FFFFFFFF"; 2146178825Sdfr 2147178825Sdfrstatic const char *default_moduli_rfc3526_MODP_group14 = 2148178825Sdfr /* name */ 2149178825Sdfr "rfc3526-MODP-group14 " 2150178825Sdfr /* bits */ 2151178825Sdfr "1760 " 2152178825Sdfr /* p */ 2153178825Sdfr "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" 2154178825Sdfr "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" 2155178825Sdfr "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" 2156178825Sdfr "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" 2157178825Sdfr "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D" 2158178825Sdfr "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F" 2159178825Sdfr "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D" 2160178825Sdfr "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B" 2161178825Sdfr "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9" 2162178825Sdfr "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510" 2163178825Sdfr "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF " 2164178825Sdfr /* g */ 2165178825Sdfr "02 " 2166178825Sdfr /* q */ 2167178825Sdfr "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68" 2168178825Sdfr "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E" 2169178825Sdfr "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122" 2170178825Sdfr "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6" 2171178825Sdfr "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E" 2172178825Sdfr "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF" 2173178825Sdfr "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36" 2174178825Sdfr "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D" 2175178825Sdfr "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964" 2176178825Sdfr "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288" 2177178825Sdfr "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF"; 2178178825Sdfr 2179178825Sdfrkrb5_error_code 2180178825Sdfr_krb5_parse_moduli(krb5_context context, const char *file, 2181178825Sdfr struct krb5_dh_moduli ***moduli) 2182178825Sdfr{ 2183178825Sdfr /* name bits P G Q */ 2184178825Sdfr krb5_error_code ret; 2185178825Sdfr struct krb5_dh_moduli **m = NULL, **m2; 2186178825Sdfr char buf[4096]; 2187178825Sdfr FILE *f; 2188178825Sdfr int lineno = 0, n = 0; 2189178825Sdfr 2190178825Sdfr *moduli = NULL; 2191178825Sdfr 2192178825Sdfr m = calloc(1, sizeof(m[0]) * 3); 2193178825Sdfr if (m == NULL) { 2194233294Sstas krb5_set_error_message(context, ENOMEM, 2195233294Sstas N_("malloc: out of memory", "")); 2196178825Sdfr return ENOMEM; 2197178825Sdfr } 2198178825Sdfr 2199178825Sdfr strlcpy(buf, default_moduli_rfc3526_MODP_group14, sizeof(buf)); 2200178825Sdfr ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[0]); 2201178825Sdfr if (ret) { 2202178825Sdfr _krb5_free_moduli(m); 2203178825Sdfr return ret; 2204178825Sdfr } 2205178825Sdfr n++; 2206178825Sdfr 2207178825Sdfr strlcpy(buf, default_moduli_RFC2412_MODP_group2, sizeof(buf)); 2208178825Sdfr ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[1]); 2209178825Sdfr if (ret) { 2210178825Sdfr _krb5_free_moduli(m); 2211178825Sdfr return ret; 2212178825Sdfr } 2213178825Sdfr n++; 2214178825Sdfr 2215178825Sdfr 2216178825Sdfr if (file == NULL) 2217178825Sdfr file = MODULI_FILE; 2218178825Sdfr 2219233294Sstas#ifdef KRB5_USE_PATH_TOKENS 2220233294Sstas { 2221233294Sstas char * exp_file; 2222233294Sstas 2223233294Sstas if (_krb5_expand_path_tokens(context, file, &exp_file) == 0) { 2224233294Sstas f = fopen(exp_file, "r"); 2225233294Sstas krb5_xfree(exp_file); 2226233294Sstas } else { 2227233294Sstas f = NULL; 2228233294Sstas } 2229233294Sstas } 2230233294Sstas#else 2231178825Sdfr f = fopen(file, "r"); 2232233294Sstas#endif 2233233294Sstas 2234178825Sdfr if (f == NULL) { 2235178825Sdfr *moduli = m; 2236178825Sdfr return 0; 2237178825Sdfr } 2238233294Sstas rk_cloexec_file(f); 2239178825Sdfr 2240178825Sdfr while(fgets(buf, sizeof(buf), f) != NULL) { 2241178825Sdfr struct krb5_dh_moduli *element; 2242178825Sdfr 2243178825Sdfr buf[strcspn(buf, "\n")] = '\0'; 2244178825Sdfr lineno++; 2245178825Sdfr 2246178825Sdfr m2 = realloc(m, (n + 2) * sizeof(m[0])); 2247178825Sdfr if (m2 == NULL) { 2248178825Sdfr _krb5_free_moduli(m); 2249233294Sstas krb5_set_error_message(context, ENOMEM, 2250233294Sstas N_("malloc: out of memory", "")); 2251178825Sdfr return ENOMEM; 2252178825Sdfr } 2253178825Sdfr m = m2; 2254233294Sstas 2255178825Sdfr m[n] = NULL; 2256178825Sdfr 2257178825Sdfr ret = _krb5_parse_moduli_line(context, file, lineno, buf, &element); 2258178825Sdfr if (ret) { 2259178825Sdfr _krb5_free_moduli(m); 2260178825Sdfr return ret; 2261178825Sdfr } 2262178825Sdfr if (element == NULL) 2263178825Sdfr continue; 2264178825Sdfr 2265178825Sdfr m[n] = element; 2266178825Sdfr m[n + 1] = NULL; 2267178825Sdfr n++; 2268178825Sdfr } 2269178825Sdfr *moduli = m; 2270178825Sdfr return 0; 2271178825Sdfr} 2272178825Sdfr 2273178825Sdfrkrb5_error_code 2274178825Sdfr_krb5_dh_group_ok(krb5_context context, unsigned long bits, 2275178825Sdfr heim_integer *p, heim_integer *g, heim_integer *q, 2276178825Sdfr struct krb5_dh_moduli **moduli, 2277178825Sdfr char **name) 2278178825Sdfr{ 2279178825Sdfr int i; 2280178825Sdfr 2281178825Sdfr if (name) 2282178825Sdfr *name = NULL; 2283178825Sdfr 2284178825Sdfr for (i = 0; moduli[i] != NULL; i++) { 2285178825Sdfr if (der_heim_integer_cmp(&moduli[i]->g, g) == 0 && 2286178825Sdfr der_heim_integer_cmp(&moduli[i]->p, p) == 0 && 2287178825Sdfr (q == NULL || der_heim_integer_cmp(&moduli[i]->q, q) == 0)) 2288233294Sstas { 2289233294Sstas if (bits && bits > moduli[i]->bits) { 2290233294Sstas krb5_set_error_message(context, 2291233294Sstas KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED, 2292233294Sstas N_("PKINIT: DH group parameter %s " 2293233294Sstas "no accepted, not enough bits " 2294233294Sstas "generated", ""), 2295233294Sstas moduli[i]->name); 2296233294Sstas return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED; 2297233294Sstas } 2298233294Sstas if (name) 2299233294Sstas *name = strdup(moduli[i]->name); 2300233294Sstas return 0; 2301178825Sdfr } 2302178825Sdfr } 2303233294Sstas krb5_set_error_message(context, 2304233294Sstas KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED, 2305233294Sstas N_("PKINIT: DH group parameter no ok", "")); 2306178825Sdfr return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED; 2307178825Sdfr} 2308233294Sstas#endif /* PKINIT */ 2309178825Sdfr 2310233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL 2311178825Sdfr_krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt) 2312178825Sdfr{ 2313178825Sdfr#ifdef PKINIT 2314178825Sdfr krb5_pk_init_ctx ctx; 2315178825Sdfr 2316178825Sdfr if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL) 2317178825Sdfr return; 2318178825Sdfr ctx = opt->opt_private->pk_init_ctx; 2319233294Sstas switch (ctx->keyex) { 2320233294Sstas case USE_DH: 2321233294Sstas if (ctx->u.dh) 2322233294Sstas DH_free(ctx->u.dh); 2323233294Sstas break; 2324233294Sstas case USE_RSA: 2325233294Sstas break; 2326233294Sstas case USE_ECDH: 2327233294Sstas#ifdef HAVE_OPENSSL 2328233294Sstas if (ctx->u.eckey) 2329233294Sstas EC_KEY_free(ctx->u.eckey); 2330233294Sstas#endif 2331233294Sstas break; 2332233294Sstas } 2333178825Sdfr if (ctx->id) { 2334178825Sdfr hx509_verify_destroy_ctx(ctx->id->verify_ctx); 2335178825Sdfr hx509_certs_free(&ctx->id->certs); 2336233294Sstas hx509_cert_free(ctx->id->cert); 2337178825Sdfr hx509_certs_free(&ctx->id->anchors); 2338178825Sdfr hx509_certs_free(&ctx->id->certpool); 2339178825Sdfr 2340178825Sdfr if (ctx->clientDHNonce) { 2341178825Sdfr krb5_free_data(NULL, ctx->clientDHNonce); 2342178825Sdfr ctx->clientDHNonce = NULL; 2343178825Sdfr } 2344178825Sdfr if (ctx->m) 2345178825Sdfr _krb5_free_moduli(ctx->m); 2346178825Sdfr free(ctx->id); 2347178825Sdfr ctx->id = NULL; 2348178825Sdfr } 2349178825Sdfr free(opt->opt_private->pk_init_ctx); 2350178825Sdfr opt->opt_private->pk_init_ctx = NULL; 2351178825Sdfr#endif 2352178825Sdfr} 2353233294Sstas 2354233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2355178825Sdfrkrb5_get_init_creds_opt_set_pkinit(krb5_context context, 2356178825Sdfr krb5_get_init_creds_opt *opt, 2357178825Sdfr krb5_principal principal, 2358178825Sdfr const char *user_id, 2359178825Sdfr const char *x509_anchors, 2360178825Sdfr char * const * pool, 2361178825Sdfr char * const * pki_revoke, 2362178825Sdfr int flags, 2363178825Sdfr krb5_prompter_fct prompter, 2364178825Sdfr void *prompter_data, 2365178825Sdfr char *password) 2366178825Sdfr{ 2367178825Sdfr#ifdef PKINIT 2368178825Sdfr krb5_error_code ret; 2369178825Sdfr char *anchors = NULL; 2370178825Sdfr 2371178825Sdfr if (opt->opt_private == NULL) { 2372233294Sstas krb5_set_error_message(context, EINVAL, 2373233294Sstas N_("PKINIT: on non extendable opt", "")); 2374178825Sdfr return EINVAL; 2375178825Sdfr } 2376178825Sdfr 2377233294Sstas opt->opt_private->pk_init_ctx = 2378178825Sdfr calloc(1, sizeof(*opt->opt_private->pk_init_ctx)); 2379178825Sdfr if (opt->opt_private->pk_init_ctx == NULL) { 2380233294Sstas krb5_set_error_message(context, ENOMEM, 2381233294Sstas N_("malloc: out of memory", "")); 2382178825Sdfr return ENOMEM; 2383178825Sdfr } 2384178825Sdfr opt->opt_private->pk_init_ctx->require_binding = 0; 2385178825Sdfr opt->opt_private->pk_init_ctx->require_eku = 1; 2386178825Sdfr opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1; 2387178825Sdfr opt->opt_private->pk_init_ctx->peer = NULL; 2388178825Sdfr 2389178825Sdfr /* XXX implement krb5_appdefault_strings */ 2390178825Sdfr if (pool == NULL) 2391178825Sdfr pool = krb5_config_get_strings(context, NULL, 2392233294Sstas "appdefaults", 2393233294Sstas "pkinit_pool", 2394178825Sdfr NULL); 2395178825Sdfr 2396178825Sdfr if (pki_revoke == NULL) 2397178825Sdfr pki_revoke = krb5_config_get_strings(context, NULL, 2398233294Sstas "appdefaults", 2399233294Sstas "pkinit_revoke", 2400178825Sdfr NULL); 2401178825Sdfr 2402178825Sdfr if (x509_anchors == NULL) { 2403178825Sdfr krb5_appdefault_string(context, "kinit", 2404233294Sstas krb5_principal_get_realm(context, principal), 2405178825Sdfr "pkinit_anchors", NULL, &anchors); 2406178825Sdfr x509_anchors = anchors; 2407178825Sdfr } 2408178825Sdfr 2409233294Sstas if (flags & 4) 2410233294Sstas opt->opt_private->pk_init_ctx->anonymous = 1; 2411233294Sstas 2412178825Sdfr ret = _krb5_pk_load_id(context, 2413178825Sdfr &opt->opt_private->pk_init_ctx->id, 2414178825Sdfr user_id, 2415178825Sdfr x509_anchors, 2416178825Sdfr pool, 2417178825Sdfr pki_revoke, 2418178825Sdfr prompter, 2419178825Sdfr prompter_data, 2420178825Sdfr password); 2421178825Sdfr if (ret) { 2422178825Sdfr free(opt->opt_private->pk_init_ctx); 2423178825Sdfr opt->opt_private->pk_init_ctx = NULL; 2424178825Sdfr return ret; 2425178825Sdfr } 2426178825Sdfr 2427233294Sstas if (opt->opt_private->pk_init_ctx->id->certs) { 2428233294Sstas _krb5_pk_set_user_id(context, 2429233294Sstas principal, 2430233294Sstas opt->opt_private->pk_init_ctx, 2431233294Sstas opt->opt_private->pk_init_ctx->id->certs); 2432233294Sstas } else 2433233294Sstas opt->opt_private->pk_init_ctx->id->cert = NULL; 2434233294Sstas 2435178825Sdfr if ((flags & 2) == 0) { 2436233294Sstas hx509_context hx509ctx = context->hx509ctx; 2437233294Sstas hx509_cert cert = opt->opt_private->pk_init_ctx->id->cert; 2438178825Sdfr 2439233294Sstas opt->opt_private->pk_init_ctx->keyex = USE_DH; 2440178825Sdfr 2441233294Sstas /* 2442233294Sstas * If its a ECDSA certs, lets select ECDSA as the keyex algorithm. 2443233294Sstas */ 2444233294Sstas if (cert) { 2445233294Sstas AlgorithmIdentifier alg; 2446178825Sdfr 2447233294Sstas ret = hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx, cert, &alg); 2448233294Sstas if (ret == 0) { 2449233294Sstas if (der_heim_oid_cmp(&alg.algorithm, &asn1_oid_id_ecPublicKey) == 0) 2450233294Sstas opt->opt_private->pk_init_ctx->keyex = USE_ECDH; 2451233294Sstas free_AlgorithmIdentifier(&alg); 2452233294Sstas } 2453178825Sdfr } 2454178825Sdfr 2455233294Sstas } else { 2456233294Sstas opt->opt_private->pk_init_ctx->keyex = USE_RSA; 2457178825Sdfr 2458233294Sstas if (opt->opt_private->pk_init_ctx->id->certs == NULL) { 2459233294Sstas krb5_set_error_message(context, EINVAL, 2460233294Sstas N_("No anonymous pkinit support in RSA mode", "")); 2461233294Sstas return EINVAL; 2462178825Sdfr } 2463178825Sdfr } 2464178825Sdfr 2465178825Sdfr return 0; 2466178825Sdfr#else 2467233294Sstas krb5_set_error_message(context, EINVAL, 2468233294Sstas N_("no support for PKINIT compiled in", "")); 2469178825Sdfr return EINVAL; 2470178825Sdfr#endif 2471178825Sdfr} 2472178825Sdfr 2473233294Sstaskrb5_error_code KRB5_LIB_FUNCTION 2474233294Sstaskrb5_get_init_creds_opt_set_pkinit_user_certs(krb5_context context, 2475233294Sstas krb5_get_init_creds_opt *opt, 2476233294Sstas struct hx509_certs_data *certs) 2477233294Sstas{ 2478233294Sstas#ifdef PKINIT 2479233294Sstas if (opt->opt_private == NULL) { 2480233294Sstas krb5_set_error_message(context, EINVAL, 2481233294Sstas N_("PKINIT: on non extendable opt", "")); 2482233294Sstas return EINVAL; 2483233294Sstas } 2484233294Sstas if (opt->opt_private->pk_init_ctx == NULL) { 2485233294Sstas krb5_set_error_message(context, EINVAL, 2486233294Sstas N_("PKINIT: on pkinit context", "")); 2487233294Sstas return EINVAL; 2488233294Sstas } 2489233294Sstas 2490233294Sstas _krb5_pk_set_user_id(context, NULL, opt->opt_private->pk_init_ctx, certs); 2491233294Sstas 2492233294Sstas return 0; 2493233294Sstas#else 2494233294Sstas krb5_set_error_message(context, EINVAL, 2495233294Sstas N_("no support for PKINIT compiled in", "")); 2496233294Sstas return EINVAL; 2497233294Sstas#endif 2498233294Sstas} 2499233294Sstas 2500233294Sstas#ifdef PKINIT 2501233294Sstas 2502233294Sstasstatic int 2503233294Sstasget_ms_san(hx509_context context, hx509_cert cert, char **upn) 2504233294Sstas{ 2505233294Sstas hx509_octet_string_list list; 2506233294Sstas int ret; 2507233294Sstas 2508233294Sstas *upn = NULL; 2509233294Sstas 2510233294Sstas ret = hx509_cert_find_subjectAltName_otherName(context, 2511233294Sstas cert, 2512233294Sstas &asn1_oid_id_pkinit_ms_san, 2513233294Sstas &list); 2514233294Sstas if (ret) 2515233294Sstas return 0; 2516233294Sstas 2517233294Sstas if (list.len > 0 && list.val[0].length > 0) 2518233294Sstas ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length, 2519233294Sstas upn, NULL); 2520233294Sstas else 2521233294Sstas ret = 1; 2522233294Sstas hx509_free_octet_string_list(&list); 2523233294Sstas 2524233294Sstas return ret; 2525233294Sstas} 2526233294Sstas 2527233294Sstasstatic int 2528233294Sstasfind_ms_san(hx509_context context, hx509_cert cert, void *ctx) 2529233294Sstas{ 2530233294Sstas char *upn; 2531233294Sstas int ret; 2532233294Sstas 2533233294Sstas ret = get_ms_san(context, cert, &upn); 2534233294Sstas if (ret == 0) 2535233294Sstas free(upn); 2536233294Sstas return ret; 2537233294Sstas} 2538233294Sstas 2539233294Sstas 2540233294Sstas 2541233294Sstas#endif 2542233294Sstas 2543178825Sdfr/* 2544233294Sstas * Private since it need to be redesigned using krb5_get_init_creds() 2545178825Sdfr */ 2546178825Sdfr 2547233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2548233294Sstaskrb5_pk_enterprise_cert(krb5_context context, 2549233294Sstas const char *user_id, 2550233294Sstas krb5_const_realm realm, 2551233294Sstas krb5_principal *principal, 2552233294Sstas struct hx509_certs_data **res) 2553178825Sdfr{ 2554233294Sstas#ifdef PKINIT 2555233294Sstas krb5_error_code ret; 2556233294Sstas hx509_certs certs, result; 2557233294Sstas hx509_cert cert = NULL; 2558233294Sstas hx509_query *q; 2559233294Sstas char *name; 2560178825Sdfr 2561233294Sstas *principal = NULL; 2562233294Sstas if (res) 2563233294Sstas *res = NULL; 2564233294Sstas 2565233294Sstas if (user_id == NULL) { 2566233294Sstas krb5_set_error_message(context, ENOENT, "no user id"); 2567233294Sstas return ENOENT; 2568178825Sdfr } 2569178825Sdfr 2570233294Sstas ret = hx509_certs_init(context->hx509ctx, user_id, 0, NULL, &certs); 2571233294Sstas if (ret) { 2572233294Sstas pk_copy_error(context, context->hx509ctx, ret, 2573233294Sstas "Failed to init cert certs"); 2574233294Sstas goto out; 2575178825Sdfr } 2576233294Sstas 2577233294Sstas ret = hx509_query_alloc(context->hx509ctx, &q); 2578233294Sstas if (ret) { 2579233294Sstas krb5_set_error_message(context, ret, "out of memory"); 2580233294Sstas hx509_certs_free(&certs); 2581233294Sstas goto out; 2582233294Sstas } 2583233294Sstas 2584233294Sstas hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); 2585233294Sstas hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); 2586233294Sstas hx509_query_match_eku(q, &asn1_oid_id_pkinit_ms_eku); 2587233294Sstas hx509_query_match_cmp_func(q, find_ms_san, NULL); 2588233294Sstas 2589233294Sstas ret = hx509_certs_filter(context->hx509ctx, certs, q, &result); 2590233294Sstas hx509_query_free(context->hx509ctx, q); 2591233294Sstas hx509_certs_free(&certs); 2592233294Sstas if (ret) { 2593233294Sstas pk_copy_error(context, context->hx509ctx, ret, 2594233294Sstas "Failed to find PKINIT certificate"); 2595233294Sstas return ret; 2596233294Sstas } 2597233294Sstas 2598233294Sstas ret = hx509_get_one_cert(context->hx509ctx, result, &cert); 2599233294Sstas hx509_certs_free(&result); 2600233294Sstas if (ret) { 2601233294Sstas pk_copy_error(context, context->hx509ctx, ret, 2602233294Sstas "Failed to get one cert"); 2603233294Sstas goto out; 2604233294Sstas } 2605233294Sstas 2606233294Sstas ret = get_ms_san(context->hx509ctx, cert, &name); 2607233294Sstas if (ret) { 2608233294Sstas pk_copy_error(context, context->hx509ctx, ret, 2609233294Sstas "Failed to get MS SAN"); 2610233294Sstas goto out; 2611233294Sstas } 2612233294Sstas 2613233294Sstas ret = krb5_make_principal(context, principal, realm, name, NULL); 2614233294Sstas free(name); 2615233294Sstas if (ret) 2616233294Sstas goto out; 2617233294Sstas 2618233294Sstas krb5_principal_set_type(context, *principal, KRB5_NT_ENTERPRISE_PRINCIPAL); 2619233294Sstas 2620233294Sstas if (res) { 2621233294Sstas ret = hx509_certs_init(context->hx509ctx, "MEMORY:", 0, NULL, res); 2622233294Sstas if (ret) 2623233294Sstas goto out; 2624233294Sstas 2625233294Sstas ret = hx509_certs_add(context->hx509ctx, *res, cert); 2626233294Sstas if (ret) { 2627233294Sstas hx509_certs_free(res); 2628233294Sstas goto out; 2629233294Sstas } 2630233294Sstas } 2631233294Sstas 2632233294Sstas out: 2633233294Sstas hx509_cert_free(cert); 2634233294Sstas 2635233294Sstas return ret; 2636233294Sstas#else 2637233294Sstas krb5_set_error_message(context, EINVAL, 2638233294Sstas N_("no support for PKINIT compiled in", "")); 2639233294Sstas return EINVAL; 2640233294Sstas#endif 2641178825Sdfr} 2642