1178825Sdfr/* 2233294Sstas * Copyright (c) 2003 - 2008 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 "kdc_locl.h" 37178825Sdfr 38178825Sdfr#ifdef PKINIT 39178825Sdfr 40178825Sdfr#include <heim_asn1.h> 41178825Sdfr#include <rfc2459_asn1.h> 42178825Sdfr#include <cms_asn1.h> 43178825Sdfr#include <pkinit_asn1.h> 44178825Sdfr 45178825Sdfr#include <hx509.h> 46178825Sdfr#include "crypto-headers.h" 47178825Sdfr 48178825Sdfrstruct pk_client_params { 49233294Sstas enum krb5_pk_type type; 50233294Sstas enum { USE_RSA, USE_DH, USE_ECDH } keyex; 51233294Sstas union { 52233294Sstas struct { 53233294Sstas BIGNUM *public_key; 54233294Sstas DH *key; 55233294Sstas } dh; 56233294Sstas#ifdef HAVE_OPENSSL 57233294Sstas struct { 58233294Sstas EC_KEY *public_key; 59233294Sstas EC_KEY *key; 60233294Sstas } ecdh; 61233294Sstas#endif 62233294Sstas } u; 63178825Sdfr hx509_cert cert; 64178825Sdfr unsigned nonce; 65178825Sdfr EncryptionKey reply_key; 66178825Sdfr char *dh_group_name; 67178825Sdfr hx509_peer_info peer; 68178825Sdfr hx509_certs client_anchors; 69233294Sstas hx509_verify_ctx verify_ctx; 70178825Sdfr}; 71178825Sdfr 72178825Sdfrstruct pk_principal_mapping { 73178825Sdfr unsigned int len; 74178825Sdfr struct pk_allowed_princ { 75178825Sdfr krb5_principal principal; 76178825Sdfr char *subject; 77178825Sdfr } *val; 78178825Sdfr}; 79178825Sdfr 80178825Sdfrstatic struct krb5_pk_identity *kdc_identity; 81178825Sdfrstatic struct pk_principal_mapping principal_mappings; 82178825Sdfrstatic struct krb5_dh_moduli **moduli; 83178825Sdfr 84178825Sdfrstatic struct { 85178825Sdfr krb5_data data; 86178825Sdfr time_t expire; 87178825Sdfr time_t next_update; 88178825Sdfr} ocsp; 89178825Sdfr 90178825Sdfr/* 91178825Sdfr * 92178825Sdfr */ 93178825Sdfr 94178825Sdfrstatic krb5_error_code 95178825Sdfrpk_check_pkauthenticator_win2k(krb5_context context, 96178825Sdfr PKAuthenticator_Win2k *a, 97178825Sdfr const KDC_REQ *req) 98178825Sdfr{ 99178825Sdfr krb5_timestamp now; 100178825Sdfr 101178825Sdfr krb5_timeofday (context, &now); 102178825Sdfr 103178825Sdfr /* XXX cusec */ 104178825Sdfr if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) { 105233294Sstas krb5_clear_error_message(context); 106178825Sdfr return KRB5KRB_AP_ERR_SKEW; 107178825Sdfr } 108178825Sdfr return 0; 109178825Sdfr} 110178825Sdfr 111178825Sdfrstatic krb5_error_code 112178825Sdfrpk_check_pkauthenticator(krb5_context context, 113178825Sdfr PKAuthenticator *a, 114178825Sdfr const KDC_REQ *req) 115178825Sdfr{ 116178825Sdfr u_char *buf = NULL; 117178825Sdfr size_t buf_size; 118178825Sdfr krb5_error_code ret; 119233294Sstas size_t len = 0; 120178825Sdfr krb5_timestamp now; 121178825Sdfr Checksum checksum; 122178825Sdfr 123178825Sdfr krb5_timeofday (context, &now); 124178825Sdfr 125178825Sdfr /* XXX cusec */ 126178825Sdfr if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) { 127233294Sstas krb5_clear_error_message(context); 128178825Sdfr return KRB5KRB_AP_ERR_SKEW; 129178825Sdfr } 130178825Sdfr 131178825Sdfr ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, &req->req_body, &len, ret); 132178825Sdfr if (ret) { 133233294Sstas krb5_clear_error_message(context); 134178825Sdfr return ret; 135178825Sdfr } 136178825Sdfr if (buf_size != len) 137178825Sdfr krb5_abortx(context, "Internal error in ASN.1 encoder"); 138178825Sdfr 139178825Sdfr ret = krb5_create_checksum(context, 140178825Sdfr NULL, 141178825Sdfr 0, 142178825Sdfr CKSUMTYPE_SHA1, 143178825Sdfr buf, 144178825Sdfr len, 145178825Sdfr &checksum); 146178825Sdfr free(buf); 147178825Sdfr if (ret) { 148233294Sstas krb5_clear_error_message(context); 149178825Sdfr return ret; 150178825Sdfr } 151233294Sstas 152178825Sdfr if (a->paChecksum == NULL) { 153233294Sstas krb5_clear_error_message(context); 154178825Sdfr ret = KRB5_KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED; 155178825Sdfr goto out; 156178825Sdfr } 157178825Sdfr 158178825Sdfr if (der_heim_octet_string_cmp(a->paChecksum, &checksum.checksum) != 0) { 159233294Sstas krb5_clear_error_message(context); 160178825Sdfr ret = KRB5KRB_ERR_GENERIC; 161178825Sdfr } 162178825Sdfr 163178825Sdfrout: 164178825Sdfr free_Checksum(&checksum); 165178825Sdfr 166178825Sdfr return ret; 167178825Sdfr} 168178825Sdfr 169178825Sdfrvoid 170233294Sstas_kdc_pk_free_client_param(krb5_context context, pk_client_params *cp) 171178825Sdfr{ 172233294Sstas if (cp == NULL) 173233294Sstas return; 174233294Sstas if (cp->cert) 175233294Sstas hx509_cert_free(cp->cert); 176233294Sstas if (cp->verify_ctx) 177233294Sstas hx509_verify_destroy_ctx(cp->verify_ctx); 178233294Sstas if (cp->keyex == USE_DH) { 179233294Sstas if (cp->u.dh.key) 180233294Sstas DH_free(cp->u.dh.key); 181233294Sstas if (cp->u.dh.public_key) 182233294Sstas BN_free(cp->u.dh.public_key); 183233294Sstas } 184233294Sstas#ifdef HAVE_OPENSSL 185233294Sstas if (cp->keyex == USE_ECDH) { 186233294Sstas if (cp->u.ecdh.key) 187233294Sstas EC_KEY_free(cp->u.ecdh.key); 188233294Sstas if (cp->u.ecdh.public_key) 189233294Sstas EC_KEY_free(cp->u.ecdh.public_key); 190233294Sstas } 191233294Sstas#endif 192233294Sstas krb5_free_keyblock_contents(context, &cp->reply_key); 193233294Sstas if (cp->dh_group_name) 194233294Sstas free(cp->dh_group_name); 195233294Sstas if (cp->peer) 196233294Sstas hx509_peer_info_free(cp->peer); 197233294Sstas if (cp->client_anchors) 198233294Sstas hx509_certs_free(&cp->client_anchors); 199233294Sstas memset(cp, 0, sizeof(*cp)); 200233294Sstas free(cp); 201178825Sdfr} 202178825Sdfr 203178825Sdfrstatic krb5_error_code 204233294Sstasgenerate_dh_keyblock(krb5_context context, 205233294Sstas pk_client_params *client_params, 206233294Sstas krb5_enctype enctype) 207178825Sdfr{ 208178825Sdfr unsigned char *dh_gen_key = NULL; 209178825Sdfr krb5_keyblock key; 210178825Sdfr krb5_error_code ret; 211178825Sdfr size_t dh_gen_keylen, size; 212178825Sdfr 213178825Sdfr memset(&key, 0, sizeof(key)); 214178825Sdfr 215233294Sstas if (client_params->keyex == USE_DH) { 216178825Sdfr 217233294Sstas if (client_params->u.dh.public_key == NULL) { 218233294Sstas ret = KRB5KRB_ERR_GENERIC; 219233294Sstas krb5_set_error_message(context, ret, "public_key"); 220233294Sstas goto out; 221233294Sstas } 222178825Sdfr 223233294Sstas if (!DH_generate_key(client_params->u.dh.key)) { 224233294Sstas ret = KRB5KRB_ERR_GENERIC; 225233294Sstas krb5_set_error_message(context, ret, 226233294Sstas "Can't generate Diffie-Hellman keys"); 227233294Sstas goto out; 228233294Sstas } 229178825Sdfr 230233294Sstas size = DH_size(client_params->u.dh.key); 231233294Sstas 232233294Sstas dh_gen_key = malloc(size); 233233294Sstas if (dh_gen_key == NULL) { 234233294Sstas ret = ENOMEM; 235233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 236233294Sstas goto out; 237233294Sstas } 238233294Sstas 239233294Sstas dh_gen_keylen = DH_compute_key(dh_gen_key,client_params->u.dh.public_key, client_params->u.dh.key); 240233294Sstas if (dh_gen_keylen == (size_t)-1) { 241233294Sstas ret = KRB5KRB_ERR_GENERIC; 242233294Sstas krb5_set_error_message(context, ret, 243233294Sstas "Can't compute Diffie-Hellman key"); 244233294Sstas goto out; 245233294Sstas } 246233294Sstas if (dh_gen_keylen < size) { 247233294Sstas size -= dh_gen_keylen; 248233294Sstas memmove(dh_gen_key + size, dh_gen_key, dh_gen_keylen); 249233294Sstas memset(dh_gen_key, 0, size); 250233294Sstas } 251233294Sstas 252233294Sstas ret = 0; 253233294Sstas#ifdef HAVE_OPENSSL 254233294Sstas } else if (client_params->keyex == USE_ECDH) { 255233294Sstas 256233294Sstas if (client_params->u.ecdh.public_key == NULL) { 257233294Sstas ret = KRB5KRB_ERR_GENERIC; 258233294Sstas krb5_set_error_message(context, ret, "public_key"); 259233294Sstas goto out; 260233294Sstas } 261233294Sstas 262233294Sstas client_params->u.ecdh.key = EC_KEY_new(); 263233294Sstas if (client_params->u.ecdh.key == NULL) { 264233294Sstas ret = ENOMEM; 265233294Sstas goto out; 266233294Sstas } 267233294Sstas EC_KEY_set_group(client_params->u.ecdh.key, 268233294Sstas EC_KEY_get0_group(client_params->u.ecdh.public_key)); 269233294Sstas 270233294Sstas if (EC_KEY_generate_key(client_params->u.ecdh.key) != 1) { 271233294Sstas ret = ENOMEM; 272233294Sstas goto out; 273233294Sstas } 274233294Sstas 275233294Sstas size = (EC_GROUP_get_degree(EC_KEY_get0_group(client_params->u.ecdh.key)) + 7) / 8; 276233294Sstas dh_gen_key = malloc(size); 277233294Sstas if (dh_gen_key == NULL) { 278233294Sstas ret = ENOMEM; 279233294Sstas krb5_set_error_message(context, ret, 280233294Sstas N_("malloc: out of memory", "")); 281233294Sstas goto out; 282233294Sstas } 283233294Sstas 284233294Sstas dh_gen_keylen = ECDH_compute_key(dh_gen_key, size, 285233294Sstas EC_KEY_get0_public_key(client_params->u.ecdh.public_key), 286233294Sstas client_params->u.ecdh.key, NULL); 287233294Sstas 288233294Sstas#endif /* HAVE_OPENSSL */ 289233294Sstas } else { 290178825Sdfr ret = KRB5KRB_ERR_GENERIC; 291233294Sstas krb5_set_error_message(context, ret, 292233294Sstas "Diffie-Hellman not selected keys"); 293178825Sdfr goto out; 294178825Sdfr } 295178825Sdfr 296178825Sdfr ret = _krb5_pk_octetstring2key(context, 297178825Sdfr enctype, 298178825Sdfr dh_gen_key, dh_gen_keylen, 299178825Sdfr NULL, NULL, 300233294Sstas &client_params->reply_key); 301178825Sdfr 302178825Sdfr out: 303178825Sdfr if (dh_gen_key) 304178825Sdfr free(dh_gen_key); 305178825Sdfr if (key.keyvalue.data) 306178825Sdfr krb5_free_keyblock_contents(context, &key); 307178825Sdfr 308178825Sdfr return ret; 309178825Sdfr} 310178825Sdfr 311178825Sdfrstatic BIGNUM * 312178825Sdfrinteger_to_BN(krb5_context context, const char *field, heim_integer *f) 313178825Sdfr{ 314178825Sdfr BIGNUM *bn; 315178825Sdfr 316178825Sdfr bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL); 317178825Sdfr if (bn == NULL) { 318233294Sstas krb5_set_error_message(context, KRB5_BADMSGTYPE, 319233294Sstas "PKINIT: parsing BN failed %s", field); 320178825Sdfr return NULL; 321178825Sdfr } 322178825Sdfr BN_set_negative(bn, f->negative); 323178825Sdfr return bn; 324178825Sdfr} 325178825Sdfr 326178825Sdfrstatic krb5_error_code 327178825Sdfrget_dh_param(krb5_context context, 328178825Sdfr krb5_kdc_configuration *config, 329178825Sdfr SubjectPublicKeyInfo *dh_key_info, 330178825Sdfr pk_client_params *client_params) 331178825Sdfr{ 332178825Sdfr DomainParameters dhparam; 333178825Sdfr DH *dh = NULL; 334178825Sdfr krb5_error_code ret; 335178825Sdfr 336178825Sdfr memset(&dhparam, 0, sizeof(dhparam)); 337178825Sdfr 338233294Sstas if ((dh_key_info->subjectPublicKey.length % 8) != 0) { 339233294Sstas ret = KRB5_BADMSGTYPE; 340233294Sstas krb5_set_error_message(context, ret, 341233294Sstas "PKINIT: subjectPublicKey not aligned " 342233294Sstas "to 8 bit boundary"); 343233294Sstas goto out; 344178825Sdfr } 345178825Sdfr 346178825Sdfr if (dh_key_info->algorithm.parameters == NULL) { 347233294Sstas krb5_set_error_message(context, KRB5_BADMSGTYPE, 348233294Sstas "PKINIT missing algorithm parameter " 349178825Sdfr "in clientPublicValue"); 350178825Sdfr return KRB5_BADMSGTYPE; 351178825Sdfr } 352178825Sdfr 353178825Sdfr ret = decode_DomainParameters(dh_key_info->algorithm.parameters->data, 354178825Sdfr dh_key_info->algorithm.parameters->length, 355178825Sdfr &dhparam, 356178825Sdfr NULL); 357178825Sdfr if (ret) { 358233294Sstas krb5_set_error_message(context, ret, "Can't decode algorithm " 359233294Sstas "parameters in clientPublicValue"); 360178825Sdfr goto out; 361178825Sdfr } 362178825Sdfr 363233294Sstas ret = _krb5_dh_group_ok(context, config->pkinit_dh_min_bits, 364178825Sdfr &dhparam.p, &dhparam.g, &dhparam.q, moduli, 365178825Sdfr &client_params->dh_group_name); 366178825Sdfr if (ret) { 367178825Sdfr /* XXX send back proposal of better group */ 368178825Sdfr goto out; 369178825Sdfr } 370178825Sdfr 371178825Sdfr dh = DH_new(); 372178825Sdfr if (dh == NULL) { 373178825Sdfr ret = ENOMEM; 374233294Sstas krb5_set_error_message(context, ret, "Cannot create DH structure"); 375178825Sdfr goto out; 376178825Sdfr } 377178825Sdfr ret = KRB5_BADMSGTYPE; 378178825Sdfr dh->p = integer_to_BN(context, "DH prime", &dhparam.p); 379178825Sdfr if (dh->p == NULL) 380178825Sdfr goto out; 381178825Sdfr dh->g = integer_to_BN(context, "DH base", &dhparam.g); 382178825Sdfr if (dh->g == NULL) 383178825Sdfr goto out; 384178825Sdfr dh->q = integer_to_BN(context, "DH p-1 factor", &dhparam.q); 385178825Sdfr if (dh->g == NULL) 386178825Sdfr goto out; 387178825Sdfr 388178825Sdfr { 389178825Sdfr heim_integer glue; 390178825Sdfr size_t size; 391178825Sdfr 392178825Sdfr ret = decode_DHPublicKey(dh_key_info->subjectPublicKey.data, 393178825Sdfr dh_key_info->subjectPublicKey.length / 8, 394178825Sdfr &glue, 395178825Sdfr &size); 396178825Sdfr if (ret) { 397233294Sstas krb5_clear_error_message(context); 398178825Sdfr return ret; 399178825Sdfr } 400178825Sdfr 401233294Sstas client_params->u.dh.public_key = integer_to_BN(context, 402233294Sstas "subjectPublicKey", 403233294Sstas &glue); 404178825Sdfr der_free_heim_integer(&glue); 405233294Sstas if (client_params->u.dh.public_key == NULL) { 406233294Sstas ret = KRB5_BADMSGTYPE; 407178825Sdfr goto out; 408233294Sstas } 409178825Sdfr } 410178825Sdfr 411233294Sstas client_params->u.dh.key = dh; 412178825Sdfr dh = NULL; 413178825Sdfr ret = 0; 414233294Sstas 415178825Sdfr out: 416178825Sdfr if (dh) 417178825Sdfr DH_free(dh); 418178825Sdfr free_DomainParameters(&dhparam); 419178825Sdfr return ret; 420178825Sdfr} 421178825Sdfr 422233294Sstas#ifdef HAVE_OPENSSL 423233294Sstas 424233294Sstasstatic krb5_error_code 425233294Sstasget_ecdh_param(krb5_context context, 426233294Sstas krb5_kdc_configuration *config, 427233294Sstas SubjectPublicKeyInfo *dh_key_info, 428233294Sstas pk_client_params *client_params) 429233294Sstas{ 430233294Sstas ECParameters ecp; 431233294Sstas EC_KEY *public = NULL; 432233294Sstas krb5_error_code ret; 433233294Sstas const unsigned char *p; 434233294Sstas size_t len; 435233294Sstas int nid; 436233294Sstas 437233294Sstas if (dh_key_info->algorithm.parameters == NULL) { 438233294Sstas krb5_set_error_message(context, KRB5_BADMSGTYPE, 439233294Sstas "PKINIT missing algorithm parameter " 440233294Sstas "in clientPublicValue"); 441233294Sstas return KRB5_BADMSGTYPE; 442233294Sstas } 443233294Sstas 444233294Sstas memset(&ecp, 0, sizeof(ecp)); 445233294Sstas 446233294Sstas ret = decode_ECParameters(dh_key_info->algorithm.parameters->data, 447233294Sstas dh_key_info->algorithm.parameters->length, &ecp, &len); 448233294Sstas if (ret) 449233294Sstas goto out; 450233294Sstas 451233294Sstas if (ecp.element != choice_ECParameters_namedCurve) { 452233294Sstas ret = KRB5_BADMSGTYPE; 453233294Sstas goto out; 454233294Sstas } 455233294Sstas 456233294Sstas if (der_heim_oid_cmp(&ecp.u.namedCurve, &asn1_oid_id_ec_group_secp256r1) == 0) 457233294Sstas nid = NID_X9_62_prime256v1; 458233294Sstas else { 459233294Sstas ret = KRB5_BADMSGTYPE; 460233294Sstas goto out; 461233294Sstas } 462233294Sstas 463233294Sstas /* XXX verify group is ok */ 464233294Sstas 465233294Sstas public = EC_KEY_new_by_curve_name(nid); 466233294Sstas 467233294Sstas p = dh_key_info->subjectPublicKey.data; 468233294Sstas len = dh_key_info->subjectPublicKey.length / 8; 469233294Sstas if (o2i_ECPublicKey(&public, &p, len) == NULL) { 470233294Sstas ret = KRB5_BADMSGTYPE; 471233294Sstas krb5_set_error_message(context, ret, 472233294Sstas "PKINIT failed to decode ECDH key"); 473233294Sstas goto out; 474233294Sstas } 475233294Sstas client_params->u.ecdh.public_key = public; 476233294Sstas public = NULL; 477233294Sstas 478233294Sstas out: 479233294Sstas if (public) 480233294Sstas EC_KEY_free(public); 481233294Sstas free_ECParameters(&ecp); 482233294Sstas return ret; 483233294Sstas} 484233294Sstas 485233294Sstas#endif /* HAVE_OPENSSL */ 486233294Sstas 487178825Sdfrkrb5_error_code 488178825Sdfr_kdc_pk_rd_padata(krb5_context context, 489178825Sdfr krb5_kdc_configuration *config, 490178825Sdfr const KDC_REQ *req, 491178825Sdfr const PA_DATA *pa, 492233294Sstas hdb_entry_ex *client, 493178825Sdfr pk_client_params **ret_params) 494178825Sdfr{ 495233294Sstas pk_client_params *cp; 496178825Sdfr krb5_error_code ret; 497178825Sdfr heim_oid eContentType = { 0, NULL }, contentInfoOid = { 0, NULL }; 498178825Sdfr krb5_data eContent = { 0, NULL }; 499178825Sdfr krb5_data signed_content = { 0, NULL }; 500178825Sdfr const char *type = "unknown type"; 501233294Sstas hx509_certs trust_anchors; 502178825Sdfr int have_data = 0; 503233294Sstas const HDB_Ext_PKINIT_cert *pc; 504178825Sdfr 505178825Sdfr *ret_params = NULL; 506233294Sstas 507178825Sdfr if (!config->enable_pkinit) { 508178825Sdfr kdc_log(context, config, 0, "PK-INIT request but PK-INIT not enabled"); 509233294Sstas krb5_clear_error_message(context); 510178825Sdfr return 0; 511178825Sdfr } 512178825Sdfr 513233294Sstas cp = calloc(1, sizeof(*cp)); 514233294Sstas if (cp == NULL) { 515233294Sstas krb5_clear_error_message(context); 516178825Sdfr ret = ENOMEM; 517178825Sdfr goto out; 518178825Sdfr } 519178825Sdfr 520233294Sstas ret = hx509_certs_init(context->hx509ctx, 521233294Sstas "MEMORY:trust-anchors", 522233294Sstas 0, NULL, &trust_anchors); 523233294Sstas if (ret) { 524233294Sstas krb5_set_error_message(context, ret, "failed to create trust anchors"); 525233294Sstas goto out; 526233294Sstas } 527233294Sstas 528233294Sstas ret = hx509_certs_merge(context->hx509ctx, trust_anchors, 529233294Sstas kdc_identity->anchors); 530233294Sstas if (ret) { 531233294Sstas hx509_certs_free(&trust_anchors); 532233294Sstas krb5_set_error_message(context, ret, "failed to create verify context"); 533233294Sstas goto out; 534233294Sstas } 535233294Sstas 536233294Sstas /* Add any registered certificates for this client as trust anchors */ 537233294Sstas ret = hdb_entry_get_pkinit_cert(&client->entry, &pc); 538233294Sstas if (ret == 0 && pc != NULL) { 539233294Sstas hx509_cert cert; 540233294Sstas unsigned int i; 541233294Sstas 542233294Sstas for (i = 0; i < pc->len; i++) { 543233294Sstas ret = hx509_cert_init_data(context->hx509ctx, 544233294Sstas pc->val[i].cert.data, 545233294Sstas pc->val[i].cert.length, 546233294Sstas &cert); 547233294Sstas if (ret) 548233294Sstas continue; 549233294Sstas hx509_certs_add(context->hx509ctx, trust_anchors, cert); 550233294Sstas hx509_cert_free(cert); 551233294Sstas } 552233294Sstas } 553233294Sstas 554233294Sstas ret = hx509_verify_init_ctx(context->hx509ctx, &cp->verify_ctx); 555233294Sstas if (ret) { 556233294Sstas hx509_certs_free(&trust_anchors); 557233294Sstas krb5_set_error_message(context, ret, "failed to create verify context"); 558233294Sstas goto out; 559233294Sstas } 560233294Sstas 561233294Sstas hx509_verify_set_time(cp->verify_ctx, kdc_time); 562233294Sstas hx509_verify_attach_anchors(cp->verify_ctx, trust_anchors); 563233294Sstas hx509_certs_free(&trust_anchors); 564233294Sstas 565233294Sstas if (config->pkinit_allow_proxy_certs) 566233294Sstas hx509_verify_set_proxy_certificate(cp->verify_ctx, 1); 567233294Sstas 568178825Sdfr if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) { 569178825Sdfr PA_PK_AS_REQ_Win2k r; 570178825Sdfr 571178825Sdfr type = "PK-INIT-Win2k"; 572178825Sdfr 573233294Sstas if (req->req_body.kdc_options.request_anonymous) { 574233294Sstas ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED; 575233294Sstas krb5_set_error_message(context, ret, 576233294Sstas "Anon not supported in RSA mode"); 577233294Sstas goto out; 578233294Sstas } 579233294Sstas 580178825Sdfr ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data, 581178825Sdfr pa->padata_value.length, 582178825Sdfr &r, 583178825Sdfr NULL); 584178825Sdfr if (ret) { 585233294Sstas krb5_set_error_message(context, ret, "Can't decode " 586233294Sstas "PK-AS-REQ-Win2k: %d", ret); 587178825Sdfr goto out; 588178825Sdfr } 589233294Sstas 590178825Sdfr ret = hx509_cms_unwrap_ContentInfo(&r.signed_auth_pack, 591178825Sdfr &contentInfoOid, 592178825Sdfr &signed_content, 593178825Sdfr &have_data); 594178825Sdfr free_PA_PK_AS_REQ_Win2k(&r); 595178825Sdfr if (ret) { 596233294Sstas krb5_set_error_message(context, ret, 597233294Sstas "Can't unwrap ContentInfo(win): %d", ret); 598178825Sdfr goto out; 599178825Sdfr } 600178825Sdfr 601178825Sdfr } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) { 602178825Sdfr PA_PK_AS_REQ r; 603178825Sdfr 604178825Sdfr type = "PK-INIT-IETF"; 605178825Sdfr 606178825Sdfr ret = decode_PA_PK_AS_REQ(pa->padata_value.data, 607178825Sdfr pa->padata_value.length, 608178825Sdfr &r, 609178825Sdfr NULL); 610178825Sdfr if (ret) { 611233294Sstas krb5_set_error_message(context, ret, 612233294Sstas "Can't decode PK-AS-REQ: %d", ret); 613178825Sdfr goto out; 614178825Sdfr } 615233294Sstas 616178825Sdfr /* XXX look at r.kdcPkId */ 617178825Sdfr if (r.trustedCertifiers) { 618178825Sdfr ExternalPrincipalIdentifiers *edi = r.trustedCertifiers; 619233294Sstas unsigned int i, maxedi; 620178825Sdfr 621233294Sstas ret = hx509_certs_init(context->hx509ctx, 622178825Sdfr "MEMORY:client-anchors", 623178825Sdfr 0, NULL, 624233294Sstas &cp->client_anchors); 625178825Sdfr if (ret) { 626233294Sstas krb5_set_error_message(context, ret, 627233294Sstas "Can't allocate client anchors: %d", 628233294Sstas ret); 629178825Sdfr goto out; 630178825Sdfr 631178825Sdfr } 632233294Sstas /* 633233294Sstas * If the client sent more then 10 EDI, don't bother 634233294Sstas * looking more then 10 of performance reasons. 635233294Sstas */ 636233294Sstas maxedi = edi->len; 637233294Sstas if (maxedi > 10) 638233294Sstas maxedi = 10; 639233294Sstas for (i = 0; i < maxedi; i++) { 640178825Sdfr IssuerAndSerialNumber iasn; 641178825Sdfr hx509_query *q; 642178825Sdfr hx509_cert cert; 643178825Sdfr size_t size; 644178825Sdfr 645178825Sdfr if (edi->val[i].issuerAndSerialNumber == NULL) 646178825Sdfr continue; 647178825Sdfr 648233294Sstas ret = hx509_query_alloc(context->hx509ctx, &q); 649178825Sdfr if (ret) { 650233294Sstas krb5_set_error_message(context, ret, 651178825Sdfr "Failed to allocate hx509_query"); 652178825Sdfr goto out; 653178825Sdfr } 654233294Sstas 655178825Sdfr ret = decode_IssuerAndSerialNumber(edi->val[i].issuerAndSerialNumber->data, 656178825Sdfr edi->val[i].issuerAndSerialNumber->length, 657178825Sdfr &iasn, 658178825Sdfr &size); 659178825Sdfr if (ret) { 660233294Sstas hx509_query_free(context->hx509ctx, q); 661178825Sdfr continue; 662178825Sdfr } 663178825Sdfr ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber); 664178825Sdfr free_IssuerAndSerialNumber(&iasn); 665233294Sstas if (ret) { 666233294Sstas hx509_query_free(context->hx509ctx, q); 667178825Sdfr continue; 668233294Sstas } 669178825Sdfr 670233294Sstas ret = hx509_certs_find(context->hx509ctx, 671178825Sdfr kdc_identity->certs, 672178825Sdfr q, 673178825Sdfr &cert); 674233294Sstas hx509_query_free(context->hx509ctx, q); 675178825Sdfr if (ret) 676178825Sdfr continue; 677233294Sstas hx509_certs_add(context->hx509ctx, 678233294Sstas cp->client_anchors, cert); 679178825Sdfr hx509_cert_free(cert); 680178825Sdfr } 681178825Sdfr } 682178825Sdfr 683178825Sdfr ret = hx509_cms_unwrap_ContentInfo(&r.signedAuthPack, 684178825Sdfr &contentInfoOid, 685178825Sdfr &signed_content, 686178825Sdfr &have_data); 687178825Sdfr free_PA_PK_AS_REQ(&r); 688178825Sdfr if (ret) { 689233294Sstas krb5_set_error_message(context, ret, 690233294Sstas "Can't unwrap ContentInfo: %d", ret); 691178825Sdfr goto out; 692178825Sdfr } 693178825Sdfr 694233294Sstas } else { 695233294Sstas krb5_clear_error_message(context); 696178825Sdfr ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 697178825Sdfr goto out; 698178825Sdfr } 699178825Sdfr 700233294Sstas ret = der_heim_oid_cmp(&contentInfoOid, &asn1_oid_id_pkcs7_signedData); 701178825Sdfr if (ret != 0) { 702178825Sdfr ret = KRB5KRB_ERR_GENERIC; 703233294Sstas krb5_set_error_message(context, ret, 704233294Sstas "PK-AS-REQ-Win2k invalid content type oid"); 705178825Sdfr goto out; 706178825Sdfr } 707233294Sstas 708178825Sdfr if (!have_data) { 709233294Sstas ret = KRB5KRB_ERR_GENERIC; 710233294Sstas krb5_set_error_message(context, ret, 711178825Sdfr "PK-AS-REQ-Win2k no signed auth pack"); 712178825Sdfr goto out; 713178825Sdfr } 714178825Sdfr 715178825Sdfr { 716178825Sdfr hx509_certs signer_certs; 717233294Sstas int flags = HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; /* BTMM */ 718178825Sdfr 719233294Sstas if (req->req_body.kdc_options.request_anonymous) 720233294Sstas flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER; 721233294Sstas 722233294Sstas ret = hx509_cms_verify_signed(context->hx509ctx, 723233294Sstas cp->verify_ctx, 724233294Sstas flags, 725178825Sdfr signed_content.data, 726178825Sdfr signed_content.length, 727178825Sdfr NULL, 728178825Sdfr kdc_identity->certpool, 729178825Sdfr &eContentType, 730178825Sdfr &eContent, 731178825Sdfr &signer_certs); 732178825Sdfr if (ret) { 733233294Sstas char *s = hx509_get_error_string(context->hx509ctx, ret); 734178825Sdfr krb5_warnx(context, "PKINIT: failed to verify signature: %s: %d", 735178825Sdfr s, ret); 736178825Sdfr free(s); 737178825Sdfr goto out; 738178825Sdfr } 739178825Sdfr 740233294Sstas if (signer_certs) { 741233294Sstas ret = hx509_get_one_cert(context->hx509ctx, signer_certs, 742233294Sstas &cp->cert); 743233294Sstas hx509_certs_free(&signer_certs); 744233294Sstas } 745178825Sdfr if (ret) 746178825Sdfr goto out; 747178825Sdfr } 748178825Sdfr 749178825Sdfr /* Signature is correct, now verify the signed message */ 750233294Sstas if (der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkcs7_data) != 0 && 751233294Sstas der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkauthdata) != 0) 752178825Sdfr { 753178825Sdfr ret = KRB5_BADMSGTYPE; 754233294Sstas krb5_set_error_message(context, ret, "got wrong oid for pkauthdata"); 755178825Sdfr goto out; 756178825Sdfr } 757178825Sdfr 758178825Sdfr if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) { 759178825Sdfr AuthPack_Win2k ap; 760178825Sdfr 761178825Sdfr ret = decode_AuthPack_Win2k(eContent.data, 762178825Sdfr eContent.length, 763178825Sdfr &ap, 764178825Sdfr NULL); 765178825Sdfr if (ret) { 766233294Sstas krb5_set_error_message(context, ret, 767233294Sstas "Can't decode AuthPack: %d", ret); 768178825Sdfr goto out; 769178825Sdfr } 770233294Sstas 771233294Sstas ret = pk_check_pkauthenticator_win2k(context, 772178825Sdfr &ap.pkAuthenticator, 773178825Sdfr req); 774178825Sdfr if (ret) { 775178825Sdfr free_AuthPack_Win2k(&ap); 776178825Sdfr goto out; 777178825Sdfr } 778178825Sdfr 779233294Sstas cp->type = PKINIT_WIN2K; 780233294Sstas cp->nonce = ap.pkAuthenticator.nonce; 781178825Sdfr 782178825Sdfr if (ap.clientPublicValue) { 783178825Sdfr ret = KRB5KRB_ERR_GENERIC; 784233294Sstas krb5_set_error_message(context, ret, 785233294Sstas "DH not supported for windows"); 786178825Sdfr goto out; 787178825Sdfr } 788178825Sdfr free_AuthPack_Win2k(&ap); 789178825Sdfr 790178825Sdfr } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) { 791178825Sdfr AuthPack ap; 792178825Sdfr 793178825Sdfr ret = decode_AuthPack(eContent.data, 794178825Sdfr eContent.length, 795178825Sdfr &ap, 796178825Sdfr NULL); 797178825Sdfr if (ret) { 798233294Sstas krb5_set_error_message(context, ret, 799233294Sstas "Can't decode AuthPack: %d", ret); 800178825Sdfr free_AuthPack(&ap); 801178825Sdfr goto out; 802178825Sdfr } 803233294Sstas 804233294Sstas if (req->req_body.kdc_options.request_anonymous && 805233294Sstas ap.clientPublicValue == NULL) { 806233294Sstas free_AuthPack(&ap); 807233294Sstas ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED; 808233294Sstas krb5_set_error_message(context, ret, 809233294Sstas "Anon not supported in RSA mode"); 810233294Sstas goto out; 811233294Sstas } 812233294Sstas 813233294Sstas ret = pk_check_pkauthenticator(context, 814178825Sdfr &ap.pkAuthenticator, 815178825Sdfr req); 816178825Sdfr if (ret) { 817178825Sdfr free_AuthPack(&ap); 818178825Sdfr goto out; 819178825Sdfr } 820178825Sdfr 821233294Sstas cp->type = PKINIT_27; 822233294Sstas cp->nonce = ap.pkAuthenticator.nonce; 823178825Sdfr 824178825Sdfr if (ap.clientPublicValue) { 825233294Sstas if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_dhpublicnumber) == 0) { 826233294Sstas cp->keyex = USE_DH; 827233294Sstas ret = get_dh_param(context, config, 828233294Sstas ap.clientPublicValue, cp); 829233294Sstas#ifdef HAVE_OPENSSL 830233294Sstas } else if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_ecPublicKey) == 0) { 831233294Sstas cp->keyex = USE_ECDH; 832233294Sstas ret = get_ecdh_param(context, config, 833233294Sstas ap.clientPublicValue, cp); 834233294Sstas#endif /* HAVE_OPENSSL */ 835233294Sstas } else { 836233294Sstas ret = KRB5_BADMSGTYPE; 837233294Sstas krb5_set_error_message(context, ret, "PKINIT unknown DH mechanism"); 838233294Sstas } 839178825Sdfr if (ret) { 840178825Sdfr free_AuthPack(&ap); 841178825Sdfr goto out; 842178825Sdfr } 843233294Sstas } else 844233294Sstas cp->keyex = USE_RSA; 845233294Sstas 846233294Sstas ret = hx509_peer_info_alloc(context->hx509ctx, 847233294Sstas &cp->peer); 848233294Sstas if (ret) { 849233294Sstas free_AuthPack(&ap); 850233294Sstas goto out; 851178825Sdfr } 852178825Sdfr 853178825Sdfr if (ap.supportedCMSTypes) { 854233294Sstas ret = hx509_peer_info_set_cms_algs(context->hx509ctx, 855233294Sstas cp->peer, 856178825Sdfr ap.supportedCMSTypes->val, 857178825Sdfr ap.supportedCMSTypes->len); 858178825Sdfr if (ret) { 859178825Sdfr free_AuthPack(&ap); 860178825Sdfr goto out; 861178825Sdfr } 862233294Sstas } else { 863233294Sstas /* assume old client */ 864233294Sstas hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer, 865233294Sstas hx509_crypto_des_rsdi_ede3_cbc()); 866233294Sstas hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer, 867233294Sstas hx509_signature_rsa_with_sha1()); 868233294Sstas hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer, 869233294Sstas hx509_signature_sha1()); 870178825Sdfr } 871178825Sdfr free_AuthPack(&ap); 872178825Sdfr } else 873178825Sdfr krb5_abortx(context, "internal pkinit error"); 874178825Sdfr 875178825Sdfr kdc_log(context, config, 0, "PK-INIT request of type %s", type); 876178825Sdfr 877178825Sdfrout: 878178825Sdfr if (ret) 879178825Sdfr krb5_warn(context, ret, "PKINIT"); 880178825Sdfr 881178825Sdfr if (signed_content.data) 882178825Sdfr free(signed_content.data); 883178825Sdfr krb5_data_free(&eContent); 884178825Sdfr der_free_oid(&eContentType); 885178825Sdfr der_free_oid(&contentInfoOid); 886233294Sstas if (ret) { 887233294Sstas _kdc_pk_free_client_param(context, cp); 888233294Sstas } else 889233294Sstas *ret_params = cp; 890178825Sdfr return ret; 891178825Sdfr} 892178825Sdfr 893178825Sdfr/* 894178825Sdfr * 895178825Sdfr */ 896178825Sdfr 897178825Sdfrstatic krb5_error_code 898178825SdfrBN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer) 899178825Sdfr{ 900178825Sdfr integer->length = BN_num_bytes(bn); 901178825Sdfr integer->data = malloc(integer->length); 902178825Sdfr if (integer->data == NULL) { 903233294Sstas krb5_clear_error_message(context); 904178825Sdfr return ENOMEM; 905178825Sdfr } 906178825Sdfr BN_bn2bin(bn, integer->data); 907178825Sdfr integer->negative = BN_is_negative(bn); 908178825Sdfr return 0; 909178825Sdfr} 910178825Sdfr 911178825Sdfrstatic krb5_error_code 912178825Sdfrpk_mk_pa_reply_enckey(krb5_context context, 913178825Sdfr krb5_kdc_configuration *config, 914233294Sstas pk_client_params *cp, 915178825Sdfr const KDC_REQ *req, 916178825Sdfr const krb5_data *req_buffer, 917178825Sdfr krb5_keyblock *reply_key, 918233294Sstas ContentInfo *content_info, 919233294Sstas hx509_cert *kdc_cert) 920178825Sdfr{ 921233294Sstas const heim_oid *envelopedAlg = NULL, *sdAlg = NULL, *evAlg = NULL; 922178825Sdfr krb5_error_code ret; 923178825Sdfr krb5_data buf, signed_data; 924233294Sstas size_t size = 0; 925178825Sdfr int do_win2k = 0; 926178825Sdfr 927178825Sdfr krb5_data_zero(&buf); 928178825Sdfr krb5_data_zero(&signed_data); 929178825Sdfr 930233294Sstas *kdc_cert = NULL; 931233294Sstas 932178825Sdfr /* 933178825Sdfr * If the message client is a win2k-type but it send pa data 934178825Sdfr * 09-binding it expects a IETF (checksum) reply so there can be 935178825Sdfr * no replay attacks. 936178825Sdfr */ 937178825Sdfr 938233294Sstas switch (cp->type) { 939233294Sstas case PKINIT_WIN2K: { 940178825Sdfr int i = 0; 941178825Sdfr if (_kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_09_BINDING) == NULL 942178825Sdfr && config->pkinit_require_binding == 0) 943178825Sdfr { 944178825Sdfr do_win2k = 1; 945178825Sdfr } 946233294Sstas sdAlg = &asn1_oid_id_pkcs7_data; 947233294Sstas evAlg = &asn1_oid_id_pkcs7_data; 948233294Sstas envelopedAlg = &asn1_oid_id_rsadsi_des_ede3_cbc; 949178825Sdfr break; 950178825Sdfr } 951233294Sstas case PKINIT_27: 952233294Sstas sdAlg = &asn1_oid_id_pkrkeydata; 953233294Sstas evAlg = &asn1_oid_id_pkcs7_signedData; 954178825Sdfr break; 955178825Sdfr default: 956178825Sdfr krb5_abortx(context, "internal pkinit error"); 957233294Sstas } 958178825Sdfr 959178825Sdfr if (do_win2k) { 960178825Sdfr ReplyKeyPack_Win2k kp; 961178825Sdfr memset(&kp, 0, sizeof(kp)); 962178825Sdfr 963178825Sdfr ret = copy_EncryptionKey(reply_key, &kp.replyKey); 964178825Sdfr if (ret) { 965233294Sstas krb5_clear_error_message(context); 966178825Sdfr goto out; 967178825Sdfr } 968233294Sstas kp.nonce = cp->nonce; 969233294Sstas 970233294Sstas ASN1_MALLOC_ENCODE(ReplyKeyPack_Win2k, 971178825Sdfr buf.data, buf.length, 972178825Sdfr &kp, &size,ret); 973178825Sdfr free_ReplyKeyPack_Win2k(&kp); 974178825Sdfr } else { 975178825Sdfr krb5_crypto ascrypto; 976178825Sdfr ReplyKeyPack kp; 977178825Sdfr memset(&kp, 0, sizeof(kp)); 978178825Sdfr 979178825Sdfr ret = copy_EncryptionKey(reply_key, &kp.replyKey); 980178825Sdfr if (ret) { 981233294Sstas krb5_clear_error_message(context); 982178825Sdfr goto out; 983178825Sdfr } 984178825Sdfr 985178825Sdfr ret = krb5_crypto_init(context, reply_key, 0, &ascrypto); 986178825Sdfr if (ret) { 987233294Sstas krb5_clear_error_message(context); 988178825Sdfr goto out; 989178825Sdfr } 990178825Sdfr 991178825Sdfr ret = krb5_create_checksum(context, ascrypto, 6, 0, 992178825Sdfr req_buffer->data, req_buffer->length, 993178825Sdfr &kp.asChecksum); 994178825Sdfr if (ret) { 995233294Sstas krb5_clear_error_message(context); 996178825Sdfr goto out; 997178825Sdfr } 998233294Sstas 999178825Sdfr ret = krb5_crypto_destroy(context, ascrypto); 1000178825Sdfr if (ret) { 1001233294Sstas krb5_clear_error_message(context); 1002178825Sdfr goto out; 1003178825Sdfr } 1004178825Sdfr ASN1_MALLOC_ENCODE(ReplyKeyPack, buf.data, buf.length, &kp, &size,ret); 1005178825Sdfr free_ReplyKeyPack(&kp); 1006178825Sdfr } 1007178825Sdfr if (ret) { 1008233294Sstas krb5_set_error_message(context, ret, "ASN.1 encoding of ReplyKeyPack " 1009233294Sstas "failed (%d)", ret); 1010178825Sdfr goto out; 1011178825Sdfr } 1012178825Sdfr if (buf.length != size) 1013178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 1014178825Sdfr 1015178825Sdfr { 1016178825Sdfr hx509_query *q; 1017178825Sdfr hx509_cert cert; 1018233294Sstas 1019233294Sstas ret = hx509_query_alloc(context->hx509ctx, &q); 1020178825Sdfr if (ret) 1021178825Sdfr goto out; 1022233294Sstas 1023178825Sdfr hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); 1024233294Sstas if (config->pkinit_kdc_friendly_name) 1025233294Sstas hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name); 1026233294Sstas 1027233294Sstas ret = hx509_certs_find(context->hx509ctx, 1028233294Sstas kdc_identity->certs, 1029233294Sstas q, 1030178825Sdfr &cert); 1031233294Sstas hx509_query_free(context->hx509ctx, q); 1032178825Sdfr if (ret) 1033178825Sdfr goto out; 1034233294Sstas 1035233294Sstas ret = hx509_cms_create_signed_1(context->hx509ctx, 1036178825Sdfr 0, 1037178825Sdfr sdAlg, 1038178825Sdfr buf.data, 1039178825Sdfr buf.length, 1040178825Sdfr NULL, 1041178825Sdfr cert, 1042233294Sstas cp->peer, 1043233294Sstas cp->client_anchors, 1044178825Sdfr kdc_identity->certpool, 1045178825Sdfr &signed_data); 1046233294Sstas *kdc_cert = cert; 1047178825Sdfr } 1048178825Sdfr 1049178825Sdfr krb5_data_free(&buf); 1050233294Sstas if (ret) 1051178825Sdfr goto out; 1052178825Sdfr 1053233294Sstas if (cp->type == PKINIT_WIN2K) { 1054233294Sstas ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData, 1055178825Sdfr &signed_data, 1056178825Sdfr &buf); 1057178825Sdfr if (ret) 1058178825Sdfr goto out; 1059178825Sdfr krb5_data_free(&signed_data); 1060178825Sdfr signed_data = buf; 1061178825Sdfr } 1062178825Sdfr 1063233294Sstas ret = hx509_cms_envelope_1(context->hx509ctx, 1064233294Sstas HX509_CMS_EV_NO_KU_CHECK, 1065233294Sstas cp->cert, 1066233294Sstas signed_data.data, signed_data.length, 1067178825Sdfr envelopedAlg, 1068233294Sstas evAlg, &buf); 1069178825Sdfr if (ret) 1070178825Sdfr goto out; 1071233294Sstas 1072178825Sdfr ret = _krb5_pk_mk_ContentInfo(context, 1073178825Sdfr &buf, 1074233294Sstas &asn1_oid_id_pkcs7_envelopedData, 1075178825Sdfr content_info); 1076178825Sdfrout: 1077233294Sstas if (ret && *kdc_cert) { 1078233294Sstas hx509_cert_free(*kdc_cert); 1079233294Sstas *kdc_cert = NULL; 1080233294Sstas } 1081233294Sstas 1082178825Sdfr krb5_data_free(&buf); 1083178825Sdfr krb5_data_free(&signed_data); 1084178825Sdfr return ret; 1085178825Sdfr} 1086178825Sdfr 1087178825Sdfr/* 1088178825Sdfr * 1089178825Sdfr */ 1090178825Sdfr 1091178825Sdfrstatic krb5_error_code 1092178825Sdfrpk_mk_pa_reply_dh(krb5_context context, 1093233294Sstas krb5_kdc_configuration *config, 1094233294Sstas pk_client_params *cp, 1095178825Sdfr ContentInfo *content_info, 1096178825Sdfr hx509_cert *kdc_cert) 1097178825Sdfr{ 1098178825Sdfr KDCDHKeyInfo dh_info; 1099178825Sdfr krb5_data signed_data, buf; 1100178825Sdfr ContentInfo contentinfo; 1101178825Sdfr krb5_error_code ret; 1102233294Sstas hx509_cert cert; 1103233294Sstas hx509_query *q; 1104233294Sstas size_t size = 0; 1105178825Sdfr 1106178825Sdfr memset(&contentinfo, 0, sizeof(contentinfo)); 1107178825Sdfr memset(&dh_info, 0, sizeof(dh_info)); 1108233294Sstas krb5_data_zero(&signed_data); 1109178825Sdfr krb5_data_zero(&buf); 1110178825Sdfr 1111178825Sdfr *kdc_cert = NULL; 1112178825Sdfr 1113233294Sstas if (cp->keyex == USE_DH) { 1114233294Sstas DH *kdc_dh = cp->u.dh.key; 1115233294Sstas heim_integer i; 1116178825Sdfr 1117233294Sstas ret = BN_to_integer(context, kdc_dh->pub_key, &i); 1118233294Sstas if (ret) 1119233294Sstas return ret; 1120178825Sdfr 1121233294Sstas ASN1_MALLOC_ENCODE(DHPublicKey, buf.data, buf.length, &i, &size, ret); 1122233294Sstas der_free_heim_integer(&i); 1123233294Sstas if (ret) { 1124233294Sstas krb5_set_error_message(context, ret, "ASN.1 encoding of " 1125233294Sstas "DHPublicKey failed (%d)", ret); 1126233294Sstas return ret; 1127233294Sstas } 1128233294Sstas if (buf.length != size) 1129233294Sstas krb5_abortx(context, "Internal ASN.1 encoder error"); 1130178825Sdfr 1131233294Sstas dh_info.subjectPublicKey.length = buf.length * 8; 1132233294Sstas dh_info.subjectPublicKey.data = buf.data; 1133233294Sstas krb5_data_zero(&buf); 1134233294Sstas#ifdef HAVE_OPENSSL 1135233294Sstas } else if (cp->keyex == USE_ECDH) { 1136233294Sstas unsigned char *p; 1137233294Sstas int len; 1138233294Sstas 1139233294Sstas len = i2o_ECPublicKey(cp->u.ecdh.key, NULL); 1140233294Sstas if (len <= 0) 1141233294Sstas abort(); 1142233294Sstas 1143233294Sstas p = malloc(len); 1144233294Sstas if (p == NULL) 1145233294Sstas abort(); 1146233294Sstas 1147233294Sstas dh_info.subjectPublicKey.length = len * 8; 1148233294Sstas dh_info.subjectPublicKey.data = p; 1149233294Sstas 1150233294Sstas len = i2o_ECPublicKey(cp->u.ecdh.key, &p); 1151233294Sstas if (len <= 0) 1152233294Sstas abort(); 1153233294Sstas#endif 1154233294Sstas } else 1155233294Sstas krb5_abortx(context, "no keyex selected ?"); 1156233294Sstas 1157233294Sstas 1158233294Sstas dh_info.nonce = cp->nonce; 1159233294Sstas 1160233294Sstas ASN1_MALLOC_ENCODE(KDCDHKeyInfo, buf.data, buf.length, &dh_info, &size, 1161178825Sdfr ret); 1162178825Sdfr if (ret) { 1163233294Sstas krb5_set_error_message(context, ret, "ASN.1 encoding of " 1164233294Sstas "KdcDHKeyInfo failed (%d)", ret); 1165178825Sdfr goto out; 1166178825Sdfr } 1167178825Sdfr if (buf.length != size) 1168178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 1169178825Sdfr 1170233294Sstas /* 1171178825Sdfr * Create the SignedData structure and sign the KdcDHKeyInfo 1172178825Sdfr * filled in above 1173178825Sdfr */ 1174178825Sdfr 1175233294Sstas ret = hx509_query_alloc(context->hx509ctx, &q); 1176178825Sdfr if (ret) 1177178825Sdfr goto out; 1178178825Sdfr 1179233294Sstas hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); 1180233294Sstas if (config->pkinit_kdc_friendly_name) 1181233294Sstas hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name); 1182233294Sstas 1183233294Sstas ret = hx509_certs_find(context->hx509ctx, 1184233294Sstas kdc_identity->certs, 1185233294Sstas q, 1186233294Sstas &cert); 1187233294Sstas hx509_query_free(context->hx509ctx, q); 1188233294Sstas if (ret) 1189233294Sstas goto out; 1190233294Sstas 1191233294Sstas ret = hx509_cms_create_signed_1(context->hx509ctx, 1192233294Sstas 0, 1193233294Sstas &asn1_oid_id_pkdhkeydata, 1194233294Sstas buf.data, 1195233294Sstas buf.length, 1196233294Sstas NULL, 1197233294Sstas cert, 1198233294Sstas cp->peer, 1199233294Sstas cp->client_anchors, 1200233294Sstas kdc_identity->certpool, 1201233294Sstas &signed_data); 1202233294Sstas if (ret) { 1203233294Sstas kdc_log(context, config, 0, "Failed signing the DH* reply: %d", ret); 1204233294Sstas goto out; 1205233294Sstas } 1206233294Sstas *kdc_cert = cert; 1207233294Sstas 1208178825Sdfr ret = _krb5_pk_mk_ContentInfo(context, 1209178825Sdfr &signed_data, 1210233294Sstas &asn1_oid_id_pkcs7_signedData, 1211178825Sdfr content_info); 1212178825Sdfr if (ret) 1213178825Sdfr goto out; 1214178825Sdfr 1215178825Sdfr out: 1216178825Sdfr if (ret && *kdc_cert) { 1217178825Sdfr hx509_cert_free(*kdc_cert); 1218178825Sdfr *kdc_cert = NULL; 1219178825Sdfr } 1220178825Sdfr 1221178825Sdfr krb5_data_free(&buf); 1222178825Sdfr krb5_data_free(&signed_data); 1223178825Sdfr free_KDCDHKeyInfo(&dh_info); 1224178825Sdfr 1225178825Sdfr return ret; 1226178825Sdfr} 1227178825Sdfr 1228178825Sdfr/* 1229178825Sdfr * 1230178825Sdfr */ 1231178825Sdfr 1232178825Sdfrkrb5_error_code 1233178825Sdfr_kdc_pk_mk_pa_reply(krb5_context context, 1234178825Sdfr krb5_kdc_configuration *config, 1235233294Sstas pk_client_params *cp, 1236178825Sdfr const hdb_entry_ex *client, 1237233294Sstas krb5_enctype sessionetype, 1238178825Sdfr const KDC_REQ *req, 1239178825Sdfr const krb5_data *req_buffer, 1240178825Sdfr krb5_keyblock **reply_key, 1241233294Sstas krb5_keyblock *sessionkey, 1242178825Sdfr METHOD_DATA *md) 1243178825Sdfr{ 1244178825Sdfr krb5_error_code ret; 1245233294Sstas void *buf = NULL; 1246233294Sstas size_t len = 0, size = 0; 1247178825Sdfr krb5_enctype enctype; 1248178825Sdfr int pa_type; 1249178825Sdfr hx509_cert kdc_cert = NULL; 1250233294Sstas size_t i; 1251178825Sdfr 1252178825Sdfr if (!config->enable_pkinit) { 1253233294Sstas krb5_clear_error_message(context); 1254178825Sdfr return 0; 1255178825Sdfr } 1256178825Sdfr 1257178825Sdfr if (req->req_body.etype.len > 0) { 1258178825Sdfr for (i = 0; i < req->req_body.etype.len; i++) 1259178825Sdfr if (krb5_enctype_valid(context, req->req_body.etype.val[i]) == 0) 1260178825Sdfr break; 1261178825Sdfr if (req->req_body.etype.len <= i) { 1262178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1263233294Sstas krb5_set_error_message(context, ret, 1264233294Sstas "No valid enctype available from client"); 1265178825Sdfr goto out; 1266233294Sstas } 1267178825Sdfr enctype = req->req_body.etype.val[i]; 1268178825Sdfr } else 1269178825Sdfr enctype = ETYPE_DES3_CBC_SHA1; 1270178825Sdfr 1271233294Sstas if (cp->type == PKINIT_27) { 1272178825Sdfr PA_PK_AS_REP rep; 1273178825Sdfr const char *type, *other = ""; 1274178825Sdfr 1275178825Sdfr memset(&rep, 0, sizeof(rep)); 1276178825Sdfr 1277178825Sdfr pa_type = KRB5_PADATA_PK_AS_REP; 1278178825Sdfr 1279233294Sstas if (cp->keyex == USE_RSA) { 1280178825Sdfr ContentInfo info; 1281178825Sdfr 1282178825Sdfr type = "enckey"; 1283178825Sdfr 1284178825Sdfr rep.element = choice_PA_PK_AS_REP_encKeyPack; 1285178825Sdfr 1286233294Sstas ret = krb5_generate_random_keyblock(context, enctype, 1287233294Sstas &cp->reply_key); 1288178825Sdfr if (ret) { 1289178825Sdfr free_PA_PK_AS_REP(&rep); 1290178825Sdfr goto out; 1291178825Sdfr } 1292178825Sdfr ret = pk_mk_pa_reply_enckey(context, 1293178825Sdfr config, 1294233294Sstas cp, 1295178825Sdfr req, 1296178825Sdfr req_buffer, 1297233294Sstas &cp->reply_key, 1298233294Sstas &info, 1299233294Sstas &kdc_cert); 1300178825Sdfr if (ret) { 1301178825Sdfr free_PA_PK_AS_REP(&rep); 1302178825Sdfr goto out; 1303178825Sdfr } 1304233294Sstas ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data, 1305233294Sstas rep.u.encKeyPack.length, &info, &size, 1306178825Sdfr ret); 1307178825Sdfr free_ContentInfo(&info); 1308178825Sdfr if (ret) { 1309233294Sstas krb5_set_error_message(context, ret, "encoding of Key ContentInfo " 1310233294Sstas "failed %d", ret); 1311178825Sdfr free_PA_PK_AS_REP(&rep); 1312178825Sdfr goto out; 1313178825Sdfr } 1314178825Sdfr if (rep.u.encKeyPack.length != size) 1315178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 1316178825Sdfr 1317233294Sstas ret = krb5_generate_random_keyblock(context, sessionetype, 1318233294Sstas sessionkey); 1319233294Sstas if (ret) { 1320233294Sstas free_PA_PK_AS_REP(&rep); 1321233294Sstas goto out; 1322233294Sstas } 1323233294Sstas 1324178825Sdfr } else { 1325178825Sdfr ContentInfo info; 1326178825Sdfr 1327233294Sstas switch (cp->keyex) { 1328233294Sstas case USE_DH: type = "dh"; break; 1329233294Sstas#ifdef HAVE_OPENSSL 1330233294Sstas case USE_ECDH: type = "ecdh"; break; 1331233294Sstas#endif 1332233294Sstas default: krb5_abortx(context, "unknown keyex"); break; 1333233294Sstas } 1334178825Sdfr 1335233294Sstas if (cp->dh_group_name) 1336233294Sstas other = cp->dh_group_name; 1337233294Sstas 1338178825Sdfr rep.element = choice_PA_PK_AS_REP_dhInfo; 1339178825Sdfr 1340233294Sstas ret = generate_dh_keyblock(context, cp, enctype); 1341178825Sdfr if (ret) 1342178825Sdfr return ret; 1343178825Sdfr 1344233294Sstas ret = pk_mk_pa_reply_dh(context, config, 1345233294Sstas cp, 1346178825Sdfr &info, 1347178825Sdfr &kdc_cert); 1348233294Sstas if (ret) { 1349233294Sstas free_PA_PK_AS_REP(&rep); 1350233294Sstas krb5_set_error_message(context, ret, 1351233294Sstas "create pa-reply-dh " 1352233294Sstas "failed %d", ret); 1353233294Sstas goto out; 1354233294Sstas } 1355178825Sdfr 1356178825Sdfr ASN1_MALLOC_ENCODE(ContentInfo, rep.u.dhInfo.dhSignedData.data, 1357178825Sdfr rep.u.dhInfo.dhSignedData.length, &info, &size, 1358178825Sdfr ret); 1359178825Sdfr free_ContentInfo(&info); 1360178825Sdfr if (ret) { 1361233294Sstas krb5_set_error_message(context, ret, 1362233294Sstas "encoding of Key ContentInfo " 1363233294Sstas "failed %d", ret); 1364178825Sdfr free_PA_PK_AS_REP(&rep); 1365178825Sdfr goto out; 1366178825Sdfr } 1367178825Sdfr if (rep.u.encKeyPack.length != size) 1368178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 1369178825Sdfr 1370233294Sstas /* XXX KRB-FX-CF2 */ 1371233294Sstas ret = krb5_generate_random_keyblock(context, sessionetype, 1372233294Sstas sessionkey); 1373233294Sstas if (ret) { 1374233294Sstas free_PA_PK_AS_REP(&rep); 1375233294Sstas goto out; 1376233294Sstas } 1377233294Sstas 1378233294Sstas /* XXX Add PA-PKINIT-KX */ 1379233294Sstas 1380178825Sdfr } 1381233294Sstas 1382233294Sstas#define use_btmm_with_enckey 0 1383233294Sstas if (use_btmm_with_enckey && rep.element == choice_PA_PK_AS_REP_encKeyPack) { 1384233294Sstas PA_PK_AS_REP_BTMM btmm; 1385233294Sstas heim_any any; 1386233294Sstas 1387233294Sstas any.data = rep.u.encKeyPack.data; 1388233294Sstas any.length = rep.u.encKeyPack.length; 1389233294Sstas 1390233294Sstas btmm.dhSignedData = NULL; 1391233294Sstas btmm.encKeyPack = &any; 1392233294Sstas 1393233294Sstas ASN1_MALLOC_ENCODE(PA_PK_AS_REP_BTMM, buf, len, &btmm, &size, ret); 1394233294Sstas } else { 1395233294Sstas ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret); 1396178825Sdfr } 1397178825Sdfr 1398178825Sdfr free_PA_PK_AS_REP(&rep); 1399178825Sdfr if (ret) { 1400233294Sstas krb5_set_error_message(context, ret, 1401233294Sstas "encode PA-PK-AS-REP failed %d", ret); 1402178825Sdfr goto out; 1403178825Sdfr } 1404178825Sdfr if (len != size) 1405178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 1406178825Sdfr 1407178825Sdfr kdc_log(context, config, 0, "PK-INIT using %s %s", type, other); 1408178825Sdfr 1409233294Sstas } else if (cp->type == PKINIT_WIN2K) { 1410178825Sdfr PA_PK_AS_REP_Win2k rep; 1411178825Sdfr ContentInfo info; 1412178825Sdfr 1413233294Sstas if (cp->keyex != USE_RSA) { 1414178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1415233294Sstas krb5_set_error_message(context, ret, 1416233294Sstas "Windows PK-INIT doesn't support DH"); 1417178825Sdfr goto out; 1418178825Sdfr } 1419178825Sdfr 1420178825Sdfr memset(&rep, 0, sizeof(rep)); 1421178825Sdfr 1422178825Sdfr pa_type = KRB5_PADATA_PK_AS_REP_19; 1423233294Sstas rep.element = choice_PA_PK_AS_REP_Win2k_encKeyPack; 1424178825Sdfr 1425233294Sstas ret = krb5_generate_random_keyblock(context, enctype, 1426233294Sstas &cp->reply_key); 1427178825Sdfr if (ret) { 1428178825Sdfr free_PA_PK_AS_REP_Win2k(&rep); 1429178825Sdfr goto out; 1430178825Sdfr } 1431178825Sdfr ret = pk_mk_pa_reply_enckey(context, 1432178825Sdfr config, 1433233294Sstas cp, 1434178825Sdfr req, 1435178825Sdfr req_buffer, 1436233294Sstas &cp->reply_key, 1437233294Sstas &info, 1438233294Sstas &kdc_cert); 1439178825Sdfr if (ret) { 1440178825Sdfr free_PA_PK_AS_REP_Win2k(&rep); 1441178825Sdfr goto out; 1442178825Sdfr } 1443233294Sstas ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data, 1444233294Sstas rep.u.encKeyPack.length, &info, &size, 1445178825Sdfr ret); 1446178825Sdfr free_ContentInfo(&info); 1447178825Sdfr if (ret) { 1448233294Sstas krb5_set_error_message(context, ret, "encoding of Key ContentInfo " 1449178825Sdfr "failed %d", ret); 1450178825Sdfr free_PA_PK_AS_REP_Win2k(&rep); 1451178825Sdfr goto out; 1452178825Sdfr } 1453178825Sdfr if (rep.u.encKeyPack.length != size) 1454178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 1455178825Sdfr 1456178825Sdfr ASN1_MALLOC_ENCODE(PA_PK_AS_REP_Win2k, buf, len, &rep, &size, ret); 1457178825Sdfr free_PA_PK_AS_REP_Win2k(&rep); 1458178825Sdfr if (ret) { 1459233294Sstas krb5_set_error_message(context, ret, 1460178825Sdfr "encode PA-PK-AS-REP-Win2k failed %d", ret); 1461178825Sdfr goto out; 1462178825Sdfr } 1463178825Sdfr if (len != size) 1464178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 1465178825Sdfr 1466233294Sstas ret = krb5_generate_random_keyblock(context, sessionetype, 1467233294Sstas sessionkey); 1468233294Sstas if (ret) { 1469233294Sstas free(buf); 1470233294Sstas goto out; 1471233294Sstas } 1472233294Sstas 1473178825Sdfr } else 1474178825Sdfr krb5_abortx(context, "PK-INIT internal error"); 1475178825Sdfr 1476178825Sdfr 1477178825Sdfr ret = krb5_padata_add(context, md, pa_type, buf, len); 1478178825Sdfr if (ret) { 1479233294Sstas krb5_set_error_message(context, ret, 1480233294Sstas "Failed adding PA-PK-AS-REP %d", ret); 1481178825Sdfr free(buf); 1482178825Sdfr goto out; 1483178825Sdfr } 1484178825Sdfr 1485178825Sdfr if (config->pkinit_kdc_ocsp_file) { 1486178825Sdfr 1487178825Sdfr if (ocsp.expire == 0 && ocsp.next_update > kdc_time) { 1488178825Sdfr struct stat sb; 1489178825Sdfr int fd; 1490178825Sdfr 1491178825Sdfr krb5_data_free(&ocsp.data); 1492178825Sdfr 1493178825Sdfr ocsp.expire = 0; 1494178825Sdfr ocsp.next_update = kdc_time + 60 * 5; 1495178825Sdfr 1496178825Sdfr fd = open(config->pkinit_kdc_ocsp_file, O_RDONLY); 1497178825Sdfr if (fd < 0) { 1498233294Sstas kdc_log(context, config, 0, 1499178825Sdfr "PK-INIT failed to open ocsp data file %d", errno); 1500178825Sdfr goto out_ocsp; 1501178825Sdfr } 1502178825Sdfr ret = fstat(fd, &sb); 1503178825Sdfr if (ret) { 1504178825Sdfr ret = errno; 1505178825Sdfr close(fd); 1506233294Sstas kdc_log(context, config, 0, 1507178825Sdfr "PK-INIT failed to stat ocsp data %d", ret); 1508178825Sdfr goto out_ocsp; 1509178825Sdfr } 1510233294Sstas 1511178825Sdfr ret = krb5_data_alloc(&ocsp.data, sb.st_size); 1512178825Sdfr if (ret) { 1513178825Sdfr close(fd); 1514233294Sstas kdc_log(context, config, 0, 1515178825Sdfr "PK-INIT failed to stat ocsp data %d", ret); 1516178825Sdfr goto out_ocsp; 1517178825Sdfr } 1518178825Sdfr ocsp.data.length = sb.st_size; 1519178825Sdfr ret = read(fd, ocsp.data.data, sb.st_size); 1520178825Sdfr close(fd); 1521178825Sdfr if (ret != sb.st_size) { 1522233294Sstas kdc_log(context, config, 0, 1523178825Sdfr "PK-INIT failed to read ocsp data %d", errno); 1524178825Sdfr goto out_ocsp; 1525178825Sdfr } 1526178825Sdfr 1527233294Sstas ret = hx509_ocsp_verify(context->hx509ctx, 1528178825Sdfr kdc_time, 1529178825Sdfr kdc_cert, 1530178825Sdfr 0, 1531178825Sdfr ocsp.data.data, ocsp.data.length, 1532178825Sdfr &ocsp.expire); 1533178825Sdfr if (ret) { 1534233294Sstas kdc_log(context, config, 0, 1535178825Sdfr "PK-INIT failed to verify ocsp data %d", ret); 1536178825Sdfr krb5_data_free(&ocsp.data); 1537178825Sdfr ocsp.expire = 0; 1538178825Sdfr } else if (ocsp.expire > 180) { 1539178825Sdfr ocsp.expire -= 180; /* refetch the ocsp before it expire */ 1540178825Sdfr ocsp.next_update = ocsp.expire; 1541178825Sdfr } else { 1542178825Sdfr ocsp.next_update = kdc_time; 1543178825Sdfr } 1544178825Sdfr out_ocsp: 1545178825Sdfr ret = 0; 1546178825Sdfr } 1547178825Sdfr 1548178825Sdfr if (ocsp.expire != 0 && ocsp.expire > kdc_time) { 1549178825Sdfr 1550233294Sstas ret = krb5_padata_add(context, md, 1551178825Sdfr KRB5_PADATA_PA_PK_OCSP_RESPONSE, 1552178825Sdfr ocsp.data.data, ocsp.data.length); 1553178825Sdfr if (ret) { 1554233294Sstas krb5_set_error_message(context, ret, 1555233294Sstas "Failed adding OCSP response %d", ret); 1556178825Sdfr goto out; 1557178825Sdfr } 1558178825Sdfr } 1559178825Sdfr } 1560178825Sdfr 1561178825Sdfrout: 1562178825Sdfr if (kdc_cert) 1563178825Sdfr hx509_cert_free(kdc_cert); 1564178825Sdfr 1565178825Sdfr if (ret == 0) 1566233294Sstas *reply_key = &cp->reply_key; 1567178825Sdfr return ret; 1568178825Sdfr} 1569178825Sdfr 1570178825Sdfrstatic int 1571233294Sstasmatch_rfc_san(krb5_context context, 1572178825Sdfr krb5_kdc_configuration *config, 1573178825Sdfr hx509_context hx509ctx, 1574233294Sstas hx509_cert client_cert, 1575178825Sdfr krb5_const_principal match) 1576178825Sdfr{ 1577178825Sdfr hx509_octet_string_list list; 1578233294Sstas int ret, found = 0; 1579233294Sstas size_t i; 1580178825Sdfr 1581178825Sdfr memset(&list, 0 , sizeof(list)); 1582178825Sdfr 1583178825Sdfr ret = hx509_cert_find_subjectAltName_otherName(hx509ctx, 1584178825Sdfr client_cert, 1585233294Sstas &asn1_oid_id_pkinit_san, 1586178825Sdfr &list); 1587178825Sdfr if (ret) 1588178825Sdfr goto out; 1589178825Sdfr 1590178825Sdfr for (i = 0; !found && i < list.len; i++) { 1591178825Sdfr krb5_principal_data principal; 1592178825Sdfr KRB5PrincipalName kn; 1593178825Sdfr size_t size; 1594178825Sdfr 1595233294Sstas ret = decode_KRB5PrincipalName(list.val[i].data, 1596178825Sdfr list.val[i].length, 1597178825Sdfr &kn, &size); 1598178825Sdfr if (ret) { 1599233294Sstas const char *msg = krb5_get_error_message(context, ret); 1600178825Sdfr kdc_log(context, config, 0, 1601233294Sstas "Decoding kerberos name in certificate failed: %s", msg); 1602233294Sstas krb5_free_error_message(context, msg); 1603178825Sdfr break; 1604178825Sdfr } 1605178825Sdfr if (size != list.val[i].length) { 1606178825Sdfr kdc_log(context, config, 0, 1607178825Sdfr "Decoding kerberos name have extra bits on the end"); 1608178825Sdfr return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; 1609178825Sdfr } 1610178825Sdfr 1611178825Sdfr principal.name = kn.principalName; 1612178825Sdfr principal.realm = kn.realm; 1613178825Sdfr 1614178825Sdfr if (krb5_principal_compare(context, &principal, match) == TRUE) 1615178825Sdfr found = 1; 1616178825Sdfr free_KRB5PrincipalName(&kn); 1617178825Sdfr } 1618178825Sdfr 1619178825Sdfrout: 1620233294Sstas hx509_free_octet_string_list(&list); 1621178825Sdfr if (ret) 1622178825Sdfr return ret; 1623178825Sdfr 1624178825Sdfr if (!found) 1625178825Sdfr return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; 1626178825Sdfr 1627178825Sdfr return 0; 1628178825Sdfr} 1629178825Sdfr 1630178825Sdfrstatic int 1631233294Sstasmatch_ms_upn_san(krb5_context context, 1632178825Sdfr krb5_kdc_configuration *config, 1633178825Sdfr hx509_context hx509ctx, 1634233294Sstas hx509_cert client_cert, 1635233294Sstas HDB *clientdb, 1636233294Sstas hdb_entry_ex *client) 1637178825Sdfr{ 1638178825Sdfr hx509_octet_string_list list; 1639178825Sdfr krb5_principal principal = NULL; 1640233294Sstas int ret; 1641178825Sdfr MS_UPN_SAN upn; 1642178825Sdfr size_t size; 1643178825Sdfr 1644178825Sdfr memset(&list, 0 , sizeof(list)); 1645178825Sdfr 1646178825Sdfr ret = hx509_cert_find_subjectAltName_otherName(hx509ctx, 1647178825Sdfr client_cert, 1648233294Sstas &asn1_oid_id_pkinit_ms_san, 1649178825Sdfr &list); 1650178825Sdfr if (ret) 1651178825Sdfr goto out; 1652178825Sdfr 1653178825Sdfr if (list.len != 1) { 1654178825Sdfr kdc_log(context, config, 0, 1655178825Sdfr "More then one PK-INIT MS UPN SAN"); 1656178825Sdfr goto out; 1657178825Sdfr } 1658178825Sdfr 1659178825Sdfr ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length, &upn, &size); 1660178825Sdfr if (ret) { 1661178825Sdfr kdc_log(context, config, 0, "Decode of MS-UPN-SAN failed"); 1662178825Sdfr goto out; 1663178825Sdfr } 1664233294Sstas if (size != list.val[0].length) { 1665233294Sstas free_MS_UPN_SAN(&upn); 1666233294Sstas kdc_log(context, config, 0, "Trailing data in "); 1667233294Sstas ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; 1668233294Sstas goto out; 1669233294Sstas } 1670178825Sdfr 1671178825Sdfr kdc_log(context, config, 0, "found MS UPN SAN: %s", upn); 1672178825Sdfr 1673178825Sdfr ret = krb5_parse_name(context, upn, &principal); 1674178825Sdfr free_MS_UPN_SAN(&upn); 1675178825Sdfr if (ret) { 1676178825Sdfr kdc_log(context, config, 0, "Failed to parse principal in MS UPN SAN"); 1677178825Sdfr goto out; 1678178825Sdfr } 1679178825Sdfr 1680233294Sstas if (clientdb->hdb_check_pkinit_ms_upn_match) { 1681233294Sstas ret = clientdb->hdb_check_pkinit_ms_upn_match(context, clientdb, client, principal); 1682233294Sstas } else { 1683178825Sdfr 1684233294Sstas /* 1685233294Sstas * This is very wrong, but will do for a fallback 1686233294Sstas */ 1687233294Sstas strupr(principal->realm); 1688178825Sdfr 1689233294Sstas if (krb5_principal_compare(context, principal, client->entry.principal) == FALSE) 1690233294Sstas ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; 1691233294Sstas } 1692233294Sstas 1693178825Sdfrout: 1694178825Sdfr if (principal) 1695178825Sdfr krb5_free_principal(context, principal); 1696233294Sstas hx509_free_octet_string_list(&list); 1697178825Sdfr 1698233294Sstas return ret; 1699178825Sdfr} 1700178825Sdfr 1701178825Sdfrkrb5_error_code 1702178825Sdfr_kdc_pk_check_client(krb5_context context, 1703178825Sdfr krb5_kdc_configuration *config, 1704233294Sstas HDB *clientdb, 1705233294Sstas hdb_entry_ex *client, 1706233294Sstas pk_client_params *cp, 1707178825Sdfr char **subject_name) 1708178825Sdfr{ 1709178825Sdfr const HDB_Ext_PKINIT_acl *acl; 1710233294Sstas const HDB_Ext_PKINIT_cert *pc; 1711178825Sdfr krb5_error_code ret; 1712178825Sdfr hx509_name name; 1713233294Sstas size_t i; 1714178825Sdfr 1715233294Sstas if (cp->cert == NULL) { 1716233294Sstas 1717233294Sstas *subject_name = strdup("anonymous client client"); 1718233294Sstas if (*subject_name == NULL) 1719233294Sstas return ENOMEM; 1720233294Sstas return 0; 1721233294Sstas } 1722233294Sstas 1723233294Sstas ret = hx509_cert_get_base_subject(context->hx509ctx, 1724233294Sstas cp->cert, 1725178825Sdfr &name); 1726178825Sdfr if (ret) 1727178825Sdfr return ret; 1728178825Sdfr 1729178825Sdfr ret = hx509_name_to_string(name, subject_name); 1730178825Sdfr hx509_name_free(&name); 1731178825Sdfr if (ret) 1732178825Sdfr return ret; 1733178825Sdfr 1734178825Sdfr kdc_log(context, config, 0, 1735233294Sstas "Trying to authorize PK-INIT subject DN %s", 1736178825Sdfr *subject_name); 1737178825Sdfr 1738233294Sstas ret = hdb_entry_get_pkinit_cert(&client->entry, &pc); 1739233294Sstas if (ret == 0 && pc) { 1740233294Sstas hx509_cert cert; 1741233294Sstas size_t j; 1742233294Sstas 1743233294Sstas for (j = 0; j < pc->len; j++) { 1744233294Sstas ret = hx509_cert_init_data(context->hx509ctx, 1745233294Sstas pc->val[j].cert.data, 1746233294Sstas pc->val[j].cert.length, 1747233294Sstas &cert); 1748233294Sstas if (ret) 1749233294Sstas continue; 1750233294Sstas ret = hx509_cert_cmp(cert, cp->cert); 1751233294Sstas hx509_cert_free(cert); 1752233294Sstas if (ret == 0) { 1753233294Sstas kdc_log(context, config, 5, 1754233294Sstas "Found matching PK-INIT cert in hdb"); 1755233294Sstas return 0; 1756233294Sstas } 1757233294Sstas } 1758233294Sstas } 1759233294Sstas 1760233294Sstas 1761178825Sdfr if (config->pkinit_princ_in_cert) { 1762178825Sdfr ret = match_rfc_san(context, config, 1763233294Sstas context->hx509ctx, 1764233294Sstas cp->cert, 1765178825Sdfr client->entry.principal); 1766178825Sdfr if (ret == 0) { 1767178825Sdfr kdc_log(context, config, 5, 1768178825Sdfr "Found matching PK-INIT SAN in certificate"); 1769178825Sdfr return 0; 1770178825Sdfr } 1771178825Sdfr ret = match_ms_upn_san(context, config, 1772233294Sstas context->hx509ctx, 1773233294Sstas cp->cert, 1774233294Sstas clientdb, 1775233294Sstas client); 1776178825Sdfr if (ret == 0) { 1777178825Sdfr kdc_log(context, config, 5, 1778178825Sdfr "Found matching MS UPN SAN in certificate"); 1779178825Sdfr return 0; 1780178825Sdfr } 1781178825Sdfr } 1782178825Sdfr 1783178825Sdfr ret = hdb_entry_get_pkinit_acl(&client->entry, &acl); 1784178825Sdfr if (ret == 0 && acl != NULL) { 1785178825Sdfr /* 1786178825Sdfr * Cheat here and compare the generated name with the string 1787178825Sdfr * and not the reverse. 1788178825Sdfr */ 1789178825Sdfr for (i = 0; i < acl->len; i++) { 1790178825Sdfr if (strcmp(*subject_name, acl->val[0].subject) != 0) 1791178825Sdfr continue; 1792178825Sdfr 1793178825Sdfr /* Don't support isser and anchor checking right now */ 1794178825Sdfr if (acl->val[0].issuer) 1795178825Sdfr continue; 1796178825Sdfr if (acl->val[0].anchor) 1797178825Sdfr continue; 1798178825Sdfr 1799178825Sdfr kdc_log(context, config, 5, 1800178825Sdfr "Found matching PK-INIT database ACL"); 1801178825Sdfr return 0; 1802178825Sdfr } 1803178825Sdfr } 1804178825Sdfr 1805178825Sdfr for (i = 0; i < principal_mappings.len; i++) { 1806178825Sdfr krb5_boolean b; 1807178825Sdfr 1808178825Sdfr b = krb5_principal_compare(context, 1809178825Sdfr client->entry.principal, 1810178825Sdfr principal_mappings.val[i].principal); 1811178825Sdfr if (b == FALSE) 1812178825Sdfr continue; 1813178825Sdfr if (strcmp(principal_mappings.val[i].subject, *subject_name) != 0) 1814178825Sdfr continue; 1815178825Sdfr kdc_log(context, config, 5, 1816178825Sdfr "Found matching PK-INIT FILE ACL"); 1817178825Sdfr return 0; 1818178825Sdfr } 1819178825Sdfr 1820233294Sstas ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; 1821233294Sstas krb5_set_error_message(context, ret, 1822178825Sdfr "PKINIT no matching principals for %s", 1823178825Sdfr *subject_name); 1824178825Sdfr 1825178825Sdfr kdc_log(context, config, 5, 1826178825Sdfr "PKINIT no matching principals for %s", 1827178825Sdfr *subject_name); 1828178825Sdfr 1829178825Sdfr free(*subject_name); 1830178825Sdfr *subject_name = NULL; 1831178825Sdfr 1832233294Sstas return ret; 1833178825Sdfr} 1834178825Sdfr 1835178825Sdfrstatic krb5_error_code 1836233294Sstasadd_principal_mapping(krb5_context context, 1837178825Sdfr const char *principal_name, 1838178825Sdfr const char * subject) 1839178825Sdfr{ 1840178825Sdfr struct pk_allowed_princ *tmp; 1841178825Sdfr krb5_principal principal; 1842178825Sdfr krb5_error_code ret; 1843178825Sdfr 1844178825Sdfr tmp = realloc(principal_mappings.val, 1845178825Sdfr (principal_mappings.len + 1) * sizeof(*tmp)); 1846178825Sdfr if (tmp == NULL) 1847178825Sdfr return ENOMEM; 1848178825Sdfr principal_mappings.val = tmp; 1849178825Sdfr 1850178825Sdfr ret = krb5_parse_name(context, principal_name, &principal); 1851178825Sdfr if (ret) 1852178825Sdfr return ret; 1853178825Sdfr 1854178825Sdfr principal_mappings.val[principal_mappings.len].principal = principal; 1855178825Sdfr 1856178825Sdfr principal_mappings.val[principal_mappings.len].subject = strdup(subject); 1857178825Sdfr if (principal_mappings.val[principal_mappings.len].subject == NULL) { 1858178825Sdfr krb5_free_principal(context, principal); 1859178825Sdfr return ENOMEM; 1860178825Sdfr } 1861178825Sdfr principal_mappings.len++; 1862178825Sdfr 1863178825Sdfr return 0; 1864178825Sdfr} 1865178825Sdfr 1866178825Sdfrkrb5_error_code 1867178825Sdfr_kdc_add_inital_verified_cas(krb5_context context, 1868178825Sdfr krb5_kdc_configuration *config, 1869233294Sstas pk_client_params *cp, 1870178825Sdfr EncTicketPart *tkt) 1871178825Sdfr{ 1872178825Sdfr AD_INITIAL_VERIFIED_CAS cas; 1873178825Sdfr krb5_error_code ret; 1874178825Sdfr krb5_data data; 1875233294Sstas size_t size = 0; 1876178825Sdfr 1877178825Sdfr memset(&cas, 0, sizeof(cas)); 1878233294Sstas 1879178825Sdfr /* XXX add CAs to cas here */ 1880178825Sdfr 1881178825Sdfr ASN1_MALLOC_ENCODE(AD_INITIAL_VERIFIED_CAS, data.data, data.length, 1882178825Sdfr &cas, &size, ret); 1883178825Sdfr if (ret) 1884178825Sdfr return ret; 1885178825Sdfr if (data.length != size) 1886178825Sdfr krb5_abortx(context, "internal asn.1 encoder error"); 1887178825Sdfr 1888233294Sstas ret = _kdc_tkt_add_if_relevant_ad(context, tkt, 1889178825Sdfr KRB5_AUTHDATA_INITIAL_VERIFIED_CAS, 1890178825Sdfr &data); 1891178825Sdfr krb5_data_free(&data); 1892178825Sdfr return ret; 1893178825Sdfr} 1894178825Sdfr 1895178825Sdfr/* 1896178825Sdfr * 1897178825Sdfr */ 1898178825Sdfr 1899178825Sdfrstatic void 1900178825Sdfrload_mappings(krb5_context context, const char *fn) 1901178825Sdfr{ 1902178825Sdfr krb5_error_code ret; 1903178825Sdfr char buf[1024]; 1904178825Sdfr unsigned long lineno = 0; 1905178825Sdfr FILE *f; 1906178825Sdfr 1907178825Sdfr f = fopen(fn, "r"); 1908178825Sdfr if (f == NULL) 1909178825Sdfr return; 1910178825Sdfr 1911178825Sdfr while (fgets(buf, sizeof(buf), f) != NULL) { 1912178825Sdfr char *subject_name, *p; 1913233294Sstas 1914178825Sdfr buf[strcspn(buf, "\n")] = '\0'; 1915178825Sdfr lineno++; 1916178825Sdfr 1917178825Sdfr p = buf + strspn(buf, " \t"); 1918178825Sdfr 1919178825Sdfr if (*p == '#' || *p == '\0') 1920178825Sdfr continue; 1921178825Sdfr 1922178825Sdfr subject_name = strchr(p, ':'); 1923178825Sdfr if (subject_name == NULL) { 1924178825Sdfr krb5_warnx(context, "pkinit mapping file line %lu " 1925178825Sdfr "missing \":\" :%s", 1926178825Sdfr lineno, buf); 1927178825Sdfr continue; 1928178825Sdfr } 1929178825Sdfr *subject_name++ = '\0'; 1930178825Sdfr 1931178825Sdfr ret = add_principal_mapping(context, p, subject_name); 1932178825Sdfr if (ret) { 1933178825Sdfr krb5_warn(context, ret, "failed to add line %lu \":\" :%s\n", 1934178825Sdfr lineno, buf); 1935178825Sdfr continue; 1936178825Sdfr } 1937233294Sstas } 1938178825Sdfr 1939178825Sdfr fclose(f); 1940178825Sdfr} 1941233294Sstas 1942178825Sdfr/* 1943178825Sdfr * 1944178825Sdfr */ 1945178825Sdfr 1946178825Sdfrkrb5_error_code 1947233294Sstaskrb5_kdc_pk_initialize(krb5_context context, 1948233294Sstas krb5_kdc_configuration *config, 1949233294Sstas const char *user_id, 1950233294Sstas const char *anchors, 1951233294Sstas char **pool, 1952233294Sstas char **revoke_list) 1953178825Sdfr{ 1954178825Sdfr const char *file; 1955178825Sdfr char *fn = NULL; 1956178825Sdfr krb5_error_code ret; 1957178825Sdfr 1958178825Sdfr file = krb5_config_get_string(context, NULL, 1959178825Sdfr "libdefaults", "moduli", NULL); 1960178825Sdfr 1961178825Sdfr ret = _krb5_parse_moduli(context, file, &moduli); 1962178825Sdfr if (ret) 1963178825Sdfr krb5_err(context, 1, ret, "PKINIT: failed to load modidi file"); 1964178825Sdfr 1965178825Sdfr principal_mappings.len = 0; 1966178825Sdfr principal_mappings.val = NULL; 1967178825Sdfr 1968178825Sdfr ret = _krb5_pk_load_id(context, 1969178825Sdfr &kdc_identity, 1970178825Sdfr user_id, 1971178825Sdfr anchors, 1972178825Sdfr pool, 1973178825Sdfr revoke_list, 1974178825Sdfr NULL, 1975178825Sdfr NULL, 1976178825Sdfr NULL); 1977178825Sdfr if (ret) { 1978178825Sdfr krb5_warn(context, ret, "PKINIT: "); 1979178825Sdfr config->enable_pkinit = 0; 1980178825Sdfr return ret; 1981178825Sdfr } 1982178825Sdfr 1983178825Sdfr { 1984178825Sdfr hx509_query *q; 1985178825Sdfr hx509_cert cert; 1986233294Sstas 1987233294Sstas ret = hx509_query_alloc(context->hx509ctx, &q); 1988178825Sdfr if (ret) { 1989178825Sdfr krb5_warnx(context, "PKINIT: out of memory"); 1990178825Sdfr return ENOMEM; 1991178825Sdfr } 1992233294Sstas 1993178825Sdfr hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); 1994233294Sstas if (config->pkinit_kdc_friendly_name) 1995233294Sstas hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name); 1996233294Sstas 1997233294Sstas ret = hx509_certs_find(context->hx509ctx, 1998178825Sdfr kdc_identity->certs, 1999178825Sdfr q, 2000178825Sdfr &cert); 2001233294Sstas hx509_query_free(context->hx509ctx, q); 2002178825Sdfr if (ret == 0) { 2003233294Sstas if (hx509_cert_check_eku(context->hx509ctx, cert, 2004233294Sstas &asn1_oid_id_pkkdcekuoid, 0)) { 2005233294Sstas hx509_name name; 2006233294Sstas char *str; 2007233294Sstas ret = hx509_cert_get_subject(cert, &name); 2008233294Sstas if (ret == 0) { 2009233294Sstas hx509_name_to_string(name, &str); 2010233294Sstas krb5_warnx(context, "WARNING Found KDC certificate (%s)" 2011233294Sstas "is missing the PK-INIT KDC EKU, this is bad for " 2012233294Sstas "interoperability.", str); 2013233294Sstas hx509_name_free(&name); 2014233294Sstas free(str); 2015233294Sstas } 2016233294Sstas } 2017178825Sdfr hx509_cert_free(cert); 2018178825Sdfr } else 2019178825Sdfr krb5_warnx(context, "PKINIT: failed to find a signing " 2020178825Sdfr "certifiate with a public key"); 2021178825Sdfr } 2022178825Sdfr 2023233294Sstas if (krb5_config_get_bool_default(context, 2024233294Sstas NULL, 2025233294Sstas FALSE, 2026233294Sstas "kdc", 2027233294Sstas "pkinit_allow_proxy_certificate", 2028233294Sstas NULL)) 2029233294Sstas config->pkinit_allow_proxy_certs = 1; 2030178825Sdfr 2031233294Sstas file = krb5_config_get_string(context, 2032178825Sdfr NULL, 2033178825Sdfr "kdc", 2034178825Sdfr "pkinit_mappings_file", 2035178825Sdfr NULL); 2036178825Sdfr if (file == NULL) { 2037178825Sdfr asprintf(&fn, "%s/pki-mapping", hdb_db_dir(context)); 2038178825Sdfr file = fn; 2039178825Sdfr } 2040178825Sdfr 2041178825Sdfr load_mappings(context, file); 2042178825Sdfr if (fn) 2043178825Sdfr free(fn); 2044178825Sdfr 2045178825Sdfr return 0; 2046178825Sdfr} 2047178825Sdfr 2048178825Sdfr#endif /* PKINIT */ 2049