1178825Sdfr/* 2178825Sdfr * Copyright (c) 2003 - 2006 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 "kdc_locl.h" 35178825Sdfr 36178825SdfrRCSID("$Id: pkinit.c 22243 2007-12-08 23:39:30Z lha $"); 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 48178825Sdfr/* XXX copied from lib/krb5/pkinit.c */ 49178825Sdfrstruct krb5_pk_identity { 50178825Sdfr hx509_context hx509ctx; 51178825Sdfr hx509_verify_ctx verify_ctx; 52178825Sdfr hx509_certs certs; 53178825Sdfr hx509_certs anchors; 54178825Sdfr hx509_certs certpool; 55178825Sdfr hx509_revoke_ctx revoke; 56178825Sdfr}; 57178825Sdfr 58178825Sdfrenum pkinit_type { 59178825Sdfr PKINIT_COMPAT_WIN2K = 1, 60178825Sdfr PKINIT_COMPAT_27 = 3 61178825Sdfr}; 62178825Sdfr 63178825Sdfrstruct pk_client_params { 64178825Sdfr enum pkinit_type type; 65178825Sdfr BIGNUM *dh_public_key; 66178825Sdfr hx509_cert cert; 67178825Sdfr unsigned nonce; 68178825Sdfr DH *dh; 69178825Sdfr EncryptionKey reply_key; 70178825Sdfr char *dh_group_name; 71178825Sdfr hx509_peer_info peer; 72178825Sdfr hx509_certs client_anchors; 73178825Sdfr}; 74178825Sdfr 75178825Sdfrstruct pk_principal_mapping { 76178825Sdfr unsigned int len; 77178825Sdfr struct pk_allowed_princ { 78178825Sdfr krb5_principal principal; 79178825Sdfr char *subject; 80178825Sdfr } *val; 81178825Sdfr}; 82178825Sdfr 83178825Sdfrstatic struct krb5_pk_identity *kdc_identity; 84178825Sdfrstatic struct pk_principal_mapping principal_mappings; 85178825Sdfrstatic struct krb5_dh_moduli **moduli; 86178825Sdfr 87178825Sdfrstatic struct { 88178825Sdfr krb5_data data; 89178825Sdfr time_t expire; 90178825Sdfr time_t next_update; 91178825Sdfr} ocsp; 92178825Sdfr 93178825Sdfr/* 94178825Sdfr * 95178825Sdfr */ 96178825Sdfr 97178825Sdfrstatic krb5_error_code 98178825Sdfrpk_check_pkauthenticator_win2k(krb5_context context, 99178825Sdfr PKAuthenticator_Win2k *a, 100178825Sdfr const KDC_REQ *req) 101178825Sdfr{ 102178825Sdfr krb5_timestamp now; 103178825Sdfr 104178825Sdfr krb5_timeofday (context, &now); 105178825Sdfr 106178825Sdfr /* XXX cusec */ 107178825Sdfr if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) { 108178825Sdfr krb5_clear_error_string(context); 109178825Sdfr return KRB5KRB_AP_ERR_SKEW; 110178825Sdfr } 111178825Sdfr return 0; 112178825Sdfr} 113178825Sdfr 114178825Sdfrstatic krb5_error_code 115178825Sdfrpk_check_pkauthenticator(krb5_context context, 116178825Sdfr PKAuthenticator *a, 117178825Sdfr const KDC_REQ *req) 118178825Sdfr{ 119178825Sdfr u_char *buf = NULL; 120178825Sdfr size_t buf_size; 121178825Sdfr krb5_error_code ret; 122178825Sdfr size_t len; 123178825Sdfr krb5_timestamp now; 124178825Sdfr Checksum checksum; 125178825Sdfr 126178825Sdfr krb5_timeofday (context, &now); 127178825Sdfr 128178825Sdfr /* XXX cusec */ 129178825Sdfr if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) { 130178825Sdfr krb5_clear_error_string(context); 131178825Sdfr return KRB5KRB_AP_ERR_SKEW; 132178825Sdfr } 133178825Sdfr 134178825Sdfr ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, &req->req_body, &len, ret); 135178825Sdfr if (ret) { 136178825Sdfr krb5_clear_error_string(context); 137178825Sdfr return ret; 138178825Sdfr } 139178825Sdfr if (buf_size != len) 140178825Sdfr krb5_abortx(context, "Internal error in ASN.1 encoder"); 141178825Sdfr 142178825Sdfr ret = krb5_create_checksum(context, 143178825Sdfr NULL, 144178825Sdfr 0, 145178825Sdfr CKSUMTYPE_SHA1, 146178825Sdfr buf, 147178825Sdfr len, 148178825Sdfr &checksum); 149178825Sdfr free(buf); 150178825Sdfr if (ret) { 151178825Sdfr krb5_clear_error_string(context); 152178825Sdfr return ret; 153178825Sdfr } 154178825Sdfr 155178825Sdfr if (a->paChecksum == NULL) { 156178825Sdfr krb5_clear_error_string(context); 157178825Sdfr ret = KRB5_KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED; 158178825Sdfr goto out; 159178825Sdfr } 160178825Sdfr 161178825Sdfr if (der_heim_octet_string_cmp(a->paChecksum, &checksum.checksum) != 0) { 162178825Sdfr krb5_clear_error_string(context); 163178825Sdfr ret = KRB5KRB_ERR_GENERIC; 164178825Sdfr } 165178825Sdfr 166178825Sdfrout: 167178825Sdfr free_Checksum(&checksum); 168178825Sdfr 169178825Sdfr return ret; 170178825Sdfr} 171178825Sdfr 172178825Sdfrvoid 173178825Sdfr_kdc_pk_free_client_param(krb5_context context, 174178825Sdfr pk_client_params *client_params) 175178825Sdfr{ 176178825Sdfr if (client_params->cert) 177178825Sdfr hx509_cert_free(client_params->cert); 178178825Sdfr if (client_params->dh) 179178825Sdfr DH_free(client_params->dh); 180178825Sdfr if (client_params->dh_public_key) 181178825Sdfr BN_free(client_params->dh_public_key); 182178825Sdfr krb5_free_keyblock_contents(context, &client_params->reply_key); 183178825Sdfr if (client_params->dh_group_name) 184178825Sdfr free(client_params->dh_group_name); 185178825Sdfr if (client_params->peer) 186178825Sdfr hx509_peer_info_free(client_params->peer); 187178825Sdfr if (client_params->client_anchors) 188178825Sdfr hx509_certs_free(&client_params->client_anchors); 189178825Sdfr memset(client_params, 0, sizeof(*client_params)); 190178825Sdfr free(client_params); 191178825Sdfr} 192178825Sdfr 193178825Sdfrstatic krb5_error_code 194178825Sdfrgenerate_dh_keyblock(krb5_context context, pk_client_params *client_params, 195178825Sdfr krb5_enctype enctype, krb5_keyblock *reply_key) 196178825Sdfr{ 197178825Sdfr unsigned char *dh_gen_key = NULL; 198178825Sdfr krb5_keyblock key; 199178825Sdfr krb5_error_code ret; 200178825Sdfr size_t dh_gen_keylen, size; 201178825Sdfr 202178825Sdfr memset(&key, 0, sizeof(key)); 203178825Sdfr 204178825Sdfr if (!DH_generate_key(client_params->dh)) { 205178825Sdfr krb5_set_error_string(context, "Can't generate Diffie-Hellman keys"); 206178825Sdfr ret = KRB5KRB_ERR_GENERIC; 207178825Sdfr goto out; 208178825Sdfr } 209178825Sdfr if (client_params->dh_public_key == NULL) { 210178825Sdfr krb5_set_error_string(context, "dh_public_key"); 211178825Sdfr ret = KRB5KRB_ERR_GENERIC; 212178825Sdfr goto out; 213178825Sdfr } 214178825Sdfr 215178825Sdfr dh_gen_keylen = DH_size(client_params->dh); 216178825Sdfr size = BN_num_bytes(client_params->dh->p); 217178825Sdfr if (size < dh_gen_keylen) 218178825Sdfr size = dh_gen_keylen; 219178825Sdfr 220178825Sdfr dh_gen_key = malloc(size); 221178825Sdfr if (dh_gen_key == NULL) { 222178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 223178825Sdfr ret = ENOMEM; 224178825Sdfr goto out; 225178825Sdfr } 226178825Sdfr memset(dh_gen_key, 0, size - dh_gen_keylen); 227178825Sdfr 228178825Sdfr dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen), 229178825Sdfr client_params->dh_public_key, 230178825Sdfr client_params->dh); 231178825Sdfr if (dh_gen_keylen == -1) { 232178825Sdfr krb5_set_error_string(context, "Can't compute Diffie-Hellman key"); 233178825Sdfr ret = KRB5KRB_ERR_GENERIC; 234178825Sdfr goto out; 235178825Sdfr } 236178825Sdfr 237178825Sdfr ret = _krb5_pk_octetstring2key(context, 238178825Sdfr enctype, 239178825Sdfr dh_gen_key, dh_gen_keylen, 240178825Sdfr NULL, NULL, 241178825Sdfr reply_key); 242178825Sdfr 243178825Sdfr out: 244178825Sdfr if (dh_gen_key) 245178825Sdfr free(dh_gen_key); 246178825Sdfr if (key.keyvalue.data) 247178825Sdfr krb5_free_keyblock_contents(context, &key); 248178825Sdfr 249178825Sdfr return ret; 250178825Sdfr} 251178825Sdfr 252178825Sdfrstatic BIGNUM * 253178825Sdfrinteger_to_BN(krb5_context context, const char *field, heim_integer *f) 254178825Sdfr{ 255178825Sdfr BIGNUM *bn; 256178825Sdfr 257178825Sdfr bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL); 258178825Sdfr if (bn == NULL) { 259178825Sdfr krb5_set_error_string(context, "PKINIT: parsing BN failed %s", field); 260178825Sdfr return NULL; 261178825Sdfr } 262178825Sdfr BN_set_negative(bn, f->negative); 263178825Sdfr return bn; 264178825Sdfr} 265178825Sdfr 266178825Sdfrstatic krb5_error_code 267178825Sdfrget_dh_param(krb5_context context, 268178825Sdfr krb5_kdc_configuration *config, 269178825Sdfr SubjectPublicKeyInfo *dh_key_info, 270178825Sdfr pk_client_params *client_params) 271178825Sdfr{ 272178825Sdfr DomainParameters dhparam; 273178825Sdfr DH *dh = NULL; 274178825Sdfr krb5_error_code ret; 275178825Sdfr 276178825Sdfr memset(&dhparam, 0, sizeof(dhparam)); 277178825Sdfr 278178825Sdfr if (der_heim_oid_cmp(&dh_key_info->algorithm.algorithm, oid_id_dhpublicnumber())) { 279178825Sdfr krb5_set_error_string(context, 280178825Sdfr "PKINIT invalid oid in clientPublicValue"); 281178825Sdfr return KRB5_BADMSGTYPE; 282178825Sdfr } 283178825Sdfr 284178825Sdfr if (dh_key_info->algorithm.parameters == NULL) { 285178825Sdfr krb5_set_error_string(context, "PKINIT missing algorithm parameter " 286178825Sdfr "in clientPublicValue"); 287178825Sdfr return KRB5_BADMSGTYPE; 288178825Sdfr } 289178825Sdfr 290178825Sdfr ret = decode_DomainParameters(dh_key_info->algorithm.parameters->data, 291178825Sdfr dh_key_info->algorithm.parameters->length, 292178825Sdfr &dhparam, 293178825Sdfr NULL); 294178825Sdfr if (ret) { 295178825Sdfr krb5_set_error_string(context, "Can't decode algorithm " 296178825Sdfr "parameters in clientPublicValue"); 297178825Sdfr goto out; 298178825Sdfr } 299178825Sdfr 300178825Sdfr if ((dh_key_info->subjectPublicKey.length % 8) != 0) { 301178825Sdfr ret = KRB5_BADMSGTYPE; 302178825Sdfr krb5_set_error_string(context, "PKINIT: subjectPublicKey not aligned " 303178825Sdfr "to 8 bit boundary"); 304178825Sdfr goto out; 305178825Sdfr } 306178825Sdfr 307178825Sdfr 308178825Sdfr ret = _krb5_dh_group_ok(context, config->pkinit_dh_min_bits, 309178825Sdfr &dhparam.p, &dhparam.g, &dhparam.q, moduli, 310178825Sdfr &client_params->dh_group_name); 311178825Sdfr if (ret) { 312178825Sdfr /* XXX send back proposal of better group */ 313178825Sdfr goto out; 314178825Sdfr } 315178825Sdfr 316178825Sdfr dh = DH_new(); 317178825Sdfr if (dh == NULL) { 318178825Sdfr krb5_set_error_string(context, "Cannot create DH structure"); 319178825Sdfr ret = ENOMEM; 320178825Sdfr goto out; 321178825Sdfr } 322178825Sdfr ret = KRB5_BADMSGTYPE; 323178825Sdfr dh->p = integer_to_BN(context, "DH prime", &dhparam.p); 324178825Sdfr if (dh->p == NULL) 325178825Sdfr goto out; 326178825Sdfr dh->g = integer_to_BN(context, "DH base", &dhparam.g); 327178825Sdfr if (dh->g == NULL) 328178825Sdfr goto out; 329178825Sdfr dh->q = integer_to_BN(context, "DH p-1 factor", &dhparam.q); 330178825Sdfr if (dh->g == NULL) 331178825Sdfr goto out; 332178825Sdfr 333178825Sdfr { 334178825Sdfr heim_integer glue; 335178825Sdfr size_t size; 336178825Sdfr 337178825Sdfr ret = decode_DHPublicKey(dh_key_info->subjectPublicKey.data, 338178825Sdfr dh_key_info->subjectPublicKey.length / 8, 339178825Sdfr &glue, 340178825Sdfr &size); 341178825Sdfr if (ret) { 342178825Sdfr krb5_clear_error_string(context); 343178825Sdfr return ret; 344178825Sdfr } 345178825Sdfr 346178825Sdfr client_params->dh_public_key = integer_to_BN(context, 347178825Sdfr "subjectPublicKey", 348178825Sdfr &glue); 349178825Sdfr der_free_heim_integer(&glue); 350178825Sdfr if (client_params->dh_public_key == NULL) 351178825Sdfr goto out; 352178825Sdfr } 353178825Sdfr 354178825Sdfr client_params->dh = dh; 355178825Sdfr dh = NULL; 356178825Sdfr ret = 0; 357178825Sdfr 358178825Sdfr out: 359178825Sdfr if (dh) 360178825Sdfr DH_free(dh); 361178825Sdfr free_DomainParameters(&dhparam); 362178825Sdfr return ret; 363178825Sdfr} 364178825Sdfr 365178825Sdfrkrb5_error_code 366178825Sdfr_kdc_pk_rd_padata(krb5_context context, 367178825Sdfr krb5_kdc_configuration *config, 368178825Sdfr const KDC_REQ *req, 369178825Sdfr const PA_DATA *pa, 370178825Sdfr pk_client_params **ret_params) 371178825Sdfr{ 372178825Sdfr pk_client_params *client_params; 373178825Sdfr krb5_error_code ret; 374178825Sdfr heim_oid eContentType = { 0, NULL }, contentInfoOid = { 0, NULL }; 375178825Sdfr krb5_data eContent = { 0, NULL }; 376178825Sdfr krb5_data signed_content = { 0, NULL }; 377178825Sdfr const char *type = "unknown type"; 378178825Sdfr int have_data = 0; 379178825Sdfr 380178825Sdfr *ret_params = NULL; 381178825Sdfr 382178825Sdfr if (!config->enable_pkinit) { 383178825Sdfr kdc_log(context, config, 0, "PK-INIT request but PK-INIT not enabled"); 384178825Sdfr krb5_clear_error_string(context); 385178825Sdfr return 0; 386178825Sdfr } 387178825Sdfr 388178825Sdfr hx509_verify_set_time(kdc_identity->verify_ctx, _kdc_now.tv_sec); 389178825Sdfr 390178825Sdfr client_params = calloc(1, sizeof(*client_params)); 391178825Sdfr if (client_params == NULL) { 392178825Sdfr krb5_clear_error_string(context); 393178825Sdfr ret = ENOMEM; 394178825Sdfr goto out; 395178825Sdfr } 396178825Sdfr 397178825Sdfr if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) { 398178825Sdfr PA_PK_AS_REQ_Win2k r; 399178825Sdfr 400178825Sdfr type = "PK-INIT-Win2k"; 401178825Sdfr 402178825Sdfr ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data, 403178825Sdfr pa->padata_value.length, 404178825Sdfr &r, 405178825Sdfr NULL); 406178825Sdfr if (ret) { 407178825Sdfr krb5_set_error_string(context, "Can't decode " 408178825Sdfr "PK-AS-REQ-Win2k: %d", ret); 409178825Sdfr goto out; 410178825Sdfr } 411178825Sdfr 412178825Sdfr ret = hx509_cms_unwrap_ContentInfo(&r.signed_auth_pack, 413178825Sdfr &contentInfoOid, 414178825Sdfr &signed_content, 415178825Sdfr &have_data); 416178825Sdfr free_PA_PK_AS_REQ_Win2k(&r); 417178825Sdfr if (ret) { 418178825Sdfr krb5_set_error_string(context, "Can't decode PK-AS-REQ: %d", ret); 419178825Sdfr goto out; 420178825Sdfr } 421178825Sdfr 422178825Sdfr } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) { 423178825Sdfr PA_PK_AS_REQ r; 424178825Sdfr 425178825Sdfr type = "PK-INIT-IETF"; 426178825Sdfr 427178825Sdfr ret = decode_PA_PK_AS_REQ(pa->padata_value.data, 428178825Sdfr pa->padata_value.length, 429178825Sdfr &r, 430178825Sdfr NULL); 431178825Sdfr if (ret) { 432178825Sdfr krb5_set_error_string(context, "Can't decode PK-AS-REQ: %d", ret); 433178825Sdfr goto out; 434178825Sdfr } 435178825Sdfr 436178825Sdfr /* XXX look at r.kdcPkId */ 437178825Sdfr if (r.trustedCertifiers) { 438178825Sdfr ExternalPrincipalIdentifiers *edi = r.trustedCertifiers; 439178825Sdfr unsigned int i; 440178825Sdfr 441178825Sdfr ret = hx509_certs_init(kdc_identity->hx509ctx, 442178825Sdfr "MEMORY:client-anchors", 443178825Sdfr 0, NULL, 444178825Sdfr &client_params->client_anchors); 445178825Sdfr if (ret) { 446178825Sdfr krb5_set_error_string(context, "Can't allocate client anchors: %d", ret); 447178825Sdfr goto out; 448178825Sdfr 449178825Sdfr } 450178825Sdfr for (i = 0; i < edi->len; i++) { 451178825Sdfr IssuerAndSerialNumber iasn; 452178825Sdfr hx509_query *q; 453178825Sdfr hx509_cert cert; 454178825Sdfr size_t size; 455178825Sdfr 456178825Sdfr if (edi->val[i].issuerAndSerialNumber == NULL) 457178825Sdfr continue; 458178825Sdfr 459178825Sdfr ret = hx509_query_alloc(kdc_identity->hx509ctx, &q); 460178825Sdfr if (ret) { 461178825Sdfr krb5_set_error_string(context, 462178825Sdfr "Failed to allocate hx509_query"); 463178825Sdfr goto out; 464178825Sdfr } 465178825Sdfr 466178825Sdfr ret = decode_IssuerAndSerialNumber(edi->val[i].issuerAndSerialNumber->data, 467178825Sdfr edi->val[i].issuerAndSerialNumber->length, 468178825Sdfr &iasn, 469178825Sdfr &size); 470178825Sdfr if (ret) { 471178825Sdfr hx509_query_free(kdc_identity->hx509ctx, q); 472178825Sdfr continue; 473178825Sdfr } 474178825Sdfr ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber); 475178825Sdfr free_IssuerAndSerialNumber(&iasn); 476178825Sdfr if (ret) 477178825Sdfr continue; 478178825Sdfr 479178825Sdfr ret = hx509_certs_find(kdc_identity->hx509ctx, 480178825Sdfr kdc_identity->certs, 481178825Sdfr q, 482178825Sdfr &cert); 483178825Sdfr hx509_query_free(kdc_identity->hx509ctx, q); 484178825Sdfr if (ret) 485178825Sdfr continue; 486178825Sdfr hx509_certs_add(kdc_identity->hx509ctx, 487178825Sdfr client_params->client_anchors, cert); 488178825Sdfr hx509_cert_free(cert); 489178825Sdfr } 490178825Sdfr } 491178825Sdfr 492178825Sdfr ret = hx509_cms_unwrap_ContentInfo(&r.signedAuthPack, 493178825Sdfr &contentInfoOid, 494178825Sdfr &signed_content, 495178825Sdfr &have_data); 496178825Sdfr free_PA_PK_AS_REQ(&r); 497178825Sdfr if (ret) { 498178825Sdfr krb5_set_error_string(context, "Can't unwrap ContentInfo: %d", ret); 499178825Sdfr goto out; 500178825Sdfr } 501178825Sdfr 502178825Sdfr } else { 503178825Sdfr krb5_clear_error_string(context); 504178825Sdfr ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 505178825Sdfr goto out; 506178825Sdfr } 507178825Sdfr 508178825Sdfr ret = der_heim_oid_cmp(&contentInfoOid, oid_id_pkcs7_signedData()); 509178825Sdfr if (ret != 0) { 510178825Sdfr krb5_set_error_string(context, "PK-AS-REQ-Win2k invalid content " 511178825Sdfr "type oid"); 512178825Sdfr ret = KRB5KRB_ERR_GENERIC; 513178825Sdfr goto out; 514178825Sdfr } 515178825Sdfr 516178825Sdfr if (!have_data) { 517178825Sdfr krb5_set_error_string(context, 518178825Sdfr "PK-AS-REQ-Win2k no signed auth pack"); 519178825Sdfr ret = KRB5KRB_ERR_GENERIC; 520178825Sdfr goto out; 521178825Sdfr } 522178825Sdfr 523178825Sdfr { 524178825Sdfr hx509_certs signer_certs; 525178825Sdfr 526178825Sdfr ret = hx509_cms_verify_signed(kdc_identity->hx509ctx, 527178825Sdfr kdc_identity->verify_ctx, 528178825Sdfr signed_content.data, 529178825Sdfr signed_content.length, 530178825Sdfr NULL, 531178825Sdfr kdc_identity->certpool, 532178825Sdfr &eContentType, 533178825Sdfr &eContent, 534178825Sdfr &signer_certs); 535178825Sdfr if (ret) { 536178825Sdfr char *s = hx509_get_error_string(kdc_identity->hx509ctx, ret); 537178825Sdfr krb5_warnx(context, "PKINIT: failed to verify signature: %s: %d", 538178825Sdfr s, ret); 539178825Sdfr free(s); 540178825Sdfr goto out; 541178825Sdfr } 542178825Sdfr 543178825Sdfr ret = hx509_get_one_cert(kdc_identity->hx509ctx, signer_certs, 544178825Sdfr &client_params->cert); 545178825Sdfr hx509_certs_free(&signer_certs); 546178825Sdfr if (ret) 547178825Sdfr goto out; 548178825Sdfr } 549178825Sdfr 550178825Sdfr /* Signature is correct, now verify the signed message */ 551178825Sdfr if (der_heim_oid_cmp(&eContentType, oid_id_pkcs7_data()) != 0 && 552178825Sdfr der_heim_oid_cmp(&eContentType, oid_id_pkauthdata()) != 0) 553178825Sdfr { 554178825Sdfr krb5_set_error_string(context, "got wrong oid for pkauthdata"); 555178825Sdfr ret = KRB5_BADMSGTYPE; 556178825Sdfr goto out; 557178825Sdfr } 558178825Sdfr 559178825Sdfr if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) { 560178825Sdfr AuthPack_Win2k ap; 561178825Sdfr 562178825Sdfr ret = decode_AuthPack_Win2k(eContent.data, 563178825Sdfr eContent.length, 564178825Sdfr &ap, 565178825Sdfr NULL); 566178825Sdfr if (ret) { 567178825Sdfr krb5_set_error_string(context, "can't decode AuthPack: %d", ret); 568178825Sdfr goto out; 569178825Sdfr } 570178825Sdfr 571178825Sdfr ret = pk_check_pkauthenticator_win2k(context, 572178825Sdfr &ap.pkAuthenticator, 573178825Sdfr req); 574178825Sdfr if (ret) { 575178825Sdfr free_AuthPack_Win2k(&ap); 576178825Sdfr goto out; 577178825Sdfr } 578178825Sdfr 579178825Sdfr client_params->type = PKINIT_COMPAT_WIN2K; 580178825Sdfr client_params->nonce = ap.pkAuthenticator.nonce; 581178825Sdfr 582178825Sdfr if (ap.clientPublicValue) { 583178825Sdfr krb5_set_error_string(context, "DH not supported for windows"); 584178825Sdfr ret = KRB5KRB_ERR_GENERIC; 585178825Sdfr goto out; 586178825Sdfr } 587178825Sdfr free_AuthPack_Win2k(&ap); 588178825Sdfr 589178825Sdfr } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) { 590178825Sdfr AuthPack ap; 591178825Sdfr 592178825Sdfr ret = decode_AuthPack(eContent.data, 593178825Sdfr eContent.length, 594178825Sdfr &ap, 595178825Sdfr NULL); 596178825Sdfr if (ret) { 597178825Sdfr krb5_set_error_string(context, "can't decode AuthPack: %d", ret); 598178825Sdfr free_AuthPack(&ap); 599178825Sdfr goto out; 600178825Sdfr } 601178825Sdfr 602178825Sdfr ret = pk_check_pkauthenticator(context, 603178825Sdfr &ap.pkAuthenticator, 604178825Sdfr req); 605178825Sdfr if (ret) { 606178825Sdfr free_AuthPack(&ap); 607178825Sdfr goto out; 608178825Sdfr } 609178825Sdfr 610178825Sdfr client_params->type = PKINIT_COMPAT_27; 611178825Sdfr client_params->nonce = ap.pkAuthenticator.nonce; 612178825Sdfr 613178825Sdfr if (ap.clientPublicValue) { 614178825Sdfr ret = get_dh_param(context, config, 615178825Sdfr ap.clientPublicValue, client_params); 616178825Sdfr if (ret) { 617178825Sdfr free_AuthPack(&ap); 618178825Sdfr goto out; 619178825Sdfr } 620178825Sdfr } 621178825Sdfr 622178825Sdfr if (ap.supportedCMSTypes) { 623178825Sdfr ret = hx509_peer_info_alloc(kdc_identity->hx509ctx, 624178825Sdfr &client_params->peer); 625178825Sdfr if (ret) { 626178825Sdfr free_AuthPack(&ap); 627178825Sdfr goto out; 628178825Sdfr } 629178825Sdfr ret = hx509_peer_info_set_cms_algs(kdc_identity->hx509ctx, 630178825Sdfr client_params->peer, 631178825Sdfr ap.supportedCMSTypes->val, 632178825Sdfr ap.supportedCMSTypes->len); 633178825Sdfr if (ret) { 634178825Sdfr free_AuthPack(&ap); 635178825Sdfr goto out; 636178825Sdfr } 637178825Sdfr } 638178825Sdfr free_AuthPack(&ap); 639178825Sdfr } else 640178825Sdfr krb5_abortx(context, "internal pkinit error"); 641178825Sdfr 642178825Sdfr kdc_log(context, config, 0, "PK-INIT request of type %s", type); 643178825Sdfr 644178825Sdfrout: 645178825Sdfr if (ret) 646178825Sdfr krb5_warn(context, ret, "PKINIT"); 647178825Sdfr 648178825Sdfr if (signed_content.data) 649178825Sdfr free(signed_content.data); 650178825Sdfr krb5_data_free(&eContent); 651178825Sdfr der_free_oid(&eContentType); 652178825Sdfr der_free_oid(&contentInfoOid); 653178825Sdfr if (ret) 654178825Sdfr _kdc_pk_free_client_param(context, client_params); 655178825Sdfr else 656178825Sdfr *ret_params = client_params; 657178825Sdfr return ret; 658178825Sdfr} 659178825Sdfr 660178825Sdfr/* 661178825Sdfr * 662178825Sdfr */ 663178825Sdfr 664178825Sdfrstatic krb5_error_code 665178825SdfrBN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer) 666178825Sdfr{ 667178825Sdfr integer->length = BN_num_bytes(bn); 668178825Sdfr integer->data = malloc(integer->length); 669178825Sdfr if (integer->data == NULL) { 670178825Sdfr krb5_clear_error_string(context); 671178825Sdfr return ENOMEM; 672178825Sdfr } 673178825Sdfr BN_bn2bin(bn, integer->data); 674178825Sdfr integer->negative = BN_is_negative(bn); 675178825Sdfr return 0; 676178825Sdfr} 677178825Sdfr 678178825Sdfrstatic krb5_error_code 679178825Sdfrpk_mk_pa_reply_enckey(krb5_context context, 680178825Sdfr krb5_kdc_configuration *config, 681178825Sdfr pk_client_params *client_params, 682178825Sdfr const KDC_REQ *req, 683178825Sdfr const krb5_data *req_buffer, 684178825Sdfr krb5_keyblock *reply_key, 685178825Sdfr ContentInfo *content_info) 686178825Sdfr{ 687178825Sdfr const heim_oid *envelopedAlg = NULL, *sdAlg = NULL; 688178825Sdfr krb5_error_code ret; 689178825Sdfr krb5_data buf, signed_data; 690178825Sdfr size_t size; 691178825Sdfr int do_win2k = 0; 692178825Sdfr 693178825Sdfr krb5_data_zero(&buf); 694178825Sdfr krb5_data_zero(&signed_data); 695178825Sdfr 696178825Sdfr /* 697178825Sdfr * If the message client is a win2k-type but it send pa data 698178825Sdfr * 09-binding it expects a IETF (checksum) reply so there can be 699178825Sdfr * no replay attacks. 700178825Sdfr */ 701178825Sdfr 702178825Sdfr switch (client_params->type) { 703178825Sdfr case PKINIT_COMPAT_WIN2K: { 704178825Sdfr int i = 0; 705178825Sdfr if (_kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_09_BINDING) == NULL 706178825Sdfr && config->pkinit_require_binding == 0) 707178825Sdfr { 708178825Sdfr do_win2k = 1; 709178825Sdfr } 710178825Sdfr break; 711178825Sdfr } 712178825Sdfr case PKINIT_COMPAT_27: 713178825Sdfr break; 714178825Sdfr default: 715178825Sdfr krb5_abortx(context, "internal pkinit error"); 716178825Sdfr } 717178825Sdfr 718178825Sdfr if (do_win2k) { 719178825Sdfr ReplyKeyPack_Win2k kp; 720178825Sdfr memset(&kp, 0, sizeof(kp)); 721178825Sdfr 722178825Sdfr envelopedAlg = oid_id_rsadsi_des_ede3_cbc(); 723178825Sdfr sdAlg = oid_id_pkcs7_data(); 724178825Sdfr 725178825Sdfr ret = copy_EncryptionKey(reply_key, &kp.replyKey); 726178825Sdfr if (ret) { 727178825Sdfr krb5_clear_error_string(context); 728178825Sdfr goto out; 729178825Sdfr } 730178825Sdfr kp.nonce = client_params->nonce; 731178825Sdfr 732178825Sdfr ASN1_MALLOC_ENCODE(ReplyKeyPack_Win2k, 733178825Sdfr buf.data, buf.length, 734178825Sdfr &kp, &size,ret); 735178825Sdfr free_ReplyKeyPack_Win2k(&kp); 736178825Sdfr } else { 737178825Sdfr krb5_crypto ascrypto; 738178825Sdfr ReplyKeyPack kp; 739178825Sdfr memset(&kp, 0, sizeof(kp)); 740178825Sdfr 741178825Sdfr sdAlg = oid_id_pkrkeydata(); 742178825Sdfr 743178825Sdfr ret = copy_EncryptionKey(reply_key, &kp.replyKey); 744178825Sdfr if (ret) { 745178825Sdfr krb5_clear_error_string(context); 746178825Sdfr goto out; 747178825Sdfr } 748178825Sdfr 749178825Sdfr ret = krb5_crypto_init(context, reply_key, 0, &ascrypto); 750178825Sdfr if (ret) { 751178825Sdfr krb5_clear_error_string(context); 752178825Sdfr goto out; 753178825Sdfr } 754178825Sdfr 755178825Sdfr ret = krb5_create_checksum(context, ascrypto, 6, 0, 756178825Sdfr req_buffer->data, req_buffer->length, 757178825Sdfr &kp.asChecksum); 758178825Sdfr if (ret) { 759178825Sdfr krb5_clear_error_string(context); 760178825Sdfr goto out; 761178825Sdfr } 762178825Sdfr 763178825Sdfr ret = krb5_crypto_destroy(context, ascrypto); 764178825Sdfr if (ret) { 765178825Sdfr krb5_clear_error_string(context); 766178825Sdfr goto out; 767178825Sdfr } 768178825Sdfr ASN1_MALLOC_ENCODE(ReplyKeyPack, buf.data, buf.length, &kp, &size,ret); 769178825Sdfr free_ReplyKeyPack(&kp); 770178825Sdfr } 771178825Sdfr if (ret) { 772178825Sdfr krb5_set_error_string(context, "ASN.1 encoding of ReplyKeyPack " 773178825Sdfr "failed (%d)", ret); 774178825Sdfr goto out; 775178825Sdfr } 776178825Sdfr if (buf.length != size) 777178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 778178825Sdfr 779178825Sdfr { 780178825Sdfr hx509_query *q; 781178825Sdfr hx509_cert cert; 782178825Sdfr 783178825Sdfr ret = hx509_query_alloc(kdc_identity->hx509ctx, &q); 784178825Sdfr if (ret) 785178825Sdfr goto out; 786178825Sdfr 787178825Sdfr hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); 788178825Sdfr hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); 789178825Sdfr 790178825Sdfr ret = hx509_certs_find(kdc_identity->hx509ctx, 791178825Sdfr kdc_identity->certs, 792178825Sdfr q, 793178825Sdfr &cert); 794178825Sdfr hx509_query_free(kdc_identity->hx509ctx, q); 795178825Sdfr if (ret) 796178825Sdfr goto out; 797178825Sdfr 798178825Sdfr ret = hx509_cms_create_signed_1(kdc_identity->hx509ctx, 799178825Sdfr 0, 800178825Sdfr sdAlg, 801178825Sdfr buf.data, 802178825Sdfr buf.length, 803178825Sdfr NULL, 804178825Sdfr cert, 805178825Sdfr client_params->peer, 806178825Sdfr client_params->client_anchors, 807178825Sdfr kdc_identity->certpool, 808178825Sdfr &signed_data); 809178825Sdfr hx509_cert_free(cert); 810178825Sdfr } 811178825Sdfr 812178825Sdfr krb5_data_free(&buf); 813178825Sdfr if (ret) 814178825Sdfr goto out; 815178825Sdfr 816178825Sdfr if (client_params->type == PKINIT_COMPAT_WIN2K) { 817178825Sdfr ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), 818178825Sdfr &signed_data, 819178825Sdfr &buf); 820178825Sdfr if (ret) 821178825Sdfr goto out; 822178825Sdfr krb5_data_free(&signed_data); 823178825Sdfr signed_data = buf; 824178825Sdfr } 825178825Sdfr 826178825Sdfr ret = hx509_cms_envelope_1(kdc_identity->hx509ctx, 827178825Sdfr 0, 828178825Sdfr client_params->cert, 829178825Sdfr signed_data.data, signed_data.length, 830178825Sdfr envelopedAlg, 831178825Sdfr oid_id_pkcs7_signedData(), &buf); 832178825Sdfr if (ret) 833178825Sdfr goto out; 834178825Sdfr 835178825Sdfr ret = _krb5_pk_mk_ContentInfo(context, 836178825Sdfr &buf, 837178825Sdfr oid_id_pkcs7_envelopedData(), 838178825Sdfr content_info); 839178825Sdfrout: 840178825Sdfr krb5_data_free(&buf); 841178825Sdfr krb5_data_free(&signed_data); 842178825Sdfr return ret; 843178825Sdfr} 844178825Sdfr 845178825Sdfr/* 846178825Sdfr * 847178825Sdfr */ 848178825Sdfr 849178825Sdfrstatic krb5_error_code 850178825Sdfrpk_mk_pa_reply_dh(krb5_context context, 851178825Sdfr DH *kdc_dh, 852178825Sdfr pk_client_params *client_params, 853178825Sdfr krb5_keyblock *reply_key, 854178825Sdfr ContentInfo *content_info, 855178825Sdfr hx509_cert *kdc_cert) 856178825Sdfr{ 857178825Sdfr KDCDHKeyInfo dh_info; 858178825Sdfr krb5_data signed_data, buf; 859178825Sdfr ContentInfo contentinfo; 860178825Sdfr krb5_error_code ret; 861178825Sdfr size_t size; 862178825Sdfr heim_integer i; 863178825Sdfr 864178825Sdfr memset(&contentinfo, 0, sizeof(contentinfo)); 865178825Sdfr memset(&dh_info, 0, sizeof(dh_info)); 866178825Sdfr krb5_data_zero(&buf); 867178825Sdfr krb5_data_zero(&signed_data); 868178825Sdfr 869178825Sdfr *kdc_cert = NULL; 870178825Sdfr 871178825Sdfr ret = BN_to_integer(context, kdc_dh->pub_key, &i); 872178825Sdfr if (ret) 873178825Sdfr return ret; 874178825Sdfr 875178825Sdfr ASN1_MALLOC_ENCODE(DHPublicKey, buf.data, buf.length, &i, &size, ret); 876178825Sdfr if (ret) { 877178825Sdfr krb5_set_error_string(context, "ASN.1 encoding of " 878178825Sdfr "DHPublicKey failed (%d)", ret); 879178825Sdfr krb5_clear_error_string(context); 880178825Sdfr return ret; 881178825Sdfr } 882178825Sdfr if (buf.length != size) 883178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 884178825Sdfr 885178825Sdfr dh_info.subjectPublicKey.length = buf.length * 8; 886178825Sdfr dh_info.subjectPublicKey.data = buf.data; 887178825Sdfr 888178825Sdfr dh_info.nonce = client_params->nonce; 889178825Sdfr 890178825Sdfr ASN1_MALLOC_ENCODE(KDCDHKeyInfo, buf.data, buf.length, &dh_info, &size, 891178825Sdfr ret); 892178825Sdfr if (ret) { 893178825Sdfr krb5_set_error_string(context, "ASN.1 encoding of " 894178825Sdfr "KdcDHKeyInfo failed (%d)", ret); 895178825Sdfr goto out; 896178825Sdfr } 897178825Sdfr if (buf.length != size) 898178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 899178825Sdfr 900178825Sdfr /* 901178825Sdfr * Create the SignedData structure and sign the KdcDHKeyInfo 902178825Sdfr * filled in above 903178825Sdfr */ 904178825Sdfr 905178825Sdfr { 906178825Sdfr hx509_query *q; 907178825Sdfr hx509_cert cert; 908178825Sdfr 909178825Sdfr ret = hx509_query_alloc(kdc_identity->hx509ctx, &q); 910178825Sdfr if (ret) 911178825Sdfr goto out; 912178825Sdfr 913178825Sdfr hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); 914178825Sdfr hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); 915178825Sdfr 916178825Sdfr ret = hx509_certs_find(kdc_identity->hx509ctx, 917178825Sdfr kdc_identity->certs, 918178825Sdfr q, 919178825Sdfr &cert); 920178825Sdfr hx509_query_free(kdc_identity->hx509ctx, q); 921178825Sdfr if (ret) 922178825Sdfr goto out; 923178825Sdfr 924178825Sdfr ret = hx509_cms_create_signed_1(kdc_identity->hx509ctx, 925178825Sdfr 0, 926178825Sdfr oid_id_pkdhkeydata(), 927178825Sdfr buf.data, 928178825Sdfr buf.length, 929178825Sdfr NULL, 930178825Sdfr cert, 931178825Sdfr client_params->peer, 932178825Sdfr client_params->client_anchors, 933178825Sdfr kdc_identity->certpool, 934178825Sdfr &signed_data); 935178825Sdfr *kdc_cert = cert; 936178825Sdfr } 937178825Sdfr if (ret) 938178825Sdfr goto out; 939178825Sdfr 940178825Sdfr ret = _krb5_pk_mk_ContentInfo(context, 941178825Sdfr &signed_data, 942178825Sdfr oid_id_pkcs7_signedData(), 943178825Sdfr content_info); 944178825Sdfr if (ret) 945178825Sdfr goto out; 946178825Sdfr 947178825Sdfr out: 948178825Sdfr if (ret && *kdc_cert) { 949178825Sdfr hx509_cert_free(*kdc_cert); 950178825Sdfr *kdc_cert = NULL; 951178825Sdfr } 952178825Sdfr 953178825Sdfr krb5_data_free(&buf); 954178825Sdfr krb5_data_free(&signed_data); 955178825Sdfr free_KDCDHKeyInfo(&dh_info); 956178825Sdfr 957178825Sdfr return ret; 958178825Sdfr} 959178825Sdfr 960178825Sdfr/* 961178825Sdfr * 962178825Sdfr */ 963178825Sdfr 964178825Sdfrkrb5_error_code 965178825Sdfr_kdc_pk_mk_pa_reply(krb5_context context, 966178825Sdfr krb5_kdc_configuration *config, 967178825Sdfr pk_client_params *client_params, 968178825Sdfr const hdb_entry_ex *client, 969178825Sdfr const KDC_REQ *req, 970178825Sdfr const krb5_data *req_buffer, 971178825Sdfr krb5_keyblock **reply_key, 972178825Sdfr METHOD_DATA *md) 973178825Sdfr{ 974178825Sdfr krb5_error_code ret; 975178825Sdfr void *buf; 976178825Sdfr size_t len, size; 977178825Sdfr krb5_enctype enctype; 978178825Sdfr int pa_type; 979178825Sdfr hx509_cert kdc_cert = NULL; 980178825Sdfr int i; 981178825Sdfr 982178825Sdfr if (!config->enable_pkinit) { 983178825Sdfr krb5_clear_error_string(context); 984178825Sdfr return 0; 985178825Sdfr } 986178825Sdfr 987178825Sdfr if (req->req_body.etype.len > 0) { 988178825Sdfr for (i = 0; i < req->req_body.etype.len; i++) 989178825Sdfr if (krb5_enctype_valid(context, req->req_body.etype.val[i]) == 0) 990178825Sdfr break; 991178825Sdfr if (req->req_body.etype.len <= i) { 992178825Sdfr ret = KRB5KRB_ERR_GENERIC; 993178825Sdfr krb5_set_error_string(context, 994178825Sdfr "No valid enctype available from client"); 995178825Sdfr goto out; 996178825Sdfr } 997178825Sdfr enctype = req->req_body.etype.val[i]; 998178825Sdfr } else 999178825Sdfr enctype = ETYPE_DES3_CBC_SHA1; 1000178825Sdfr 1001178825Sdfr if (client_params->type == PKINIT_COMPAT_27) { 1002178825Sdfr PA_PK_AS_REP rep; 1003178825Sdfr const char *type, *other = ""; 1004178825Sdfr 1005178825Sdfr memset(&rep, 0, sizeof(rep)); 1006178825Sdfr 1007178825Sdfr pa_type = KRB5_PADATA_PK_AS_REP; 1008178825Sdfr 1009178825Sdfr if (client_params->dh == NULL) { 1010178825Sdfr ContentInfo info; 1011178825Sdfr 1012178825Sdfr type = "enckey"; 1013178825Sdfr 1014178825Sdfr rep.element = choice_PA_PK_AS_REP_encKeyPack; 1015178825Sdfr 1016178825Sdfr ret = krb5_generate_random_keyblock(context, enctype, 1017178825Sdfr &client_params->reply_key); 1018178825Sdfr if (ret) { 1019178825Sdfr free_PA_PK_AS_REP(&rep); 1020178825Sdfr goto out; 1021178825Sdfr } 1022178825Sdfr ret = pk_mk_pa_reply_enckey(context, 1023178825Sdfr config, 1024178825Sdfr client_params, 1025178825Sdfr req, 1026178825Sdfr req_buffer, 1027178825Sdfr &client_params->reply_key, 1028178825Sdfr &info); 1029178825Sdfr if (ret) { 1030178825Sdfr free_PA_PK_AS_REP(&rep); 1031178825Sdfr goto out; 1032178825Sdfr } 1033178825Sdfr ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data, 1034178825Sdfr rep.u.encKeyPack.length, &info, &size, 1035178825Sdfr ret); 1036178825Sdfr free_ContentInfo(&info); 1037178825Sdfr if (ret) { 1038178825Sdfr krb5_set_error_string(context, "encoding of Key ContentInfo " 1039178825Sdfr "failed %d", ret); 1040178825Sdfr free_PA_PK_AS_REP(&rep); 1041178825Sdfr goto out; 1042178825Sdfr } 1043178825Sdfr if (rep.u.encKeyPack.length != size) 1044178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 1045178825Sdfr 1046178825Sdfr } else { 1047178825Sdfr ContentInfo info; 1048178825Sdfr 1049178825Sdfr type = "dh"; 1050178825Sdfr if (client_params->dh_group_name) 1051178825Sdfr other = client_params->dh_group_name; 1052178825Sdfr 1053178825Sdfr rep.element = choice_PA_PK_AS_REP_dhInfo; 1054178825Sdfr 1055178825Sdfr ret = generate_dh_keyblock(context, client_params, enctype, 1056178825Sdfr &client_params->reply_key); 1057178825Sdfr if (ret) 1058178825Sdfr return ret; 1059178825Sdfr 1060178825Sdfr ret = pk_mk_pa_reply_dh(context, client_params->dh, 1061178825Sdfr client_params, 1062178825Sdfr &client_params->reply_key, 1063178825Sdfr &info, 1064178825Sdfr &kdc_cert); 1065178825Sdfr 1066178825Sdfr ASN1_MALLOC_ENCODE(ContentInfo, rep.u.dhInfo.dhSignedData.data, 1067178825Sdfr rep.u.dhInfo.dhSignedData.length, &info, &size, 1068178825Sdfr ret); 1069178825Sdfr free_ContentInfo(&info); 1070178825Sdfr if (ret) { 1071178825Sdfr krb5_set_error_string(context, "encoding of Key ContentInfo " 1072178825Sdfr "failed %d", ret); 1073178825Sdfr free_PA_PK_AS_REP(&rep); 1074178825Sdfr goto out; 1075178825Sdfr } 1076178825Sdfr if (rep.u.encKeyPack.length != size) 1077178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 1078178825Sdfr 1079178825Sdfr } 1080178825Sdfr if (ret) { 1081178825Sdfr free_PA_PK_AS_REP(&rep); 1082178825Sdfr goto out; 1083178825Sdfr } 1084178825Sdfr 1085178825Sdfr ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret); 1086178825Sdfr free_PA_PK_AS_REP(&rep); 1087178825Sdfr if (ret) { 1088178825Sdfr krb5_set_error_string(context, "encode PA-PK-AS-REP failed %d", 1089178825Sdfr ret); 1090178825Sdfr goto out; 1091178825Sdfr } 1092178825Sdfr if (len != size) 1093178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 1094178825Sdfr 1095178825Sdfr kdc_log(context, config, 0, "PK-INIT using %s %s", type, other); 1096178825Sdfr 1097178825Sdfr } else if (client_params->type == PKINIT_COMPAT_WIN2K) { 1098178825Sdfr PA_PK_AS_REP_Win2k rep; 1099178825Sdfr ContentInfo info; 1100178825Sdfr 1101178825Sdfr if (client_params->dh) { 1102178825Sdfr krb5_set_error_string(context, "Windows PK-INIT doesn't support DH"); 1103178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1104178825Sdfr goto out; 1105178825Sdfr } 1106178825Sdfr 1107178825Sdfr memset(&rep, 0, sizeof(rep)); 1108178825Sdfr 1109178825Sdfr pa_type = KRB5_PADATA_PK_AS_REP_19; 1110178825Sdfr rep.element = choice_PA_PK_AS_REP_encKeyPack; 1111178825Sdfr 1112178825Sdfr ret = krb5_generate_random_keyblock(context, enctype, 1113178825Sdfr &client_params->reply_key); 1114178825Sdfr if (ret) { 1115178825Sdfr free_PA_PK_AS_REP_Win2k(&rep); 1116178825Sdfr goto out; 1117178825Sdfr } 1118178825Sdfr ret = pk_mk_pa_reply_enckey(context, 1119178825Sdfr config, 1120178825Sdfr client_params, 1121178825Sdfr req, 1122178825Sdfr req_buffer, 1123178825Sdfr &client_params->reply_key, 1124178825Sdfr &info); 1125178825Sdfr if (ret) { 1126178825Sdfr free_PA_PK_AS_REP_Win2k(&rep); 1127178825Sdfr goto out; 1128178825Sdfr } 1129178825Sdfr ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data, 1130178825Sdfr rep.u.encKeyPack.length, &info, &size, 1131178825Sdfr ret); 1132178825Sdfr free_ContentInfo(&info); 1133178825Sdfr if (ret) { 1134178825Sdfr krb5_set_error_string(context, "encoding of Key ContentInfo " 1135178825Sdfr "failed %d", ret); 1136178825Sdfr free_PA_PK_AS_REP_Win2k(&rep); 1137178825Sdfr goto out; 1138178825Sdfr } 1139178825Sdfr if (rep.u.encKeyPack.length != size) 1140178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 1141178825Sdfr 1142178825Sdfr ASN1_MALLOC_ENCODE(PA_PK_AS_REP_Win2k, buf, len, &rep, &size, ret); 1143178825Sdfr free_PA_PK_AS_REP_Win2k(&rep); 1144178825Sdfr if (ret) { 1145178825Sdfr krb5_set_error_string(context, 1146178825Sdfr "encode PA-PK-AS-REP-Win2k failed %d", ret); 1147178825Sdfr goto out; 1148178825Sdfr } 1149178825Sdfr if (len != size) 1150178825Sdfr krb5_abortx(context, "Internal ASN.1 encoder error"); 1151178825Sdfr 1152178825Sdfr } else 1153178825Sdfr krb5_abortx(context, "PK-INIT internal error"); 1154178825Sdfr 1155178825Sdfr 1156178825Sdfr ret = krb5_padata_add(context, md, pa_type, buf, len); 1157178825Sdfr if (ret) { 1158178825Sdfr krb5_set_error_string(context, "failed adding PA-PK-AS-REP %d", ret); 1159178825Sdfr free(buf); 1160178825Sdfr goto out; 1161178825Sdfr } 1162178825Sdfr 1163178825Sdfr if (config->pkinit_kdc_ocsp_file) { 1164178825Sdfr 1165178825Sdfr if (ocsp.expire == 0 && ocsp.next_update > kdc_time) { 1166178825Sdfr struct stat sb; 1167178825Sdfr int fd; 1168178825Sdfr 1169178825Sdfr krb5_data_free(&ocsp.data); 1170178825Sdfr 1171178825Sdfr ocsp.expire = 0; 1172178825Sdfr ocsp.next_update = kdc_time + 60 * 5; 1173178825Sdfr 1174178825Sdfr fd = open(config->pkinit_kdc_ocsp_file, O_RDONLY); 1175178825Sdfr if (fd < 0) { 1176178825Sdfr kdc_log(context, config, 0, 1177178825Sdfr "PK-INIT failed to open ocsp data file %d", errno); 1178178825Sdfr goto out_ocsp; 1179178825Sdfr } 1180178825Sdfr ret = fstat(fd, &sb); 1181178825Sdfr if (ret) { 1182178825Sdfr ret = errno; 1183178825Sdfr close(fd); 1184178825Sdfr kdc_log(context, config, 0, 1185178825Sdfr "PK-INIT failed to stat ocsp data %d", ret); 1186178825Sdfr goto out_ocsp; 1187178825Sdfr } 1188178825Sdfr 1189178825Sdfr ret = krb5_data_alloc(&ocsp.data, sb.st_size); 1190178825Sdfr if (ret) { 1191178825Sdfr close(fd); 1192178825Sdfr kdc_log(context, config, 0, 1193178825Sdfr "PK-INIT failed to stat ocsp data %d", ret); 1194178825Sdfr goto out_ocsp; 1195178825Sdfr } 1196178825Sdfr ocsp.data.length = sb.st_size; 1197178825Sdfr ret = read(fd, ocsp.data.data, sb.st_size); 1198178825Sdfr close(fd); 1199178825Sdfr if (ret != sb.st_size) { 1200178825Sdfr kdc_log(context, config, 0, 1201178825Sdfr "PK-INIT failed to read ocsp data %d", errno); 1202178825Sdfr goto out_ocsp; 1203178825Sdfr } 1204178825Sdfr 1205178825Sdfr ret = hx509_ocsp_verify(kdc_identity->hx509ctx, 1206178825Sdfr kdc_time, 1207178825Sdfr kdc_cert, 1208178825Sdfr 0, 1209178825Sdfr ocsp.data.data, ocsp.data.length, 1210178825Sdfr &ocsp.expire); 1211178825Sdfr if (ret) { 1212178825Sdfr kdc_log(context, config, 0, 1213178825Sdfr "PK-INIT failed to verify ocsp data %d", ret); 1214178825Sdfr krb5_data_free(&ocsp.data); 1215178825Sdfr ocsp.expire = 0; 1216178825Sdfr } else if (ocsp.expire > 180) { 1217178825Sdfr ocsp.expire -= 180; /* refetch the ocsp before it expire */ 1218178825Sdfr ocsp.next_update = ocsp.expire; 1219178825Sdfr } else { 1220178825Sdfr ocsp.next_update = kdc_time; 1221178825Sdfr } 1222178825Sdfr out_ocsp: 1223178825Sdfr ret = 0; 1224178825Sdfr } 1225178825Sdfr 1226178825Sdfr if (ocsp.expire != 0 && ocsp.expire > kdc_time) { 1227178825Sdfr 1228178825Sdfr ret = krb5_padata_add(context, md, 1229178825Sdfr KRB5_PADATA_PA_PK_OCSP_RESPONSE, 1230178825Sdfr ocsp.data.data, ocsp.data.length); 1231178825Sdfr if (ret) { 1232178825Sdfr krb5_set_error_string(context, 1233178825Sdfr "Failed adding OCSP response %d", ret); 1234178825Sdfr goto out; 1235178825Sdfr } 1236178825Sdfr } 1237178825Sdfr } 1238178825Sdfr 1239178825Sdfrout: 1240178825Sdfr if (kdc_cert) 1241178825Sdfr hx509_cert_free(kdc_cert); 1242178825Sdfr 1243178825Sdfr if (ret == 0) 1244178825Sdfr *reply_key = &client_params->reply_key; 1245178825Sdfr return ret; 1246178825Sdfr} 1247178825Sdfr 1248178825Sdfrstatic int 1249178825Sdfrmatch_rfc_san(krb5_context context, 1250178825Sdfr krb5_kdc_configuration *config, 1251178825Sdfr hx509_context hx509ctx, 1252178825Sdfr hx509_cert client_cert, 1253178825Sdfr krb5_const_principal match) 1254178825Sdfr{ 1255178825Sdfr hx509_octet_string_list list; 1256178825Sdfr int ret, i, found = 0; 1257178825Sdfr 1258178825Sdfr memset(&list, 0 , sizeof(list)); 1259178825Sdfr 1260178825Sdfr ret = hx509_cert_find_subjectAltName_otherName(hx509ctx, 1261178825Sdfr client_cert, 1262178825Sdfr oid_id_pkinit_san(), 1263178825Sdfr &list); 1264178825Sdfr if (ret) 1265178825Sdfr goto out; 1266178825Sdfr 1267178825Sdfr for (i = 0; !found && i < list.len; i++) { 1268178825Sdfr krb5_principal_data principal; 1269178825Sdfr KRB5PrincipalName kn; 1270178825Sdfr size_t size; 1271178825Sdfr 1272178825Sdfr ret = decode_KRB5PrincipalName(list.val[i].data, 1273178825Sdfr list.val[i].length, 1274178825Sdfr &kn, &size); 1275178825Sdfr if (ret) { 1276178825Sdfr kdc_log(context, config, 0, 1277178825Sdfr "Decoding kerberos name in certificate failed: %s", 1278178825Sdfr krb5_get_err_text(context, ret)); 1279178825Sdfr break; 1280178825Sdfr } 1281178825Sdfr if (size != list.val[i].length) { 1282178825Sdfr kdc_log(context, config, 0, 1283178825Sdfr "Decoding kerberos name have extra bits on the end"); 1284178825Sdfr return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; 1285178825Sdfr } 1286178825Sdfr 1287178825Sdfr principal.name = kn.principalName; 1288178825Sdfr principal.realm = kn.realm; 1289178825Sdfr 1290178825Sdfr if (krb5_principal_compare(context, &principal, match) == TRUE) 1291178825Sdfr found = 1; 1292178825Sdfr free_KRB5PrincipalName(&kn); 1293178825Sdfr } 1294178825Sdfr 1295178825Sdfrout: 1296178825Sdfr hx509_free_octet_string_list(&list); 1297178825Sdfr if (ret) 1298178825Sdfr return ret; 1299178825Sdfr 1300178825Sdfr if (!found) 1301178825Sdfr return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; 1302178825Sdfr 1303178825Sdfr return 0; 1304178825Sdfr} 1305178825Sdfr 1306178825Sdfrstatic int 1307178825Sdfrmatch_ms_upn_san(krb5_context context, 1308178825Sdfr krb5_kdc_configuration *config, 1309178825Sdfr hx509_context hx509ctx, 1310178825Sdfr hx509_cert client_cert, 1311178825Sdfr krb5_const_principal match) 1312178825Sdfr{ 1313178825Sdfr hx509_octet_string_list list; 1314178825Sdfr krb5_principal principal = NULL; 1315178825Sdfr int ret, found = 0; 1316178825Sdfr MS_UPN_SAN upn; 1317178825Sdfr size_t size; 1318178825Sdfr 1319178825Sdfr memset(&list, 0 , sizeof(list)); 1320178825Sdfr 1321178825Sdfr ret = hx509_cert_find_subjectAltName_otherName(hx509ctx, 1322178825Sdfr client_cert, 1323178825Sdfr oid_id_pkinit_ms_san(), 1324178825Sdfr &list); 1325178825Sdfr if (ret) 1326178825Sdfr goto out; 1327178825Sdfr 1328178825Sdfr if (list.len != 1) { 1329178825Sdfr kdc_log(context, config, 0, 1330178825Sdfr "More then one PK-INIT MS UPN SAN"); 1331178825Sdfr goto out; 1332178825Sdfr } 1333178825Sdfr 1334178825Sdfr ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length, &upn, &size); 1335178825Sdfr if (ret) { 1336178825Sdfr kdc_log(context, config, 0, "Decode of MS-UPN-SAN failed"); 1337178825Sdfr goto out; 1338178825Sdfr } 1339178825Sdfr 1340178825Sdfr kdc_log(context, config, 0, "found MS UPN SAN: %s", upn); 1341178825Sdfr 1342178825Sdfr ret = krb5_parse_name(context, upn, &principal); 1343178825Sdfr free_MS_UPN_SAN(&upn); 1344178825Sdfr if (ret) { 1345178825Sdfr kdc_log(context, config, 0, "Failed to parse principal in MS UPN SAN"); 1346178825Sdfr goto out; 1347178825Sdfr } 1348178825Sdfr 1349178825Sdfr /* 1350178825Sdfr * This is very wrong, but will do for now, should really and a 1351178825Sdfr * plugin to the windc layer to very this ACL. 1352178825Sdfr */ 1353178825Sdfr strupr(principal->realm); 1354178825Sdfr 1355178825Sdfr if (krb5_principal_compare(context, principal, match) == TRUE) 1356178825Sdfr found = 1; 1357178825Sdfr 1358178825Sdfrout: 1359178825Sdfr if (principal) 1360178825Sdfr krb5_free_principal(context, principal); 1361178825Sdfr hx509_free_octet_string_list(&list); 1362178825Sdfr if (ret) 1363178825Sdfr return ret; 1364178825Sdfr 1365178825Sdfr if (!found) 1366178825Sdfr return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; 1367178825Sdfr 1368178825Sdfr return 0; 1369178825Sdfr} 1370178825Sdfr 1371178825Sdfrkrb5_error_code 1372178825Sdfr_kdc_pk_check_client(krb5_context context, 1373178825Sdfr krb5_kdc_configuration *config, 1374178825Sdfr const hdb_entry_ex *client, 1375178825Sdfr pk_client_params *client_params, 1376178825Sdfr char **subject_name) 1377178825Sdfr{ 1378178825Sdfr const HDB_Ext_PKINIT_acl *acl; 1379178825Sdfr krb5_error_code ret; 1380178825Sdfr hx509_name name; 1381178825Sdfr int i; 1382178825Sdfr 1383178825Sdfr ret = hx509_cert_get_base_subject(kdc_identity->hx509ctx, 1384178825Sdfr client_params->cert, 1385178825Sdfr &name); 1386178825Sdfr if (ret) 1387178825Sdfr return ret; 1388178825Sdfr 1389178825Sdfr ret = hx509_name_to_string(name, subject_name); 1390178825Sdfr hx509_name_free(&name); 1391178825Sdfr if (ret) 1392178825Sdfr return ret; 1393178825Sdfr 1394178825Sdfr kdc_log(context, config, 0, 1395178825Sdfr "Trying to authorize PK-INIT subject DN %s", 1396178825Sdfr *subject_name); 1397178825Sdfr 1398178825Sdfr if (config->pkinit_princ_in_cert) { 1399178825Sdfr ret = match_rfc_san(context, config, 1400178825Sdfr kdc_identity->hx509ctx, 1401178825Sdfr client_params->cert, 1402178825Sdfr client->entry.principal); 1403178825Sdfr if (ret == 0) { 1404178825Sdfr kdc_log(context, config, 5, 1405178825Sdfr "Found matching PK-INIT SAN in certificate"); 1406178825Sdfr return 0; 1407178825Sdfr } 1408178825Sdfr ret = match_ms_upn_san(context, config, 1409178825Sdfr kdc_identity->hx509ctx, 1410178825Sdfr client_params->cert, 1411178825Sdfr client->entry.principal); 1412178825Sdfr if (ret == 0) { 1413178825Sdfr kdc_log(context, config, 5, 1414178825Sdfr "Found matching MS UPN SAN in certificate"); 1415178825Sdfr return 0; 1416178825Sdfr } 1417178825Sdfr } 1418178825Sdfr 1419178825Sdfr ret = hdb_entry_get_pkinit_acl(&client->entry, &acl); 1420178825Sdfr if (ret == 0 && acl != NULL) { 1421178825Sdfr /* 1422178825Sdfr * Cheat here and compare the generated name with the string 1423178825Sdfr * and not the reverse. 1424178825Sdfr */ 1425178825Sdfr for (i = 0; i < acl->len; i++) { 1426178825Sdfr if (strcmp(*subject_name, acl->val[0].subject) != 0) 1427178825Sdfr continue; 1428178825Sdfr 1429178825Sdfr /* Don't support isser and anchor checking right now */ 1430178825Sdfr if (acl->val[0].issuer) 1431178825Sdfr continue; 1432178825Sdfr if (acl->val[0].anchor) 1433178825Sdfr continue; 1434178825Sdfr 1435178825Sdfr kdc_log(context, config, 5, 1436178825Sdfr "Found matching PK-INIT database ACL"); 1437178825Sdfr return 0; 1438178825Sdfr } 1439178825Sdfr } 1440178825Sdfr 1441178825Sdfr for (i = 0; i < principal_mappings.len; i++) { 1442178825Sdfr krb5_boolean b; 1443178825Sdfr 1444178825Sdfr b = krb5_principal_compare(context, 1445178825Sdfr client->entry.principal, 1446178825Sdfr principal_mappings.val[i].principal); 1447178825Sdfr if (b == FALSE) 1448178825Sdfr continue; 1449178825Sdfr if (strcmp(principal_mappings.val[i].subject, *subject_name) != 0) 1450178825Sdfr continue; 1451178825Sdfr kdc_log(context, config, 5, 1452178825Sdfr "Found matching PK-INIT FILE ACL"); 1453178825Sdfr return 0; 1454178825Sdfr } 1455178825Sdfr 1456178825Sdfr krb5_set_error_string(context, 1457178825Sdfr "PKINIT no matching principals for %s", 1458178825Sdfr *subject_name); 1459178825Sdfr 1460178825Sdfr kdc_log(context, config, 5, 1461178825Sdfr "PKINIT no matching principals for %s", 1462178825Sdfr *subject_name); 1463178825Sdfr 1464178825Sdfr free(*subject_name); 1465178825Sdfr *subject_name = NULL; 1466178825Sdfr 1467178825Sdfr return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; 1468178825Sdfr} 1469178825Sdfr 1470178825Sdfrstatic krb5_error_code 1471178825Sdfradd_principal_mapping(krb5_context context, 1472178825Sdfr const char *principal_name, 1473178825Sdfr const char * subject) 1474178825Sdfr{ 1475178825Sdfr struct pk_allowed_princ *tmp; 1476178825Sdfr krb5_principal principal; 1477178825Sdfr krb5_error_code ret; 1478178825Sdfr 1479178825Sdfr tmp = realloc(principal_mappings.val, 1480178825Sdfr (principal_mappings.len + 1) * sizeof(*tmp)); 1481178825Sdfr if (tmp == NULL) 1482178825Sdfr return ENOMEM; 1483178825Sdfr principal_mappings.val = tmp; 1484178825Sdfr 1485178825Sdfr ret = krb5_parse_name(context, principal_name, &principal); 1486178825Sdfr if (ret) 1487178825Sdfr return ret; 1488178825Sdfr 1489178825Sdfr principal_mappings.val[principal_mappings.len].principal = principal; 1490178825Sdfr 1491178825Sdfr principal_mappings.val[principal_mappings.len].subject = strdup(subject); 1492178825Sdfr if (principal_mappings.val[principal_mappings.len].subject == NULL) { 1493178825Sdfr krb5_free_principal(context, principal); 1494178825Sdfr return ENOMEM; 1495178825Sdfr } 1496178825Sdfr principal_mappings.len++; 1497178825Sdfr 1498178825Sdfr return 0; 1499178825Sdfr} 1500178825Sdfr 1501178825Sdfrkrb5_error_code 1502178825Sdfr_kdc_add_inital_verified_cas(krb5_context context, 1503178825Sdfr krb5_kdc_configuration *config, 1504178825Sdfr pk_client_params *params, 1505178825Sdfr EncTicketPart *tkt) 1506178825Sdfr{ 1507178825Sdfr AD_INITIAL_VERIFIED_CAS cas; 1508178825Sdfr krb5_error_code ret; 1509178825Sdfr krb5_data data; 1510178825Sdfr size_t size; 1511178825Sdfr 1512178825Sdfr memset(&cas, 0, sizeof(cas)); 1513178825Sdfr 1514178825Sdfr /* XXX add CAs to cas here */ 1515178825Sdfr 1516178825Sdfr ASN1_MALLOC_ENCODE(AD_INITIAL_VERIFIED_CAS, data.data, data.length, 1517178825Sdfr &cas, &size, ret); 1518178825Sdfr if (ret) 1519178825Sdfr return ret; 1520178825Sdfr if (data.length != size) 1521178825Sdfr krb5_abortx(context, "internal asn.1 encoder error"); 1522178825Sdfr 1523178825Sdfr ret = _kdc_tkt_add_if_relevant_ad(context, tkt, 1524178825Sdfr KRB5_AUTHDATA_INITIAL_VERIFIED_CAS, 1525178825Sdfr &data); 1526178825Sdfr krb5_data_free(&data); 1527178825Sdfr return ret; 1528178825Sdfr} 1529178825Sdfr 1530178825Sdfr/* 1531178825Sdfr * 1532178825Sdfr */ 1533178825Sdfr 1534178825Sdfrstatic void 1535178825Sdfrload_mappings(krb5_context context, const char *fn) 1536178825Sdfr{ 1537178825Sdfr krb5_error_code ret; 1538178825Sdfr char buf[1024]; 1539178825Sdfr unsigned long lineno = 0; 1540178825Sdfr FILE *f; 1541178825Sdfr 1542178825Sdfr f = fopen(fn, "r"); 1543178825Sdfr if (f == NULL) 1544178825Sdfr return; 1545178825Sdfr 1546178825Sdfr while (fgets(buf, sizeof(buf), f) != NULL) { 1547178825Sdfr char *subject_name, *p; 1548178825Sdfr 1549178825Sdfr buf[strcspn(buf, "\n")] = '\0'; 1550178825Sdfr lineno++; 1551178825Sdfr 1552178825Sdfr p = buf + strspn(buf, " \t"); 1553178825Sdfr 1554178825Sdfr if (*p == '#' || *p == '\0') 1555178825Sdfr continue; 1556178825Sdfr 1557178825Sdfr subject_name = strchr(p, ':'); 1558178825Sdfr if (subject_name == NULL) { 1559178825Sdfr krb5_warnx(context, "pkinit mapping file line %lu " 1560178825Sdfr "missing \":\" :%s", 1561178825Sdfr lineno, buf); 1562178825Sdfr continue; 1563178825Sdfr } 1564178825Sdfr *subject_name++ = '\0'; 1565178825Sdfr 1566178825Sdfr ret = add_principal_mapping(context, p, subject_name); 1567178825Sdfr if (ret) { 1568178825Sdfr krb5_warn(context, ret, "failed to add line %lu \":\" :%s\n", 1569178825Sdfr lineno, buf); 1570178825Sdfr continue; 1571178825Sdfr } 1572178825Sdfr } 1573178825Sdfr 1574178825Sdfr fclose(f); 1575178825Sdfr} 1576178825Sdfr 1577178825Sdfr/* 1578178825Sdfr * 1579178825Sdfr */ 1580178825Sdfr 1581178825Sdfrkrb5_error_code 1582178825Sdfr_kdc_pk_initialize(krb5_context context, 1583178825Sdfr krb5_kdc_configuration *config, 1584178825Sdfr const char *user_id, 1585178825Sdfr const char *anchors, 1586178825Sdfr char **pool, 1587178825Sdfr char **revoke_list) 1588178825Sdfr{ 1589178825Sdfr const char *file; 1590178825Sdfr char *fn = NULL; 1591178825Sdfr krb5_error_code ret; 1592178825Sdfr 1593178825Sdfr file = krb5_config_get_string(context, NULL, 1594178825Sdfr "libdefaults", "moduli", NULL); 1595178825Sdfr 1596178825Sdfr ret = _krb5_parse_moduli(context, file, &moduli); 1597178825Sdfr if (ret) 1598178825Sdfr krb5_err(context, 1, ret, "PKINIT: failed to load modidi file"); 1599178825Sdfr 1600178825Sdfr principal_mappings.len = 0; 1601178825Sdfr principal_mappings.val = NULL; 1602178825Sdfr 1603178825Sdfr ret = _krb5_pk_load_id(context, 1604178825Sdfr &kdc_identity, 1605178825Sdfr user_id, 1606178825Sdfr anchors, 1607178825Sdfr pool, 1608178825Sdfr revoke_list, 1609178825Sdfr NULL, 1610178825Sdfr NULL, 1611178825Sdfr NULL); 1612178825Sdfr if (ret) { 1613178825Sdfr krb5_warn(context, ret, "PKINIT: "); 1614178825Sdfr config->enable_pkinit = 0; 1615178825Sdfr return ret; 1616178825Sdfr } 1617178825Sdfr 1618178825Sdfr { 1619178825Sdfr hx509_query *q; 1620178825Sdfr hx509_cert cert; 1621178825Sdfr 1622178825Sdfr ret = hx509_query_alloc(kdc_identity->hx509ctx, &q); 1623178825Sdfr if (ret) { 1624178825Sdfr krb5_warnx(context, "PKINIT: out of memory"); 1625178825Sdfr return ENOMEM; 1626178825Sdfr } 1627178825Sdfr 1628178825Sdfr hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); 1629178825Sdfr hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); 1630178825Sdfr 1631178825Sdfr ret = hx509_certs_find(kdc_identity->hx509ctx, 1632178825Sdfr kdc_identity->certs, 1633178825Sdfr q, 1634178825Sdfr &cert); 1635178825Sdfr hx509_query_free(kdc_identity->hx509ctx, q); 1636178825Sdfr if (ret == 0) { 1637178825Sdfr if (hx509_cert_check_eku(kdc_identity->hx509ctx, cert, 1638178825Sdfr oid_id_pkkdcekuoid(), 0)) 1639178825Sdfr krb5_warnx(context, "WARNING Found KDC certificate " 1640178825Sdfr "is missing the PK-INIT KDC EKU, this is bad for " 1641178825Sdfr "interoperability."); 1642178825Sdfr hx509_cert_free(cert); 1643178825Sdfr } else 1644178825Sdfr krb5_warnx(context, "PKINIT: failed to find a signing " 1645178825Sdfr "certifiate with a public key"); 1646178825Sdfr } 1647178825Sdfr 1648178825Sdfr ret = krb5_config_get_bool_default(context, 1649178825Sdfr NULL, 1650178825Sdfr FALSE, 1651178825Sdfr "kdc", 1652178825Sdfr "pkinit_allow_proxy_certificate", 1653178825Sdfr NULL); 1654178825Sdfr _krb5_pk_allow_proxy_certificate(kdc_identity, ret); 1655178825Sdfr 1656178825Sdfr file = krb5_config_get_string(context, 1657178825Sdfr NULL, 1658178825Sdfr "kdc", 1659178825Sdfr "pkinit_mappings_file", 1660178825Sdfr NULL); 1661178825Sdfr if (file == NULL) { 1662178825Sdfr asprintf(&fn, "%s/pki-mapping", hdb_db_dir(context)); 1663178825Sdfr file = fn; 1664178825Sdfr } 1665178825Sdfr 1666178825Sdfr load_mappings(context, file); 1667178825Sdfr if (fn) 1668178825Sdfr free(fn); 1669178825Sdfr 1670178825Sdfr return 0; 1671178825Sdfr} 1672178825Sdfr 1673178825Sdfr#endif /* PKINIT */ 1674