root/source4/heimdal/lib/krb5/pkinit.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _krb5_pk_cert_free
  2. BN_to_integer
  3. integer_to_BN
  4. find_cert
  5. create_signature
  6. cert2epi
  7. build_edi
  8. build_auth_pack
  9. _krb5_pk_mk_ContentInfo
  10. pk_mk_padata
  11. _krb5_pk_mk_padata
  12. _krb5_pk_verify_sign
  13. get_reply_key_win
  14. get_reply_key
  15. pk_verify_host
  16. pk_rd_pa_reply_enckey
  17. pk_rd_pa_reply_dh
  18. _krb5_pk_rd_pa_reply
  19. hx_pass_prompter
  20. _krb5_pk_allow_proxy_certificate
  21. _krb5_pk_load_id
  22. select_dh_group
  23. pk_copy_error
  24. parse_integer
  25. _krb5_parse_moduli_line
  26. _krb5_free_moduli
  27. _krb5_parse_moduli
  28. _krb5_dh_group_ok
  29. _krb5_get_init_creds_opt_free_pkinit
  30. krb5_get_init_creds_opt_set_pkinit

   1 /*
   2  * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
   3  * (Royal Institute of Technology, Stockholm, Sweden).
   4  * All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  *
  13  * 2. Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in the
  15  *    documentation and/or other materials provided with the distribution.
  16  *
  17  * 3. Neither the name of the Institute nor the names of its contributors
  18  *    may be used to endorse or promote products derived from this software
  19  *    without specific prior written permission.
  20  *
  21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31  * SUCH DAMAGE.
  32  */
  33 
  34 #include "krb5_locl.h"
  35 
  36 RCSID("$Id$");
  37 
  38 struct krb5_dh_moduli {
  39     char *name;
  40     unsigned long bits;
  41     heim_integer p;
  42     heim_integer g;
  43     heim_integer q;
  44 };
  45 
  46 #ifdef PKINIT
  47 
  48 #include <cms_asn1.h>
  49 #include <pkcs8_asn1.h>
  50 #include <pkcs9_asn1.h>
  51 #include <pkcs12_asn1.h>
  52 #include <pkinit_asn1.h>
  53 #include <asn1_err.h>
  54 
  55 #include <der.h>
  56 
  57 struct krb5_pk_cert {
  58     hx509_cert cert;
  59 };
  60 
  61 struct krb5_pk_init_ctx_data {
  62     struct krb5_pk_identity *id;
  63     DH *dh;
  64     krb5_data *clientDHNonce;
  65     struct krb5_dh_moduli **m;
  66     hx509_peer_info peer;
  67     enum krb5_pk_type type;
  68     unsigned int require_binding:1;
  69     unsigned int require_eku:1;
  70     unsigned int require_krbtgt_otherName:1;
  71     unsigned int require_hostname_match:1;
  72     unsigned int trustedCertifiers:1;
  73 };
  74 
  75 static void
  76 pk_copy_error(krb5_context context,
  77               hx509_context hx509ctx,
  78               int hxret,
  79               const char *fmt,
  80               ...)
  81     __attribute__ ((format (printf, 4, 5)));
  82 
  83 /*
  84  *
  85  */
  86 
  87 void KRB5_LIB_FUNCTION
  88 _krb5_pk_cert_free(struct krb5_pk_cert *cert)
     /* [<][>][^][v][top][bottom][index][help] */
  89 {
  90     if (cert->cert) {
  91         hx509_cert_free(cert->cert);
  92     }
  93     free(cert);
  94 }
  95 
  96 static krb5_error_code
  97 BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer)
     /* [<][>][^][v][top][bottom][index][help] */
  98 {
  99     integer->length = BN_num_bytes(bn);
 100     integer->data = malloc(integer->length);
 101     if (integer->data == NULL) {
 102         krb5_clear_error_message(context);
 103         return ENOMEM;
 104     }
 105     BN_bn2bin(bn, integer->data);
 106     integer->negative = BN_is_negative(bn);
 107     return 0;
 108 }
 109 
 110 static BIGNUM *
 111 integer_to_BN(krb5_context context, const char *field, const heim_integer *f)
     /* [<][>][^][v][top][bottom][index][help] */
 112 {
 113     BIGNUM *bn;
 114 
 115     bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL);
 116     if (bn == NULL) {
 117         krb5_set_error_message(context, ENOMEM,
 118                                N_("PKINIT: parsing BN failed %s", ""), field);
 119         return NULL;
 120     }
 121     BN_set_negative(bn, f->negative);
 122     return bn;
 123 }
 124 
 125 struct certfind {
 126     const char *type;
 127     const heim_oid *oid;
 128 };
 129 
 130 /*
 131  * Try searchin the key by to use by first looking for for PK-INIT
 132  * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
 133  */
 134 
 135 static krb5_error_code
 136 find_cert(krb5_context context, struct krb5_pk_identity *id,
     /* [<][>][^][v][top][bottom][index][help] */
 137           hx509_query *q, hx509_cert *cert)
 138 {
 139     struct certfind cf[3] = {
 140         { "PKINIT EKU" },
 141         { "MS EKU" },
 142         { "no" }
 143     };
 144     int i, ret;
 145 
 146     cf[0].oid = oid_id_pkekuoid();
 147     cf[1].oid = oid_id_pkinit_ms_eku();
 148     cf[2].oid = NULL;
 149 
 150     for (i = 0; i < sizeof(cf)/sizeof(cf[0]); i++) {
 151         ret = hx509_query_match_eku(q, cf[i].oid);
 152         if (ret) {
 153             pk_copy_error(context, id->hx509ctx, ret,
 154                           "Failed setting %s OID", cf[i].type);
 155             return ret;
 156         }
 157 
 158         ret = hx509_certs_find(id->hx509ctx, id->certs, q, cert);
 159         if (ret == 0)
 160             break;
 161         pk_copy_error(context, id->hx509ctx, ret,
 162                       "Failed cert for finding %s OID", cf[i].type);
 163     }
 164     return ret;
 165 }
 166 
 167 
 168 static krb5_error_code
 169 create_signature(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 170                  const heim_oid *eContentType,
 171                  krb5_data *eContent,
 172                  struct krb5_pk_identity *id,
 173                  hx509_peer_info peer,
 174                  krb5_data *sd_data)
 175 {
 176     hx509_cert cert = NULL;
 177     hx509_query *q = NULL;
 178     int ret;
 179 
 180     ret = hx509_query_alloc(id->hx509ctx, &q);
 181     if (ret) {
 182         pk_copy_error(context, id->hx509ctx, ret,
 183                       "Allocate query to find signing certificate");
 184         return ret;
 185     }
 186 
 187     hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
 188     hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
 189 
 190     ret = find_cert(context, id, q, &cert);
 191     hx509_query_free(id->hx509ctx, q);
 192     if (ret)
 193         return ret;
 194 
 195     ret = hx509_cms_create_signed_1(id->hx509ctx,
 196                                     0,
 197                                     eContentType,
 198                                     eContent->data,
 199                                     eContent->length,
 200                                     NULL,
 201                                     cert,
 202                                     peer,
 203                                     NULL,
 204                                     id->certs,
 205                                     sd_data);
 206     hx509_cert_free(cert);
 207     if (ret) {
 208         pk_copy_error(context, id->hx509ctx, ret,
 209                       "Create CMS signedData");
 210         return ret;
 211     }
 212 
 213     return 0;
 214 }
 215 
 216 static int
 217 cert2epi(hx509_context context, void *ctx, hx509_cert c)
     /* [<][>][^][v][top][bottom][index][help] */
 218 {
 219     ExternalPrincipalIdentifiers *ids = ctx;
 220     ExternalPrincipalIdentifier id;
 221     hx509_name subject = NULL;
 222     void *p;
 223     int ret;
 224 
 225     memset(&id, 0, sizeof(id));
 226 
 227     ret = hx509_cert_get_subject(c, &subject);
 228     if (ret)
 229         return ret;
 230 
 231     if (hx509_name_is_null_p(subject) != 0) {
 232 
 233         id.subjectName = calloc(1, sizeof(*id.subjectName));
 234         if (id.subjectName == NULL) {
 235             hx509_name_free(&subject);
 236             free_ExternalPrincipalIdentifier(&id);
 237             return ENOMEM;
 238         }
 239 
 240         ret = hx509_name_binary(subject, id.subjectName);
 241         if (ret) {
 242             hx509_name_free(&subject);
 243             free_ExternalPrincipalIdentifier(&id);
 244             return ret;
 245         }
 246     }
 247     hx509_name_free(&subject);
 248 
 249 
 250     id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber));
 251     if (id.issuerAndSerialNumber == NULL) {
 252         free_ExternalPrincipalIdentifier(&id);
 253         return ENOMEM;
 254     }
 255 
 256     {
 257         IssuerAndSerialNumber iasn;
 258         hx509_name issuer;
 259         size_t size;
 260         
 261         memset(&iasn, 0, sizeof(iasn));
 262 
 263         ret = hx509_cert_get_issuer(c, &issuer);
 264         if (ret) {
 265             free_ExternalPrincipalIdentifier(&id);
 266             return ret;
 267         }
 268 
 269         ret = hx509_name_to_Name(issuer, &iasn.issuer);
 270         hx509_name_free(&issuer);
 271         if (ret) {
 272             free_ExternalPrincipalIdentifier(&id);
 273             return ret;
 274         }
 275         
 276         ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber);
 277         if (ret) {
 278             free_IssuerAndSerialNumber(&iasn);
 279             free_ExternalPrincipalIdentifier(&id);
 280             return ret;
 281         }
 282 
 283         ASN1_MALLOC_ENCODE(IssuerAndSerialNumber,
 284                            id.issuerAndSerialNumber->data,
 285                            id.issuerAndSerialNumber->length,
 286                            &iasn, &size, ret);
 287         free_IssuerAndSerialNumber(&iasn);
 288         if (ret)
 289             return ret;
 290         if (id.issuerAndSerialNumber->length != size)
 291             abort();
 292     }
 293 
 294     id.subjectKeyIdentifier = NULL;
 295 
 296     p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1));
 297     if (p == NULL) {
 298         free_ExternalPrincipalIdentifier(&id);
 299         return ENOMEM;
 300     }
 301 
 302     ids->val = p;
 303     ids->val[ids->len] = id;
 304     ids->len++;
 305 
 306     return 0;
 307 }
 308 
 309 static krb5_error_code
 310 build_edi(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 311           hx509_context hx509ctx,
 312           hx509_certs certs,
 313           ExternalPrincipalIdentifiers *ids)
 314 {
 315     return hx509_certs_iter(hx509ctx, certs, cert2epi, ids);
 316 }
 317 
 318 static krb5_error_code
 319 build_auth_pack(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 320                 unsigned nonce,
 321                 krb5_pk_init_ctx ctx,
 322                 DH *dh,
 323                 const KDC_REQ_BODY *body,
 324                 AuthPack *a)
 325 {
 326     size_t buf_size, len;
 327     krb5_error_code ret;
 328     void *buf;
 329     krb5_timestamp sec;
 330     int32_t usec;
 331     Checksum checksum;
 332 
 333     krb5_clear_error_message(context);
 334 
 335     memset(&checksum, 0, sizeof(checksum));
 336 
 337     krb5_us_timeofday(context, &sec, &usec);
 338     a->pkAuthenticator.ctime = sec;
 339     a->pkAuthenticator.nonce = nonce;
 340 
 341     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
 342     if (ret)
 343         return ret;
 344     if (buf_size != len)
 345         krb5_abortx(context, "internal error in ASN.1 encoder");
 346 
 347     ret = krb5_create_checksum(context,
 348                                NULL,
 349                                0,
 350                                CKSUMTYPE_SHA1,
 351                                buf,
 352                                len,
 353                                &checksum);
 354     free(buf);
 355     if (ret)
 356         return ret;
 357 
 358     ALLOC(a->pkAuthenticator.paChecksum, 1);
 359     if (a->pkAuthenticator.paChecksum == NULL) {
 360         krb5_set_error_message(context, ENOMEM,
 361                                N_("malloc: out of memory", ""));
 362         return ENOMEM;
 363     }
 364 
 365     ret = krb5_data_copy(a->pkAuthenticator.paChecksum,
 366                          checksum.checksum.data, checksum.checksum.length);
 367     free_Checksum(&checksum);
 368     if (ret)
 369         return ret;
 370 
 371     if (dh) {
 372         DomainParameters dp;
 373         heim_integer dh_pub_key;
 374         krb5_data dhbuf;
 375         size_t size;
 376 
 377         if (1 /* support_cached_dh */) {
 378             ALLOC(a->clientDHNonce, 1);
 379             if (a->clientDHNonce == NULL) {
 380                 krb5_clear_error_message(context);
 381                 return ENOMEM;
 382             }
 383             ret = krb5_data_alloc(a->clientDHNonce, 40);
 384             if (a->clientDHNonce == NULL) {
 385                 krb5_clear_error_message(context);
 386                 return ret;
 387             }
 388             memset(a->clientDHNonce->data, 0, a->clientDHNonce->length);
 389             ret = krb5_copy_data(context, a->clientDHNonce,
 390                                  &ctx->clientDHNonce);
 391             if (ret)
 392                 return ret;
 393         }
 394 
 395         ALLOC(a->clientPublicValue, 1);
 396         if (a->clientPublicValue == NULL)
 397             return ENOMEM;
 398         ret = der_copy_oid(oid_id_dhpublicnumber(),
 399                            &a->clientPublicValue->algorithm.algorithm);
 400         if (ret)
 401             return ret;
 402         
 403         memset(&dp, 0, sizeof(dp));
 404 
 405         ret = BN_to_integer(context, dh->p, &dp.p);
 406         if (ret) {
 407             free_DomainParameters(&dp);
 408             return ret;
 409         }
 410         ret = BN_to_integer(context, dh->g, &dp.g);
 411         if (ret) {
 412             free_DomainParameters(&dp);
 413             return ret;
 414         }
 415         ret = BN_to_integer(context, dh->q, &dp.q);
 416         if (ret) {
 417             free_DomainParameters(&dp);
 418             return ret;
 419         }
 420         dp.j = NULL;
 421         dp.validationParms = NULL;
 422 
 423         a->clientPublicValue->algorithm.parameters =
 424             malloc(sizeof(*a->clientPublicValue->algorithm.parameters));
 425         if (a->clientPublicValue->algorithm.parameters == NULL) {
 426             free_DomainParameters(&dp);
 427             return ret;
 428         }
 429 
 430         ASN1_MALLOC_ENCODE(DomainParameters,
 431                            a->clientPublicValue->algorithm.parameters->data,
 432                            a->clientPublicValue->algorithm.parameters->length,
 433                            &dp, &size, ret);
 434         free_DomainParameters(&dp);
 435         if (ret)
 436             return ret;
 437         if (size != a->clientPublicValue->algorithm.parameters->length)
 438             krb5_abortx(context, "Internal ASN1 encoder error");
 439 
 440         ret = BN_to_integer(context, dh->pub_key, &dh_pub_key);
 441         if (ret)
 442             return ret;
 443 
 444         ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length,
 445                            &dh_pub_key, &size, ret);
 446         der_free_heim_integer(&dh_pub_key);
 447         if (ret)
 448             return ret;
 449         if (size != dhbuf.length)
 450             krb5_abortx(context, "asn1 internal error");
 451 
 452         a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8;
 453         a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
 454     }
 455 
 456     {
 457         a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes));
 458         if (a->supportedCMSTypes == NULL)
 459             return ENOMEM;
 460 
 461         ret = hx509_crypto_available(ctx->id->hx509ctx, HX509_SELECT_ALL, NULL,
 462                                      &a->supportedCMSTypes->val,
 463                                      &a->supportedCMSTypes->len);
 464         if (ret)
 465             return ret;
 466     }
 467 
 468     return ret;
 469 }
 470 
 471 krb5_error_code KRB5_LIB_FUNCTION
 472 _krb5_pk_mk_ContentInfo(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 473                         const krb5_data *buf,
 474                         const heim_oid *oid,
 475                         struct ContentInfo *content_info)
 476 {
 477     krb5_error_code ret;
 478 
 479     ret = der_copy_oid(oid, &content_info->contentType);
 480     if (ret)
 481         return ret;
 482     ALLOC(content_info->content, 1);
 483     if (content_info->content == NULL)
 484         return ENOMEM;
 485     content_info->content->data = malloc(buf->length);
 486     if (content_info->content->data == NULL)
 487         return ENOMEM;
 488     memcpy(content_info->content->data, buf->data, buf->length);
 489     content_info->content->length = buf->length;
 490     return 0;
 491 }
 492 
 493 static krb5_error_code
 494 pk_mk_padata(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 495              krb5_pk_init_ctx ctx,
 496              const KDC_REQ_BODY *req_body,
 497              unsigned nonce,
 498              METHOD_DATA *md)
 499 {
 500     struct ContentInfo content_info;
 501     krb5_error_code ret;
 502     const heim_oid *oid;
 503     size_t size;
 504     krb5_data buf, sd_buf;
 505     int pa_type;
 506 
 507     krb5_data_zero(&buf);
 508     krb5_data_zero(&sd_buf);
 509     memset(&content_info, 0, sizeof(content_info));
 510 
 511     if (ctx->type == PKINIT_WIN2K) {
 512         AuthPack_Win2k ap;
 513         krb5_timestamp sec;
 514         int32_t usec;
 515 
 516         memset(&ap, 0, sizeof(ap));
 517 
 518         /* fill in PKAuthenticator */
 519         ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName);
 520         if (ret) {
 521             free_AuthPack_Win2k(&ap);
 522             krb5_clear_error_message(context);
 523             goto out;
 524         }
 525         ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm);
 526         if (ret) {
 527             free_AuthPack_Win2k(&ap);
 528             krb5_clear_error_message(context);
 529             goto out;
 530         }
 531 
 532         krb5_us_timeofday(context, &sec, &usec);
 533         ap.pkAuthenticator.ctime = sec;
 534         ap.pkAuthenticator.cusec = usec;
 535         ap.pkAuthenticator.nonce = nonce;
 536 
 537         ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length,
 538                            &ap, &size, ret);
 539         free_AuthPack_Win2k(&ap);
 540         if (ret) {
 541             krb5_set_error_message(context, ret,
 542                                    N_("Failed encoding AuthPackWin: %d", ""),
 543                                    (int)ret);
 544             goto out;
 545         }
 546         if (buf.length != size)
 547             krb5_abortx(context, "internal ASN1 encoder error");
 548 
 549         oid = oid_id_pkcs7_data();
 550     } else if (ctx->type == PKINIT_27) {
 551         AuthPack ap;
 552         
 553         memset(&ap, 0, sizeof(ap));
 554 
 555         ret = build_auth_pack(context, nonce, ctx, ctx->dh, req_body, &ap);
 556         if (ret) {
 557             free_AuthPack(&ap);
 558             goto out;
 559         }
 560 
 561         ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret);
 562         free_AuthPack(&ap);
 563         if (ret) {
 564             krb5_set_error_message(context, ret,
 565                                    N_("Failed encoding AuthPack: %d", ""),
 566                                    (int)ret);
 567             goto out;
 568         }
 569         if (buf.length != size)
 570             krb5_abortx(context, "internal ASN1 encoder error");
 571 
 572         oid = oid_id_pkauthdata();
 573     } else
 574         krb5_abortx(context, "internal pkinit error");
 575 
 576     ret = create_signature(context, oid, &buf, ctx->id,
 577                            ctx->peer, &sd_buf);
 578     krb5_data_free(&buf);
 579     if (ret)
 580         goto out;
 581 
 582     ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), &sd_buf, &buf);
 583     krb5_data_free(&sd_buf);
 584     if (ret) {
 585         krb5_set_error_message(context, ret,
 586                                N_("ContentInfo wrapping of signedData failed",""));
 587         goto out;
 588     }
 589 
 590     if (ctx->type == PKINIT_WIN2K) {
 591         PA_PK_AS_REQ_Win2k winreq;
 592 
 593         pa_type = KRB5_PADATA_PK_AS_REQ_WIN;
 594 
 595         memset(&winreq, 0, sizeof(winreq));
 596 
 597         winreq.signed_auth_pack = buf;
 598 
 599         ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length,
 600                            &winreq, &size, ret);
 601         free_PA_PK_AS_REQ_Win2k(&winreq);
 602 
 603     } else if (ctx->type == PKINIT_27) {
 604         PA_PK_AS_REQ req;
 605 
 606         pa_type = KRB5_PADATA_PK_AS_REQ;
 607 
 608         memset(&req, 0, sizeof(req));
 609         req.signedAuthPack = buf;       
 610 
 611         if (ctx->trustedCertifiers) {
 612 
 613             req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers));
 614             if (req.trustedCertifiers == NULL) {
 615                 ret = ENOMEM;
 616                 krb5_set_error_message(context, ret,
 617                                        N_("malloc: out of memory", ""));
 618                 free_PA_PK_AS_REQ(&req);
 619                 goto out;
 620             }
 621             ret = build_edi(context, ctx->id->hx509ctx,
 622                             ctx->id->anchors, req.trustedCertifiers);
 623             if (ret) {
 624                 krb5_set_error_message(context, ret,
 625                                        N_("pk-init: failed to build "
 626                                           "trustedCertifiers", ""));
 627                 free_PA_PK_AS_REQ(&req);
 628                 goto out;
 629             }
 630         }
 631         req.kdcPkId = NULL;
 632 
 633         ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length,
 634                            &req, &size, ret);
 635 
 636         free_PA_PK_AS_REQ(&req);
 637 
 638     } else
 639         krb5_abortx(context, "internal pkinit error");
 640     if (ret) {
 641         krb5_set_error_message(context, ret, "PA-PK-AS-REQ %d", (int)ret);
 642         goto out;
 643     }
 644     if (buf.length != size)
 645         krb5_abortx(context, "Internal ASN1 encoder error");
 646 
 647     ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length);
 648     if (ret)
 649         free(buf.data);
 650 
 651     if (ret == 0 && ctx->type == PKINIT_WIN2K)
 652         krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
 653 
 654  out:
 655     free_ContentInfo(&content_info);
 656 
 657     return ret;
 658 }
 659 
 660 
 661 krb5_error_code KRB5_LIB_FUNCTION
 662 _krb5_pk_mk_padata(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 663                    void *c,
 664                    const KDC_REQ_BODY *req_body,
 665                    unsigned nonce,
 666                    METHOD_DATA *md)
 667 {
 668     krb5_pk_init_ctx ctx = c;
 669     int win2k_compat;
 670 
 671     win2k_compat = krb5_config_get_bool_default(context, NULL,
 672                                                 FALSE,
 673                                                 "realms",
 674                                                 req_body->realm,
 675                                                 "pkinit_win2k",
 676                                                 NULL);
 677 
 678     if (win2k_compat) {
 679         ctx->require_binding =
 680             krb5_config_get_bool_default(context, NULL,
 681                                          FALSE,
 682                                          "realms",
 683                                          req_body->realm,
 684                                          "pkinit_win2k_require_binding",
 685                                          NULL);
 686         ctx->type = PKINIT_WIN2K;
 687     } else
 688         ctx->type = PKINIT_27;
 689 
 690     ctx->require_eku =
 691         krb5_config_get_bool_default(context, NULL,
 692                                      TRUE,
 693                                      "realms",
 694                                      req_body->realm,
 695                                      "pkinit_require_eku",
 696                                      NULL);
 697     ctx->require_krbtgt_otherName =
 698         krb5_config_get_bool_default(context, NULL,
 699                                      TRUE,
 700                                      "realms",
 701                                      req_body->realm,
 702                                      "pkinit_require_krbtgt_otherName",
 703                                      NULL);
 704 
 705     ctx->require_hostname_match =
 706         krb5_config_get_bool_default(context, NULL,
 707                                      FALSE,
 708                                      "realms",
 709                                      req_body->realm,
 710                                      "pkinit_require_hostname_match",
 711                                      NULL);
 712 
 713     ctx->trustedCertifiers =
 714         krb5_config_get_bool_default(context, NULL,
 715                                      TRUE,
 716                                      "realms",
 717                                      req_body->realm,
 718                                      "pkinit_trustedCertifiers",
 719                                      NULL);
 720 
 721     return pk_mk_padata(context, ctx, req_body, nonce, md);
 722 }
 723 
 724 krb5_error_code KRB5_LIB_FUNCTION
 725 _krb5_pk_verify_sign(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 726                      const void *data,
 727                      size_t length,
 728                      struct krb5_pk_identity *id,
 729                      heim_oid *contentType,
 730                      krb5_data *content,
 731                      struct krb5_pk_cert **signer)
 732 {
 733     hx509_certs signer_certs;
 734     int ret;
 735 
 736     *signer = NULL;
 737 
 738     ret = hx509_cms_verify_signed(id->hx509ctx,
 739                                   id->verify_ctx,
 740                                   data,
 741                                   length,
 742                                   NULL,
 743                                   id->certpool,
 744                                   contentType,
 745                                   content,
 746                                   &signer_certs);
 747     if (ret) {
 748         pk_copy_error(context, id->hx509ctx, ret,
 749                       "CMS verify signed failed");
 750         return ret;
 751     }
 752 
 753     *signer = calloc(1, sizeof(**signer));
 754     if (*signer == NULL) {
 755         krb5_clear_error_message(context);
 756         ret = ENOMEM;
 757         goto out;
 758     }
 759         
 760     ret = hx509_get_one_cert(id->hx509ctx, signer_certs, &(*signer)->cert);
 761     if (ret) {
 762         pk_copy_error(context, id->hx509ctx, ret,
 763                       "Failed to get on of the signer certs");
 764         goto out;
 765     }
 766 
 767  out:
 768     hx509_certs_free(&signer_certs);
 769     if (ret) {
 770         if (*signer) {
 771             hx509_cert_free((*signer)->cert);
 772             free(*signer);
 773             *signer = NULL;
 774         }
 775     }
 776 
 777     return ret;
 778 }
 779 
 780 static krb5_error_code
 781 get_reply_key_win(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 782                   const krb5_data *content,
 783                   unsigned nonce,
 784                   krb5_keyblock **key)
 785 {
 786     ReplyKeyPack_Win2k key_pack;
 787     krb5_error_code ret;
 788     size_t size;
 789 
 790     ret = decode_ReplyKeyPack_Win2k(content->data,
 791                                     content->length,
 792                                     &key_pack,
 793                                     &size);
 794     if (ret) {
 795         krb5_set_error_message(context, ret,
 796                                N_("PKINIT decoding reply key failed", ""));
 797         free_ReplyKeyPack_Win2k(&key_pack);
 798         return ret;
 799     }
 800 
 801     if (key_pack.nonce != nonce) {
 802         krb5_set_error_message(context, ret,
 803                                N_("PKINIT enckey nonce is wrong", ""));
 804         free_ReplyKeyPack_Win2k(&key_pack);
 805         return KRB5KRB_AP_ERR_MODIFIED;
 806     }
 807 
 808     *key = malloc (sizeof (**key));
 809     if (*key == NULL) {
 810         free_ReplyKeyPack_Win2k(&key_pack);
 811         krb5_set_error_message(context, ENOMEM,
 812                                N_("malloc: out of memory", ""));
 813         return ENOMEM;
 814     }
 815 
 816     ret = copy_EncryptionKey(&key_pack.replyKey, *key);
 817     free_ReplyKeyPack_Win2k(&key_pack);
 818     if (ret) {
 819         krb5_set_error_message(context, ret,
 820                                N_("PKINIT failed copying reply key", ""));
 821         free(*key);
 822         *key = NULL;
 823     }
 824 
 825     return ret;
 826 }
 827 
 828 static krb5_error_code
 829 get_reply_key(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 830               const krb5_data *content,
 831               const krb5_data *req_buffer,
 832               krb5_keyblock **key)
 833 {
 834     ReplyKeyPack key_pack;
 835     krb5_error_code ret;
 836     size_t size;
 837 
 838     ret = decode_ReplyKeyPack(content->data,
 839                               content->length,
 840                               &key_pack,
 841                               &size);
 842     if (ret) {
 843         krb5_set_error_message(context, ret,
 844                                N_("PKINIT decoding reply key failed", ""));
 845         free_ReplyKeyPack(&key_pack);
 846         return ret;
 847     }
 848 
 849     {
 850         krb5_crypto crypto;
 851 
 852         /*
 853          * XXX Verify kp.replyKey is a allowed enctype in the
 854          * configuration file
 855          */
 856 
 857         ret = krb5_crypto_init(context, &key_pack.replyKey, 0, &crypto);
 858         if (ret) {
 859             free_ReplyKeyPack(&key_pack);
 860             return ret;
 861         }
 862 
 863         ret = krb5_verify_checksum(context, crypto, 6,
 864                                    req_buffer->data, req_buffer->length,
 865                                    &key_pack.asChecksum);
 866         krb5_crypto_destroy(context, crypto);
 867         if (ret) {
 868             free_ReplyKeyPack(&key_pack);
 869             return ret;
 870         }
 871     }
 872 
 873     *key = malloc (sizeof (**key));
 874     if (*key == NULL) {
 875         free_ReplyKeyPack(&key_pack);
 876         krb5_set_error_message(context, ENOMEM,
 877                                N_("malloc: out of memory", ""));
 878         return ENOMEM;
 879     }
 880 
 881     ret = copy_EncryptionKey(&key_pack.replyKey, *key);
 882     free_ReplyKeyPack(&key_pack);
 883     if (ret) {
 884         krb5_set_error_message(context, ret,
 885                                N_("PKINIT failed copying reply key", ""));
 886         free(*key);
 887         *key = NULL;
 888     }
 889 
 890     return ret;
 891 }
 892 
 893 
 894 static krb5_error_code
 895 pk_verify_host(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 896                const char *realm,
 897                const krb5_krbhst_info *hi,
 898                struct krb5_pk_init_ctx_data *ctx,
 899                struct krb5_pk_cert *host)
 900 {
 901     krb5_error_code ret = 0;
 902 
 903     if (ctx->require_eku) {
 904         ret = hx509_cert_check_eku(ctx->id->hx509ctx, host->cert,
 905                                    oid_id_pkkdcekuoid(), 0);
 906         if (ret) {
 907             krb5_set_error_message(context, ret,
 908                                    N_("No PK-INIT KDC EKU in kdc certificate", ""));
 909             return ret;
 910         }
 911     }
 912     if (ctx->require_krbtgt_otherName) {
 913         hx509_octet_string_list list;
 914         int i;
 915 
 916         ret = hx509_cert_find_subjectAltName_otherName(ctx->id->hx509ctx,
 917                                                        host->cert,
 918                                                        oid_id_pkinit_san(),
 919                                                        &list);
 920         if (ret) {
 921             krb5_set_error_message(context, ret,
 922                                    N_("Failed to find the PK-INIT "
 923                                       "subjectAltName in the KDC "
 924                                       "certificate", ""));
 925 
 926             return ret;
 927         }
 928 
 929         for (i = 0; i < list.len; i++) {
 930             KRB5PrincipalName r;
 931 
 932             ret = decode_KRB5PrincipalName(list.val[i].data,
 933                                            list.val[i].length,
 934                                            &r,
 935                                            NULL);
 936             if (ret) {
 937                 krb5_set_error_message(context, ret,
 938                                        N_("Failed to decode the PK-INIT "
 939                                           "subjectAltName in the "
 940                                           "KDC certificate", ""));
 941 
 942                 break;
 943             }
 944 
 945             if (r.principalName.name_string.len != 2 ||
 946                 strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) != 0 ||
 947                 strcmp(r.principalName.name_string.val[1], realm) != 0 ||
 948                 strcmp(r.realm, realm) != 0)
 949                 {
 950                     ret = KRB5_KDC_ERR_INVALID_CERTIFICATE;
 951                     krb5_set_error_message(context, ret,
 952                                            N_("KDC have wrong realm name in "
 953                                               "the certificate", ""));
 954                 }
 955 
 956             free_KRB5PrincipalName(&r);
 957             if (ret)
 958                 break;
 959         }
 960         hx509_free_octet_string_list(&list);
 961     }
 962     if (ret)
 963         return ret;
 964 
 965     if (hi) {
 966         ret = hx509_verify_hostname(ctx->id->hx509ctx, host->cert,
 967                                     ctx->require_hostname_match,
 968                                     HX509_HN_HOSTNAME,
 969                                     hi->hostname,
 970                                     hi->ai->ai_addr, hi->ai->ai_addrlen);
 971 
 972         if (ret)
 973             krb5_set_error_message(context, ret,
 974                                    N_("Address mismatch in "
 975                                       "the KDC certificate", ""));
 976     }
 977     return ret;
 978 }
 979 
 980 static krb5_error_code
 981 pk_rd_pa_reply_enckey(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 982                       int type,
 983                       const heim_octet_string *indata,
 984                       const heim_oid *dataType,
 985                       const char *realm,
 986                       krb5_pk_init_ctx ctx,
 987                       krb5_enctype etype,
 988                       const krb5_krbhst_info *hi,
 989                       unsigned nonce,
 990                       const krb5_data *req_buffer,
 991                       PA_DATA *pa,
 992                       krb5_keyblock **key)
 993 {
 994     krb5_error_code ret;
 995     struct krb5_pk_cert *host = NULL;
 996     krb5_data content;
 997     heim_oid contentType = { 0, NULL };
 998 
 999     if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), dataType)) {
1000         krb5_set_error_message(context, EINVAL,
1001                                N_("PKINIT: Invalid content type", ""));
1002         return EINVAL;
1003     }
1004 
1005     ret = hx509_cms_unenvelope(ctx->id->hx509ctx,
1006                                ctx->id->certs,
1007                                HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT,
1008                                indata->data,
1009                                indata->length,
1010                                NULL,
1011                                0,
1012                                &contentType,
1013                                &content);
1014     if (ret) {
1015         pk_copy_error(context, ctx->id->hx509ctx, ret,
1016                       "Failed to unenvelope CMS data in PK-INIT reply");
1017         return ret;
1018     }
1019     der_free_oid(&contentType);
1020 
1021 #if 0 /* windows LH with interesting CMS packets, leaks memory */
1022     {
1023         size_t ph = 1 + der_length_len (length);
1024         unsigned char *ptr = malloc(length + ph);
1025         size_t l;
1026 
1027         memcpy(ptr + ph, p, length);
1028 
1029         ret = der_put_length_and_tag (ptr + ph - 1, ph, length,
1030                                       ASN1_C_UNIV, CONS, UT_Sequence, &l);
1031         if (ret)
1032             return ret;
1033         ptr += ph - l;
1034         length += l;
1035         p = ptr;
1036     }
1037 #endif
1038 
1039     /* win2k uses ContentInfo */
1040     if (type == PKINIT_WIN2K) {
1041         heim_oid type;
1042         heim_octet_string out;
1043 
1044         ret = hx509_cms_unwrap_ContentInfo(&content, &type, &out, NULL);
1045         if (der_heim_oid_cmp(&type, oid_id_pkcs7_signedData())) {
1046             ret = EINVAL; /* XXX */
1047             krb5_set_error_message(context, ret,
1048                                    N_("PKINIT: Invalid content type", ""));
1049             der_free_oid(&type);
1050             der_free_octet_string(&out);
1051             goto out;
1052         }
1053         der_free_oid(&type);
1054         krb5_data_free(&content);
1055         ret = krb5_data_copy(&content, out.data, out.length);
1056         der_free_octet_string(&out);
1057         if (ret) {
1058             krb5_set_error_message(context, ret,
1059                                    N_("malloc: out of memory", ""));
1060             goto out;
1061         }
1062     }
1063 
1064     ret = _krb5_pk_verify_sign(context,
1065                                content.data,
1066                                content.length,
1067                                ctx->id,
1068                                &contentType,
1069                                &content,
1070                                &host);
1071     if (ret)
1072         goto out;
1073 
1074     /* make sure that it is the kdc's certificate */
1075     ret = pk_verify_host(context, realm, hi, ctx, host);
1076     if (ret) {
1077         goto out;
1078     }
1079 
1080 #if 0
1081     if (type == PKINIT_WIN2K) {
1082         if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) != 0) {
1083             ret = KRB5KRB_AP_ERR_MSG_TYPE;
1084             krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1085             goto out;
1086         }
1087     } else {
1088         if (der_heim_oid_cmp(&contentType, oid_id_pkrkeydata()) != 0) {
1089             ret = KRB5KRB_AP_ERR_MSG_TYPE;
1090             krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1091             goto out;
1092         }
1093     }
1094 #endif
1095 
1096     switch(type) {
1097     case PKINIT_WIN2K:
1098         ret = get_reply_key(context, &content, req_buffer, key);
1099         if (ret != 0 && ctx->require_binding == 0)
1100             ret = get_reply_key_win(context, &content, nonce, key);
1101         break;
1102     case PKINIT_27:
1103         ret = get_reply_key(context, &content, req_buffer, key);
1104         break;
1105     }
1106     if (ret)
1107         goto out;
1108 
1109     /* XXX compare given etype with key->etype */
1110 
1111  out:
1112     if (host)
1113         _krb5_pk_cert_free(host);
1114     der_free_oid(&contentType);
1115     krb5_data_free(&content);
1116 
1117     return ret;
1118 }
1119 
1120 static krb5_error_code
1121 pk_rd_pa_reply_dh(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1122                   const heim_octet_string *indata,
1123                   const heim_oid *dataType,
1124                   const char *realm,
1125                   krb5_pk_init_ctx ctx,
1126                   krb5_enctype etype,
1127                   const krb5_krbhst_info *hi,
1128                   const DHNonce *c_n,
1129                   const DHNonce *k_n,
1130                   unsigned nonce,
1131                   PA_DATA *pa,
1132                   krb5_keyblock **key)
1133 {
1134     unsigned char *p, *dh_gen_key = NULL;
1135     struct krb5_pk_cert *host = NULL;
1136     BIGNUM *kdc_dh_pubkey = NULL;
1137     KDCDHKeyInfo kdc_dh_info;
1138     heim_oid contentType = { 0, NULL };
1139     krb5_data content;
1140     krb5_error_code ret;
1141     int dh_gen_keylen;
1142     size_t size;
1143 
1144     krb5_data_zero(&content);
1145     memset(&kdc_dh_info, 0, sizeof(kdc_dh_info));
1146 
1147     if (der_heim_oid_cmp(oid_id_pkcs7_signedData(), dataType)) {
1148         krb5_set_error_message(context, EINVAL,
1149                                N_("PKINIT: Invalid content type", ""));
1150         return EINVAL;
1151     }
1152 
1153     ret = _krb5_pk_verify_sign(context,
1154                                indata->data,
1155                                indata->length,
1156                                ctx->id,
1157                                &contentType,
1158                                &content,
1159                                &host);
1160     if (ret)
1161         goto out;
1162 
1163     /* make sure that it is the kdc's certificate */
1164     ret = pk_verify_host(context, realm, hi, ctx, host);
1165     if (ret)
1166         goto out;
1167 
1168     if (der_heim_oid_cmp(&contentType, oid_id_pkdhkeydata())) {
1169         ret = KRB5KRB_AP_ERR_MSG_TYPE;
1170         krb5_set_error_message(context, ret,
1171                                N_("pkinit - dh reply contains wrong oid", ""));
1172         goto out;
1173     }
1174 
1175     ret = decode_KDCDHKeyInfo(content.data,
1176                               content.length,
1177                               &kdc_dh_info,
1178                               &size);
1179 
1180     if (ret) {
1181         krb5_set_error_message(context, ret,
1182                                N_("pkinit - failed to decode "
1183                                   "KDC DH Key Info", ""));
1184         goto out;
1185     }
1186 
1187     if (kdc_dh_info.nonce != nonce) {
1188         ret = KRB5KRB_AP_ERR_MODIFIED;
1189         krb5_set_error_message(context, ret,
1190                                N_("PKINIT: DH nonce is wrong", ""));
1191         goto out;
1192     }
1193 
1194     if (kdc_dh_info.dhKeyExpiration) {
1195         if (k_n == NULL) {
1196             ret = KRB5KRB_ERR_GENERIC;
1197             krb5_set_error_message(context, ret,
1198                                    N_("pkinit; got key expiration "
1199                                       "without server nonce", ""));
1200             goto out;
1201         }
1202         if (c_n == NULL) {
1203             ret = KRB5KRB_ERR_GENERIC;
1204             krb5_set_error_message(context, ret,
1205                                    N_("pkinit; got DH reuse but no "
1206                                       "client nonce", ""));
1207             goto out;
1208         }
1209     } else {
1210         if (k_n) {
1211             ret = KRB5KRB_ERR_GENERIC;
1212             krb5_set_error_message(context, ret,
1213                                    N_("pkinit: got server nonce "
1214                                       "without key expiration", ""));
1215             goto out;
1216         }
1217         c_n = NULL;
1218     }
1219 
1220 
1221     p = kdc_dh_info.subjectPublicKey.data;
1222     size = (kdc_dh_info.subjectPublicKey.length + 7) / 8;
1223 
1224     {
1225         DHPublicKey k;
1226         ret = decode_DHPublicKey(p, size, &k, NULL);
1227         if (ret) {
1228             krb5_set_error_message(context, ret,
1229                                    N_("pkinit: can't decode "
1230                                       "without key expiration", ""));
1231             goto out;
1232         }
1233 
1234         kdc_dh_pubkey = integer_to_BN(context, "DHPublicKey", &k);
1235         free_DHPublicKey(&k);
1236         if (kdc_dh_pubkey == NULL) {
1237             ret = ENOMEM;
1238             goto out;
1239         }
1240     }
1241 
1242     dh_gen_keylen = DH_size(ctx->dh);
1243     size = BN_num_bytes(ctx->dh->p);
1244     if (size < dh_gen_keylen)
1245         size = dh_gen_keylen;
1246 
1247     dh_gen_key = malloc(size);
1248     if (dh_gen_key == NULL) {
1249         ret = ENOMEM;
1250         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1251         goto out;
1252     }
1253     memset(dh_gen_key, 0, size - dh_gen_keylen);
1254 
1255     dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen),
1256                                    kdc_dh_pubkey, ctx->dh);
1257     if (dh_gen_keylen == -1) {
1258         ret = KRB5KRB_ERR_GENERIC;
1259         krb5_set_error_message(context, ret,
1260                                N_("PKINIT: Can't compute Diffie-Hellman key", ""));
1261         goto out;
1262     }
1263 
1264     *key = malloc (sizeof (**key));
1265     if (*key == NULL) {
1266         ret = ENOMEM;
1267         krb5_set_error_message(context, ret,
1268                                N_("malloc: out of memory", ""));
1269         goto out;
1270     }
1271 
1272     ret = _krb5_pk_octetstring2key(context,
1273                                    etype,
1274                                    dh_gen_key, dh_gen_keylen,
1275                                    c_n, k_n,
1276                                    *key);
1277     if (ret) {
1278         krb5_set_error_message(context, ret,
1279                                N_("PKINIT: can't create key from DH key", ""));
1280         free(*key);
1281         *key = NULL;
1282         goto out;
1283     }
1284 
1285  out:
1286     if (kdc_dh_pubkey)
1287         BN_free(kdc_dh_pubkey);
1288     if (dh_gen_key) {
1289         memset(dh_gen_key, 0, DH_size(ctx->dh));
1290         free(dh_gen_key);
1291     }
1292     if (host)
1293         _krb5_pk_cert_free(host);
1294     if (content.data)
1295         krb5_data_free(&content);
1296     der_free_oid(&contentType);
1297     free_KDCDHKeyInfo(&kdc_dh_info);
1298 
1299     return ret;
1300 }
1301 
1302 krb5_error_code KRB5_LIB_FUNCTION
1303 _krb5_pk_rd_pa_reply(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1304                      const char *realm,
1305                      void *c,
1306                      krb5_enctype etype,
1307                      const krb5_krbhst_info *hi,
1308                      unsigned nonce,
1309                      const krb5_data *req_buffer,
1310                      PA_DATA *pa,
1311                      krb5_keyblock **key)
1312 {
1313     krb5_pk_init_ctx ctx = c;
1314     krb5_error_code ret;
1315     size_t size;
1316 
1317     /* Check for IETF PK-INIT first */
1318     if (ctx->type == PKINIT_27) {
1319         PA_PK_AS_REP rep;
1320         heim_octet_string os, data;
1321         heim_oid oid;
1322         
1323         if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1324             krb5_set_error_message(context, EINVAL,
1325                                    N_("PKINIT: wrong padata recv", ""));
1326             return EINVAL;
1327         }
1328 
1329         ret = decode_PA_PK_AS_REP(pa->padata_value.data,
1330                                   pa->padata_value.length,
1331                                   &rep,
1332                                   &size);
1333         if (ret) {
1334             krb5_set_error_message(context, ret,
1335                                    N_("Failed to decode pkinit AS rep", ""));
1336             return ret;
1337         }
1338 
1339         switch (rep.element) {
1340         case choice_PA_PK_AS_REP_dhInfo:
1341             os = rep.u.dhInfo.dhSignedData;
1342             break;
1343         case choice_PA_PK_AS_REP_encKeyPack:
1344             os = rep.u.encKeyPack;
1345             break;
1346         default:
1347             free_PA_PK_AS_REP(&rep);
1348             krb5_set_error_message(context, EINVAL,
1349                                    N_("PKINIT: -27 reply "
1350                                       "invalid content type", ""));
1351             return EINVAL;
1352         }
1353 
1354         ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL);
1355         if (ret) {
1356             free_PA_PK_AS_REP(&rep);
1357             krb5_set_error_message(context, ret,
1358                                    N_("PKINIT: failed to unwrap CI", ""));
1359             return ret;
1360         }
1361 
1362         switch (rep.element) {
1363         case choice_PA_PK_AS_REP_dhInfo:
1364             ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi,
1365                                     ctx->clientDHNonce,
1366                                     rep.u.dhInfo.serverDHNonce,
1367                                     nonce, pa, key);
1368             break;
1369         case choice_PA_PK_AS_REP_encKeyPack:
1370             ret = pk_rd_pa_reply_enckey(context, PKINIT_27, &data, &oid, realm,
1371                                         ctx, etype, hi, nonce, req_buffer, pa, key);
1372             break;
1373         default:
1374             krb5_abortx(context, "pk-init as-rep case not possible to happen");
1375         }
1376         der_free_octet_string(&data);
1377         der_free_oid(&oid);
1378         free_PA_PK_AS_REP(&rep);
1379 
1380     } else if (ctx->type == PKINIT_WIN2K) {
1381         PA_PK_AS_REP_Win2k w2krep;
1382 
1383         /* Check for Windows encoding of the AS-REP pa data */
1384 
1385 #if 0 /* should this be ? */
1386         if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1387             krb5_set_error_message(context, EINVAL,
1388                                    "PKINIT: wrong padata recv");
1389             return EINVAL;
1390         }
1391 #endif
1392 
1393         memset(&w2krep, 0, sizeof(w2krep));
1394         
1395         ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data,
1396                                         pa->padata_value.length,
1397                                         &w2krep,
1398                                         &size);
1399         if (ret) {
1400             krb5_set_error_message(context, ret,
1401                                    N_("PKINIT: Failed decoding windows "
1402                                       "pkinit reply %d", ""), (int)ret);
1403             return ret;
1404         }
1405 
1406         krb5_clear_error_message(context);
1407         
1408         switch (w2krep.element) {
1409         case choice_PA_PK_AS_REP_Win2k_encKeyPack: {
1410             heim_octet_string data;
1411             heim_oid oid;
1412         
1413             ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack,
1414                                                &oid, &data, NULL);
1415             free_PA_PK_AS_REP_Win2k(&w2krep);
1416             if (ret) {
1417                 krb5_set_error_message(context, ret,
1418                                        N_("PKINIT: failed to unwrap CI", ""));
1419                 return ret;
1420             }
1421 
1422             ret = pk_rd_pa_reply_enckey(context, PKINIT_WIN2K, &data, &oid, realm,
1423                                         ctx, etype, hi, nonce, req_buffer, pa, key);
1424             der_free_octet_string(&data);
1425             der_free_oid(&oid);
1426 
1427             break;
1428         }
1429         default:
1430             free_PA_PK_AS_REP_Win2k(&w2krep);
1431             ret = EINVAL;
1432             krb5_set_error_message(context, ret,
1433                                    N_("PKINIT: win2k reply invalid "
1434                                       "content type", ""));
1435             break;
1436         }
1437 
1438     } else {
1439         ret = EINVAL;
1440         krb5_set_error_message(context, ret,
1441                                N_("PKINIT: unknown reply type", ""));
1442     }
1443 
1444     return ret;
1445 }
1446 
1447 struct prompter {
1448     krb5_context context;
1449     krb5_prompter_fct prompter;
1450     void *prompter_data;
1451 };
1452 
1453 static int
1454 hx_pass_prompter(void *data, const hx509_prompt *prompter)
     /* [<][>][^][v][top][bottom][index][help] */
