1178825Sdfr/* 2178825Sdfr * Copyright (c) 2003 - 2007 Kungliga Tekniska H�gskolan 3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden). 4178825Sdfr * All rights reserved. 5178825Sdfr * 6178825Sdfr * Redistribution and use in source and binary forms, with or without 7178825Sdfr * modification, are permitted provided that the following conditions 8178825Sdfr * are met: 9178825Sdfr * 10178825Sdfr * 1. Redistributions of source code must retain the above copyright 11178825Sdfr * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 14178825Sdfr * notice, this list of conditions and the following disclaimer in the 15178825Sdfr * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors 18178825Sdfr * may be used to endorse or promote products derived from this software 19178825Sdfr * without specific prior written permission. 20178825Sdfr * 21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31178825Sdfr * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#include "krb5_locl.h" 35178825Sdfr 36178825SdfrRCSID("$Id: pkinit.c 22433 2008-01-13 14:11:46Z lha $"); 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 <heim_asn1.h> 49178825Sdfr#include <rfc2459_asn1.h> 50178825Sdfr#include <cms_asn1.h> 51178825Sdfr#include <pkcs8_asn1.h> 52178825Sdfr#include <pkcs9_asn1.h> 53178825Sdfr#include <pkcs12_asn1.h> 54178825Sdfr#include <pkinit_asn1.h> 55178825Sdfr#include <asn1_err.h> 56178825Sdfr 57178825Sdfr#include <der.h> 58178825Sdfr 59178825Sdfr#include <hx509.h> 60178825Sdfr 61178825Sdfrenum { 62178825Sdfr COMPAT_WIN2K = 1, 63178825Sdfr COMPAT_IETF = 2 64178825Sdfr}; 65178825Sdfr 66178825Sdfrstruct krb5_pk_identity { 67178825Sdfr hx509_context hx509ctx; 68178825Sdfr hx509_verify_ctx verify_ctx; 69178825Sdfr hx509_certs certs; 70178825Sdfr hx509_certs anchors; 71178825Sdfr hx509_certs certpool; 72178825Sdfr hx509_revoke_ctx revokectx; 73178825Sdfr}; 74178825Sdfr 75178825Sdfrstruct krb5_pk_cert { 76178825Sdfr hx509_cert cert; 77178825Sdfr}; 78178825Sdfr 79178825Sdfrstruct krb5_pk_init_ctx_data { 80178825Sdfr struct krb5_pk_identity *id; 81178825Sdfr DH *dh; 82178825Sdfr krb5_data *clientDHNonce; 83178825Sdfr struct krb5_dh_moduli **m; 84178825Sdfr hx509_peer_info peer; 85178825Sdfr int type; 86178825Sdfr unsigned int require_binding:1; 87178825Sdfr unsigned int require_eku:1; 88178825Sdfr unsigned int require_krbtgt_otherName:1; 89178825Sdfr unsigned int require_hostname_match:1; 90178825Sdfr unsigned int trustedCertifiers:1; 91178825Sdfr}; 92178825Sdfr 93178825Sdfrstatic void 94178825Sdfr_krb5_pk_copy_error(krb5_context context, 95178825Sdfr hx509_context hx509ctx, 96178825Sdfr int hxret, 97178825Sdfr const char *fmt, 98178825Sdfr ...) 99178825Sdfr __attribute__ ((format (printf, 4, 5))); 100178825Sdfr 101178825Sdfr/* 102178825Sdfr * 103178825Sdfr */ 104178825Sdfr 105178825Sdfrvoid KRB5_LIB_FUNCTION 106178825Sdfr_krb5_pk_cert_free(struct krb5_pk_cert *cert) 107178825Sdfr{ 108178825Sdfr if (cert->cert) { 109178825Sdfr hx509_cert_free(cert->cert); 110178825Sdfr } 111178825Sdfr free(cert); 112178825Sdfr} 113178825Sdfr 114178825Sdfrstatic krb5_error_code 115178825SdfrBN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer) 116178825Sdfr{ 117178825Sdfr integer->length = BN_num_bytes(bn); 118178825Sdfr integer->data = malloc(integer->length); 119178825Sdfr if (integer->data == NULL) { 120178825Sdfr krb5_clear_error_string(context); 121178825Sdfr return ENOMEM; 122178825Sdfr } 123178825Sdfr BN_bn2bin(bn, integer->data); 124178825Sdfr integer->negative = BN_is_negative(bn); 125178825Sdfr return 0; 126178825Sdfr} 127178825Sdfr 128178825Sdfrstatic BIGNUM * 129178825Sdfrinteger_to_BN(krb5_context context, const char *field, const heim_integer *f) 130178825Sdfr{ 131178825Sdfr BIGNUM *bn; 132178825Sdfr 133178825Sdfr bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL); 134178825Sdfr if (bn == NULL) { 135178825Sdfr krb5_set_error_string(context, "PKINIT: parsing BN failed %s", field); 136178825Sdfr return NULL; 137178825Sdfr } 138178825Sdfr BN_set_negative(bn, f->negative); 139178825Sdfr return bn; 140178825Sdfr} 141178825Sdfr 142178825Sdfr 143178825Sdfrstatic krb5_error_code 144178825Sdfr_krb5_pk_create_sign(krb5_context context, 145178825Sdfr const heim_oid *eContentType, 146178825Sdfr krb5_data *eContent, 147178825Sdfr struct krb5_pk_identity *id, 148178825Sdfr hx509_peer_info peer, 149178825Sdfr krb5_data *sd_data) 150178825Sdfr{ 151178825Sdfr hx509_cert cert; 152178825Sdfr hx509_query *q; 153178825Sdfr int ret; 154178825Sdfr 155178825Sdfr ret = hx509_query_alloc(id->hx509ctx, &q); 156178825Sdfr if (ret) { 157178825Sdfr _krb5_pk_copy_error(context, id->hx509ctx, ret, 158178825Sdfr "Allocate query to find signing certificate"); 159178825Sdfr return ret; 160178825Sdfr } 161178825Sdfr 162178825Sdfr hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); 163178825Sdfr hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); 164178825Sdfr 165178825Sdfr ret = hx509_certs_find(id->hx509ctx, id->certs, q, &cert); 166178825Sdfr hx509_query_free(id->hx509ctx, q); 167178825Sdfr if (ret) { 168178825Sdfr _krb5_pk_copy_error(context, id->hx509ctx, ret, 169178825Sdfr "Find certificate to signed CMS data"); 170178825Sdfr return ret; 171178825Sdfr } 172178825Sdfr 173178825Sdfr ret = hx509_cms_create_signed_1(id->hx509ctx, 174178825Sdfr 0, 175178825Sdfr eContentType, 176178825Sdfr eContent->data, 177178825Sdfr eContent->length, 178178825Sdfr NULL, 179178825Sdfr cert, 180178825Sdfr peer, 181178825Sdfr NULL, 182178825Sdfr id->certs, 183178825Sdfr sd_data); 184178825Sdfr if (ret) 185178825Sdfr _krb5_pk_copy_error(context, id->hx509ctx, ret, "create CMS signedData"); 186178825Sdfr hx509_cert_free(cert); 187178825Sdfr 188178825Sdfr return ret; 189178825Sdfr} 190178825Sdfr 191178825Sdfrstatic int 192178825Sdfrcert2epi(hx509_context context, void *ctx, hx509_cert c) 193178825Sdfr{ 194178825Sdfr ExternalPrincipalIdentifiers *ids = ctx; 195178825Sdfr ExternalPrincipalIdentifier id; 196178825Sdfr hx509_name subject = NULL; 197178825Sdfr void *p; 198178825Sdfr int ret; 199178825Sdfr 200178825Sdfr memset(&id, 0, sizeof(id)); 201178825Sdfr 202178825Sdfr ret = hx509_cert_get_subject(c, &subject); 203178825Sdfr if (ret) 204178825Sdfr return ret; 205178825Sdfr 206178825Sdfr if (hx509_name_is_null_p(subject) != 0) { 207178825Sdfr 208178825Sdfr id.subjectName = calloc(1, sizeof(*id.subjectName)); 209178825Sdfr if (id.subjectName == NULL) { 210178825Sdfr hx509_name_free(&subject); 211178825Sdfr free_ExternalPrincipalIdentifier(&id); 212178825Sdfr return ENOMEM; 213178825Sdfr } 214178825Sdfr 215178825Sdfr ret = hx509_name_binary(subject, id.subjectName); 216178825Sdfr if (ret) { 217178825Sdfr hx509_name_free(&subject); 218178825Sdfr free_ExternalPrincipalIdentifier(&id); 219178825Sdfr return ret; 220178825Sdfr } 221178825Sdfr } 222178825Sdfr hx509_name_free(&subject); 223178825Sdfr 224178825Sdfr 225178825Sdfr id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber)); 226178825Sdfr if (id.issuerAndSerialNumber == NULL) { 227178825Sdfr free_ExternalPrincipalIdentifier(&id); 228178825Sdfr return ENOMEM; 229178825Sdfr } 230178825Sdfr 231178825Sdfr { 232178825Sdfr IssuerAndSerialNumber iasn; 233178825Sdfr hx509_name issuer; 234178825Sdfr size_t size; 235178825Sdfr 236178825Sdfr memset(&iasn, 0, sizeof(iasn)); 237178825Sdfr 238178825Sdfr ret = hx509_cert_get_issuer(c, &issuer); 239178825Sdfr if (ret) { 240178825Sdfr free_ExternalPrincipalIdentifier(&id); 241178825Sdfr return ret; 242178825Sdfr } 243178825Sdfr 244178825Sdfr ret = hx509_name_to_Name(issuer, &iasn.issuer); 245178825Sdfr hx509_name_free(&issuer); 246178825Sdfr if (ret) { 247178825Sdfr free_ExternalPrincipalIdentifier(&id); 248178825Sdfr return ret; 249178825Sdfr } 250178825Sdfr 251178825Sdfr ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber); 252178825Sdfr if (ret) { 253178825Sdfr free_IssuerAndSerialNumber(&iasn); 254178825Sdfr free_ExternalPrincipalIdentifier(&id); 255178825Sdfr return ret; 256178825Sdfr } 257178825Sdfr 258178825Sdfr ASN1_MALLOC_ENCODE(IssuerAndSerialNumber, 259178825Sdfr id.issuerAndSerialNumber->data, 260178825Sdfr id.issuerAndSerialNumber->length, 261178825Sdfr &iasn, &size, ret); 262178825Sdfr free_IssuerAndSerialNumber(&iasn); 263178825Sdfr if (ret) 264178825Sdfr return ret; 265178825Sdfr if (id.issuerAndSerialNumber->length != size) 266178825Sdfr abort(); 267178825Sdfr } 268178825Sdfr 269178825Sdfr id.subjectKeyIdentifier = NULL; 270178825Sdfr 271178825Sdfr p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1)); 272178825Sdfr if (p == NULL) { 273178825Sdfr free_ExternalPrincipalIdentifier(&id); 274178825Sdfr return ENOMEM; 275178825Sdfr } 276178825Sdfr 277178825Sdfr ids->val = p; 278178825Sdfr ids->val[ids->len] = id; 279178825Sdfr ids->len++; 280178825Sdfr 281178825Sdfr return 0; 282178825Sdfr} 283178825Sdfr 284178825Sdfrstatic krb5_error_code 285178825Sdfrbuild_edi(krb5_context context, 286178825Sdfr hx509_context hx509ctx, 287178825Sdfr hx509_certs certs, 288178825Sdfr ExternalPrincipalIdentifiers *ids) 289178825Sdfr{ 290178825Sdfr return hx509_certs_iter(hx509ctx, certs, cert2epi, ids); 291178825Sdfr} 292178825Sdfr 293178825Sdfrstatic krb5_error_code 294178825Sdfrbuild_auth_pack(krb5_context context, 295178825Sdfr unsigned nonce, 296178825Sdfr krb5_pk_init_ctx ctx, 297178825Sdfr DH *dh, 298178825Sdfr const KDC_REQ_BODY *body, 299178825Sdfr AuthPack *a) 300178825Sdfr{ 301178825Sdfr size_t buf_size, len; 302178825Sdfr krb5_error_code ret; 303178825Sdfr void *buf; 304178825Sdfr krb5_timestamp sec; 305178825Sdfr int32_t usec; 306178825Sdfr Checksum checksum; 307178825Sdfr 308178825Sdfr krb5_clear_error_string(context); 309178825Sdfr 310178825Sdfr memset(&checksum, 0, sizeof(checksum)); 311178825Sdfr 312178825Sdfr krb5_us_timeofday(context, &sec, &usec); 313178825Sdfr a->pkAuthenticator.ctime = sec; 314178825Sdfr a->pkAuthenticator.nonce = nonce; 315178825Sdfr 316178825Sdfr ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret); 317178825Sdfr if (ret) 318178825Sdfr return ret; 319178825Sdfr if (buf_size != len) 320178825Sdfr krb5_abortx(context, "internal error in ASN.1 encoder"); 321178825Sdfr 322178825Sdfr ret = krb5_create_checksum(context, 323178825Sdfr NULL, 324178825Sdfr 0, 325178825Sdfr CKSUMTYPE_SHA1, 326178825Sdfr buf, 327178825Sdfr len, 328178825Sdfr &checksum); 329178825Sdfr free(buf); 330178825Sdfr if (ret) 331178825Sdfr return ret; 332178825Sdfr 333178825Sdfr ALLOC(a->pkAuthenticator.paChecksum, 1); 334178825Sdfr if (a->pkAuthenticator.paChecksum == NULL) { 335178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 336178825Sdfr return ENOMEM; 337178825Sdfr } 338178825Sdfr 339178825Sdfr ret = krb5_data_copy(a->pkAuthenticator.paChecksum, 340178825Sdfr checksum.checksum.data, checksum.checksum.length); 341178825Sdfr free_Checksum(&checksum); 342178825Sdfr if (ret) 343178825Sdfr return ret; 344178825Sdfr 345178825Sdfr if (dh) { 346178825Sdfr DomainParameters dp; 347178825Sdfr heim_integer dh_pub_key; 348178825Sdfr krb5_data dhbuf; 349178825Sdfr size_t size; 350178825Sdfr 351178825Sdfr if (1 /* support_cached_dh */) { 352178825Sdfr ALLOC(a->clientDHNonce, 1); 353178825Sdfr if (a->clientDHNonce == NULL) { 354178825Sdfr krb5_clear_error_string(context); 355178825Sdfr return ENOMEM; 356178825Sdfr } 357178825Sdfr ret = krb5_data_alloc(a->clientDHNonce, 40); 358178825Sdfr if (a->clientDHNonce == NULL) { 359178825Sdfr krb5_clear_error_string(context); 360178825Sdfr return ENOMEM; 361178825Sdfr } 362178825Sdfr memset(a->clientDHNonce->data, 0, a->clientDHNonce->length); 363178825Sdfr ret = krb5_copy_data(context, a->clientDHNonce, 364178825Sdfr &ctx->clientDHNonce); 365178825Sdfr if (ret) 366178825Sdfr return ret; 367178825Sdfr } 368178825Sdfr 369178825Sdfr ALLOC(a->clientPublicValue, 1); 370178825Sdfr if (a->clientPublicValue == NULL) 371178825Sdfr return ENOMEM; 372178825Sdfr ret = der_copy_oid(oid_id_dhpublicnumber(), 373178825Sdfr &a->clientPublicValue->algorithm.algorithm); 374178825Sdfr if (ret) 375178825Sdfr return ret; 376178825Sdfr 377178825Sdfr memset(&dp, 0, sizeof(dp)); 378178825Sdfr 379178825Sdfr ret = BN_to_integer(context, dh->p, &dp.p); 380178825Sdfr if (ret) { 381178825Sdfr free_DomainParameters(&dp); 382178825Sdfr return ret; 383178825Sdfr } 384178825Sdfr ret = BN_to_integer(context, dh->g, &dp.g); 385178825Sdfr if (ret) { 386178825Sdfr free_DomainParameters(&dp); 387178825Sdfr return ret; 388178825Sdfr } 389178825Sdfr ret = BN_to_integer(context, dh->q, &dp.q); 390178825Sdfr if (ret) { 391178825Sdfr free_DomainParameters(&dp); 392178825Sdfr return ret; 393178825Sdfr } 394178825Sdfr dp.j = NULL; 395178825Sdfr dp.validationParms = NULL; 396178825Sdfr 397178825Sdfr a->clientPublicValue->algorithm.parameters = 398178825Sdfr malloc(sizeof(*a->clientPublicValue->algorithm.parameters)); 399178825Sdfr if (a->clientPublicValue->algorithm.parameters == NULL) { 400178825Sdfr free_DomainParameters(&dp); 401178825Sdfr return ret; 402178825Sdfr } 403178825Sdfr 404178825Sdfr ASN1_MALLOC_ENCODE(DomainParameters, 405178825Sdfr a->clientPublicValue->algorithm.parameters->data, 406178825Sdfr a->clientPublicValue->algorithm.parameters->length, 407178825Sdfr &dp, &size, ret); 408178825Sdfr free_DomainParameters(&dp); 409178825Sdfr if (ret) 410178825Sdfr return ret; 411178825Sdfr if (size != a->clientPublicValue->algorithm.parameters->length) 412178825Sdfr krb5_abortx(context, "Internal ASN1 encoder error"); 413178825Sdfr 414178825Sdfr ret = BN_to_integer(context, dh->pub_key, &dh_pub_key); 415178825Sdfr if (ret) 416178825Sdfr return ret; 417178825Sdfr 418178825Sdfr ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length, 419178825Sdfr &dh_pub_key, &size, ret); 420178825Sdfr der_free_heim_integer(&dh_pub_key); 421178825Sdfr if (ret) 422178825Sdfr return ret; 423178825Sdfr if (size != dhbuf.length) 424178825Sdfr krb5_abortx(context, "asn1 internal error"); 425178825Sdfr 426178825Sdfr a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8; 427178825Sdfr a->clientPublicValue->subjectPublicKey.data = dhbuf.data; 428178825Sdfr } 429178825Sdfr 430178825Sdfr { 431178825Sdfr a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes)); 432178825Sdfr if (a->supportedCMSTypes == NULL) 433178825Sdfr return ENOMEM; 434178825Sdfr 435178825Sdfr ret = hx509_crypto_available(ctx->id->hx509ctx, HX509_SELECT_ALL, NULL, 436178825Sdfr &a->supportedCMSTypes->val, 437178825Sdfr &a->supportedCMSTypes->len); 438178825Sdfr if (ret) 439178825Sdfr return ret; 440178825Sdfr } 441178825Sdfr 442178825Sdfr return ret; 443178825Sdfr} 444178825Sdfr 445178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 446178825Sdfr_krb5_pk_mk_ContentInfo(krb5_context context, 447178825Sdfr const krb5_data *buf, 448178825Sdfr const heim_oid *oid, 449178825Sdfr struct ContentInfo *content_info) 450178825Sdfr{ 451178825Sdfr krb5_error_code ret; 452178825Sdfr 453178825Sdfr ret = der_copy_oid(oid, &content_info->contentType); 454178825Sdfr if (ret) 455178825Sdfr return ret; 456178825Sdfr ALLOC(content_info->content, 1); 457178825Sdfr if (content_info->content == NULL) 458178825Sdfr return ENOMEM; 459178825Sdfr content_info->content->data = malloc(buf->length); 460178825Sdfr if (content_info->content->data == NULL) 461178825Sdfr return ENOMEM; 462178825Sdfr memcpy(content_info->content->data, buf->data, buf->length); 463178825Sdfr content_info->content->length = buf->length; 464178825Sdfr return 0; 465178825Sdfr} 466178825Sdfr 467178825Sdfrstatic krb5_error_code 468178825Sdfrpk_mk_padata(krb5_context context, 469178825Sdfr krb5_pk_init_ctx ctx, 470178825Sdfr const KDC_REQ_BODY *req_body, 471178825Sdfr unsigned nonce, 472178825Sdfr METHOD_DATA *md) 473178825Sdfr{ 474178825Sdfr struct ContentInfo content_info; 475178825Sdfr krb5_error_code ret; 476178825Sdfr const heim_oid *oid; 477178825Sdfr size_t size; 478178825Sdfr krb5_data buf, sd_buf; 479178825Sdfr int pa_type; 480178825Sdfr 481178825Sdfr krb5_data_zero(&buf); 482178825Sdfr krb5_data_zero(&sd_buf); 483178825Sdfr memset(&content_info, 0, sizeof(content_info)); 484178825Sdfr 485178825Sdfr if (ctx->type == COMPAT_WIN2K) { 486178825Sdfr AuthPack_Win2k ap; 487178825Sdfr krb5_timestamp sec; 488178825Sdfr int32_t usec; 489178825Sdfr 490178825Sdfr memset(&ap, 0, sizeof(ap)); 491178825Sdfr 492178825Sdfr /* fill in PKAuthenticator */ 493178825Sdfr ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName); 494178825Sdfr if (ret) { 495178825Sdfr free_AuthPack_Win2k(&ap); 496178825Sdfr krb5_clear_error_string(context); 497178825Sdfr goto out; 498178825Sdfr } 499178825Sdfr ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm); 500178825Sdfr if (ret) { 501178825Sdfr free_AuthPack_Win2k(&ap); 502178825Sdfr krb5_clear_error_string(context); 503178825Sdfr goto out; 504178825Sdfr } 505178825Sdfr 506178825Sdfr krb5_us_timeofday(context, &sec, &usec); 507178825Sdfr ap.pkAuthenticator.ctime = sec; 508178825Sdfr ap.pkAuthenticator.cusec = usec; 509178825Sdfr ap.pkAuthenticator.nonce = nonce; 510178825Sdfr 511178825Sdfr ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length, 512178825Sdfr &ap, &size, ret); 513178825Sdfr free_AuthPack_Win2k(&ap); 514178825Sdfr if (ret) { 515178825Sdfr krb5_set_error_string(context, "AuthPack_Win2k: %d", ret); 516178825Sdfr goto out; 517178825Sdfr } 518178825Sdfr if (buf.length != size) 519178825Sdfr krb5_abortx(context, "internal ASN1 encoder error"); 520178825Sdfr 521178825Sdfr oid = oid_id_pkcs7_data(); 522178825Sdfr } else if (ctx->type == COMPAT_IETF) { 523178825Sdfr AuthPack ap; 524178825Sdfr 525178825Sdfr memset(&ap, 0, sizeof(ap)); 526178825Sdfr 527178825Sdfr ret = build_auth_pack(context, nonce, ctx, ctx->dh, req_body, &ap); 528178825Sdfr if (ret) { 529178825Sdfr free_AuthPack(&ap); 530178825Sdfr goto out; 531178825Sdfr } 532178825Sdfr 533178825Sdfr ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret); 534178825Sdfr free_AuthPack(&ap); 535178825Sdfr if (ret) { 536178825Sdfr krb5_set_error_string(context, "AuthPack: %d", ret); 537178825Sdfr goto out; 538178825Sdfr } 539178825Sdfr if (buf.length != size) 540178825Sdfr krb5_abortx(context, "internal ASN1 encoder error"); 541178825Sdfr 542178825Sdfr oid = oid_id_pkauthdata(); 543178825Sdfr } else 544178825Sdfr krb5_abortx(context, "internal pkinit error"); 545178825Sdfr 546178825Sdfr ret = _krb5_pk_create_sign(context, 547178825Sdfr oid, 548178825Sdfr &buf, 549178825Sdfr ctx->id, 550178825Sdfr ctx->peer, 551178825Sdfr &sd_buf); 552178825Sdfr krb5_data_free(&buf); 553178825Sdfr if (ret) 554178825Sdfr goto out; 555178825Sdfr 556178825Sdfr ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), &sd_buf, &buf); 557178825Sdfr krb5_data_free(&sd_buf); 558178825Sdfr if (ret) { 559178825Sdfr krb5_set_error_string(context, 560178825Sdfr "ContentInfo wrapping of signedData failed"); 561178825Sdfr goto out; 562178825Sdfr } 563178825Sdfr 564178825Sdfr if (ctx->type == COMPAT_WIN2K) { 565178825Sdfr PA_PK_AS_REQ_Win2k winreq; 566178825Sdfr 567178825Sdfr pa_type = KRB5_PADATA_PK_AS_REQ_WIN; 568178825Sdfr 569178825Sdfr memset(&winreq, 0, sizeof(winreq)); 570178825Sdfr 571178825Sdfr winreq.signed_auth_pack = buf; 572178825Sdfr 573178825Sdfr ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length, 574178825Sdfr &winreq, &size, ret); 575178825Sdfr free_PA_PK_AS_REQ_Win2k(&winreq); 576178825Sdfr 577178825Sdfr } else if (ctx->type == COMPAT_IETF) { 578178825Sdfr PA_PK_AS_REQ req; 579178825Sdfr 580178825Sdfr pa_type = KRB5_PADATA_PK_AS_REQ; 581178825Sdfr 582178825Sdfr memset(&req, 0, sizeof(req)); 583178825Sdfr req.signedAuthPack = buf; 584178825Sdfr 585178825Sdfr if (ctx->trustedCertifiers) { 586178825Sdfr 587178825Sdfr req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers)); 588178825Sdfr if (req.trustedCertifiers == NULL) { 589178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 590178825Sdfr free_PA_PK_AS_REQ(&req); 591178825Sdfr goto out; 592178825Sdfr } 593178825Sdfr ret = build_edi(context, ctx->id->hx509ctx, 594178825Sdfr ctx->id->anchors, req.trustedCertifiers); 595178825Sdfr if (ret) { 596178825Sdfr krb5_set_error_string(context, "pk-init: failed to build trustedCertifiers"); 597178825Sdfr free_PA_PK_AS_REQ(&req); 598178825Sdfr goto out; 599178825Sdfr } 600178825Sdfr } 601178825Sdfr req.kdcPkId = NULL; 602178825Sdfr 603178825Sdfr ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length, 604178825Sdfr &req, &size, ret); 605178825Sdfr 606178825Sdfr free_PA_PK_AS_REQ(&req); 607178825Sdfr 608178825Sdfr } else 609178825Sdfr krb5_abortx(context, "internal pkinit error"); 610178825Sdfr if (ret) { 611178825Sdfr krb5_set_error_string(context, "PA-PK-AS-REQ %d", ret); 612178825Sdfr goto out; 613178825Sdfr } 614178825Sdfr if (buf.length != size) 615178825Sdfr krb5_abortx(context, "Internal ASN1 encoder error"); 616178825Sdfr 617178825Sdfr ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length); 618178825Sdfr if (ret) 619178825Sdfr free(buf.data); 620178825Sdfr 621178825Sdfr if (ret == 0 && ctx->type == COMPAT_WIN2K) 622178825Sdfr krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0); 623178825Sdfr 624178825Sdfrout: 625178825Sdfr free_ContentInfo(&content_info); 626178825Sdfr 627178825Sdfr return ret; 628178825Sdfr} 629178825Sdfr 630178825Sdfr 631178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 632178825Sdfr_krb5_pk_mk_padata(krb5_context context, 633178825Sdfr void *c, 634178825Sdfr const KDC_REQ_BODY *req_body, 635178825Sdfr unsigned nonce, 636178825Sdfr METHOD_DATA *md) 637178825Sdfr{ 638178825Sdfr krb5_pk_init_ctx ctx = c; 639178825Sdfr int win2k_compat; 640178825Sdfr 641178825Sdfr win2k_compat = krb5_config_get_bool_default(context, NULL, 642178825Sdfr FALSE, 643178825Sdfr "realms", 644178825Sdfr req_body->realm, 645178825Sdfr "pkinit_win2k", 646178825Sdfr NULL); 647178825Sdfr 648178825Sdfr if (win2k_compat) { 649178825Sdfr ctx->require_binding = 650178825Sdfr krb5_config_get_bool_default(context, NULL, 651178825Sdfr FALSE, 652178825Sdfr "realms", 653178825Sdfr req_body->realm, 654178825Sdfr "pkinit_win2k_require_binding", 655178825Sdfr NULL); 656178825Sdfr ctx->type = COMPAT_WIN2K; 657178825Sdfr } else 658178825Sdfr ctx->type = COMPAT_IETF; 659178825Sdfr 660178825Sdfr ctx->require_eku = 661178825Sdfr krb5_config_get_bool_default(context, NULL, 662178825Sdfr TRUE, 663178825Sdfr "realms", 664178825Sdfr req_body->realm, 665178825Sdfr "pkinit_require_eku", 666178825Sdfr NULL); 667178825Sdfr ctx->require_krbtgt_otherName = 668178825Sdfr krb5_config_get_bool_default(context, NULL, 669178825Sdfr TRUE, 670178825Sdfr "realms", 671178825Sdfr req_body->realm, 672178825Sdfr "pkinit_require_krbtgt_otherName", 673178825Sdfr NULL); 674178825Sdfr 675178825Sdfr ctx->require_hostname_match = 676178825Sdfr krb5_config_get_bool_default(context, NULL, 677178825Sdfr FALSE, 678178825Sdfr "realms", 679178825Sdfr req_body->realm, 680178825Sdfr "pkinit_require_hostname_match", 681178825Sdfr NULL); 682178825Sdfr 683178825Sdfr ctx->trustedCertifiers = 684178825Sdfr krb5_config_get_bool_default(context, NULL, 685178825Sdfr TRUE, 686178825Sdfr "realms", 687178825Sdfr req_body->realm, 688178825Sdfr "pkinit_trustedCertifiers", 689178825Sdfr NULL); 690178825Sdfr 691178825Sdfr return pk_mk_padata(context, ctx, req_body, nonce, md); 692178825Sdfr} 693178825Sdfr 694178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 695178825Sdfr_krb5_pk_verify_sign(krb5_context context, 696178825Sdfr const void *data, 697178825Sdfr size_t length, 698178825Sdfr struct krb5_pk_identity *id, 699178825Sdfr heim_oid *contentType, 700178825Sdfr krb5_data *content, 701178825Sdfr struct krb5_pk_cert **signer) 702178825Sdfr{ 703178825Sdfr hx509_certs signer_certs; 704178825Sdfr int ret; 705178825Sdfr 706178825Sdfr *signer = NULL; 707178825Sdfr 708178825Sdfr ret = hx509_cms_verify_signed(id->hx509ctx, 709178825Sdfr id->verify_ctx, 710178825Sdfr data, 711178825Sdfr length, 712178825Sdfr NULL, 713178825Sdfr id->certpool, 714178825Sdfr contentType, 715178825Sdfr content, 716178825Sdfr &signer_certs); 717178825Sdfr if (ret) { 718178825Sdfr _krb5_pk_copy_error(context, id->hx509ctx, ret, 719178825Sdfr "CMS verify signed failed"); 720178825Sdfr return ret; 721178825Sdfr } 722178825Sdfr 723178825Sdfr *signer = calloc(1, sizeof(**signer)); 724178825Sdfr if (*signer == NULL) { 725178825Sdfr krb5_clear_error_string(context); 726178825Sdfr ret = ENOMEM; 727178825Sdfr goto out; 728178825Sdfr } 729178825Sdfr 730178825Sdfr ret = hx509_get_one_cert(id->hx509ctx, signer_certs, &(*signer)->cert); 731178825Sdfr if (ret) { 732178825Sdfr _krb5_pk_copy_error(context, id->hx509ctx, ret, 733178825Sdfr "Failed to get on of the signer certs"); 734178825Sdfr goto out; 735178825Sdfr } 736178825Sdfr 737178825Sdfrout: 738178825Sdfr hx509_certs_free(&signer_certs); 739178825Sdfr if (ret) { 740178825Sdfr if (*signer) { 741178825Sdfr hx509_cert_free((*signer)->cert); 742178825Sdfr free(*signer); 743178825Sdfr *signer = NULL; 744178825Sdfr } 745178825Sdfr } 746178825Sdfr 747178825Sdfr return ret; 748178825Sdfr} 749178825Sdfr 750178825Sdfrstatic krb5_error_code 751178825Sdfrget_reply_key_win(krb5_context context, 752178825Sdfr const krb5_data *content, 753178825Sdfr unsigned nonce, 754178825Sdfr krb5_keyblock **key) 755178825Sdfr{ 756178825Sdfr ReplyKeyPack_Win2k key_pack; 757178825Sdfr krb5_error_code ret; 758178825Sdfr size_t size; 759178825Sdfr 760178825Sdfr ret = decode_ReplyKeyPack_Win2k(content->data, 761178825Sdfr content->length, 762178825Sdfr &key_pack, 763178825Sdfr &size); 764178825Sdfr if (ret) { 765178825Sdfr krb5_set_error_string(context, "PKINIT decoding reply key failed"); 766178825Sdfr free_ReplyKeyPack_Win2k(&key_pack); 767178825Sdfr return ret; 768178825Sdfr } 769178825Sdfr 770178825Sdfr if (key_pack.nonce != nonce) { 771178825Sdfr krb5_set_error_string(context, "PKINIT enckey nonce is wrong"); 772178825Sdfr free_ReplyKeyPack_Win2k(&key_pack); 773178825Sdfr return KRB5KRB_AP_ERR_MODIFIED; 774178825Sdfr } 775178825Sdfr 776178825Sdfr *key = malloc (sizeof (**key)); 777178825Sdfr if (*key == NULL) { 778178825Sdfr krb5_set_error_string(context, "PKINIT failed allocating reply key"); 779178825Sdfr free_ReplyKeyPack_Win2k(&key_pack); 780178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 781178825Sdfr return ENOMEM; 782178825Sdfr } 783178825Sdfr 784178825Sdfr ret = copy_EncryptionKey(&key_pack.replyKey, *key); 785178825Sdfr free_ReplyKeyPack_Win2k(&key_pack); 786178825Sdfr if (ret) { 787178825Sdfr krb5_set_error_string(context, "PKINIT failed copying reply key"); 788178825Sdfr free(*key); 789178825Sdfr *key = NULL; 790178825Sdfr } 791178825Sdfr 792178825Sdfr return ret; 793178825Sdfr} 794178825Sdfr 795178825Sdfrstatic krb5_error_code 796178825Sdfrget_reply_key(krb5_context context, 797178825Sdfr const krb5_data *content, 798178825Sdfr const krb5_data *req_buffer, 799178825Sdfr krb5_keyblock **key) 800178825Sdfr{ 801178825Sdfr ReplyKeyPack key_pack; 802178825Sdfr krb5_error_code ret; 803178825Sdfr size_t size; 804178825Sdfr 805178825Sdfr ret = decode_ReplyKeyPack(content->data, 806178825Sdfr content->length, 807178825Sdfr &key_pack, 808178825Sdfr &size); 809178825Sdfr if (ret) { 810178825Sdfr krb5_set_error_string(context, "PKINIT decoding reply key failed"); 811178825Sdfr free_ReplyKeyPack(&key_pack); 812178825Sdfr return ret; 813178825Sdfr } 814178825Sdfr 815178825Sdfr { 816178825Sdfr krb5_crypto crypto; 817178825Sdfr 818178825Sdfr /* 819178825Sdfr * XXX Verify kp.replyKey is a allowed enctype in the 820178825Sdfr * configuration file 821178825Sdfr */ 822178825Sdfr 823178825Sdfr ret = krb5_crypto_init(context, &key_pack.replyKey, 0, &crypto); 824178825Sdfr if (ret) { 825178825Sdfr free_ReplyKeyPack(&key_pack); 826178825Sdfr return ret; 827178825Sdfr } 828178825Sdfr 829178825Sdfr ret = krb5_verify_checksum(context, crypto, 6, 830178825Sdfr req_buffer->data, req_buffer->length, 831178825Sdfr &key_pack.asChecksum); 832178825Sdfr krb5_crypto_destroy(context, crypto); 833178825Sdfr if (ret) { 834178825Sdfr free_ReplyKeyPack(&key_pack); 835178825Sdfr return ret; 836178825Sdfr } 837178825Sdfr } 838178825Sdfr 839178825Sdfr *key = malloc (sizeof (**key)); 840178825Sdfr if (*key == NULL) { 841178825Sdfr krb5_set_error_string(context, "PKINIT failed allocating reply key"); 842178825Sdfr free_ReplyKeyPack(&key_pack); 843178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 844178825Sdfr return ENOMEM; 845178825Sdfr } 846178825Sdfr 847178825Sdfr ret = copy_EncryptionKey(&key_pack.replyKey, *key); 848178825Sdfr free_ReplyKeyPack(&key_pack); 849178825Sdfr if (ret) { 850178825Sdfr krb5_set_error_string(context, "PKINIT failed copying reply key"); 851178825Sdfr free(*key); 852178825Sdfr *key = NULL; 853178825Sdfr } 854178825Sdfr 855178825Sdfr return ret; 856178825Sdfr} 857178825Sdfr 858178825Sdfr 859178825Sdfrstatic krb5_error_code 860178825Sdfrpk_verify_host(krb5_context context, 861178825Sdfr const char *realm, 862178825Sdfr const krb5_krbhst_info *hi, 863178825Sdfr struct krb5_pk_init_ctx_data *ctx, 864178825Sdfr struct krb5_pk_cert *host) 865178825Sdfr{ 866178825Sdfr krb5_error_code ret = 0; 867178825Sdfr 868178825Sdfr if (ctx->require_eku) { 869178825Sdfr ret = hx509_cert_check_eku(ctx->id->hx509ctx, host->cert, 870178825Sdfr oid_id_pkkdcekuoid(), 0); 871178825Sdfr if (ret) { 872178825Sdfr krb5_set_error_string(context, "No PK-INIT KDC EKU in kdc certificate"); 873178825Sdfr return ret; 874178825Sdfr } 875178825Sdfr } 876178825Sdfr if (ctx->require_krbtgt_otherName) { 877178825Sdfr hx509_octet_string_list list; 878178825Sdfr int i; 879178825Sdfr 880178825Sdfr ret = hx509_cert_find_subjectAltName_otherName(ctx->id->hx509ctx, 881178825Sdfr host->cert, 882178825Sdfr oid_id_pkinit_san(), 883178825Sdfr &list); 884178825Sdfr if (ret) { 885178825Sdfr krb5_set_error_string(context, "Failed to find the PK-INIT " 886178825Sdfr "subjectAltName in the KDC certificate"); 887178825Sdfr 888178825Sdfr return ret; 889178825Sdfr } 890178825Sdfr 891178825Sdfr for (i = 0; i < list.len; i++) { 892178825Sdfr KRB5PrincipalName r; 893178825Sdfr 894178825Sdfr ret = decode_KRB5PrincipalName(list.val[i].data, 895178825Sdfr list.val[i].length, 896178825Sdfr &r, 897178825Sdfr NULL); 898178825Sdfr if (ret) { 899178825Sdfr krb5_set_error_string(context, "Failed to decode the PK-INIT " 900178825Sdfr "subjectAltName in the KDC certificate"); 901178825Sdfr 902178825Sdfr break; 903178825Sdfr } 904178825Sdfr 905178825Sdfr if (r.principalName.name_string.len != 2 || 906178825Sdfr strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) != 0 || 907178825Sdfr strcmp(r.principalName.name_string.val[1], realm) != 0 || 908178825Sdfr strcmp(r.realm, realm) != 0) 909178825Sdfr { 910178825Sdfr krb5_set_error_string(context, "KDC have wrong realm name in " 911178825Sdfr "the certificate"); 912178825Sdfr ret = KRB5_KDC_ERR_INVALID_CERTIFICATE; 913178825Sdfr } 914178825Sdfr 915178825Sdfr free_KRB5PrincipalName(&r); 916178825Sdfr if (ret) 917178825Sdfr break; 918178825Sdfr } 919178825Sdfr hx509_free_octet_string_list(&list); 920178825Sdfr } 921178825Sdfr if (ret) 922178825Sdfr return ret; 923178825Sdfr 924178825Sdfr if (hi) { 925178825Sdfr ret = hx509_verify_hostname(ctx->id->hx509ctx, host->cert, 926178825Sdfr ctx->require_hostname_match, 927178825Sdfr HX509_HN_HOSTNAME, 928178825Sdfr hi->hostname, 929178825Sdfr hi->ai->ai_addr, hi->ai->ai_addrlen); 930178825Sdfr 931178825Sdfr if (ret) 932178825Sdfr krb5_set_error_string(context, "Address mismatch in " 933178825Sdfr "the KDC certificate"); 934178825Sdfr } 935178825Sdfr return ret; 936178825Sdfr} 937178825Sdfr 938178825Sdfrstatic krb5_error_code 939178825Sdfrpk_rd_pa_reply_enckey(krb5_context context, 940178825Sdfr int type, 941178825Sdfr const heim_octet_string *indata, 942178825Sdfr const heim_oid *dataType, 943178825Sdfr const char *realm, 944178825Sdfr krb5_pk_init_ctx ctx, 945178825Sdfr krb5_enctype etype, 946178825Sdfr const krb5_krbhst_info *hi, 947178825Sdfr unsigned nonce, 948178825Sdfr const krb5_data *req_buffer, 949178825Sdfr PA_DATA *pa, 950178825Sdfr krb5_keyblock **key) 951178825Sdfr{ 952178825Sdfr krb5_error_code ret; 953178825Sdfr struct krb5_pk_cert *host = NULL; 954178825Sdfr krb5_data content; 955178825Sdfr heim_oid contentType = { 0, NULL }; 956178825Sdfr 957178825Sdfr if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), dataType)) { 958178825Sdfr krb5_set_error_string(context, "PKINIT: Invalid content type"); 959178825Sdfr return EINVAL; 960178825Sdfr } 961178825Sdfr 962178825Sdfr ret = hx509_cms_unenvelope(ctx->id->hx509ctx, 963178825Sdfr ctx->id->certs, 964178825Sdfr HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT, 965178825Sdfr indata->data, 966178825Sdfr indata->length, 967178825Sdfr NULL, 968178825Sdfr &contentType, 969178825Sdfr &content); 970178825Sdfr if (ret) { 971178825Sdfr _krb5_pk_copy_error(context, ctx->id->hx509ctx, ret, 972178825Sdfr "Failed to unenvelope CMS data in PK-INIT reply"); 973178825Sdfr return ret; 974178825Sdfr } 975178825Sdfr der_free_oid(&contentType); 976178825Sdfr 977178825Sdfr#if 0 /* windows LH with interesting CMS packets, leaks memory */ 978178825Sdfr { 979178825Sdfr size_t ph = 1 + der_length_len (length); 980178825Sdfr unsigned char *ptr = malloc(length + ph); 981178825Sdfr size_t l; 982178825Sdfr 983178825Sdfr memcpy(ptr + ph, p, length); 984178825Sdfr 985178825Sdfr ret = der_put_length_and_tag (ptr + ph - 1, ph, length, 986178825Sdfr ASN1_C_UNIV, CONS, UT_Sequence, &l); 987178825Sdfr if (ret) 988178825Sdfr return ret; 989178825Sdfr ptr += ph - l; 990178825Sdfr length += l; 991178825Sdfr p = ptr; 992178825Sdfr } 993178825Sdfr#endif 994178825Sdfr 995178825Sdfr /* win2k uses ContentInfo */ 996178825Sdfr if (type == COMPAT_WIN2K) { 997178825Sdfr heim_oid type; 998178825Sdfr heim_octet_string out; 999178825Sdfr 1000178825Sdfr ret = hx509_cms_unwrap_ContentInfo(&content, &type, &out, NULL); 1001178825Sdfr if (der_heim_oid_cmp(&type, oid_id_pkcs7_signedData())) { 1002178825Sdfr ret = EINVAL; /* XXX */ 1003178825Sdfr krb5_set_error_string(context, "PKINIT: Invalid content type"); 1004178825Sdfr der_free_oid(&type); 1005178825Sdfr der_free_octet_string(&out); 1006178825Sdfr goto out; 1007178825Sdfr } 1008178825Sdfr der_free_oid(&type); 1009178825Sdfr krb5_data_free(&content); 1010178825Sdfr ret = krb5_data_copy(&content, out.data, out.length); 1011178825Sdfr der_free_octet_string(&out); 1012178825Sdfr if (ret) { 1013178825Sdfr krb5_set_error_string(context, "PKINIT: out of memory"); 1014178825Sdfr goto out; 1015178825Sdfr } 1016178825Sdfr } 1017178825Sdfr 1018178825Sdfr ret = _krb5_pk_verify_sign(context, 1019178825Sdfr content.data, 1020178825Sdfr content.length, 1021178825Sdfr ctx->id, 1022178825Sdfr &contentType, 1023178825Sdfr &content, 1024178825Sdfr &host); 1025178825Sdfr if (ret) 1026178825Sdfr goto out; 1027178825Sdfr 1028178825Sdfr /* make sure that it is the kdc's certificate */ 1029178825Sdfr ret = pk_verify_host(context, realm, hi, ctx, host); 1030178825Sdfr if (ret) { 1031178825Sdfr goto out; 1032178825Sdfr } 1033178825Sdfr 1034178825Sdfr#if 0 1035178825Sdfr if (type == COMPAT_WIN2K) { 1036178825Sdfr if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) != 0) { 1037178825Sdfr krb5_set_error_string(context, "PKINIT: reply key, wrong oid"); 1038178825Sdfr ret = KRB5KRB_AP_ERR_MSG_TYPE; 1039178825Sdfr goto out; 1040178825Sdfr } 1041178825Sdfr } else { 1042178825Sdfr if (der_heim_oid_cmp(&contentType, oid_id_pkrkeydata()) != 0) { 1043178825Sdfr krb5_set_error_string(context, "PKINIT: reply key, wrong oid"); 1044178825Sdfr ret = KRB5KRB_AP_ERR_MSG_TYPE; 1045178825Sdfr goto out; 1046178825Sdfr } 1047178825Sdfr } 1048178825Sdfr#endif 1049178825Sdfr 1050178825Sdfr switch(type) { 1051178825Sdfr case COMPAT_WIN2K: 1052178825Sdfr ret = get_reply_key(context, &content, req_buffer, key); 1053178825Sdfr if (ret != 0 && ctx->require_binding == 0) 1054178825Sdfr ret = get_reply_key_win(context, &content, nonce, key); 1055178825Sdfr break; 1056178825Sdfr case COMPAT_IETF: 1057178825Sdfr ret = get_reply_key(context, &content, req_buffer, key); 1058178825Sdfr break; 1059178825Sdfr } 1060178825Sdfr if (ret) 1061178825Sdfr goto out; 1062178825Sdfr 1063178825Sdfr /* XXX compare given etype with key->etype */ 1064178825Sdfr 1065178825Sdfr out: 1066178825Sdfr if (host) 1067178825Sdfr _krb5_pk_cert_free(host); 1068178825Sdfr der_free_oid(&contentType); 1069178825Sdfr krb5_data_free(&content); 1070178825Sdfr 1071178825Sdfr return ret; 1072178825Sdfr} 1073178825Sdfr 1074178825Sdfrstatic krb5_error_code 1075178825Sdfrpk_rd_pa_reply_dh(krb5_context context, 1076178825Sdfr const heim_octet_string *indata, 1077178825Sdfr const heim_oid *dataType, 1078178825Sdfr const char *realm, 1079178825Sdfr krb5_pk_init_ctx ctx, 1080178825Sdfr krb5_enctype etype, 1081178825Sdfr const krb5_krbhst_info *hi, 1082178825Sdfr const DHNonce *c_n, 1083178825Sdfr const DHNonce *k_n, 1084178825Sdfr unsigned nonce, 1085178825Sdfr PA_DATA *pa, 1086178825Sdfr krb5_keyblock **key) 1087178825Sdfr{ 1088178825Sdfr unsigned char *p, *dh_gen_key = NULL; 1089178825Sdfr struct krb5_pk_cert *host = NULL; 1090178825Sdfr BIGNUM *kdc_dh_pubkey = NULL; 1091178825Sdfr KDCDHKeyInfo kdc_dh_info; 1092178825Sdfr heim_oid contentType = { 0, NULL }; 1093178825Sdfr krb5_data content; 1094178825Sdfr krb5_error_code ret; 1095178825Sdfr int dh_gen_keylen; 1096178825Sdfr size_t size; 1097178825Sdfr 1098178825Sdfr krb5_data_zero(&content); 1099178825Sdfr memset(&kdc_dh_info, 0, sizeof(kdc_dh_info)); 1100178825Sdfr 1101178825Sdfr if (der_heim_oid_cmp(oid_id_pkcs7_signedData(), dataType)) { 1102178825Sdfr krb5_set_error_string(context, "PKINIT: Invalid content type"); 1103178825Sdfr return EINVAL; 1104178825Sdfr } 1105178825Sdfr 1106178825Sdfr ret = _krb5_pk_verify_sign(context, 1107178825Sdfr indata->data, 1108178825Sdfr indata->length, 1109178825Sdfr ctx->id, 1110178825Sdfr &contentType, 1111178825Sdfr &content, 1112178825Sdfr &host); 1113178825Sdfr if (ret) 1114178825Sdfr goto out; 1115178825Sdfr 1116178825Sdfr /* make sure that it is the kdc's certificate */ 1117178825Sdfr ret = pk_verify_host(context, realm, hi, ctx, host); 1118178825Sdfr if (ret) 1119178825Sdfr goto out; 1120178825Sdfr 1121178825Sdfr if (der_heim_oid_cmp(&contentType, oid_id_pkdhkeydata())) { 1122178825Sdfr krb5_set_error_string(context, "pkinit - dh reply contains wrong oid"); 1123178825Sdfr ret = KRB5KRB_AP_ERR_MSG_TYPE; 1124178825Sdfr goto out; 1125178825Sdfr } 1126178825Sdfr 1127178825Sdfr ret = decode_KDCDHKeyInfo(content.data, 1128178825Sdfr content.length, 1129178825Sdfr &kdc_dh_info, 1130178825Sdfr &size); 1131178825Sdfr 1132178825Sdfr if (ret) { 1133178825Sdfr krb5_set_error_string(context, "pkinit - " 1134178825Sdfr "failed to decode KDC DH Key Info"); 1135178825Sdfr goto out; 1136178825Sdfr } 1137178825Sdfr 1138178825Sdfr if (kdc_dh_info.nonce != nonce) { 1139178825Sdfr krb5_set_error_string(context, "PKINIT: DH nonce is wrong"); 1140178825Sdfr ret = KRB5KRB_AP_ERR_MODIFIED; 1141178825Sdfr goto out; 1142178825Sdfr } 1143178825Sdfr 1144178825Sdfr if (kdc_dh_info.dhKeyExpiration) { 1145178825Sdfr if (k_n == NULL) { 1146178825Sdfr krb5_set_error_string(context, "pkinit; got key expiration " 1147178825Sdfr "without server nonce"); 1148178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1149178825Sdfr goto out; 1150178825Sdfr } 1151178825Sdfr if (c_n == NULL) { 1152178825Sdfr krb5_set_error_string(context, "pkinit; got DH reuse but no " 1153178825Sdfr "client nonce"); 1154178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1155178825Sdfr goto out; 1156178825Sdfr } 1157178825Sdfr } else { 1158178825Sdfr if (k_n) { 1159178825Sdfr krb5_set_error_string(context, "pkinit: got server nonce " 1160178825Sdfr "without key expiration"); 1161178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1162178825Sdfr goto out; 1163178825Sdfr } 1164178825Sdfr c_n = NULL; 1165178825Sdfr } 1166178825Sdfr 1167178825Sdfr 1168178825Sdfr p = kdc_dh_info.subjectPublicKey.data; 1169178825Sdfr size = (kdc_dh_info.subjectPublicKey.length + 7) / 8; 1170178825Sdfr 1171178825Sdfr { 1172178825Sdfr DHPublicKey k; 1173178825Sdfr ret = decode_DHPublicKey(p, size, &k, NULL); 1174178825Sdfr if (ret) { 1175178825Sdfr krb5_set_error_string(context, "pkinit: can't decode " 1176178825Sdfr "without key expiration"); 1177178825Sdfr goto out; 1178178825Sdfr } 1179178825Sdfr 1180178825Sdfr kdc_dh_pubkey = integer_to_BN(context, "DHPublicKey", &k); 1181178825Sdfr free_DHPublicKey(&k); 1182178825Sdfr if (kdc_dh_pubkey == NULL) { 1183178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1184178825Sdfr goto out; 1185178825Sdfr } 1186178825Sdfr } 1187178825Sdfr 1188178825Sdfr dh_gen_keylen = DH_size(ctx->dh); 1189178825Sdfr size = BN_num_bytes(ctx->dh->p); 1190178825Sdfr if (size < dh_gen_keylen) 1191178825Sdfr size = dh_gen_keylen; 1192178825Sdfr 1193178825Sdfr dh_gen_key = malloc(size); 1194178825Sdfr if (dh_gen_key == NULL) { 1195178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 1196178825Sdfr ret = ENOMEM; 1197178825Sdfr goto out; 1198178825Sdfr } 1199178825Sdfr memset(dh_gen_key, 0, size - dh_gen_keylen); 1200178825Sdfr 1201178825Sdfr dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen), 1202178825Sdfr kdc_dh_pubkey, ctx->dh); 1203178825Sdfr if (dh_gen_keylen == -1) { 1204178825Sdfr krb5_set_error_string(context, 1205178825Sdfr "PKINIT: Can't compute Diffie-Hellman key"); 1206178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1207178825Sdfr goto out; 1208178825Sdfr } 1209178825Sdfr 1210178825Sdfr *key = malloc (sizeof (**key)); 1211178825Sdfr if (*key == NULL) { 1212178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 1213178825Sdfr ret = ENOMEM; 1214178825Sdfr goto out; 1215178825Sdfr } 1216178825Sdfr 1217178825Sdfr ret = _krb5_pk_octetstring2key(context, 1218178825Sdfr etype, 1219178825Sdfr dh_gen_key, dh_gen_keylen, 1220178825Sdfr c_n, k_n, 1221178825Sdfr *key); 1222178825Sdfr if (ret) { 1223178825Sdfr krb5_set_error_string(context, 1224178825Sdfr "PKINIT: can't create key from DH key"); 1225178825Sdfr free(*key); 1226178825Sdfr *key = NULL; 1227178825Sdfr goto out; 1228178825Sdfr } 1229178825Sdfr 1230178825Sdfr out: 1231178825Sdfr if (kdc_dh_pubkey) 1232178825Sdfr BN_free(kdc_dh_pubkey); 1233178825Sdfr if (dh_gen_key) { 1234178825Sdfr memset(dh_gen_key, 0, DH_size(ctx->dh)); 1235178825Sdfr free(dh_gen_key); 1236178825Sdfr } 1237178825Sdfr if (host) 1238178825Sdfr _krb5_pk_cert_free(host); 1239178825Sdfr if (content.data) 1240178825Sdfr krb5_data_free(&content); 1241178825Sdfr der_free_oid(&contentType); 1242178825Sdfr free_KDCDHKeyInfo(&kdc_dh_info); 1243178825Sdfr 1244178825Sdfr return ret; 1245178825Sdfr} 1246178825Sdfr 1247178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 1248178825Sdfr_krb5_pk_rd_pa_reply(krb5_context context, 1249178825Sdfr const char *realm, 1250178825Sdfr void *c, 1251178825Sdfr krb5_enctype etype, 1252178825Sdfr const krb5_krbhst_info *hi, 1253178825Sdfr unsigned nonce, 1254178825Sdfr const krb5_data *req_buffer, 1255178825Sdfr PA_DATA *pa, 1256178825Sdfr krb5_keyblock **key) 1257178825Sdfr{ 1258178825Sdfr krb5_pk_init_ctx ctx = c; 1259178825Sdfr krb5_error_code ret; 1260178825Sdfr size_t size; 1261178825Sdfr 1262178825Sdfr /* Check for IETF PK-INIT first */ 1263178825Sdfr if (ctx->type == COMPAT_IETF) { 1264178825Sdfr PA_PK_AS_REP rep; 1265178825Sdfr heim_octet_string os, data; 1266178825Sdfr heim_oid oid; 1267178825Sdfr 1268178825Sdfr if (pa->padata_type != KRB5_PADATA_PK_AS_REP) { 1269178825Sdfr krb5_set_error_string(context, "PKINIT: wrong padata recv"); 1270178825Sdfr return EINVAL; 1271178825Sdfr } 1272178825Sdfr 1273178825Sdfr ret = decode_PA_PK_AS_REP(pa->padata_value.data, 1274178825Sdfr pa->padata_value.length, 1275178825Sdfr &rep, 1276178825Sdfr &size); 1277178825Sdfr if (ret) { 1278178825Sdfr krb5_set_error_string(context, "Failed to decode pkinit AS rep"); 1279178825Sdfr return ret; 1280178825Sdfr } 1281178825Sdfr 1282178825Sdfr switch (rep.element) { 1283178825Sdfr case choice_PA_PK_AS_REP_dhInfo: 1284178825Sdfr os = rep.u.dhInfo.dhSignedData; 1285178825Sdfr break; 1286178825Sdfr case choice_PA_PK_AS_REP_encKeyPack: 1287178825Sdfr os = rep.u.encKeyPack; 1288178825Sdfr break; 1289178825Sdfr default: 1290178825Sdfr free_PA_PK_AS_REP(&rep); 1291178825Sdfr krb5_set_error_string(context, "PKINIT: -27 reply " 1292178825Sdfr "invalid content type"); 1293178825Sdfr return EINVAL; 1294178825Sdfr } 1295178825Sdfr 1296178825Sdfr ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL); 1297178825Sdfr if (ret) { 1298178825Sdfr free_PA_PK_AS_REP(&rep); 1299178825Sdfr krb5_set_error_string(context, "PKINIT: failed to unwrap CI"); 1300178825Sdfr return ret; 1301178825Sdfr } 1302178825Sdfr 1303178825Sdfr switch (rep.element) { 1304178825Sdfr case choice_PA_PK_AS_REP_dhInfo: 1305178825Sdfr ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi, 1306178825Sdfr ctx->clientDHNonce, 1307178825Sdfr rep.u.dhInfo.serverDHNonce, 1308178825Sdfr nonce, pa, key); 1309178825Sdfr break; 1310178825Sdfr case choice_PA_PK_AS_REP_encKeyPack: 1311178825Sdfr ret = pk_rd_pa_reply_enckey(context, COMPAT_IETF, &data, &oid, realm, 1312178825Sdfr ctx, etype, hi, nonce, req_buffer, pa, key); 1313178825Sdfr break; 1314178825Sdfr default: 1315178825Sdfr krb5_abortx(context, "pk-init as-rep case not possible to happen"); 1316178825Sdfr } 1317178825Sdfr der_free_octet_string(&data); 1318178825Sdfr der_free_oid(&oid); 1319178825Sdfr free_PA_PK_AS_REP(&rep); 1320178825Sdfr 1321178825Sdfr } else if (ctx->type == COMPAT_WIN2K) { 1322178825Sdfr PA_PK_AS_REP_Win2k w2krep; 1323178825Sdfr 1324178825Sdfr /* Check for Windows encoding of the AS-REP pa data */ 1325178825Sdfr 1326178825Sdfr#if 0 /* should this be ? */ 1327178825Sdfr if (pa->padata_type != KRB5_PADATA_PK_AS_REP) { 1328178825Sdfr krb5_set_error_string(context, "PKINIT: wrong padata recv"); 1329178825Sdfr return EINVAL; 1330178825Sdfr } 1331178825Sdfr#endif 1332178825Sdfr 1333178825Sdfr memset(&w2krep, 0, sizeof(w2krep)); 1334178825Sdfr 1335178825Sdfr ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data, 1336178825Sdfr pa->padata_value.length, 1337178825Sdfr &w2krep, 1338178825Sdfr &size); 1339178825Sdfr if (ret) { 1340178825Sdfr krb5_set_error_string(context, "PKINIT: Failed decoding windows " 1341178825Sdfr "pkinit reply %d", ret); 1342178825Sdfr return ret; 1343178825Sdfr } 1344178825Sdfr 1345178825Sdfr krb5_clear_error_string(context); 1346178825Sdfr 1347178825Sdfr switch (w2krep.element) { 1348178825Sdfr case choice_PA_PK_AS_REP_Win2k_encKeyPack: { 1349178825Sdfr heim_octet_string data; 1350178825Sdfr heim_oid oid; 1351178825Sdfr 1352178825Sdfr ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack, 1353178825Sdfr &oid, &data, NULL); 1354178825Sdfr free_PA_PK_AS_REP_Win2k(&w2krep); 1355178825Sdfr if (ret) { 1356178825Sdfr krb5_set_error_string(context, "PKINIT: failed to unwrap CI"); 1357178825Sdfr return ret; 1358178825Sdfr } 1359178825Sdfr 1360178825Sdfr ret = pk_rd_pa_reply_enckey(context, COMPAT_WIN2K, &data, &oid, realm, 1361178825Sdfr ctx, etype, hi, nonce, req_buffer, pa, key); 1362178825Sdfr der_free_octet_string(&data); 1363178825Sdfr der_free_oid(&oid); 1364178825Sdfr 1365178825Sdfr break; 1366178825Sdfr } 1367178825Sdfr default: 1368178825Sdfr free_PA_PK_AS_REP_Win2k(&w2krep); 1369178825Sdfr krb5_set_error_string(context, "PKINIT: win2k reply invalid " 1370178825Sdfr "content type"); 1371178825Sdfr ret = EINVAL; 1372178825Sdfr break; 1373178825Sdfr } 1374178825Sdfr 1375178825Sdfr } else { 1376178825Sdfr krb5_set_error_string(context, "PKINIT: unknown reply type"); 1377178825Sdfr ret = EINVAL; 1378178825Sdfr } 1379178825Sdfr 1380178825Sdfr return ret; 1381178825Sdfr} 1382178825Sdfr 1383178825Sdfrstruct prompter { 1384178825Sdfr krb5_context context; 1385178825Sdfr krb5_prompter_fct prompter; 1386178825Sdfr void *prompter_data; 1387178825Sdfr}; 1388178825Sdfr 1389178825Sdfrstatic int 1390178825Sdfrhx_pass_prompter(void *data, const hx509_prompt *prompter) 1391178825Sdfr{ 1392178825Sdfr krb5_error_code ret; 1393178825Sdfr krb5_prompt prompt; 1394178825Sdfr krb5_data password_data; 1395178825Sdfr struct prompter *p = data; 1396178825Sdfr 1397178825Sdfr password_data.data = prompter->reply.data; 1398178825Sdfr password_data.length = prompter->reply.length; 1399178825Sdfr 1400178825Sdfr prompt.prompt = prompter->prompt; 1401178825Sdfr prompt.hidden = hx509_prompt_hidden(prompter->type); 1402178825Sdfr prompt.reply = &password_data; 1403178825Sdfr 1404178825Sdfr switch (prompter->type) { 1405178825Sdfr case HX509_PROMPT_TYPE_INFO: 1406178825Sdfr prompt.type = KRB5_PROMPT_TYPE_INFO; 1407178825Sdfr break; 1408178825Sdfr case HX509_PROMPT_TYPE_PASSWORD: 1409178825Sdfr case HX509_PROMPT_TYPE_QUESTION: 1410178825Sdfr default: 1411178825Sdfr prompt.type = KRB5_PROMPT_TYPE_PASSWORD; 1412178825Sdfr break; 1413178825Sdfr } 1414178825Sdfr 1415178825Sdfr ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt); 1416178825Sdfr if (ret) { 1417178825Sdfr memset (prompter->reply.data, 0, prompter->reply.length); 1418178825Sdfr return 1; 1419178825Sdfr } 1420178825Sdfr return 0; 1421178825Sdfr} 1422178825Sdfr 1423178825Sdfr 1424178825Sdfrvoid KRB5_LIB_FUNCTION 1425178825Sdfr_krb5_pk_allow_proxy_certificate(struct krb5_pk_identity *id, 1426178825Sdfr int boolean) 1427178825Sdfr{ 1428178825Sdfr hx509_verify_set_proxy_certificate(id->verify_ctx, boolean); 1429178825Sdfr} 1430178825Sdfr 1431178825Sdfr 1432178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 1433178825Sdfr_krb5_pk_load_id(krb5_context context, 1434178825Sdfr struct krb5_pk_identity **ret_id, 1435178825Sdfr const char *user_id, 1436178825Sdfr const char *anchor_id, 1437178825Sdfr char * const *chain_list, 1438178825Sdfr char * const *revoke_list, 1439178825Sdfr krb5_prompter_fct prompter, 1440178825Sdfr void *prompter_data, 1441178825Sdfr char *password) 1442178825Sdfr{ 1443178825Sdfr struct krb5_pk_identity *id = NULL; 1444178825Sdfr hx509_lock lock = NULL; 1445178825Sdfr struct prompter p; 1446178825Sdfr int ret; 1447178825Sdfr 1448178825Sdfr *ret_id = NULL; 1449178825Sdfr 1450178825Sdfr if (anchor_id == NULL) { 1451178825Sdfr krb5_set_error_string(context, "PKINIT: No anchor given"); 1452178825Sdfr return HEIM_PKINIT_NO_VALID_CA; 1453178825Sdfr } 1454178825Sdfr 1455178825Sdfr if (user_id == NULL) { 1456178825Sdfr krb5_set_error_string(context, 1457178825Sdfr "PKINIT: No user certificate given"); 1458178825Sdfr return HEIM_PKINIT_NO_PRIVATE_KEY; 1459178825Sdfr } 1460178825Sdfr 1461178825Sdfr /* load cert */ 1462178825Sdfr 1463178825Sdfr id = calloc(1, sizeof(*id)); 1464178825Sdfr if (id == NULL) { 1465178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 1466178825Sdfr return ENOMEM; 1467178825Sdfr } 1468178825Sdfr 1469178825Sdfr ret = hx509_context_init(&id->hx509ctx); 1470178825Sdfr if (ret) 1471178825Sdfr goto out; 1472178825Sdfr 1473178825Sdfr ret = hx509_lock_init(id->hx509ctx, &lock); 1474178825Sdfr if (password && password[0]) 1475178825Sdfr hx509_lock_add_password(lock, password); 1476178825Sdfr 1477178825Sdfr if (prompter) { 1478178825Sdfr p.context = context; 1479178825Sdfr p.prompter = prompter; 1480178825Sdfr p.prompter_data = prompter_data; 1481178825Sdfr 1482178825Sdfr ret = hx509_lock_set_prompter(lock, hx_pass_prompter, &p); 1483178825Sdfr if (ret) 1484178825Sdfr goto out; 1485178825Sdfr } 1486178825Sdfr 1487178825Sdfr ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs); 1488178825Sdfr if (ret) { 1489178825Sdfr _krb5_pk_copy_error(context, id->hx509ctx, ret, 1490178825Sdfr "Failed to init cert certs"); 1491178825Sdfr goto out; 1492178825Sdfr } 1493178825Sdfr 1494178825Sdfr ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors); 1495178825Sdfr if (ret) { 1496178825Sdfr _krb5_pk_copy_error(context, id->hx509ctx, ret, 1497178825Sdfr "Failed to init anchors"); 1498178825Sdfr goto out; 1499178825Sdfr } 1500178825Sdfr 1501178825Sdfr ret = hx509_certs_init(id->hx509ctx, "MEMORY:pkinit-cert-chain", 1502178825Sdfr 0, NULL, &id->certpool); 1503178825Sdfr if (ret) { 1504178825Sdfr _krb5_pk_copy_error(context, id->hx509ctx, ret, 1505178825Sdfr "Failed to init chain"); 1506178825Sdfr goto out; 1507178825Sdfr } 1508178825Sdfr 1509178825Sdfr while (chain_list && *chain_list) { 1510178825Sdfr ret = hx509_certs_append(id->hx509ctx, id->certpool, 1511178825Sdfr NULL, *chain_list); 1512178825Sdfr if (ret) { 1513178825Sdfr _krb5_pk_copy_error(context, id->hx509ctx, ret, 1514178825Sdfr "Failed to laod chain %s", 1515178825Sdfr *chain_list); 1516178825Sdfr goto out; 1517178825Sdfr } 1518178825Sdfr chain_list++; 1519178825Sdfr } 1520178825Sdfr 1521178825Sdfr if (revoke_list) { 1522178825Sdfr ret = hx509_revoke_init(id->hx509ctx, &id->revokectx); 1523178825Sdfr if (ret) { 1524178825Sdfr _krb5_pk_copy_error(context, id->hx509ctx, ret, 1525178825Sdfr "Failed init revoke list"); 1526178825Sdfr goto out; 1527178825Sdfr } 1528178825Sdfr 1529178825Sdfr while (*revoke_list) { 1530178825Sdfr ret = hx509_revoke_add_crl(id->hx509ctx, 1531178825Sdfr id->revokectx, 1532178825Sdfr *revoke_list); 1533178825Sdfr if (ret) { 1534178825Sdfr _krb5_pk_copy_error(context, id->hx509ctx, ret, 1535178825Sdfr "Failed load revoke list"); 1536178825Sdfr goto out; 1537178825Sdfr } 1538178825Sdfr revoke_list++; 1539178825Sdfr } 1540178825Sdfr } else 1541178825Sdfr hx509_context_set_missing_revoke(id->hx509ctx, 1); 1542178825Sdfr 1543178825Sdfr ret = hx509_verify_init_ctx(id->hx509ctx, &id->verify_ctx); 1544178825Sdfr if (ret) { 1545178825Sdfr _krb5_pk_copy_error(context, id->hx509ctx, ret, 1546178825Sdfr "Failed init verify context"); 1547178825Sdfr goto out; 1548178825Sdfr } 1549178825Sdfr 1550178825Sdfr hx509_verify_attach_anchors(id->verify_ctx, id->anchors); 1551178825Sdfr hx509_verify_attach_revoke(id->verify_ctx, id->revokectx); 1552178825Sdfr 1553178825Sdfrout: 1554178825Sdfr if (ret) { 1555178825Sdfr hx509_verify_destroy_ctx(id->verify_ctx); 1556178825Sdfr hx509_certs_free(&id->certs); 1557178825Sdfr hx509_certs_free(&id->anchors); 1558178825Sdfr hx509_certs_free(&id->certpool); 1559178825Sdfr hx509_revoke_free(&id->revokectx); 1560178825Sdfr hx509_context_free(&id->hx509ctx); 1561178825Sdfr free(id); 1562178825Sdfr } else 1563178825Sdfr *ret_id = id; 1564178825Sdfr 1565178825Sdfr hx509_lock_free(lock); 1566178825Sdfr 1567178825Sdfr return ret; 1568178825Sdfr} 1569178825Sdfr 1570178825Sdfrstatic krb5_error_code 1571178825Sdfrselect_dh_group(krb5_context context, DH *dh, unsigned long bits, 1572178825Sdfr struct krb5_dh_moduli **moduli) 1573178825Sdfr{ 1574178825Sdfr const struct krb5_dh_moduli *m; 1575178825Sdfr 1576178825Sdfr if (bits == 0) { 1577178825Sdfr m = moduli[1]; /* XXX */ 1578178825Sdfr if (m == NULL) 1579178825Sdfr m = moduli[0]; /* XXX */ 1580178825Sdfr } else { 1581178825Sdfr int i; 1582178825Sdfr for (i = 0; moduli[i] != NULL; i++) { 1583178825Sdfr if (bits < moduli[i]->bits) 1584178825Sdfr break; 1585178825Sdfr } 1586178825Sdfr if (moduli[i] == NULL) { 1587178825Sdfr krb5_set_error_string(context, 1588178825Sdfr "Did not find a DH group parameter " 1589178825Sdfr "matching requirement of %lu bits", 1590178825Sdfr bits); 1591178825Sdfr return EINVAL; 1592178825Sdfr } 1593178825Sdfr m = moduli[i]; 1594178825Sdfr } 1595178825Sdfr 1596178825Sdfr dh->p = integer_to_BN(context, "p", &m->p); 1597178825Sdfr if (dh->p == NULL) 1598178825Sdfr return ENOMEM; 1599178825Sdfr dh->g = integer_to_BN(context, "g", &m->g); 1600178825Sdfr if (dh->g == NULL) 1601178825Sdfr return ENOMEM; 1602178825Sdfr dh->q = integer_to_BN(context, "q", &m->q); 1603178825Sdfr if (dh->q == NULL) 1604178825Sdfr return ENOMEM; 1605178825Sdfr 1606178825Sdfr return 0; 1607178825Sdfr} 1608178825Sdfr 1609178825Sdfr#endif /* PKINIT */ 1610178825Sdfr 1611178825Sdfrstatic int 1612178825Sdfrparse_integer(krb5_context context, char **p, const char *file, int lineno, 1613178825Sdfr const char *name, heim_integer *integer) 1614178825Sdfr{ 1615178825Sdfr int ret; 1616178825Sdfr char *p1; 1617178825Sdfr p1 = strsep(p, " \t"); 1618178825Sdfr if (p1 == NULL) { 1619178825Sdfr krb5_set_error_string(context, "moduli file %s missing %s on line %d", 1620178825Sdfr file, name, lineno); 1621178825Sdfr return EINVAL; 1622178825Sdfr } 1623178825Sdfr ret = der_parse_hex_heim_integer(p1, integer); 1624178825Sdfr if (ret) { 1625178825Sdfr krb5_set_error_string(context, "moduli file %s failed parsing %s " 1626178825Sdfr "on line %d", 1627178825Sdfr file, name, lineno); 1628178825Sdfr return ret; 1629178825Sdfr } 1630178825Sdfr 1631178825Sdfr return 0; 1632178825Sdfr} 1633178825Sdfr 1634178825Sdfrkrb5_error_code 1635178825Sdfr_krb5_parse_moduli_line(krb5_context context, 1636178825Sdfr const char *file, 1637178825Sdfr int lineno, 1638178825Sdfr char *p, 1639178825Sdfr struct krb5_dh_moduli **m) 1640178825Sdfr{ 1641178825Sdfr struct krb5_dh_moduli *m1; 1642178825Sdfr char *p1; 1643178825Sdfr int ret; 1644178825Sdfr 1645178825Sdfr *m = NULL; 1646178825Sdfr 1647178825Sdfr m1 = calloc(1, sizeof(*m1)); 1648178825Sdfr if (m1 == NULL) { 1649178825Sdfr krb5_set_error_string(context, "malloc - out of memory"); 1650178825Sdfr return ENOMEM; 1651178825Sdfr } 1652178825Sdfr 1653178825Sdfr while (isspace((unsigned char)*p)) 1654178825Sdfr p++; 1655178825Sdfr if (*p == '#') 1656178825Sdfr return 0; 1657178825Sdfr ret = EINVAL; 1658178825Sdfr 1659178825Sdfr p1 = strsep(&p, " \t"); 1660178825Sdfr if (p1 == NULL) { 1661178825Sdfr krb5_set_error_string(context, "moduli file %s missing name " 1662178825Sdfr "on line %d", file, lineno); 1663178825Sdfr goto out; 1664178825Sdfr } 1665178825Sdfr m1->name = strdup(p1); 1666178825Sdfr if (p1 == NULL) { 1667178825Sdfr krb5_set_error_string(context, "malloc - out of memeory"); 1668178825Sdfr ret = ENOMEM; 1669178825Sdfr goto out; 1670178825Sdfr } 1671178825Sdfr 1672178825Sdfr p1 = strsep(&p, " \t"); 1673178825Sdfr if (p1 == NULL) { 1674178825Sdfr krb5_set_error_string(context, "moduli file %s missing bits on line %d", 1675178825Sdfr file, lineno); 1676178825Sdfr goto out; 1677178825Sdfr } 1678178825Sdfr 1679178825Sdfr m1->bits = atoi(p1); 1680178825Sdfr if (m1->bits == 0) { 1681178825Sdfr krb5_set_error_string(context, "moduli file %s have un-parsable " 1682178825Sdfr "bits on line %d", file, lineno); 1683178825Sdfr goto out; 1684178825Sdfr } 1685178825Sdfr 1686178825Sdfr ret = parse_integer(context, &p, file, lineno, "p", &m1->p); 1687178825Sdfr if (ret) 1688178825Sdfr goto out; 1689178825Sdfr ret = parse_integer(context, &p, file, lineno, "g", &m1->g); 1690178825Sdfr if (ret) 1691178825Sdfr goto out; 1692178825Sdfr ret = parse_integer(context, &p, file, lineno, "q", &m1->q); 1693178825Sdfr if (ret) 1694178825Sdfr goto out; 1695178825Sdfr 1696178825Sdfr *m = m1; 1697178825Sdfr 1698178825Sdfr return 0; 1699178825Sdfrout: 1700178825Sdfr free(m1->name); 1701178825Sdfr der_free_heim_integer(&m1->p); 1702178825Sdfr der_free_heim_integer(&m1->g); 1703178825Sdfr der_free_heim_integer(&m1->q); 1704178825Sdfr free(m1); 1705178825Sdfr return ret; 1706178825Sdfr} 1707178825Sdfr 1708178825Sdfrvoid 1709178825Sdfr_krb5_free_moduli(struct krb5_dh_moduli **moduli) 1710178825Sdfr{ 1711178825Sdfr int i; 1712178825Sdfr for (i = 0; moduli[i] != NULL; i++) { 1713178825Sdfr free(moduli[i]->name); 1714178825Sdfr der_free_heim_integer(&moduli[i]->p); 1715178825Sdfr der_free_heim_integer(&moduli[i]->g); 1716178825Sdfr der_free_heim_integer(&moduli[i]->q); 1717178825Sdfr free(moduli[i]); 1718178825Sdfr } 1719178825Sdfr free(moduli); 1720178825Sdfr} 1721178825Sdfr 1722178825Sdfrstatic const char *default_moduli_RFC2412_MODP_group2 = 1723178825Sdfr /* name */ 1724178825Sdfr "RFC2412-MODP-group2 " 1725178825Sdfr /* bits */ 1726178825Sdfr "1024 " 1727178825Sdfr /* p */ 1728178825Sdfr "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" 1729178825Sdfr "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" 1730178825Sdfr "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" 1731178825Sdfr "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" 1732178825Sdfr "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" 1733178825Sdfr "FFFFFFFF" "FFFFFFFF " 1734178825Sdfr /* g */ 1735178825Sdfr "02 " 1736178825Sdfr /* q */ 1737178825Sdfr "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68" 1738178825Sdfr "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E" 1739178825Sdfr "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122" 1740178825Sdfr "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6" 1741178825Sdfr "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0" 1742178825Sdfr "FFFFFFFF" "FFFFFFFF"; 1743178825Sdfr 1744178825Sdfrstatic const char *default_moduli_rfc3526_MODP_group14 = 1745178825Sdfr /* name */ 1746178825Sdfr "rfc3526-MODP-group14 " 1747178825Sdfr /* bits */ 1748178825Sdfr "1760 " 1749178825Sdfr /* p */ 1750178825Sdfr "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" 1751178825Sdfr "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" 1752178825Sdfr "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" 1753178825Sdfr "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" 1754178825Sdfr "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D" 1755178825Sdfr "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F" 1756178825Sdfr "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D" 1757178825Sdfr "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B" 1758178825Sdfr "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9" 1759178825Sdfr "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510" 1760178825Sdfr "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF " 1761178825Sdfr /* g */ 1762178825Sdfr "02 " 1763178825Sdfr /* q */ 1764178825Sdfr "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68" 1765178825Sdfr "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E" 1766178825Sdfr "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122" 1767178825Sdfr "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6" 1768178825Sdfr "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E" 1769178825Sdfr "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF" 1770178825Sdfr "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36" 1771178825Sdfr "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D" 1772178825Sdfr "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964" 1773178825Sdfr "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288" 1774178825Sdfr "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF"; 1775178825Sdfr 1776178825Sdfrkrb5_error_code 1777178825Sdfr_krb5_parse_moduli(krb5_context context, const char *file, 1778178825Sdfr struct krb5_dh_moduli ***moduli) 1779178825Sdfr{ 1780178825Sdfr /* name bits P G Q */ 1781178825Sdfr krb5_error_code ret; 1782178825Sdfr struct krb5_dh_moduli **m = NULL, **m2; 1783178825Sdfr char buf[4096]; 1784178825Sdfr FILE *f; 1785178825Sdfr int lineno = 0, n = 0; 1786178825Sdfr 1787178825Sdfr *moduli = NULL; 1788178825Sdfr 1789178825Sdfr m = calloc(1, sizeof(m[0]) * 3); 1790178825Sdfr if (m == NULL) { 1791178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 1792178825Sdfr return ENOMEM; 1793178825Sdfr } 1794178825Sdfr 1795178825Sdfr strlcpy(buf, default_moduli_rfc3526_MODP_group14, sizeof(buf)); 1796178825Sdfr ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[0]); 1797178825Sdfr if (ret) { 1798178825Sdfr _krb5_free_moduli(m); 1799178825Sdfr return ret; 1800178825Sdfr } 1801178825Sdfr n++; 1802178825Sdfr 1803178825Sdfr strlcpy(buf, default_moduli_RFC2412_MODP_group2, sizeof(buf)); 1804178825Sdfr ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[1]); 1805178825Sdfr if (ret) { 1806178825Sdfr _krb5_free_moduli(m); 1807178825Sdfr return ret; 1808178825Sdfr } 1809178825Sdfr n++; 1810178825Sdfr 1811178825Sdfr 1812178825Sdfr if (file == NULL) 1813178825Sdfr file = MODULI_FILE; 1814178825Sdfr 1815178825Sdfr f = fopen(file, "r"); 1816178825Sdfr if (f == NULL) { 1817178825Sdfr *moduli = m; 1818178825Sdfr return 0; 1819178825Sdfr } 1820178825Sdfr 1821178825Sdfr while(fgets(buf, sizeof(buf), f) != NULL) { 1822178825Sdfr struct krb5_dh_moduli *element; 1823178825Sdfr 1824178825Sdfr buf[strcspn(buf, "\n")] = '\0'; 1825178825Sdfr lineno++; 1826178825Sdfr 1827178825Sdfr m2 = realloc(m, (n + 2) * sizeof(m[0])); 1828178825Sdfr if (m2 == NULL) { 1829178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 1830178825Sdfr _krb5_free_moduli(m); 1831178825Sdfr return ENOMEM; 1832178825Sdfr } 1833178825Sdfr m = m2; 1834178825Sdfr 1835178825Sdfr m[n] = NULL; 1836178825Sdfr 1837178825Sdfr ret = _krb5_parse_moduli_line(context, file, lineno, buf, &element); 1838178825Sdfr if (ret) { 1839178825Sdfr _krb5_free_moduli(m); 1840178825Sdfr return ret; 1841178825Sdfr } 1842178825Sdfr if (element == NULL) 1843178825Sdfr continue; 1844178825Sdfr 1845178825Sdfr m[n] = element; 1846178825Sdfr m[n + 1] = NULL; 1847178825Sdfr n++; 1848178825Sdfr } 1849178825Sdfr *moduli = m; 1850178825Sdfr return 0; 1851178825Sdfr} 1852178825Sdfr 1853178825Sdfrkrb5_error_code 1854178825Sdfr_krb5_dh_group_ok(krb5_context context, unsigned long bits, 1855178825Sdfr heim_integer *p, heim_integer *g, heim_integer *q, 1856178825Sdfr struct krb5_dh_moduli **moduli, 1857178825Sdfr char **name) 1858178825Sdfr{ 1859178825Sdfr int i; 1860178825Sdfr 1861178825Sdfr if (name) 1862178825Sdfr *name = NULL; 1863178825Sdfr 1864178825Sdfr for (i = 0; moduli[i] != NULL; i++) { 1865178825Sdfr if (der_heim_integer_cmp(&moduli[i]->g, g) == 0 && 1866178825Sdfr der_heim_integer_cmp(&moduli[i]->p, p) == 0 && 1867178825Sdfr (q == NULL || der_heim_integer_cmp(&moduli[i]->q, q) == 0)) 1868178825Sdfr { 1869178825Sdfr if (bits && bits > moduli[i]->bits) { 1870178825Sdfr krb5_set_error_string(context, "PKINIT: DH group parameter %s " 1871178825Sdfr "no accepted, not enough bits generated", 1872178825Sdfr moduli[i]->name); 1873178825Sdfr return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED; 1874178825Sdfr } 1875178825Sdfr if (name) 1876178825Sdfr *name = strdup(moduli[i]->name); 1877178825Sdfr return 0; 1878178825Sdfr } 1879178825Sdfr } 1880178825Sdfr krb5_set_error_string(context, "PKINIT: DH group parameter no ok"); 1881178825Sdfr return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED; 1882178825Sdfr} 1883178825Sdfr 1884178825Sdfrvoid KRB5_LIB_FUNCTION 1885178825Sdfr_krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt) 1886178825Sdfr{ 1887178825Sdfr#ifdef PKINIT 1888178825Sdfr krb5_pk_init_ctx ctx; 1889178825Sdfr 1890178825Sdfr if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL) 1891178825Sdfr return; 1892178825Sdfr ctx = opt->opt_private->pk_init_ctx; 1893178825Sdfr if (ctx->dh) 1894178825Sdfr DH_free(ctx->dh); 1895178825Sdfr ctx->dh = NULL; 1896178825Sdfr if (ctx->id) { 1897178825Sdfr hx509_verify_destroy_ctx(ctx->id->verify_ctx); 1898178825Sdfr hx509_certs_free(&ctx->id->certs); 1899178825Sdfr hx509_certs_free(&ctx->id->anchors); 1900178825Sdfr hx509_certs_free(&ctx->id->certpool); 1901178825Sdfr hx509_context_free(&ctx->id->hx509ctx); 1902178825Sdfr 1903178825Sdfr if (ctx->clientDHNonce) { 1904178825Sdfr krb5_free_data(NULL, ctx->clientDHNonce); 1905178825Sdfr ctx->clientDHNonce = NULL; 1906178825Sdfr } 1907178825Sdfr if (ctx->m) 1908178825Sdfr _krb5_free_moduli(ctx->m); 1909178825Sdfr free(ctx->id); 1910178825Sdfr ctx->id = NULL; 1911178825Sdfr } 1912178825Sdfr free(opt->opt_private->pk_init_ctx); 1913178825Sdfr opt->opt_private->pk_init_ctx = NULL; 1914178825Sdfr#endif 1915178825Sdfr} 1916178825Sdfr 1917178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 1918178825Sdfrkrb5_get_init_creds_opt_set_pkinit(krb5_context context, 1919178825Sdfr krb5_get_init_creds_opt *opt, 1920178825Sdfr krb5_principal principal, 1921178825Sdfr const char *user_id, 1922178825Sdfr const char *x509_anchors, 1923178825Sdfr char * const * pool, 1924178825Sdfr char * const * pki_revoke, 1925178825Sdfr int flags, 1926178825Sdfr krb5_prompter_fct prompter, 1927178825Sdfr void *prompter_data, 1928178825Sdfr char *password) 1929178825Sdfr{ 1930178825Sdfr#ifdef PKINIT 1931178825Sdfr krb5_error_code ret; 1932178825Sdfr char *anchors = NULL; 1933178825Sdfr 1934178825Sdfr if (opt->opt_private == NULL) { 1935178825Sdfr krb5_set_error_string(context, "PKINIT: on non extendable opt"); 1936178825Sdfr return EINVAL; 1937178825Sdfr } 1938178825Sdfr 1939178825Sdfr opt->opt_private->pk_init_ctx = 1940178825Sdfr calloc(1, sizeof(*opt->opt_private->pk_init_ctx)); 1941178825Sdfr if (opt->opt_private->pk_init_ctx == NULL) { 1942178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 1943178825Sdfr return ENOMEM; 1944178825Sdfr } 1945178825Sdfr opt->opt_private->pk_init_ctx->dh = NULL; 1946178825Sdfr opt->opt_private->pk_init_ctx->id = NULL; 1947178825Sdfr opt->opt_private->pk_init_ctx->clientDHNonce = NULL; 1948178825Sdfr opt->opt_private->pk_init_ctx->require_binding = 0; 1949178825Sdfr opt->opt_private->pk_init_ctx->require_eku = 1; 1950178825Sdfr opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1; 1951178825Sdfr opt->opt_private->pk_init_ctx->peer = NULL; 1952178825Sdfr 1953178825Sdfr /* XXX implement krb5_appdefault_strings */ 1954178825Sdfr if (pool == NULL) 1955178825Sdfr pool = krb5_config_get_strings(context, NULL, 1956178825Sdfr "appdefaults", 1957178825Sdfr "pkinit_pool", 1958178825Sdfr NULL); 1959178825Sdfr 1960178825Sdfr if (pki_revoke == NULL) 1961178825Sdfr pki_revoke = krb5_config_get_strings(context, NULL, 1962178825Sdfr "appdefaults", 1963178825Sdfr "pkinit_revoke", 1964178825Sdfr NULL); 1965178825Sdfr 1966178825Sdfr if (x509_anchors == NULL) { 1967178825Sdfr krb5_appdefault_string(context, "kinit", 1968178825Sdfr krb5_principal_get_realm(context, principal), 1969178825Sdfr "pkinit_anchors", NULL, &anchors); 1970178825Sdfr x509_anchors = anchors; 1971178825Sdfr } 1972178825Sdfr 1973178825Sdfr ret = _krb5_pk_load_id(context, 1974178825Sdfr &opt->opt_private->pk_init_ctx->id, 1975178825Sdfr user_id, 1976178825Sdfr x509_anchors, 1977178825Sdfr pool, 1978178825Sdfr pki_revoke, 1979178825Sdfr prompter, 1980178825Sdfr prompter_data, 1981178825Sdfr password); 1982178825Sdfr if (ret) { 1983178825Sdfr free(opt->opt_private->pk_init_ctx); 1984178825Sdfr opt->opt_private->pk_init_ctx = NULL; 1985178825Sdfr return ret; 1986178825Sdfr } 1987178825Sdfr 1988178825Sdfr if ((flags & 2) == 0) { 1989178825Sdfr const char *moduli_file; 1990178825Sdfr unsigned long dh_min_bits; 1991178825Sdfr 1992178825Sdfr moduli_file = krb5_config_get_string(context, NULL, 1993178825Sdfr "libdefaults", 1994178825Sdfr "moduli", 1995178825Sdfr NULL); 1996178825Sdfr 1997178825Sdfr dh_min_bits = 1998178825Sdfr krb5_config_get_int_default(context, NULL, 0, 1999178825Sdfr "libdefaults", 2000178825Sdfr "pkinit_dh_min_bits", 2001178825Sdfr NULL); 2002178825Sdfr 2003178825Sdfr ret = _krb5_parse_moduli(context, moduli_file, 2004178825Sdfr &opt->opt_private->pk_init_ctx->m); 2005178825Sdfr if (ret) { 2006178825Sdfr _krb5_get_init_creds_opt_free_pkinit(opt); 2007178825Sdfr return ret; 2008178825Sdfr } 2009178825Sdfr 2010178825Sdfr opt->opt_private->pk_init_ctx->dh = DH_new(); 2011178825Sdfr if (opt->opt_private->pk_init_ctx->dh == NULL) { 2012178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 2013178825Sdfr _krb5_get_init_creds_opt_free_pkinit(opt); 2014178825Sdfr return ENOMEM; 2015178825Sdfr } 2016178825Sdfr 2017178825Sdfr ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh, 2018178825Sdfr dh_min_bits, 2019178825Sdfr opt->opt_private->pk_init_ctx->m); 2020178825Sdfr if (ret) { 2021178825Sdfr _krb5_get_init_creds_opt_free_pkinit(opt); 2022178825Sdfr return ret; 2023178825Sdfr } 2024178825Sdfr 2025178825Sdfr if (DH_generate_key(opt->opt_private->pk_init_ctx->dh) != 1) { 2026178825Sdfr krb5_set_error_string(context, "pkinit: failed to generate DH key"); 2027178825Sdfr _krb5_get_init_creds_opt_free_pkinit(opt); 2028178825Sdfr return ENOMEM; 2029178825Sdfr } 2030178825Sdfr } 2031178825Sdfr 2032178825Sdfr return 0; 2033178825Sdfr#else 2034178825Sdfr krb5_set_error_string(context, "no support for PKINIT compiled in"); 2035178825Sdfr return EINVAL; 2036178825Sdfr#endif 2037178825Sdfr} 2038178825Sdfr 2039178825Sdfr/* 2040178825Sdfr * 2041178825Sdfr */ 2042178825Sdfr 2043178825Sdfrstatic void 2044178825Sdfr_krb5_pk_copy_error(krb5_context context, 2045178825Sdfr hx509_context hx509ctx, 2046178825Sdfr int hxret, 2047178825Sdfr const char *fmt, 2048178825Sdfr ...) 2049178825Sdfr{ 2050178825Sdfr va_list va; 2051178825Sdfr char *s, *f; 2052178825Sdfr 2053178825Sdfr va_start(va, fmt); 2054178825Sdfr vasprintf(&f, fmt, va); 2055178825Sdfr va_end(va); 2056178825Sdfr if (f == NULL) { 2057178825Sdfr krb5_clear_error_string(context); 2058178825Sdfr return; 2059178825Sdfr } 2060178825Sdfr 2061178825Sdfr s = hx509_get_error_string(hx509ctx, hxret); 2062178825Sdfr if (s == NULL) { 2063178825Sdfr krb5_clear_error_string(context); 2064178825Sdfr free(f); 2065178825Sdfr return; 2066178825Sdfr } 2067178825Sdfr krb5_set_error_string(context, "%s: %s", f, s); 2068178825Sdfr free(s); 2069178825Sdfr free(f); 2070178825Sdfr} 2071