/ kdc / pkinit.c
pkinit.c
   1  /*
   2   * Copyright (c) 2003 - 2008 Kungliga Tekniska Högskolan
   3   * (Royal Institute of Technology, Stockholm, Sweden).
   4   * All rights reserved.
   5   *
   6   * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
   7   *
   8   * Redistribution and use in source and binary forms, with or without
   9   * modification, are permitted provided that the following conditions
  10   * are met:
  11   *
  12   * 1. Redistributions of source code must retain the above copyright
  13   *    notice, this list of conditions and the following disclaimer.
  14   *
  15   * 2. Redistributions in binary form must reproduce the above copyright
  16   *    notice, this list of conditions and the following disclaimer in the
  17   *    documentation and/or other materials provided with the distribution.
  18   *
  19   * 3. Neither the name of the Institute nor the names of its contributors
  20   *    may be used to endorse or promote products derived from this software
  21   *    without specific prior written permission.
  22   *
  23   * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  24   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26   * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  27   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33   * SUCH DAMAGE.
  34   */
  35  
  36  #include "kdc_locl.h"
  37  
  38  #ifdef PKINIT
  39  
  40  #include <heim_asn1.h>
  41  #include <rfc2459_asn1.h>
  42  #include <cms_asn1.h>
  43  #include <pkinit_asn1.h>
  44  
  45  #include <hx509.h>
  46  #include "crypto-headers.h"
  47  
  48  struct pk_client_params {
  49      enum krb5_pk_type type;
  50      enum { USE_RSA, USE_DH, USE_ECDH } keyex;
  51      union {
  52  	struct {
  53  	    BIGNUM *public_key;
  54  	    DH *key;
  55  	} dh;
  56  #ifdef HAVE_OPENSSL
  57  	struct {
  58  	    EC_KEY *public_key;
  59  	    EC_KEY *key;
  60  	} ecdh;
  61  #endif
  62      } u;
  63      hx509_cert cert;
  64      hx509_cert tacert;
  65      unsigned nonce;
  66      EncryptionKey reply_key;
  67      char *dh_group_name;
  68      hx509_peer_info peer;
  69      hx509_certs client_anchors;
  70      hx509_verify_ctx verify_ctx;
  71  };
  72  
  73  struct pk_principal_mapping {
  74      unsigned int len;
  75      struct pk_allowed_princ {
  76  	krb5_principal principal;
  77  	char *subject;
  78      } *val;
  79  };
  80  
  81  static struct krb5_pk_identity *kdc_identity;
  82  static struct pk_principal_mapping principal_mappings;
  83  static struct krb5_dh_moduli **moduli;
  84  
  85  static struct {
  86      krb5_data data;
  87      time_t expire;
  88      time_t next_update;
  89  } ocsp;
  90  
  91  /*
  92   *
  93   */
  94  
  95  static krb5_error_code
  96  pk_check_pkauthenticator_win2k(krb5_context context,
  97  			       PKAuthenticator_Win2k *a,
  98  			       const KDC_REQ *req)
  99  {
 100      krb5_timestamp now;
 101  
 102      krb5_timeofday (context, &now);
 103  
 104      /* XXX cusec */
 105      if (a->ctime == 0 || krb5_time_abs(a->ctime, now) > context->max_skew) {
 106  	krb5_clear_error_message(context);
 107  	return KRB5KRB_AP_ERR_SKEW;
 108      }
 109      return 0;
 110  }
 111  
 112  static krb5_error_code
 113  pk_check_pkauthenticator(krb5_context context,
 114  			 PKAuthenticator *a,
 115  			 const KDC_REQ *req)
 116  {
 117      u_char *buf = NULL;
 118      size_t buf_size;
 119      krb5_error_code ret;
 120      size_t len = 0;
 121      krb5_timestamp now;
 122      Checksum checksum;
 123  
 124      krb5_timeofday (context, &now);
 125  
 126      /* XXX cusec */
 127      if (a->ctime == 0 || krb5_time_abs(a->ctime, now) > context->max_skew) {
 128  	krb5_clear_error_message(context);
 129  	return KRB5KRB_AP_ERR_SKEW;
 130      }
 131  
 132      ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, &req->req_body, &len, ret);
 133      if (ret) {
 134  	krb5_clear_error_message(context);
 135  	return ret;
 136      }
 137      if (buf_size != len)
 138  	krb5_abortx(context, "Internal error in ASN.1 encoder");
 139  
 140      ret = krb5_create_checksum(context,
 141  			       NULL,
 142  			       0,
 143  			       CKSUMTYPE_SHA1,
 144  			       buf,
 145  			       len,
 146  			       &checksum);
 147      free(buf);
 148      if (ret) {
 149  	krb5_clear_error_message(context);
 150  	return ret;
 151      }
 152  
 153      if (a->paChecksum == NULL) {
 154  	krb5_clear_error_message(context);
 155  	ret = KRB5_KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
 156  	goto out;
 157      }
 158  
 159      if (der_heim_octet_string_cmp(a->paChecksum, &checksum.checksum) != 0) {
 160  	krb5_clear_error_message(context);
 161  	ret = KRB5KRB_ERR_GENERIC;
 162      }
 163  
 164  out:
 165      free_Checksum(&checksum);
 166  
 167      return ret;
 168  }
 169  
 170  void
 171  _kdc_pk_free_client_param(krb5_context context, pk_client_params *cp)
 172  {
 173      if (cp == NULL)
 174          return;
 175      if (cp->cert)
 176  	hx509_cert_free(cp->cert);
 177      if (cp->tacert)
 178  	hx509_cert_free(cp->tacert);
 179      if (cp->verify_ctx)
 180  	hx509_verify_destroy_ctx(cp->verify_ctx);
 181      if (cp->keyex == USE_DH) {
 182  	if (cp->u.dh.key)
 183  	    DH_free(cp->u.dh.key);
 184  	if (cp->u.dh.public_key)
 185  	    BN_free(cp->u.dh.public_key);
 186      }
 187  #ifdef HAVE_OPENSSL
 188      if (cp->keyex == USE_ECDH) {
 189  	if (cp->u.ecdh.key)
 190  	    EC_KEY_free(cp->u.ecdh.key);
 191  	if (cp->u.ecdh.public_key)
 192  	    EC_KEY_free(cp->u.ecdh.public_key);
 193      }
 194  #endif
 195      krb5_free_keyblock_contents(context, &cp->reply_key);
 196      if (cp->dh_group_name)
 197  	free(cp->dh_group_name);
 198      if (cp->peer)
 199  	hx509_peer_info_free(cp->peer);
 200      if (cp->client_anchors)
 201  	hx509_certs_free(&cp->client_anchors);
 202      memset(cp, 0, sizeof(*cp));
 203      free(cp);
 204  }
 205  
 206  static krb5_error_code
 207  generate_dh_keyblock(krb5_context context,
 208  		     pk_client_params *client_params,
 209                       krb5_enctype enctype)
 210  {
 211      unsigned char *dh_gen_key = NULL;
 212      krb5_keyblock key;
 213      krb5_error_code ret;
 214      int dh_gen_keylen;
 215      size_t size;
 216  
 217      memset(&key, 0, sizeof(key));
 218  
 219      if (client_params->keyex == USE_DH) {
 220  
 221  	if (client_params->u.dh.public_key == NULL) {
 222  	    ret = KRB5KRB_ERR_GENERIC;
 223  	    krb5_set_error_message(context, ret, "public_key");
 224  	    goto out;
 225  	}
 226  
 227  	if (!DH_generate_key(client_params->u.dh.key)) {
 228  	    ret = KRB5KRB_ERR_GENERIC;
 229  	    krb5_set_error_message(context, ret,
 230  				   "Can't generate Diffie-Hellman keys");
 231  	    goto out;
 232  	}
 233  
 234  	size = DH_size(client_params->u.dh.key);
 235  
 236  	dh_gen_key = malloc(size);
 237  	if (dh_gen_key == NULL) {
 238  	    ret = ENOMEM;
 239  	    krb5_set_error_message(context, ret, "malloc: out of memory");
 240  	    goto out;
 241  	}
 242  
 243  	dh_gen_keylen = DH_compute_key(dh_gen_key, client_params->u.dh.public_key, client_params->u.dh.key);
 244  	if (dh_gen_keylen <= 0 || (size_t)dh_gen_keylen < size / 2) {
 245  	    ret = KRB5KRB_ERR_GENERIC;
 246  	    krb5_set_error_message(context, ret,
 247  				   "Can't compute Diffie-Hellman key");
 248  	    goto out;
 249  	}
 250  
 251  	if ((size_t)dh_gen_keylen < size) {
 252  	    size_t diff = size - dh_gen_keylen;
 253  	    memmove(dh_gen_key + diff, dh_gen_key, dh_gen_keylen);
 254  	    memset(dh_gen_key, 0, diff);
 255  	    dh_gen_keylen = (int)size;
 256  	}
 257  
 258  #ifdef HAVE_OPENSSL
 259      } else if (client_params->keyex == USE_ECDH) {
 260  
 261  	if (client_params->u.ecdh.public_key == NULL) {
 262  	    ret = KRB5KRB_ERR_GENERIC;
 263  	    krb5_set_error_message(context, ret, "public_key");
 264  	    goto out;
 265  	}
 266  
 267  	client_params->u.ecdh.key = EC_KEY_new();
 268  	if (client_params->u.ecdh.key == NULL) {
 269  	    ret = ENOMEM;
 270  	    goto out;
 271  	}
 272  	EC_KEY_set_group(client_params->u.ecdh.key,
 273  			 EC_KEY_get0_group(client_params->u.ecdh.public_key));
 274  
 275  	if (EC_KEY_generate_key(client_params->u.ecdh.key) != 1) {
 276  	    ret = ENOMEM;
 277  	    goto out;
 278  	}
 279  
 280  	size = (EC_GROUP_get_degree(EC_KEY_get0_group(client_params->u.ecdh.key)) + 7) / 8;
 281  	dh_gen_key = malloc(size);
 282  	if (dh_gen_key == NULL) {
 283  	    ret = ENOMEM;
 284  	    krb5_set_error_message(context, ret,
 285  				   N_("malloc: out of memory", ""));
 286  	    goto out;
 287  	}
 288  
 289  	dh_gen_keylen = ECDH_compute_key(dh_gen_key, size,
 290  					 EC_KEY_get0_public_key(client_params->u.ecdh.public_key),
 291  					 client_params->u.ecdh.key, NULL);
 292  
 293  #endif /* HAVE_OPENSSL */
 294      } else {
 295  	ret = KRB5KRB_ERR_GENERIC;
 296  	krb5_set_error_message(context, ret,
 297  			       "Diffie-Hellman not selected keys");
 298  	goto out;
 299      }
 300  
 301      ret = _krb5_pk_octetstring2key(context,
 302  				   enctype,
 303  				   dh_gen_key, dh_gen_keylen,
 304  				   NULL, NULL,
 305  				   &client_params->reply_key);
 306  
 307   out:
 308      if (dh_gen_key)
 309  	free(dh_gen_key);
 310      if (key.keyvalue.data)
 311  	krb5_free_keyblock_contents(context, &key);
 312  
 313      return ret;
 314  }
 315  
 316  static BIGNUM *
 317  integer_to_BN(krb5_context context, const char *field, heim_integer *f)
 318  {
 319      BIGNUM *bn;
 320  
 321      bn = BN_bin2bn((const unsigned char *)f->data, (int)f->length, NULL);
 322      if (bn == NULL) {
 323  	krb5_set_error_message(context, KRB5_BADMSGTYPE,
 324  			       "PKINIT: parsing BN failed %s", field);
 325  	return NULL;
 326      }
 327      BN_set_negative(bn, f->negative);
 328      return bn;
 329  }
 330  
 331  static krb5_error_code
 332  get_dh_param(krb5_context context,
 333  	     krb5_kdc_configuration *config,
 334  	     SubjectPublicKeyInfo *dh_key_info,
 335  	     pk_client_params *client_params)
 336  {
 337      DomainParameters dhparam;
 338      DH *dh = NULL;
 339      krb5_error_code ret;
 340  
 341      memset(&dhparam, 0, sizeof(dhparam));
 342  
 343      if ((dh_key_info->subjectPublicKey.length % 8) != 0) {
 344  	ret = KRB5_BADMSGTYPE;
 345  	krb5_set_error_message(context, ret,
 346  			       "PKINIT: subjectPublicKey not aligned "
 347  			       "to 8 bit boundary");
 348  	goto out;
 349      }
 350  
 351      if (dh_key_info->algorithm.parameters == NULL) {
 352  	krb5_set_error_message(context, KRB5_BADMSGTYPE,
 353  			       "PKINIT missing algorithm parameter "
 354  			      "in clientPublicValue");
 355  	return KRB5_BADMSGTYPE;
 356      }
 357  
 358      ret = decode_DomainParameters(dh_key_info->algorithm.parameters->data,
 359  				  dh_key_info->algorithm.parameters->length,
 360  				  &dhparam,
 361  				  NULL);
 362      if (ret) {
 363  	krb5_set_error_message(context, ret, "Can't decode algorithm "
 364  			       "parameters in clientPublicValue");
 365  	goto out;
 366      }
 367  
 368      ret = _krb5_dh_group_ok(context, config->pkinit_dh_min_bits,
 369  			    &dhparam.p, &dhparam.g, &dhparam.q, moduli,
 370  			    &client_params->dh_group_name);
 371      if (ret) {
 372  	/* XXX send back proposal of better group */
 373  	goto out;
 374      }
 375  
 376      dh = DH_new();
 377      if (dh == NULL) {
 378  	ret = ENOMEM;
 379  	krb5_set_error_message(context, ret, "Cannot create DH structure");
 380  	goto out;
 381      }
 382      ret = KRB5_BADMSGTYPE;
 383      dh->p = integer_to_BN(context, "DH prime", &dhparam.p);
 384      if (dh->p == NULL)
 385  	goto out;
 386      dh->g = integer_to_BN(context, "DH base", &dhparam.g);
 387      if (dh->g == NULL)
 388  	goto out;
 389      dh->q = integer_to_BN(context, "DH p-1 factor", &dhparam.q);
 390      if (dh->g == NULL)
 391  	goto out;
 392  
 393      {
 394  	heim_integer glue;
 395  	size_t size;
 396  
 397  	ret = decode_DHPublicKey(dh_key_info->subjectPublicKey.data,
 398  				 dh_key_info->subjectPublicKey.length / 8,
 399  				 &glue,
 400  				 &size);
 401  	if (ret) {
 402  	    krb5_clear_error_message(context);
 403  	    return ret;
 404  	}
 405  
 406  	client_params->u.dh.public_key = integer_to_BN(context,
 407  						       "subjectPublicKey",
 408  						       &glue);
 409  	der_free_heim_integer(&glue);
 410  	if (client_params->u.dh.public_key == NULL) {
 411  	    ret = KRB5_BADMSGTYPE;
 412  	    goto out;
 413  	}
 414      }
 415  
 416      client_params->u.dh.key = dh;
 417      dh = NULL;
 418      ret = 0;
 419  
 420   out:
 421      if (dh)
 422  	DH_free(dh);
 423      free_DomainParameters(&dhparam);
 424      return ret;
 425  }
 426  
 427  #ifdef HAVE_OPENSSL
 428  
 429  static krb5_error_code
 430  get_ecdh_param(krb5_context context,
 431  	       krb5_kdc_configuration *config,
 432  	       SubjectPublicKeyInfo *dh_key_info,
 433  	       pk_client_params *client_params)
 434  {
 435      ECParameters ecp;
 436      EC_KEY *public = NULL;
 437      krb5_error_code ret;
 438      const unsigned char *p;
 439      size_t len;
 440      int nid;
 441  
 442      if (dh_key_info->algorithm.parameters == NULL) {
 443  	krb5_set_error_message(context, KRB5_BADMSGTYPE,
 444  			       "PKINIT missing algorithm parameter "
 445  			       "in clientPublicValue");
 446  	return KRB5_BADMSGTYPE;
 447      }
 448  
 449      memset(&ecp, 0, sizeof(ecp));
 450  
 451      ret = decode_ECParameters(dh_key_info->algorithm.parameters->data,
 452  			      dh_key_info->algorithm.parameters->length, &ecp, &len);
 453      if (ret)
 454  	goto out;
 455  
 456      if (ecp.element != choice_ECParameters_namedCurve) {
 457  	ret = KRB5_BADMSGTYPE;
 458  	goto out;
 459      }
 460  
 461      if (der_heim_oid_cmp(&ecp.u.namedCurve, &asn1_oid_id_ec_group_secp256r1) == 0)
 462  	nid = NID_X9_62_prime256v1;
 463      else {
 464  	ret = KRB5_BADMSGTYPE;
 465  	goto out;
 466      }
 467  
 468      /* XXX verify group is ok */
 469  
 470      public = EC_KEY_new_by_curve_name(nid);
 471  
 472      p = dh_key_info->subjectPublicKey.data;
 473      len = dh_key_info->subjectPublicKey.length / 8;
 474      if (o2i_ECPublicKey(&public, &p, len) == NULL) {
 475  	ret = KRB5_BADMSGTYPE;
 476  	krb5_set_error_message(context, ret,
 477  			       "PKINIT failed to decode ECDH key");
 478  	goto out;
 479      }
 480      client_params->u.ecdh.public_key = public;
 481      public = NULL;
 482  
 483   out:
 484      if (public)
 485  	EC_KEY_free(public);
 486      free_ECParameters(&ecp);
 487      return ret;
 488  }
 489  
 490  #endif /* HAVE_OPENSSL */
 491  
 492  krb5_error_code
 493  _kdc_pk_rd_padata(krb5_context context,
 494  		  krb5_kdc_configuration *config,
 495  		  const KDC_REQ *req,
 496  		  const PA_DATA *pa,
 497  		  hdb_entry_ex *client,
 498  		  pk_client_params **ret_params)
 499  {
 500      pk_client_params *cp;
 501      krb5_error_code ret;
 502      heim_oid eContentType = { 0, NULL }, contentInfoOid = { 0, NULL };
 503      krb5_data eContent = { 0, NULL };
 504      krb5_data signed_content = { 0, NULL };
 505      const char *type = "unknown type";
 506      hx509_certs trust_anchors;
 507      int have_data = 0;
 508      const HDB_Ext_PKINIT_cert *pc;
 509      heim_array_t signer_certs = NULL;
 510  
 511      *ret_params = NULL;
 512  
 513      if (!config->enable_pkinit) {
 514  	kdc_log(context, config, 0, "PK-INIT request but PK-INIT not enabled");
 515  	krb5_clear_error_message(context);
 516  	return 0;
 517      }
 518  
 519      cp = calloc(1, sizeof(*cp));
 520      if (cp == NULL) {
 521  	krb5_clear_error_message(context);
 522  	ret = ENOMEM;
 523  	goto out;
 524      }
 525  
 526      ret = hx509_certs_init(context->hx509ctx,
 527  			   "MEMORY:trust-anchors",
 528  			   0, NULL, &trust_anchors);
 529      if (ret) {
 530  	krb5_set_error_message(context, ret, "failed to create trust anchors");
 531  	goto out;
 532      }
 533  
 534      ret = hx509_certs_merge(context->hx509ctx, trust_anchors,
 535  			    kdc_identity->anchors);
 536      if (ret) {
 537  	hx509_certs_free(&trust_anchors);
 538  	krb5_set_error_message(context, ret, "failed to merge trust anchors");
 539  	goto out;
 540      }
 541  
 542      /* Add any registered certificates for this client as trust anchors */
 543      ret = hdb_entry_get_pkinit_cert(&client->entry, &pc);
 544      if (ret == 0 && pc != NULL) {
 545  	hx509_cert cert;
 546  	unsigned int i;
 547  
 548  	for (i = 0; i < pc->len; i++) {
 549  	    ret = hx509_cert_init_data(context->hx509ctx,
 550  				       pc->val[i].cert.data,
 551  				       pc->val[i].cert.length,
 552  				       &cert);
 553  	    if (ret)
 554  		continue;
 555  	    hx509_certs_add(context->hx509ctx, trust_anchors, cert);
 556  	    hx509_cert_free(cert);
 557  	}
 558      }
 559  
 560      ret = hx509_verify_init_ctx(context->hx509ctx, &cp->verify_ctx);
 561      if (ret) {
 562  	hx509_certs_free(&trust_anchors);
 563  	krb5_set_error_message(context, ret, "failed to create verify context");
 564  	goto out;
 565      }
 566  
 567      hx509_verify_set_time(cp->verify_ctx, kdc_time);
 568      hx509_verify_attach_anchors(cp->verify_ctx, trust_anchors);
 569      hx509_certs_free(&trust_anchors);
 570  
 571      if (config->pkinit_allow_proxy_certs)
 572  	hx509_verify_set_proxy_certificate(cp->verify_ctx, 1);
 573  
 574      if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
 575  	PA_PK_AS_REQ_Win2k r;
 576  
 577  	type = "PK-INIT-Win2k";
 578  
 579  	if (req->req_body.kdc_options.request_anonymous) {
 580  	    ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED;
 581  	    krb5_set_error_message(context, ret,
 582  				   "Anon not supported in RSA mode");
 583  	    goto out;
 584  	}
 585  
 586  	ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data,
 587  					pa->padata_value.length,
 588  					&r,
 589  					NULL);
 590  	if (ret) {
 591  	    krb5_set_error_message(context, ret, "Can't decode "
 592  				   "PK-AS-REQ-Win2k: %d", ret);
 593  	    goto out;
 594  	}
 595  
 596  	ret = hx509_cms_unwrap_ContentInfo(&r.signed_auth_pack,
 597  					   &contentInfoOid,
 598  					   &signed_content,
 599  					   &have_data);
 600  	free_PA_PK_AS_REQ_Win2k(&r);
 601  	if (ret) {
 602  	    krb5_set_error_message(context, ret,
 603  				   "Can't unwrap ContentInfo(win): %d", ret);
 604  	    goto out;
 605  	}
 606  
 607      } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
 608  	PA_PK_AS_REQ r;
 609  
 610  	type = "PK-INIT-IETF";
 611  
 612  	ret = decode_PA_PK_AS_REQ(pa->padata_value.data,
 613  				  pa->padata_value.length,
 614  				  &r,
 615  				  NULL);
 616  	if (ret) {
 617  	    krb5_set_error_message(context, ret,
 618  				   "Can't decode PK-AS-REQ: %d", ret);
 619  	    goto out;
 620  	}
 621  
 622  	/* XXX look at r.kdcPkId */
 623  	if (r.trustedCertifiers) {
 624  	    ExternalPrincipalIdentifiers *edi = r.trustedCertifiers;
 625  	    unsigned int i, maxedi;
 626  
 627  	    ret = hx509_certs_init(context->hx509ctx,
 628  				   "MEMORY:client-anchors",
 629  				   0, NULL,
 630  				   &cp->client_anchors);
 631  	    if (ret) {
 632  		krb5_set_error_message(context, ret,
 633  				       "Can't allocate client anchors: %d",
 634  				       ret);
 635  		goto out;
 636  
 637  	    }
 638  	    /*
 639  	     * If the client sent more then 10 EDI, don't bother
 640  	     * looking more then 10 of performance reasons.
 641  	     */
 642  	    maxedi = edi->len;
 643  	    if (maxedi > 10)
 644  		maxedi = 10;
 645  	    for (i = 0; i < maxedi; i++) {
 646  		IssuerAndSerialNumber iasn;
 647  		hx509_query *q;
 648  		hx509_cert cert;
 649  		size_t size;
 650  
 651  		if (edi->val[i].issuerAndSerialNumber == NULL)
 652  		    continue;
 653  
 654  		ret = hx509_query_alloc(context->hx509ctx, &q);
 655  		if (ret) {
 656  		    krb5_set_error_message(context, ret,
 657  					  "Failed to allocate hx509_query");
 658  		    goto out;
 659  		}
 660  
 661  		ret = decode_IssuerAndSerialNumber(edi->val[i].issuerAndSerialNumber->data,
 662  						   edi->val[i].issuerAndSerialNumber->length,
 663  						   &iasn,
 664  						   &size);
 665  		if (ret) {
 666  		    hx509_query_free(context->hx509ctx, q);
 667  		    continue;
 668  		}
 669  		ret = hx509_query_match_issuer_serial(q, &iasn.issuer, &iasn.serialNumber);
 670  		free_IssuerAndSerialNumber(&iasn);
 671  		if (ret) {
 672  		    hx509_query_free(context->hx509ctx, q);
 673  		    continue;
 674  		}
 675  
 676  		ret = hx509_certs_find(context->hx509ctx,
 677  				       kdc_identity->certs,
 678  				       q,
 679  				       &cert);
 680  		hx509_query_free(context->hx509ctx, q);
 681  		if (ret)
 682  		    continue;
 683  		hx509_certs_add(context->hx509ctx,
 684  				cp->client_anchors, cert);
 685  		hx509_cert_free(cert);
 686  	    }
 687  	}
 688  
 689  	ret = hx509_cms_unwrap_ContentInfo(&r.signedAuthPack,
 690  					   &contentInfoOid,
 691  					   &signed_content,
 692  					   &have_data);
 693  	free_PA_PK_AS_REQ(&r);
 694  	if (ret) {
 695  	    krb5_set_error_message(context, ret,
 696  				   "Can't unwrap ContentInfo: %d", ret);
 697  	    goto out;
 698  	}
 699  
 700      } else {
 701  	krb5_clear_error_message(context);
 702  	ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
 703  	goto out;
 704      }
 705  
 706      ret = der_heim_oid_cmp(&contentInfoOid, &asn1_oid_id_pkcs7_signedData);
 707      if (ret != 0) {
 708  	ret = KRB5KRB_ERR_GENERIC;
 709  	krb5_set_error_message(context, ret,
 710  			       "PK-AS-REQ-Win2k invalid content type oid");
 711  	goto out;
 712      }
 713  
 714      if (!have_data) {
 715  	ret = KRB5KRB_ERR_GENERIC;
 716  	krb5_set_error_message(context, ret,
 717  			      "PK-AS-REQ-Win2k no signed auth pack");
 718  	goto out;
 719      }
 720  
 721      {
 722  	int flags = HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; /* BTMM */
 723  	hx509_evaluate eval;
 724  	size_t len;
 725  
 726  	if (req->req_body.kdc_options.request_anonymous)
 727  	    flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER;
 728  
 729  	ret = hx509_cms_verify_signed(context->hx509ctx,
 730  				      cp->verify_ctx,
 731  				      flags,
 732  				      signed_content.data,
 733  				      signed_content.length,
 734  				      NULL,
 735  				      kdc_identity->certpool,
 736  				      &eContentType,
 737  				      &eContent,
 738  				      &signer_certs);
 739  	if (ret) {
 740  	    char *s = hx509_get_error_string(context->hx509ctx, ret);
 741  	    krb5_warnx(context, "PKINIT: failed to verify signature: %s: %d",
 742  		       s, ret);
 743  	    free(s);
 744  	    goto out;
 745  	}
 746  
 747  	/* if not anonymous, pick up certs */
 748  	if (signer_certs) {
 749  	    ret = KRB5_KDC_ERR_CANT_VERIFY_CERTIFICATE;
 750  
 751  	    len = heim_array_get_length(signer_certs);
 752  	    if (len == 0)
 753  		goto out;
 754  
 755  	    eval = heim_array_copy_value(signer_certs, 0);
 756  	    if (eval == NULL)
 757  		goto out;
 758  
 759  	    len = hx509_evaluate_get_length(eval);
 760  	    if (len == 0) {
 761  		hx509_evaluate_free(eval);
 762  		goto out;
 763  	    }
 764  
 765  	    cp->cert = hx509_evaluate_get_cert(eval, 0);
 766  	    if (cp->cert == NULL) {
 767  		hx509_evaluate_free(eval);
 768  		goto out;
 769  	    }
 770  
 771  	    cp->tacert = hx509_evaluate_get_ta(eval);
 772  	    hx509_evaluate_free(eval);
 773  	    if (cp->tacert == NULL)
 774  		goto out;
 775  	}
 776      }
 777  
 778      /* Signature is correct, now verify the signed message */
 779      if (der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkcs7_data) != 0 &&
 780  	der_heim_oid_cmp(&eContentType, &asn1_oid_id_pkauthdata) != 0)
 781      {
 782  	ret = KRB5_BADMSGTYPE;
 783  	krb5_set_error_message(context, ret, "got wrong oid for pkauthdata");
 784  	goto out;
 785      }
 786  
 787      if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) {
 788  	AuthPack_Win2k ap;
 789  
 790  	ret = decode_AuthPack_Win2k(eContent.data,
 791  				    eContent.length,
 792  				    &ap,
 793  				    NULL);
 794  	if (ret) {
 795  	    krb5_set_error_message(context, ret,
 796  				   "Can't decode AuthPack: %d", ret);
 797  	    goto out;
 798  	}
 799  
 800  	ret = pk_check_pkauthenticator_win2k(context,
 801  					     &ap.pkAuthenticator,
 802  					     req);
 803  	if (ret) {
 804  	    free_AuthPack_Win2k(&ap);
 805  	    goto out;
 806  	}
 807  
 808  	cp->type = PKINIT_WIN2K;
 809  	cp->nonce = ap.pkAuthenticator.nonce;
 810  
 811  	if (ap.clientPublicValue) {
 812  	    ret = KRB5KRB_ERR_GENERIC;
 813  	    krb5_set_error_message(context, ret,
 814  				   "DH not supported for windows");
 815  	    goto out;
 816  	}
 817  	free_AuthPack_Win2k(&ap);
 818  
 819      } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) {
 820  	AuthPack ap;
 821  
 822  	ret = decode_AuthPack(eContent.data,
 823  			      eContent.length,
 824  			      &ap,
 825  			      NULL);
 826  	if (ret) {
 827  	    krb5_set_error_message(context, ret,
 828  				   "Can't decode AuthPack: %d", ret);
 829  	    free_AuthPack(&ap);
 830  	    goto out;
 831  	}
 832  
 833  	if (req->req_body.kdc_options.request_anonymous &&
 834  	    ap.clientPublicValue == NULL) {
 835  	    free_AuthPack(&ap);
 836  	    ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED;
 837  	    krb5_set_error_message(context, ret,
 838  				   "Anon not supported in RSA mode");
 839  	    goto out;
 840  	}
 841  
 842  	ret = pk_check_pkauthenticator(context,
 843  				       &ap.pkAuthenticator,
 844  				       req);
 845  	if (ret) {
 846  	    free_AuthPack(&ap);
 847  	    goto out;
 848  	}
 849  
 850  	cp->type = PKINIT_27;
 851  	cp->nonce = ap.pkAuthenticator.nonce;
 852  
 853  	if (ap.clientPublicValue) {
 854  	    if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_dhpublicnumber) == 0) {
 855  		cp->keyex = USE_DH;
 856  		ret = get_dh_param(context, config,
 857  				   ap.clientPublicValue, cp);
 858  #ifdef HAVE_OPENSSL
 859  	    } else if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_ecPublicKey) == 0) {
 860  		cp->keyex = USE_ECDH;
 861  		ret = get_ecdh_param(context, config,
 862  				     ap.clientPublicValue, cp);
 863  #endif /* HAVE_OPENSSL */
 864  	    } else {
 865  		ret = KRB5_BADMSGTYPE;
 866  		krb5_set_error_message(context, ret, "PKINIT unknown DH mechanism");
 867  	    }
 868  	    if (ret) {
 869  		free_AuthPack(&ap);
 870  		goto out;
 871  	    }
 872  	} else
 873  	    cp->keyex = USE_RSA;
 874  
 875  	ret = hx509_peer_info_alloc(context->hx509ctx,
 876  					&cp->peer);
 877  	if (ret) {
 878  	    free_AuthPack(&ap);
 879  	    goto out;
 880  	}
 881  
 882  	if (ap.supportedCMSTypes) {
 883  	    ret = hx509_peer_info_set_cms_algs(context->hx509ctx,
 884  					       cp->peer,
 885  					       ap.supportedCMSTypes->val,
 886  					       ap.supportedCMSTypes->len);
 887  	    if (ret) {
 888  		free_AuthPack(&ap);
 889  		goto out;
 890  	    }
 891  	} else {
 892  	    /* assume old client */
 893  	    hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer,
 894  					hx509_crypto_des_rsdi_ede3_cbc());
 895  	    hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer,
 896  					hx509_signature_rsa_with_sha1());
 897  	    hx509_peer_info_add_cms_alg(context->hx509ctx, cp->peer,
 898  					hx509_signature_sha1());
 899  	}
 900  	free_AuthPack(&ap);
 901      } else
 902  	krb5_abortx(context, "internal pkinit error");
 903  
 904      kdc_log(context, config, 0, "PK-INIT request of type %s", type);
 905  
 906  out:
 907      if (ret)
 908  	krb5_warn(context, ret, "PKINIT");
 909  
 910      heim_release(signer_certs);
 911  
 912      if (signed_content.data)
 913  	free(signed_content.data);
 914      krb5_data_free(&eContent);
 915      der_free_oid(&eContentType);
 916      der_free_oid(&contentInfoOid);
 917      if (ret) {
 918          _kdc_pk_free_client_param(context, cp);
 919      } else
 920  	*ret_params = cp;
 921      return ret;
 922  }
 923  
 924  /*
 925   *
 926   */
 927  
 928  static krb5_error_code
 929  BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer)
 930  {
 931      integer->length = BN_num_bytes(bn);
 932      integer->data = malloc(integer->length);
 933      if (integer->data == NULL) {
 934  	krb5_clear_error_message(context);
 935  	return ENOMEM;
 936      }
 937      BN_bn2bin(bn, integer->data);
 938      integer->negative = BN_is_negative(bn);
 939      return 0;
 940  }
 941  
 942  static krb5_error_code
 943  pk_mk_pa_reply_enckey(krb5_context context,
 944  		      krb5_kdc_configuration *config,
 945  		      pk_client_params *cp,
 946  		      const KDC_REQ *req,
 947  		      const krb5_data *req_buffer,
 948  		      krb5_keyblock *reply_key,
 949  		      ContentInfo *content_info,
 950  		      hx509_cert *kdc_cert)
 951  {
 952      const heim_oid *envelopedAlg = NULL, *sdAlg = NULL, *evAlg = NULL;
 953      krb5_error_code ret;
 954      krb5_data buf, signed_data;
 955      size_t size = 0;
 956      int do_win2k = 0;
 957  
 958      krb5_data_zero(&buf);
 959      krb5_data_zero(&signed_data);
 960  
 961      *kdc_cert = NULL;
 962  
 963      /*
 964       * If the message client is a win2k-type but it send pa data
 965       * 09-binding it expects a IETF (checksum) reply so there can be
 966       * no replay attacks.
 967       */
 968  
 969      switch (cp->type) {
 970      case PKINIT_WIN2K: {
 971  	int i = 0;
 972  	if (_kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_09_BINDING) == NULL
 973  	    && config->pkinit_require_binding == 0)
 974  	{
 975  	    do_win2k = 1;
 976  	}
 977  	sdAlg = &asn1_oid_id_pkcs7_data;
 978  	evAlg = &asn1_oid_id_pkcs7_data;
 979  	envelopedAlg = &asn1_oid_id_rsadsi_des_ede3_cbc;
 980  	break;
 981      }
 982      case PKINIT_27:
 983  	sdAlg = &asn1_oid_id_pkrkeydata;
 984  	evAlg = &asn1_oid_id_pkcs7_signedData;
 985  	break;
 986      }
 987  
 988      if (do_win2k) {
 989  	ReplyKeyPack_Win2k kp;
 990  	memset(&kp, 0, sizeof(kp));
 991  
 992  	ret = copy_EncryptionKey(reply_key, &kp.replyKey);
 993  	if (ret) {
 994  	    krb5_clear_error_message(context);
 995  	    goto out;
 996  	}
 997  	kp.nonce = cp->nonce;
 998  
 999  	ASN1_MALLOC_ENCODE(ReplyKeyPack_Win2k,
1000  			   buf.data, buf.length,
1001  			   &kp, &size,ret);
1002  	free_ReplyKeyPack_Win2k(&kp);
1003      } else {
1004  	krb5_crypto ascrypto;
1005  	ReplyKeyPack kp;
1006  	memset(&kp, 0, sizeof(kp));
1007  
1008  	ret = copy_EncryptionKey(reply_key, &kp.replyKey);
1009  	if (ret) {
1010  	    krb5_clear_error_message(context);
1011  	    goto out;
1012  	}
1013  
1014  	ret = krb5_crypto_init(context, reply_key, 0, &ascrypto);
1015  	if (ret) {
1016  	    krb5_clear_error_message(context);
1017  	    goto out;
1018  	}
1019  
1020  	ret = krb5_create_checksum(context, ascrypto, 6, 0,
1021  				   req_buffer->data, req_buffer->length,
1022  				   &kp.asChecksum);
1023  	if (ret) {
1024  	    krb5_clear_error_message(context);
1025  	    goto out;
1026  	}
1027  
1028  	ret = krb5_crypto_destroy(context, ascrypto);
1029  	if (ret) {
1030  	    krb5_clear_error_message(context);
1031  	    goto out;
1032  	}
1033  	ASN1_MALLOC_ENCODE(ReplyKeyPack, buf.data, buf.length, &kp, &size,ret);
1034  	free_ReplyKeyPack(&kp);
1035      }
1036      if (ret) {
1037  	krb5_set_error_message(context, ret, "ASN.1 encoding of ReplyKeyPack "
1038  			       "failed (%d)", ret);
1039  	goto out;
1040      }
1041      if (buf.length != size)
1042  	krb5_abortx(context, "Internal ASN.1 encoder error");
1043  
1044      {
1045  	hx509_query *q;
1046  	hx509_cert cert;
1047  
1048  	ret = hx509_query_alloc(context->hx509ctx, &q);
1049  	if (ret)
1050  	    goto out;
1051  
1052  	hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
1053  	if (config->pkinit_kdc_friendly_name)
1054  	    hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);
1055  
1056  	ret = hx509_certs_find(context->hx509ctx,
1057  			       kdc_identity->certs,
1058  			       q,
1059  			       &cert);
1060  	hx509_query_free(context->hx509ctx, q);
1061  	if (ret)
1062  	    goto out;
1063  
1064  	ret = hx509_cms_create_signed_1(context->hx509ctx,
1065  					0,
1066  					sdAlg,
1067  					buf.data,
1068  					buf.length,
1069  					NULL,
1070  					cert,
1071  					cp->peer,
1072  					cp->client_anchors,
1073  					kdc_identity->certpool,
1074  					&signed_data);
1075  	*kdc_cert = cert;
1076      }
1077  
1078      krb5_data_free(&buf);
1079      if (ret)
1080  	goto out;
1081  
1082      if (cp->type == PKINIT_WIN2K) {
1083  	ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData,
1084  					 &signed_data,
1085  					 &buf);
1086  	if (ret)
1087  	    goto out;
1088  	krb5_data_free(&signed_data);
1089  	signed_data = buf;
1090      }
1091  
1092      ret = hx509_cms_envelope_1(context->hx509ctx,
1093  			       HX509_CMS_EV_NO_KU_CHECK,
1094  			       cp->cert,
1095  			       signed_data.data, signed_data.length,
1096  			       envelopedAlg,
1097  			       evAlg, &buf);
1098      if (ret)
1099  	goto out;
1100  
1101      ret = _krb5_pk_mk_ContentInfo(context,
1102  				  &buf,
1103  				  &asn1_oid_id_pkcs7_envelopedData,
1104  				  content_info);
1105  out:
1106      if (ret && *kdc_cert) {
1107          hx509_cert_free(*kdc_cert);
1108  	*kdc_cert = NULL;
1109      }
1110  
1111      krb5_data_free(&buf);
1112      krb5_data_free(&signed_data);
1113      return ret;
1114  }
1115  
1116  /*
1117   *
1118   */
1119  
1120  static krb5_error_code
1121  pk_mk_pa_reply_dh(krb5_context context,
1122  		  krb5_kdc_configuration *config,
1123        		  pk_client_params *cp,
1124  		  ContentInfo *content_info,
1125  		  hx509_cert *kdc_cert)
1126  {
1127      KDCDHKeyInfo dh_info;
1128      krb5_data signed_data, buf;
1129      ContentInfo contentinfo;
1130      krb5_error_code ret;
1131      hx509_cert cert;
1132      hx509_query *q;
1133      size_t size = 0;
1134  
1135      memset(&contentinfo, 0, sizeof(contentinfo));
1136      memset(&dh_info, 0, sizeof(dh_info));
1137      krb5_data_zero(&signed_data);
1138      krb5_data_zero(&buf);
1139  
1140      *kdc_cert = NULL;
1141  
1142      if (cp->keyex == USE_DH) {
1143  	DH *kdc_dh = cp->u.dh.key;
1144  	heim_integer i;
1145  
1146  	ret = BN_to_integer(context, kdc_dh->pub_key, &i);
1147  	if (ret)
1148  	    return ret;
1149  
1150  	ASN1_MALLOC_ENCODE(DHPublicKey, buf.data, buf.length, &i, &size, ret);
1151  	der_free_heim_integer(&i);
1152  	if (ret) {
1153  	    krb5_set_error_message(context, ret, "ASN.1 encoding of "
1154  				   "DHPublicKey failed (%d)", ret);
1155  	    return ret;
1156  	}
1157  	if (buf.length != size)
1158  	    krb5_abortx(context, "Internal ASN.1 encoder error");
1159  
1160  	dh_info.subjectPublicKey.length = buf.length * 8;
1161  	dh_info.subjectPublicKey.data = buf.data;
1162  	krb5_data_zero(&buf);
1163  #ifdef HAVE_OPENSSL
1164      } else if (cp->keyex == USE_ECDH) {
1165  	unsigned char *p;
1166  	int len;
1167  
1168  	len = i2o_ECPublicKey(cp->u.ecdh.key, NULL);
1169  	if (len <= 0)
1170  	    abort();
1171  
1172  	p = malloc(len);
1173  	if (p == NULL)
1174  	    abort();
1175  
1176  	dh_info.subjectPublicKey.length = len * 8;
1177  	dh_info.subjectPublicKey.data = p;
1178  
1179  	len = i2o_ECPublicKey(cp->u.ecdh.key, &p);
1180  	if (len <= 0)
1181  	    abort();
1182  #endif
1183      } else
1184  	krb5_abortx(context, "no keyex selected ?");
1185  
1186  
1187      dh_info.nonce = cp->nonce;
1188  
1189      ASN1_MALLOC_ENCODE(KDCDHKeyInfo, buf.data, buf.length, &dh_info, &size,
1190  		       ret);
1191      if (ret) {
1192  	krb5_set_error_message(context, ret, "ASN.1 encoding of "
1193  			       "KdcDHKeyInfo failed (%d)", ret);
1194  	goto out;
1195      }
1196      if (buf.length != size)
1197  	krb5_abortx(context, "Internal ASN.1 encoder error");
1198  
1199      /*
1200       * Create the SignedData structure and sign the KdcDHKeyInfo
1201       * filled in above
1202       */
1203  
1204      ret = hx509_query_alloc(context->hx509ctx, &q);
1205      if (ret)
1206  	goto out;
1207  
1208      hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
1209      if (config->pkinit_kdc_friendly_name)
1210  	hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);
1211  
1212      ret = hx509_certs_find(context->hx509ctx,
1213  			   kdc_identity->certs,
1214  			   q,
1215  			   &cert);
1216      hx509_query_free(context->hx509ctx, q);
1217      if (ret)
1218  	goto out;
1219  
1220      ret = hx509_cms_create_signed_1(context->hx509ctx,
1221  				    0,
1222  				    &asn1_oid_id_pkdhkeydata,
1223  				    buf.data,
1224  				    buf.length,
1225  				    NULL,
1226  				    cert,
1227  				    cp->peer,
1228  				    cp->client_anchors,
1229  				    kdc_identity->certpool,
1230  				    &signed_data);
1231      if (ret) {
1232  	kdc_log(context, config, 0, "Failed signing the DH* reply: %d", ret);
1233  	goto out;
1234      }
1235      *kdc_cert = cert;
1236  
1237      ret = _krb5_pk_mk_ContentInfo(context,
1238  				  &signed_data,
1239  				  &asn1_oid_id_pkcs7_signedData,
1240  				  content_info);
1241      if (ret)
1242  	goto out;
1243  
1244   out:
1245      if (ret && *kdc_cert) {
1246  	hx509_cert_free(*kdc_cert);
1247  	*kdc_cert = NULL;
1248      }
1249  
1250      krb5_data_free(&buf);
1251      krb5_data_free(&signed_data);
1252      free_KDCDHKeyInfo(&dh_info);
1253  
1254      return ret;
1255  }
1256  
1257  /*
1258   *
1259   */
1260  
1261  static krb5_error_code
1262  create_fxkey(krb5_context context,
1263  	     METHOD_DATA *md,
1264  	     krb5_keyblock *reply_key,
1265  	     krb5_enctype sessionetype,
1266  	     krb5_keyblock *sessionkey)
1267  {
1268      krb5_crypto reply_crypto = NULL, kxkey_crypto = NULL;
1269      krb5_data pepper1, pepper2, data;
1270      EncryptedData encdata;
1271      krb5_error_code ret;
1272      krb5_keyblock kxkey;
1273      size_t size = 0;
1274  
1275      ret = krb5_generate_random_keyblock(context, sessionetype, &kxkey);
1276      if (ret)
1277  	return ret;
1278  
1279      ret = krb5_crypto_init(context, reply_key, 0, &reply_crypto);
1280      if (ret)
1281  	goto out;
1282  
1283      ret = krb5_crypto_init(context, &kxkey, 0, &kxkey_crypto);
1284      if (ret)
1285  	goto out;
1286  
1287      pepper1.data = "PKINIT";
1288      pepper1.length = strlen(pepper1.data);
1289      /* MIT uses KEYEXCHANGE, rfc6112 say KeyExchange */
1290      pepper2.data = "KEYEXCHANGE";
1291      pepper2.length = strlen(pepper2.data);
1292  
1293      ret = krb5_crypto_fx_cf2(context, kxkey_crypto, reply_crypto,
1294  			     &pepper1, &pepper2, sessionetype,
1295  			     sessionkey);
1296      if (ret)
1297  	goto out;
1298  
1299      ASN1_MALLOC_ENCODE(EncryptionKey, data.data, data.length, &kxkey, &size, ret);
1300      if (ret)
1301  	goto out;
1302      if(data.length != size)
1303  	krb5_abortx(context, "internal error in ASN.1 encoder");
1304  
1305      ret = krb5_encrypt_EncryptedData(context,
1306  				     reply_crypto,
1307  				     KRB5_KU_PA_PKINIT_KX,
1308  				     data.data,
1309  				     data.length,
1310  				     0,
1311  				     &encdata);
1312      free(data.data);
1313  
1314      ASN1_MALLOC_ENCODE(EncryptedData, data.data, data.length, &encdata, &size, ret);
1315      free_EncryptedData(&encdata);
1316      if (ret)
1317  	goto out;
1318      if(data.length != size)
1319  	krb5_abortx(context, "internal error in ASN.1 encoder");
1320  
1321      ret = krb5_padata_add(context, md, KRB5_PADATA_PKINIT_KX, data.data, data.length);
1322      if (ret)
1323  	free(data.data);
1324  
1325   out:
1326      if (ret)
1327  	krb5_set_error_message(context, ret, "Failed adding PKINIT_KX %d padata", ret);
1328  
1329      krb5_free_keyblock_contents(context, &kxkey);
1330      if (reply_crypto)
1331  	krb5_crypto_destroy(context, reply_crypto);
1332      if (kxkey_crypto)
1333  	krb5_crypto_destroy(context, kxkey_crypto);
1334  
1335      return ret;
1336  }
1337  
1338  
1339  /*
1340   *
1341   */
1342  
1343  krb5_error_code
1344  _kdc_pk_mk_pa_reply(kdc_request_t r, pk_client_params *cp)
1345  {
1346      hx509_cert kdc_cert = NULL;
1347      size_t len = 0, size = 0;
1348      krb5_enctype enctype;
1349      krb5_error_code ret;
1350      void *buf = NULL;
1351      int pa_type;
1352  
1353      if (!r->config->enable_pkinit) {
1354  	krb5_clear_error_message(r->context);
1355  	return 0;
1356      }
1357  
1358      ret = _kdc_get_preferred_enctype(r->context,
1359  				     r->config,
1360  				     r->client,
1361  				     r->client_name,
1362  				     r->req.req_body.etype.val,
1363  				     r->req.req_body.etype.len,
1364  				     &enctype);
1365      if (ret)
1366  	return ret;
1367  
1368      if (cp->type == PKINIT_27) {
1369  	PA_PK_AS_REP rep;
1370  	const char *type = "unknown", *other = "";
1371  
1372  	memset(&rep, 0, sizeof(rep));
1373  
1374  	pa_type = KRB5_PADATA_PK_AS_REP;
1375  
1376  	if (cp->keyex == USE_RSA) {
1377  	    ContentInfo info;
1378  
1379  	    type = "enckey";
1380  
1381  	    rep.element = choice_PA_PK_AS_REP_encKeyPack;
1382  
1383  	    ret = krb5_generate_random_keyblock(r->context, enctype,
1384  						&cp->reply_key);
1385  	    if (ret) {
1386  		free_PA_PK_AS_REP(&rep);
1387  		goto out;
1388  	    }
1389  	    ret = pk_mk_pa_reply_enckey(r->context,
1390  					r->config,
1391  					cp,
1392  					&r->req,
1393  					&r->request,
1394  					&cp->reply_key,
1395  					&info,
1396  					&kdc_cert);
1397  	    if (ret) {
1398  		free_PA_PK_AS_REP(&rep);
1399  		goto out;
1400  	    }
1401  	    ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data,
1402  			       rep.u.encKeyPack.length, &info, &size,
1403  			       ret);
1404  	    free_ContentInfo(&info);
1405  	    if (ret) {
1406  		krb5_set_error_message(r->context, ret, "encoding of Key ContentInfo "
1407  				       "failed %d", ret);
1408  		free_PA_PK_AS_REP(&rep);
1409  		goto out;
1410  	    }
1411  	    if (rep.u.encKeyPack.length != size)
1412  		krb5_abortx(r->context, "Internal ASN.1 encoder error");
1413  
1414  	    ret = krb5_generate_random_keyblock(r->context, r->sessionetype,
1415  						&r->session_key);
1416  	    if (ret) {
1417  		free_PA_PK_AS_REP(&rep);
1418  		goto out;
1419  	    }
1420  
1421  	} else {
1422  	    ContentInfo info;
1423  
1424  	    switch (cp->keyex) {
1425  	    case USE_DH: type = "dh"; break;
1426  #ifdef HAVE_OPENSSL
1427  	    case USE_ECDH: type = "ecdh"; break;
1428  #endif
1429  	    default: krb5_abortx(r->context, "unknown keyex");
1430  	    }
1431  
1432  	    if (cp->dh_group_name)
1433  		other = cp->dh_group_name;
1434  
1435  	    rep.element = choice_PA_PK_AS_REP_dhInfo;
1436  
1437  	    ret = generate_dh_keyblock(r->context, cp, enctype);
1438  	    if (ret)
1439  		return ret;
1440  
1441  	    ret = pk_mk_pa_reply_dh(r->context, r->config,
1442  				    cp,
1443  				    &info,
1444  				    &kdc_cert);
1445  	    if (ret) {
1446  		free_PA_PK_AS_REP(&rep);
1447  		krb5_set_error_message(r->context, ret,
1448  				       "create pa-reply-dh "
1449  				       "failed %d", ret);
1450  		goto out;
1451  	    }
1452  
1453  	    ASN1_MALLOC_ENCODE(ContentInfo, rep.u.dhInfo.dhSignedData.data,
1454  			       rep.u.dhInfo.dhSignedData.length, &info, &size,
1455  			       ret);
1456  	    free_ContentInfo(&info);
1457  	    if (ret) {
1458  		krb5_set_error_message(r->context, ret,
1459  				       "encoding of Key ContentInfo "
1460  				       "failed %d", ret);
1461  		free_PA_PK_AS_REP(&rep);
1462  		goto out;
1463  	    }
1464  	    if (rep.u.encKeyPack.length != size)
1465  		krb5_abortx(r->context, "Internal ASN.1 encoder error");
1466  
1467  	    ret = create_fxkey(r->context, &r->outpadata, &cp->reply_key, r->sessionetype, &r->session_key);
1468  	    if (ret) {
1469  		free_PA_PK_AS_REP(&rep);
1470  		goto out;
1471  	    }
1472  	}
1473  
1474  #define use_btmm_with_enckey 1
1475  	if (use_btmm_with_enckey && rep.element == choice_PA_PK_AS_REP_encKeyPack) {
1476  	    PA_PK_AS_REP_BTMM btmm;
1477  	    heim_any any;
1478  
1479  	    any.data = rep.u.encKeyPack.data;
1480  	    any.length = rep.u.encKeyPack.length;
1481  
1482  	    btmm.dhSignedData = NULL;
1483  	    btmm.encKeyPack = &any;
1484  
1485  	    ASN1_MALLOC_ENCODE(PA_PK_AS_REP_BTMM, buf, len, &btmm, &size, ret);
1486  	} else {
1487  	    ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret);
1488  	}
1489  
1490  	free_PA_PK_AS_REP(&rep);
1491  	if (ret) {
1492  	    krb5_set_error_message(r->context, ret,
1493  				   "encode PA-PK-AS-REP failed %d", ret);
1494  	    goto out;
1495  	}
1496  	if (len != size)
1497  	    krb5_abortx(r->context, "Internal ASN.1 encoder error");
1498  
1499  	kdc_log(r->context, r->config, 0, "PK-INIT using %s %s", type, other);
1500  
1501      } else if (cp->type == PKINIT_WIN2K) {
1502  	PA_PK_AS_REP_Win2k rep;
1503  	ContentInfo info;
1504  
1505  	if (cp->keyex != USE_RSA) {
1506  	    ret = KRB5KRB_ERR_GENERIC;
1507  	    krb5_set_error_message(r->context, ret,
1508  				   "Windows PK-INIT doesn't support DH");
1509  	    goto out;
1510  	}
1511  
1512  	memset(&rep, 0, sizeof(rep));
1513  
1514  	pa_type = KRB5_PADATA_PK_AS_REP_19;
1515  	rep.element = choice_PA_PK_AS_REP_Win2k_encKeyPack;
1516  
1517  	ret = krb5_generate_random_keyblock(r->context, enctype,
1518  					    &cp->reply_key);
1519  	if (ret) {
1520  	    free_PA_PK_AS_REP_Win2k(&rep);
1521  	    goto out;
1522  	}
1523  	ret = pk_mk_pa_reply_enckey(r->context,
1524  				    r->config,
1525  				    cp,
1526  				    &r->req,
1527  				    &r->request,
1528  				    &cp->reply_key,
1529  				    &info,
1530  				    &kdc_cert);
1531  	if (ret) {
1532  	    free_PA_PK_AS_REP_Win2k(&rep);
1533  	    goto out;
1534  	}
1535  	ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data,
1536  			   rep.u.encKeyPack.length, &info, &size,
1537  			   ret);
1538  	free_ContentInfo(&info);
1539  	if (ret) {
1540  	    krb5_set_error_message(r->context, ret, "encoding of Key ContentInfo "
1541  				  "failed %d", ret);
1542  	    free_PA_PK_AS_REP_Win2k(&rep);
1543  	    goto out;
1544  	}
1545  	if (rep.u.encKeyPack.length != size)
1546  	    krb5_abortx(r->context, "Internal ASN.1 encoder error");
1547  
1548  	ASN1_MALLOC_ENCODE(PA_PK_AS_REP_Win2k, buf, len, &rep, &size, ret);
1549  	free_PA_PK_AS_REP_Win2k(&rep);
1550  	if (ret) {
1551  	    krb5_set_error_message(r->context, ret,
1552  				  "encode PA-PK-AS-REP-Win2k failed %d", ret);
1553  	    goto out;
1554  	}
1555  	if (len != size)
1556  	    krb5_abortx(r->context, "Internal ASN.1 encoder error");
1557  
1558  	ret = krb5_generate_random_keyblock(r->context, r->sessionetype,
1559  					    &r->session_key);
1560  	if (ret) {
1561  	    free(buf);
1562  	    goto out;
1563  	}
1564  
1565      } else
1566  	krb5_abortx(r->context, "PK-INIT internal error");
1567  
1568  
1569      ret = krb5_padata_add(r->context, &r->outpadata, pa_type, buf, len);
1570      if (ret) {
1571  	krb5_set_error_message(r->context, ret,
1572  			       "Failed adding PA-PK-AS-REP %d", ret);
1573  	free(buf);
1574  	goto out;
1575      }
1576  
1577      if (r->config->pkinit_kdc_ocsp_file) {
1578  
1579  	if (ocsp.expire == 0 && ocsp.next_update > kdc_time) {
1580  	    struct stat sb;
1581  	    ssize_t sret;
1582  	    int fd;
1583  
1584  	    krb5_data_free(&ocsp.data);
1585  
1586  	    ocsp.expire = 0;
1587  	    ocsp.next_update = kdc_time + 60 * 5;
1588  
1589  	    fd = open(r->config->pkinit_kdc_ocsp_file, O_RDONLY);
1590  	    if (fd < 0) {
1591  		kdc_log(r->context, r->config, 0,
1592  			"PK-INIT failed to open ocsp data file %d", errno);
1593  		goto out_ocsp;
1594  	    }
1595  	    ret = fstat(fd, &sb);
1596  	    if (ret) {
1597  		ret = errno;
1598  		close(fd);
1599  		kdc_log(r->context, r->config, 0,
1600  			"PK-INIT failed to stat ocsp data %d", ret);
1601  		goto out_ocsp;
1602  	    }
1603  	    if (sb.st_size > (off_t)(SIZE_T_MAX >> 1)) {
1604  		ret = errno;
1605  		close(fd);
1606  		kdc_log(r->context, r->config, 0,
1607  			"PK-INIT OCSP data too large %d", ret);
1608  		goto out_ocsp;
1609  	    }
1610  	    ret = krb5_data_alloc(&ocsp.data, (size_t)sb.st_size);
1611  	    if (ret) {
1612  		close(fd);
1613  		kdc_log(r->context, r->config, 0,
1614  			"PK-INIT failed to stat ocsp data %d", ret);
1615  		goto out_ocsp;
1616  	    }
1617  	    ocsp.data.length = (size_t)sb.st_size;
1618  	    sret = read(fd, ocsp.data.data, (size_t)sb.st_size);
1619  	    close(fd);
1620  	    if (sret != sb.st_size) {
1621  		kdc_log(r->context, r->config, 0,
1622  			"PK-INIT failed to read ocsp data %d", errno);
1623  		goto out_ocsp;
1624  	    }
1625  
1626  	    ret = hx509_ocsp_verify(r->context->hx509ctx,
1627  				    kdc_time,
1628  				    kdc_cert,
1629  				    0,
1630  				    ocsp.data.data, ocsp.data.length,
1631  				    &ocsp.expire);
1632  	    if (ret) {
1633  		kdc_log(r->context, r->config, 0,
1634  			"PK-INIT failed to verify ocsp data %d", ret);
1635  		krb5_data_free(&ocsp.data);
1636  		ocsp.expire = 0;
1637  	    } else if (ocsp.expire > 180) {
1638  		ocsp.expire -= 180; /* refetch the ocsp before it expire */
1639  		ocsp.next_update = ocsp.expire;
1640  	    } else {
1641  		ocsp.next_update = kdc_time;
1642  	    }
1643  	out_ocsp:
1644  	    ret = 0;
1645  	}
1646  
1647  	if (ocsp.expire != 0 && ocsp.expire > kdc_time) {
1648  
1649  	    ret = krb5_padata_add(r->context, &r->outpadata,
1650  				  KRB5_PADATA_PA_PK_OCSP_RESPONSE,
1651  				  ocsp.data.data, ocsp.data.length);
1652  	    if (ret) {
1653  		krb5_set_error_message(r->context, ret,
1654  				       "Failed adding OCSP response %d", ret);
1655  		goto out;
1656  	    }
1657  	}
1658      }
1659  
1660  out:
1661      if (kdc_cert)
1662  	hx509_cert_free(kdc_cert);
1663  
1664      if (ret == 0)
1665  	ret = krb5_copy_keyblock_contents(r->context, &cp->reply_key, &r->reply_key);
1666      return ret;
1667  }
1668  
1669  static int
1670  match_rfc_san(krb5_context context,
1671  	      krb5_kdc_configuration *config,
1672  	      hx509_context hx509ctx,
1673  	      hx509_cert client_cert,
1674  	      krb5_const_principal match)
1675  {
1676      hx509_octet_string_list list;
1677      int ret, found = 0;
1678      size_t i;
1679  
1680      memset(&list, 0 , sizeof(list));
1681  
1682      ret = hx509_cert_find_subjectAltName_otherName(hx509ctx,
1683  						   client_cert,
1684  						   &asn1_oid_id_pkinit_san,
1685  						   &list);
1686      if (ret)
1687  	goto out;
1688  
1689      for (i = 0; !found && i < list.len; i++) {
1690  	krb5_principal_data principal;
1691  	KRB5PrincipalName kn;
1692  	size_t size;
1693  
1694  	ret = decode_KRB5PrincipalName(list.val[i].data,
1695  				       list.val[i].length,
1696  				       &kn, &size);
1697  	if (ret) {
1698  	    const char *msg = krb5_get_error_message(context, ret);
1699  	    kdc_log(context, config, 0,
1700  		    "Decoding kerberos name in certificate failed: %s", msg);
1701  	    krb5_free_error_message(context, msg);
1702  	    break;
1703  	}
1704  	if (size != list.val[i].length) {
1705  	    kdc_log(context, config, 0,
1706  		    "Decoding kerberos name have extra bits on the end");
1707  	    ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1708  	    break;
1709  	}
1710  
1711  	principal.name = kn.principalName;
1712  	principal.realm = kn.realm;
1713  
1714  	if (krb5_principal_compare(context, &principal, match) == TRUE)
1715  	    found = 1;
1716  	free_KRB5PrincipalName(&kn);
1717      }
1718  
1719  out:
1720      hx509_free_octet_string_list(&list);
1721      if (ret)
1722  	return ret;
1723  
1724      if (!found)
1725  	return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1726  
1727      return 0;
1728  }
1729  
1730  static int
1731  match_ms_upn_san(krb5_context context,
1732  		 krb5_kdc_configuration *config,
1733  		 hx509_context hx509ctx,
1734  		 hx509_cert client_cert,
1735  		 HDB *clientdb,
1736  		 hdb_entry_ex *client)
1737  {
1738      hx509_octet_string_list list;
1739      krb5_principal principal = NULL;
1740      int ret;
1741      MS_UPN_SAN upn;
1742      size_t size;
1743  
1744      memset(&list, 0 , sizeof(list));
1745  
1746      ret = hx509_cert_find_subjectAltName_otherName(hx509ctx,
1747  						   client_cert,
1748  						   &asn1_oid_id_pkinit_ms_san,
1749  						   &list);
1750      if (ret)
1751  	goto out;
1752      if (list.len == 0) {
1753  	ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1754  	goto out;
1755      }
1756  
1757      if (list.len != 1) {
1758  	ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1759  	kdc_log(context, config, 0,
1760  		"More then one PK-INIT MS UPN SAN");
1761  	goto out;
1762      }
1763  
1764      ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length, &upn, &size);
1765      if (ret) {
1766  	kdc_log(context, config, 0, "Decode of MS-UPN-SAN failed");
1767  	goto out;
1768      }
1769      if (size != list.val[0].length) {
1770  	free_MS_UPN_SAN(&upn);
1771  	kdc_log(context, config, 0, "Trailing data in ");
1772  	ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1773  	goto out;
1774      }
1775  
1776      kdc_log(context, config, 0, "found MS UPN SAN: %s", upn);
1777  
1778      ret = krb5_parse_name(context, upn, &principal);
1779      free_MS_UPN_SAN(&upn);
1780      if (ret) {
1781  	kdc_log(context, config, 0, "Failed to parse principal in MS UPN SAN");
1782  	goto out;
1783      }
1784  
1785      if (clientdb->hdb_check_pkinit_ms_upn_match) {
1786  	ret = clientdb->hdb_check_pkinit_ms_upn_match(context, clientdb, client, principal);
1787      } else {
1788  
1789  	/*
1790  	 * This is very wrong, but will do for a fallback
1791  	 */
1792  	strupr(principal->realm);
1793  
1794  	if (krb5_principal_compare(context, principal, client->entry.principal) == FALSE)
1795  	    ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1796      }
1797  
1798  out:
1799      if (principal)
1800  	krb5_free_principal(context, principal);
1801      hx509_free_octet_string_list(&list);
1802  
1803      return ret;
1804  }
1805  
1806  krb5_error_code
1807  _kdc_pk_check_client(krb5_context context,
1808  		     krb5_kdc_configuration *config,
1809  		     HDB *clientdb,
1810  		     hdb_entry_ex *client,
1811  		     InitiatorName *pku2uInitiatorAssertion,
1812  		     pk_client_params *cp,
1813  		     char **subject_name)
1814  {
1815      const HDB_Ext_PKINIT_acl *acl;
1816      const HDB_Ext_PKINIT_cert *pc;
1817      krb5_error_code ret;
1818      hx509_name name, issuer = NULL, taname = NULL;
1819      size_t i;
1820  
1821      if (cp->cert == NULL) {
1822  
1823  	*subject_name = strdup("anonymous client");
1824  	if (*subject_name == NULL)
1825  	    return ENOMEM;
1826  	return 0;
1827      }
1828  
1829      ret = hx509_cert_get_base_subject(context->hx509ctx,
1830  				      cp->cert,
1831  				      &name);
1832      if (ret)
1833  	return ret;
1834  
1835      ret = hx509_cert_get_issuer(cp->cert, &issuer);
1836      if (ret) {
1837  	hx509_name_free(&name);
1838  	return ret;
1839      }
1840  
1841      ret = hx509_cert_get_subject(cp->tacert, &taname);
1842      if (ret) {
1843  	hx509_name_free(&name);
1844  	hx509_name_free(&issuer);
1845  	return ret;
1846      }
1847  
1848      ret = hx509_name_to_string(name, subject_name);
1849      if (ret) {
1850  	hx509_name_free(&name);
1851  	hx509_name_free(&issuer);
1852  	hx509_name_free(&taname);
1853  	return ret;
1854      }
1855  
1856      kdc_log(context, config, 0,
1857  	    "Trying to authorize PK-INIT subject DN %s",
1858  	    *subject_name);
1859  
1860      if (pku2uInitiatorAssertion) {
1861  	if (pku2uInitiatorAssertion->element != choice_InitiatorName_nameNotInCert) {
1862  	    kdc_log(context, config, 5,
1863  		    "init name assertion not nameNotInCert");
1864  	    goto fail;
1865  	}
1866  	/* XXX check that assertion is in the cert */
1867      }
1868  
1869      ret = hdb_entry_get_pkinit_cert(&client->entry, &pc);
1870      if (ret == 0 && pc) {
1871  	hx509_cert cert;
1872  	size_t j;
1873  
1874  	for (j = 0; j < pc->len; j++) {
1875  	    ret = hx509_cert_init_data(context->hx509ctx,
1876  				       pc->val[j].cert.data,
1877  				       pc->val[j].cert.length,
1878  				       &cert);
1879  	    if (ret)
1880  		continue;
1881  	    ret = hx509_cert_cmp(cert, cp->cert);
1882  	    hx509_cert_free(cert);
1883  	    if (ret == 0) {
1884  		hx509_name_free(&name);
1885  		hx509_name_free(&issuer);
1886  		hx509_name_free(&taname);
1887  		kdc_log(context, config, 5,
1888  			"Found matching PK-INIT cert in hdb");
1889  		return 0;
1890  	    }
1891  	}
1892      }
1893  
1894      if (config->pkinit_princ_in_cert) {
1895  	ret = match_rfc_san(context, config,
1896  			    context->hx509ctx,
1897  			    cp->cert,
1898  			    client->entry.principal);
1899  	if (ret == 0) {
1900  	    hx509_name_free(&name);
1901  	    hx509_name_free(&issuer);
1902  	    hx509_name_free(&taname);
1903  	    kdc_log(context, config, 5,
1904  		    "Found matching PK-INIT SAN in certificate");
1905  	    return 0;
1906  	}
1907  	ret = match_ms_upn_san(context, config,
1908  			       context->hx509ctx,
1909  			       cp->cert,
1910  			       clientdb,
1911  			       client);
1912  	if (ret == 0) {
1913  	    hx509_name_free(&name);
1914  	    hx509_name_free(&issuer);
1915  	    hx509_name_free(&taname);
1916  	    kdc_log(context, config, 5,
1917  		    "Found matching MS UPN SAN in certificate");
1918  	    return 0;
1919  	}
1920      }
1921  
1922      ret = hdb_entry_get_pkinit_acl(&client->entry, &acl);
1923      if (ret == 0 && acl != NULL) {
1924  
1925  	for (i = 0; i < acl->len; i++) {
1926  	    hx509_name n;
1927  
1928  	    ret = hx509_parse_name(context->hx509ctx, acl->val[i].subject, &n);
1929  	    if (ret)
1930  		continue;
1931  
1932  	    ret = hx509_name_cmp(name, n);
1933  	    hx509_name_free(&n);
1934  	    if (ret)
1935  		continue;
1936  
1937  	    if (acl->val[i].issuer) {
1938  		ret = hx509_parse_name(context->hx509ctx,
1939  				       *acl->val[i].issuer, &n);     
1940  		if (ret)
1941  		    continue;
1942  
1943  		ret = hx509_name_cmp(issuer, n);
1944  		hx509_name_free(&n);
1945  		if (ret)
1946  		    continue;
1947  	    }
1948  	    /* Don't support anchor checking right now */
1949  	    if (acl->val[i].anchor) {
1950  		ret = hx509_parse_name(context->hx509ctx,
1951  				       *acl->val[i].anchor, &n);     
1952  		if (ret)
1953  		    continue;
1954  
1955  		ret = hx509_name_cmp(taname, n);
1956  		hx509_name_free(&n);
1957  		if (ret)
1958  		    continue;
1959  	    }
1960  
1961  	    hx509_name_free(&name);
1962  	    hx509_name_free(&issuer);
1963  	    hx509_name_free(&taname);
1964  	    kdc_log(context, config, 5,
1965  		    "Found matching PK-INIT database ACL");
1966  	    return 0;
1967  	}
1968      }
1969  
1970      for (i = 0; i < principal_mappings.len; i++) {
1971  	krb5_boolean b;
1972  
1973  	b = krb5_principal_compare(context,
1974  				   client->entry.principal,
1975  				   principal_mappings.val[i].principal);
1976  	if (b == FALSE)
1977  	    continue;
1978  	if (strcmp(principal_mappings.val[i].subject, *subject_name) != 0)
1979  	    continue;
1980  
1981  	hx509_name_free(&name);
1982  	hx509_name_free(&issuer);
1983  	hx509_name_free(&taname);
1984  
1985  	kdc_log(context, config, 5,
1986  		"Found matching PK-INIT FILE ACL");
1987  	return 0;
1988      }
1989  
1990   fail:
1991      hx509_name_free(&name);
1992      hx509_name_free(&issuer);
1993      hx509_name_free(&taname);
1994  
1995      ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1996      krb5_set_error_message(context, ret,
1997  			  "PKINIT no matching principals for %s",
1998  			  *subject_name);
1999  
2000      kdc_log(context, config, 5,
2001  	    "PKINIT no matching principals for %s",
2002  	    *subject_name);
2003  
2004      free(*subject_name);
2005      *subject_name = NULL;
2006  
2007      return ret;
2008  }
2009  
2010  static krb5_error_code
2011  add_principal_mapping(krb5_context context,
2012  		      const char *principal_name,
2013  		      const char * subject)
2014  {
2015     struct pk_allowed_princ *tmp;
2016     krb5_principal principal;
2017     krb5_error_code ret;
2018  
2019     tmp = realloc(principal_mappings.val,
2020  	         (principal_mappings.len + 1) * sizeof(*tmp));
2021     if (tmp == NULL)
2022         return ENOMEM;
2023     principal_mappings.val = tmp;
2024  
2025     ret = krb5_parse_name(context, principal_name, &principal);
2026     if (ret)
2027         return ret;
2028  
2029     principal_mappings.val[principal_mappings.len].principal = principal;
2030  
2031     principal_mappings.val[principal_mappings.len].subject = strdup(subject);
2032     if (principal_mappings.val[principal_mappings.len].subject == NULL) {
2033         krb5_free_principal(context, principal);
2034         return ENOMEM;
2035     }
2036     principal_mappings.len++;
2037  
2038     return 0;
2039  }
2040  
2041  krb5_error_code
2042  _kdc_add_inital_verified_cas(krb5_context context,
2043  			     krb5_kdc_configuration *config,
2044  			     pk_client_params *cp,
2045  			     EncTicketPart *tkt)
2046  {
2047      AD_INITIAL_VERIFIED_CAS cas;
2048      krb5_error_code ret;
2049      krb5_data data;
2050      size_t size = 0;
2051  
2052      memset(&cas, 0, sizeof(cas));
2053  
2054      /* XXX add CAs to cas here */
2055  
2056      ASN1_MALLOC_ENCODE(AD_INITIAL_VERIFIED_CAS, data.data, data.length,
2057  		       &cas, &size, ret);
2058      if (ret)
2059  	return ret;
2060      if (data.length != size)
2061  	krb5_abortx(context, "internal asn.1 encoder error");
2062  
2063      ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
2064  				      KRB5_AUTHDATA_INITIAL_VERIFIED_CAS,
2065  				      &data);
2066      krb5_data_free(&data);
2067      return ret;
2068  }
2069  
2070  /*
2071   *
2072   */
2073  
2074  static void
2075  load_mappings(krb5_context context, const char *fn)
2076  {
2077      krb5_error_code ret;
2078      char buf[1024];
2079      unsigned long lineno = 0;
2080      FILE *f;
2081  
2082      f = fopen(fn, "r");
2083      if (f == NULL)
2084  	return;
2085  
2086      while (fgets(buf, sizeof(buf), f) != NULL) {
2087  	char *subject_name, *p;
2088  
2089  	buf[strcspn(buf, "\n")] = '\0';
2090  	lineno++;
2091  
2092  	p = buf + strspn(buf, " \t");
2093  
2094  	if (*p == '#' || *p == '\0')
2095  	    continue;
2096  
2097  	subject_name = strchr(p, ':');
2098  	if (subject_name == NULL) {
2099  	    krb5_warnx(context, "pkinit mapping file line %lu "
2100  		       "missing \":\" :%s",
2101  		       lineno, buf);
2102  	    continue;
2103  	}
2104  	*subject_name++ = '\0';
2105  
2106  	ret = add_principal_mapping(context, p, subject_name);
2107  	if (ret) {
2108  	    krb5_warn(context, ret, "failed to add line %lu \":\" :%s\n",
2109  		      lineno, buf);
2110  	    continue;
2111  	}
2112      }
2113  
2114      fclose(f);
2115  }
2116  
2117  /*
2118   *
2119   */
2120  
2121  krb5_error_code
2122  krb5_kdc_pk_initialize(krb5_context context,
2123  		       krb5_kdc_configuration *config,
2124  		       const char *user_id,
2125  		       const char *anchors,
2126  		       char **pool,
2127  		       char **revoke_list)
2128  {
2129      const char *file;
2130      char *fn = NULL;
2131      krb5_error_code ret;
2132  
2133      file = krb5_config_get_string(context, NULL,
2134  				  "libdefaults", "moduli", NULL);
2135  
2136      ret = _krb5_parse_moduli(context, file, &moduli);
2137      if (ret)
2138  	krb5_err(context, 1, ret, "PKINIT: failed to load modidi file");
2139  
2140      principal_mappings.len = 0;
2141      principal_mappings.val = NULL;
2142  
2143      ret = _krb5_pk_load_id(context,
2144  			   &kdc_identity,
2145  			   user_id,
2146  			   anchors,
2147  			   pool,
2148  			   revoke_list,
2149  			   NULL,
2150  			   NULL,
2151  			   NULL);
2152      if (ret) {
2153  	krb5_warn(context, ret, "PKINIT: ");
2154  	config->enable_pkinit = 0;
2155  	return ret;
2156      }
2157  
2158      {
2159  	hx509_query *q;
2160  	hx509_cert cert;
2161  
2162  	ret = hx509_query_alloc(context->hx509ctx, &q);
2163  	if (ret) {
2164  	    krb5_warnx(context, "PKINIT: out of memory");
2165  	    return ENOMEM;
2166  	}
2167  
2168  	hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
2169  	if (config->pkinit_kdc_friendly_name)
2170  	    hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name);
2171  
2172  	ret = hx509_certs_find(context->hx509ctx,
2173  			       kdc_identity->certs,
2174  			       q,
2175  			       &cert);
2176  	hx509_query_free(context->hx509ctx, q);
2177  	if (ret == 0) {
2178  	    if (hx509_cert_check_eku(context->hx509ctx, cert,
2179  				     &asn1_oid_id_apple_system_id, 0) == 0)
2180  	    {
2181  		/* AppleID BTMM cert, then is all fine */
2182  	    } else if (hx509_cert_check_eku(context->hx509ctx, cert,
2183  					    &asn1_oid_id_pkkdcekuoid, 0))
2184  	    {
2185  		hx509_name name;
2186  		char *str;
2187  		ret = hx509_cert_get_subject(cert, &name);
2188  		if (ret == 0) {
2189  		    hx509_name_to_string(name, &str);
2190  		    krb5_warnx(context, "WARNING Found KDC certificate (%s)"
2191  			       "is missing the PK-INIT KDC EKU, this is bad for "
2192  			       "interoperability.", str);
2193  		    hx509_name_free(&name);
2194  		    free(str);
2195  		}
2196  	    }
2197  	    hx509_cert_free(cert);
2198  	} else
2199  	    krb5_warnx(context, "PKINIT: failed to find a signing "
2200  		       "certifiate with a public key");
2201      }
2202  
2203      if (krb5_config_get_bool_default(context,
2204  				     NULL,
2205  				     FALSE,
2206  				     "kdc",
2207  				     "pkinit_allow_proxy_certificate",
2208  				     NULL))
2209  	config->pkinit_allow_proxy_certs = 1;
2210  
2211      file = krb5_config_get_string(context,
2212  				  NULL,
2213  				  "kdc",
2214  				  "pkinit_mappings_file",
2215  				  NULL);
2216      if (file == NULL) {
2217  	asprintf(&fn, "%s/pki-mapping", hdb_db_dir(context));
2218  	file = fn;
2219      }
2220  
2221      load_mappings(context, file);
2222      if (fn)
2223  	free(fn);
2224  
2225      return 0;
2226  }
2227  
2228  #endif /* PKINIT */