1455 {
1456     krb5_error_code ret;
1457     krb5_prompt prompt;
1458     krb5_data password_data;
1459     struct prompter *p = data;
1460 
1461     password_data.data   = prompter->reply.data;
1462     password_data.length = prompter->reply.length;
1463 
1464     prompt.prompt = prompter->prompt;
1465     prompt.hidden = hx509_prompt_hidden(prompter->type);
1466     prompt.reply  = &password_data;
1467 
1468     switch (prompter->type) {
1469     case HX509_PROMPT_TYPE_INFO:
1470         prompt.type   = KRB5_PROMPT_TYPE_INFO;
1471         break;
1472     case HX509_PROMPT_TYPE_PASSWORD:
1473     case HX509_PROMPT_TYPE_QUESTION:
1474     default:
1475         prompt.type   = KRB5_PROMPT_TYPE_PASSWORD;
1476         break;
1477     }   
1478 
1479     ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt);
1480     if (ret) {
1481         memset (prompter->reply.data, 0, prompter->reply.length);
1482         return 1;
1483     }
1484     return 0;
1485 }
1486 
1487 
1488 void KRB5_LIB_FUNCTION
1489 _krb5_pk_allow_proxy_certificate(struct krb5_pk_identity *id,
     /* [<][>][^][v][top][bottom][index][help] */
1490                                  int boolean)
1491 {
1492     hx509_verify_set_proxy_certificate(id->verify_ctx, boolean);
1493 }
1494 
1495 
1496 krb5_error_code KRB5_LIB_FUNCTION
1497 _krb5_pk_load_id(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1498                  struct krb5_pk_identity **ret_id,
1499                  const char *user_id,
1500                  const char *anchor_id,
1501                  char * const *chain_list,
1502                  char * const *revoke_list,
1503                  krb5_prompter_fct prompter,
1504                  void *prompter_data,
1505                  char *password)
1506 {
1507     struct krb5_pk_identity *id = NULL;
1508     hx509_lock lock = NULL;
1509     struct prompter p;
1510     int ret;
1511 
1512     *ret_id = NULL;
1513 
1514     if (anchor_id == NULL) {
1515         krb5_set_error_message(context, HEIM_PKINIT_NO_VALID_CA,
1516                                N_("PKINIT: No anchor given", ""));
1517         return HEIM_PKINIT_NO_VALID_CA;
1518     }
1519 
1520     if (user_id == NULL) {
1521         krb5_set_error_message(context, HEIM_PKINIT_NO_PRIVATE_KEY,
1522                                N_("PKINIT: No user certificate given", ""));
1523         return HEIM_PKINIT_NO_PRIVATE_KEY;
1524     }
1525 
1526     /* load cert */
1527 
1528     id = calloc(1, sizeof(*id));
1529     if (id == NULL) {
1530         krb5_set_error_message(context, ENOMEM,
1531                                N_("malloc: out of memory", ""));
1532         return ENOMEM;
1533     }   
1534 
1535     ret = hx509_context_init(&id->hx509ctx);
1536     if (ret)
1537         goto out;
1538 
1539     ret = hx509_lock_init(id->hx509ctx, &lock);
1540     if (password && password[0])
1541         hx509_lock_add_password(lock, password);
1542 
1543     if (prompter) {
1544         p.context = context;
1545         p.prompter = prompter;
1546         p.prompter_data = prompter_data;
1547 
1548         ret = hx509_lock_set_prompter(lock, hx_pass_prompter, &p);
1549         if (ret)
1550             goto out;
1551     }
1552 
1553     ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs);
1554     if (ret) {
1555         pk_copy_error(context, id->hx509ctx, ret,
1556                       "Failed to init cert certs");
1557         goto out;
1558     }
1559 
1560     ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors);
1561     if (ret) {
1562         pk_copy_error(context, id->hx509ctx, ret,
1563                       "Failed to init anchors");
1564         goto out;
1565     }
1566 
1567     ret = hx509_certs_init(id->hx509ctx, "MEMORY:pkinit-cert-chain",
1568                            0, NULL, &id->certpool);
1569     if (ret) {
1570         pk_copy_error(context, id->hx509ctx, ret,
1571                       "Failed to init chain");
1572         goto out;
1573     }
1574 
1575     while (chain_list && *chain_list) {
1576         ret = hx509_certs_append(id->hx509ctx, id->certpool,
1577                                  NULL, *chain_list);
1578         if (ret) {
1579             pk_copy_error(context, id->hx509ctx, ret,
1580                           "Failed to laod chain %s",
1581                           *chain_list);
1582             goto out;
1583         }
1584         chain_list++;
1585     }
1586 
1587     if (revoke_list) {
1588         ret = hx509_revoke_init(id->hx509ctx, &id->revokectx);
1589         if (ret) {
1590             pk_copy_error(context, id->hx509ctx, ret,
1591                           "Failed init revoke list");
1592             goto out;
1593         }
1594 
1595         while (*revoke_list) {
1596             ret = hx509_revoke_add_crl(id->hx509ctx,
1597                                        id->revokectx,
1598                                        *revoke_list);
1599             if (ret) {
1600                 pk_copy_error(context, id->hx509ctx, ret,
1601                               "Failed load revoke list");
1602                 goto out;
1603             }
1604             revoke_list++;
1605         }
1606     } else
1607         hx509_context_set_missing_revoke(id->hx509ctx, 1);
1608 
1609     ret = hx509_verify_init_ctx(id->hx509ctx, &id->verify_ctx);
1610     if (ret) {
1611         pk_copy_error(context, id->hx509ctx, ret,
1612                       "Failed init verify context");
1613         goto out;
1614     }
1615 
1616     hx509_verify_attach_anchors(id->verify_ctx, id->anchors);
1617     hx509_verify_attach_revoke(id->verify_ctx, id->revokectx);
1618 
1619  out:
1620     if (ret) {
1621         hx509_verify_destroy_ctx(id->verify_ctx);
1622         hx509_certs_free(&id->certs);
1623         hx509_certs_free(&id->anchors);
1624         hx509_certs_free(&id->certpool);
1625         hx509_revoke_free(&id->revokectx);
1626         hx509_context_free(&id->hx509ctx);
1627         free(id);
1628     } else
1629         *ret_id = id;
1630 
1631     hx509_lock_free(lock);
1632 
1633     return ret;
1634 }
1635 
1636 static krb5_error_code
1637 select_dh_group(krb5_context context, DH *dh, unsigned long bits,
     /* [<][>][^][v][top][bottom][index][help] */
1638                 struct krb5_dh_moduli **moduli)
1639 {
1640     const struct krb5_dh_moduli *m;
1641 
1642     if (bits == 0) {
1643         m = moduli[1]; /* XXX */
1644         if (m == NULL)
1645             m = moduli[0]; /* XXX */
1646     } else {
1647         int i;
1648         for (i = 0; moduli[i] != NULL; i++) {
1649             if (bits < moduli[i]->bits)
1650                 break;
1651         }
1652         if (moduli[i] == NULL) {
1653             krb5_set_error_message(context, EINVAL,
1654                                    N_("Did not find a DH group parameter "
1655                                       "matching requirement of %lu bits", ""),
1656                                    bits);
1657             return EINVAL;
1658         }
1659         m = moduli[i];
1660     }
1661 
1662     dh->p = integer_to_BN(context, "p", &m->p);
1663     if (dh->p == NULL)
1664         return ENOMEM;
1665     dh->g = integer_to_BN(context, "g", &m->g);
1666     if (dh->g == NULL)
1667         return ENOMEM;
1668     dh->q = integer_to_BN(context, "q", &m->q);
1669     if (dh->q == NULL)
1670         return ENOMEM;
1671 
1672     return 0;
1673 }
1674 
1675 /*
1676  *
1677  */
1678 
1679 static void
1680 pk_copy_error(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1681               hx509_context hx509ctx,
1682               int hxret,
1683               const char *fmt,
1684               ...)
1685 {
1686     va_list va;
1687     char *s, *f;
1688 
1689     va_start(va, fmt);
1690     vasprintf(&f, fmt, va);
1691     va_end(va);
1692     if (f == NULL) {
1693         krb5_clear_error_message(context);
1694         return;
1695     }
1696 
1697     s = hx509_get_error_string(hx509ctx, hxret);
1698     if (s == NULL) {
1699         krb5_clear_error_message(context);
1700         free(f);
1701         return;
1702     }
1703     krb5_set_error_message(context, hxret, "%s: %s", f, s);
1704     free(s);
1705     free(f);
1706 }
1707 
1708 static int
1709 parse_integer(krb5_context context, char **p, const char *file, int lineno,
     /* [<][>][^][v][top][bottom][index][help] */
1710               const char *name, heim_integer *integer)
1711 {
1712     int ret;
1713     char *p1;
1714     p1 = strsep(p, " \t");
1715     if (p1 == NULL) {
1716         krb5_set_error_message(context, EINVAL,
1717                                N_("moduli file %s missing %s on line %d", ""),
1718                                file, name, lineno);
1719         return EINVAL;
1720     }
1721     ret = der_parse_hex_heim_integer(p1, integer);
1722     if (ret) {
1723         krb5_set_error_message(context, ret,
1724                                N_("moduli file %s failed parsing %s "
1725                                   "on line %d", ""),
1726                                file, name, lineno);
1727         return ret;
1728     }
1729 
1730     return 0;
1731 }
1732 
1733 krb5_error_code
1734 _krb5_parse_moduli_line(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1735                         const char *file,
1736                         int lineno,
1737                         char *p,
1738                         struct krb5_dh_moduli **m)
1739 {
1740     struct krb5_dh_moduli *m1;
1741     char *p1;
1742     int ret;
1743 
1744     *m = NULL;
1745 
1746     m1 = calloc(1, sizeof(*m1));
1747     if (m1 == NULL) {
1748         krb5_set_error_message(context, ENOMEM,
1749                                N_("malloc: out of memory", ""));
1750         return ENOMEM;
1751     }
1752 
1753     while (isspace((unsigned char)*p))
1754         p++;
1755     if (*p  == '#')
1756         return 0;
1757     ret = EINVAL;
1758 
1759     p1 = strsep(&p, " \t");
1760     if (p1 == NULL) {
1761         krb5_set_error_message(context, ret,
1762                                N_("moduli file %s missing name on line %d", ""),
1763                                file, lineno);
1764         goto out;
1765     }
1766     m1->name = strdup(p1);
1767     if (p1 == NULL) {
1768         ret = ENOMEM;
1769         krb5_set_error_message(context, ret, N_("malloc: out of memeory", ""));
1770         goto out;
1771     }
1772 
1773     p1 = strsep(&p, " \t");
1774     if (p1 == NULL) {
1775         krb5_set_error_message(context, ret,
1776                                N_("moduli file %s missing bits on line %d", ""),
1777                                file, lineno);
1778         goto out;
1779     }
1780 
1781     m1->bits = atoi(p1);
1782     if (m1->bits == 0) {
1783         krb5_set_error_message(context, ret,
1784                                N_("moduli file %s have un-parsable "
1785                                   "bits on line %d", ""), file, lineno);
1786         goto out;
1787     }
1788         
1789     ret = parse_integer(context, &p, file, lineno, "p", &m1->p);
1790     if (ret)
1791         goto out;
1792     ret = parse_integer(context, &p, file, lineno, "g", &m1->g);
1793     if (ret)
1794         goto out;
1795     ret = parse_integer(context, &p, file, lineno, "q", &m1->q);
1796     if (ret)
1797         goto out;
1798 
1799     *m = m1;
1800 
1801     return 0;
1802  out:
1803     free(m1->name);
1804     der_free_heim_integer(&m1->p);
1805     der_free_heim_integer(&m1->g);
1806     der_free_heim_integer(&m1->q);
1807     free(m1);
1808     return ret;
1809 }
1810 
1811 void
1812 _krb5_free_moduli(struct krb5_dh_moduli **moduli)
     /* [<][>][^][v][top][bottom][index][help] */
1813 {
1814     int i;
1815     for (i = 0; moduli[i] != NULL; i++) {
1816         free(moduli[i]->name);
1817         der_free_heim_integer(&moduli[i]->p);
1818         der_free_heim_integer(&moduli[i]->g);
1819         der_free_heim_integer(&moduli[i]->q);
1820         free(moduli[i]);
1821     }
1822     free(moduli);
1823 }
1824 
1825 static const char *default_moduli_RFC2412_MODP_group2 =
1826     /* name */
1827     "RFC2412-MODP-group2 "
1828     /* bits */
1829     "1024 "
1830     /* p */
1831     "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1832     "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1833     "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1834     "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1835     "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
1836     "FFFFFFFF" "FFFFFFFF "
1837     /* g */
1838     "02 "
1839     /* q */
1840     "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
1841     "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
1842     "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
1843     "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
1844     "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
1845     "FFFFFFFF" "FFFFFFFF";
1846 
1847 static const char *default_moduli_rfc3526_MODP_group14 =
1848     /* name */
1849     "rfc3526-MODP-group14 "
1850     /* bits */
1851     "1760 "
1852     /* p */
1853     "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1854     "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1855     "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1856     "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1857     "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
1858     "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
1859     "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
1860     "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
1861     "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
1862     "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
1863     "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
1864     /* g */
1865     "02 "
1866     /* q */
1867     "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
1868     "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
1869     "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
1870     "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
1871     "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
1872     "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
1873     "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
1874     "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
1875     "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
1876     "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
1877     "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
1878 
1879 krb5_error_code
1880 _krb5_parse_moduli(krb5_context context, const char *file,
     /* [<][>][^][v][top][bottom][index][help] */
1881                    struct krb5_dh_moduli ***moduli)
1882 {
1883     /* name bits P G Q */
1884     krb5_error_code ret;
1885     struct krb5_dh_moduli **m = NULL, **m2;
1886     char buf[4096];
1887     FILE *f;
1888     int lineno = 0, n = 0;
1889 
1890     *moduli = NULL;
1891 
1892     m = calloc(1, sizeof(m[0]) * 3);
1893     if (m == NULL) {
1894         krb5_set_error_message(context, ENOMEM,
1895                                N_("malloc: out of memory", ""));
1896         return ENOMEM;
1897     }
1898 
1899     strlcpy(buf, default_moduli_rfc3526_MODP_group14, sizeof(buf));
1900     ret = _krb5_parse_moduli_line(context, "builtin", 1, buf,  &m[0]);
1901     if (ret) {
1902         _krb5_free_moduli(m);
1903         return ret;
1904     }
1905     n++;
1906 
1907     strlcpy(buf, default_moduli_RFC2412_MODP_group2, sizeof(buf));
1908     ret = _krb5_parse_moduli_line(context, "builtin", 1, buf,  &m[1]);
1909     if (ret) {
1910         _krb5_free_moduli(m);
1911         return ret;
1912     }
1913     n++;
1914 
1915 
1916     if (file == NULL)
1917         file = MODULI_FILE;
1918 
1919     f = fopen(file, "r");
1920     if (f == NULL) {
1921         *moduli = m;
1922         return 0;
1923     }
1924     rk_cloexec_file(f);
1925 
1926     while(fgets(buf, sizeof(buf), f) != NULL) {
1927         struct krb5_dh_moduli *element;
1928 
1929         buf[strcspn(buf, "\n")] = '\0';
1930         lineno++;
1931 
1932         m2 = realloc(m, (n + 2) * sizeof(m[0]));
1933         if (m2 == NULL) {
1934             _krb5_free_moduli(m);
1935             krb5_set_error_message(context, ENOMEM,
1936                                    N_("malloc: out of memory", ""));
1937             return ENOMEM;
1938         }
1939         m = m2;
1940         
1941         m[n] = NULL;
1942 
1943         ret = _krb5_parse_moduli_line(context, file, lineno, buf,  &element);
1944         if (ret) {
1945             _krb5_free_moduli(m);
1946             return ret;
1947         }
1948         if (element == NULL)
1949             continue;
1950 
1951         m[n] = element;
1952         m[n + 1] = NULL;
1953         n++;
1954     }
1955     *moduli = m;
1956     return 0;
1957 }
1958 
1959 krb5_error_code
1960 _krb5_dh_group_ok(krb5_context context, unsigned long bits,
     /* [<][>][^][v][top][bottom][index][help] */
1961                   heim_integer *p, heim_integer *g, heim_integer *q,
1962                   struct krb5_dh_moduli **moduli,
1963                   char **name)
1964 {
1965     int i;
1966 
1967     if (name)
1968         *name = NULL;
1969 
1970     for (i = 0; moduli[i] != NULL; i++) {
1971         if (der_heim_integer_cmp(&moduli[i]->g, g) == 0 &&
1972             der_heim_integer_cmp(&moduli[i]->p, p) == 0 &&
1973             (q == NULL || der_heim_integer_cmp(&moduli[i]->q, q) == 0))
1974             {
1975                 if (bits && bits > moduli[i]->bits) {
1976                     krb5_set_error_message(context,
1977                                            KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
1978                                            N_("PKINIT: DH group parameter %s "
1979                                               "no accepted, not enough bits "
1980                                               "generated", ""),
1981                                            moduli[i]->name);
1982                     return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
1983                 }
1984                 if (name)
1985                     *name = strdup(moduli[i]->name);
1986                 return 0;
1987             }
1988     }
1989     krb5_set_error_message(context,
1990                            KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
1991                            N_("PKINIT: DH group parameter no ok", ""));
1992     return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
1993 }
1994 #endif /* PKINIT */
1995 
1996 void KRB5_LIB_FUNCTION
1997 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt)
     /* [<][>][^][v][top][bottom][index][help] */
1998 {
1999 #ifdef PKINIT
2000     krb5_pk_init_ctx ctx;
2001 
2002     if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL)
2003         return;
2004     ctx = opt->opt_private->pk_init_ctx;
2005     if (ctx->dh)
2006         DH_free(ctx->dh);
2007     ctx->dh = NULL;
2008     if (ctx->id) {
2009         hx509_verify_destroy_ctx(ctx->id->verify_ctx);
2010         hx509_certs_free(&ctx->id->certs);
2011         hx509_certs_free(&ctx->id->anchors);
2012         hx509_certs_free(&ctx->id->certpool);
2013         hx509_context_free(&ctx->id->hx509ctx);
2014 
2015         if (ctx->clientDHNonce) {
2016             krb5_free_data(NULL, ctx->clientDHNonce);
2017             ctx->clientDHNonce = NULL;
2018         }
2019         if (ctx->m)
2020             _krb5_free_moduli(ctx->m);
2021         free(ctx->id);
2022         ctx->id = NULL;
2023     }
2024     free(opt->opt_private->pk_init_ctx);
2025     opt->opt_private->pk_init_ctx = NULL;
2026 #endif
2027 }
2028 
2029 krb5_error_code KRB5_LIB_FUNCTION
2030 krb5_get_init_creds_opt_set_pkinit(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
2031                                    krb5_get_init_creds_opt *opt,
2032                                    krb5_principal principal,
2033                                    const char *user_id,
2034                                    const char *x509_anchors,
2035                                    char * const * pool,
2036                                    char * const * pki_revoke,
2037                                    int flags,
2038                                    krb5_prompter_fct prompter,
2039                                    void *prompter_data,
2040                                    char *password)
2041 {
2042 #ifdef PKINIT
2043     krb5_error_code ret;
2044     char *anchors = NULL;
2045 
2046     if (opt->opt_private == NULL) {
2047         krb5_set_error_message(context, EINVAL,
2048                                N_("PKINIT: on non extendable opt", ""));
2049         return EINVAL;
2050     }
2051 
2052     opt->opt_private->pk_init_ctx =
2053         calloc(1, sizeof(*opt->opt_private->pk_init_ctx));
2054     if (opt->opt_private->pk_init_ctx == NULL) {
2055         krb5_set_error_message(context, ENOMEM,
2056                                N_("malloc: out of memory", ""));
2057         return ENOMEM;
2058     }
2059     opt->opt_private->pk_init_ctx->dh = NULL;
2060     opt->opt_private->pk_init_ctx->id = NULL;
2061     opt->opt_private->pk_init_ctx->clientDHNonce = NULL;
2062     opt->opt_private->pk_init_ctx->require_binding = 0;
2063     opt->opt_private->pk_init_ctx->require_eku = 1;
2064     opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1;
2065     opt->opt_private->pk_init_ctx->peer = NULL;
2066 
2067     /* XXX implement krb5_appdefault_strings  */
2068     if (pool == NULL)
2069         pool = krb5_config_get_strings(context, NULL,
2070                                        "appdefaults",
2071                                        "pkinit_pool",
2072                                        NULL);
2073 
2074     if (pki_revoke == NULL)
2075         pki_revoke = krb5_config_get_strings(context, NULL,
2076                                              "appdefaults",
2077                                              "pkinit_revoke",
2078                                              NULL);
2079 
2080     if (x509_anchors == NULL) {
2081         krb5_appdefault_string(context, "kinit",
2082                                krb5_principal_get_realm(context, principal),
2083                                "pkinit_anchors", NULL, &anchors);
2084         x509_anchors = anchors;
2085     }
2086 
2087     ret = _krb5_pk_load_id(context,
2088                            &opt->opt_private->pk_init_ctx->id,
2089                            user_id,
2090                            x509_anchors,
2091                            pool,
2092                            pki_revoke,
2093                            prompter,
2094                            prompter_data,
2095                            password);
2096     if (ret) {
2097         free(opt->opt_private->pk_init_ctx);
2098         opt->opt_private->pk_init_ctx = NULL;
2099         return ret;
2100     }
2101 
2102     if ((flags & 2) == 0) {
2103         const char *moduli_file;
2104         unsigned long dh_min_bits;
2105 
2106         moduli_file = krb5_config_get_string(context, NULL,
2107                                              "libdefaults",
2108                                              "moduli",
2109                                              NULL);
2110 
2111         dh_min_bits =
2112             krb5_config_get_int_default(context, NULL, 0,
2113                                         "libdefaults",
2114                                         "pkinit_dh_min_bits",
2115                                         NULL);
2116 
2117         ret = _krb5_parse_moduli(context, moduli_file,
2118                                  &opt->opt_private->pk_init_ctx->m);
2119         if (ret) {
2120             _krb5_get_init_creds_opt_free_pkinit(opt);
2121             return ret;
2122         }
2123         
2124         opt->opt_private->pk_init_ctx->dh = DH_new();
2125         if (opt->opt_private->pk_init_ctx->dh == NULL) {
2126             _krb5_get_init_creds_opt_free_pkinit(opt);
2127             krb5_set_error_message(context, ENOMEM,
2128                                    N_("malloc: out of memory", ""));
2129             return ENOMEM;
2130         }
2131 
2132         ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh,
2133                               dh_min_bits,
2134                               opt->opt_private->pk_init_ctx->m);
2135         if (ret) {
2136             _krb5_get_init_creds_opt_free_pkinit(opt);
2137             return ret;
2138         }
2139 
2140         if (DH_generate_key(opt->opt_private->pk_init_ctx->dh) != 1) {
2141             _krb5_get_init_creds_opt_free_pkinit(opt);
2142             krb5_set_error_message(context, ENOMEM,
2143                                    N_("pkinit: failed to generate DH key", ""));
2144             return ENOMEM;
2145         }
2146     }
2147 
2148     return 0;
2149 #else
2150     krb5_set_error_message(context, EINVAL,
2151                            N_("no support for PKINIT compiled in", ""));
2152     return EINVAL;
2153 #endif
2154 }

/* [<][>][^][v][top][bottom][index][help] */