LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - pkinit.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 382 1334 28.6 %
Date: 2024-06-13 04:01:37 Functions: 17 36 47.2 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2003 - 2016 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 "krb5_locl.h"
      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             : static void
      62             : pk_copy_error(krb5_context context,
      63             :               hx509_context hx509ctx,
      64             :               int hxret,
      65             :               const char *fmt,
      66             :               ...)
      67             :     __attribute__ ((__format__ (__printf__, 4, 5)));
      68             : 
      69             : /*
      70             :  *
      71             :  */
      72             : 
      73             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
      74           0 : _krb5_pk_cert_free(struct krb5_pk_cert *cert)
      75             : {
      76           0 :     if (cert->cert) {
      77           0 :         hx509_cert_free(cert->cert);
      78             :     }
      79           0 :     free(cert);
      80           0 : }
      81             : 
      82             : static krb5_error_code
      83         308 : BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer)
      84             : {
      85         308 :     integer->length = BN_num_bytes(bn);
      86         308 :     integer->data = malloc(integer->length);
      87         308 :     if (integer->data == NULL) {
      88           0 :         krb5_clear_error_message(context);
      89           0 :         return ENOMEM;
      90             :     }
      91         308 :     BN_bn2bin(bn, integer->data);
      92         308 :     integer->negative = BN_is_negative(bn);
      93         308 :     return 0;
      94             : }
      95             : 
      96             : static BIGNUM *
      97         231 : integer_to_BN(krb5_context context, const char *field, const heim_integer *f)
      98             : {
      99             :     BIGNUM *bn;
     100             : 
     101         231 :     bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL);
     102         231 :     if (bn == NULL) {
     103           0 :         krb5_set_error_message(context, ENOMEM,
     104           0 :                                N_("PKINIT: parsing BN failed %s", ""), field);
     105           0 :         return NULL;
     106             :     }
     107         231 :     BN_set_negative(bn, f->negative);
     108         231 :     return bn;
     109             : }
     110             : 
     111             : static krb5_error_code
     112          77 : select_dh_group(krb5_context context, DH *dh, unsigned long bits,
     113             :                 struct krb5_dh_moduli **moduli)
     114             : {
     115             :     const struct krb5_dh_moduli *m;
     116             : 
     117          77 :     if (moduli[0] == NULL) {
     118           0 :         krb5_set_error_message(context, EINVAL,
     119           0 :                                N_("Did not find a DH group parameter "
     120             :                                   "matching requirement of %lu bits", ""),
     121             :                                bits);
     122           0 :         return EINVAL;
     123             :     }
     124             : 
     125          77 :     if (bits == 0) {
     126          77 :         m = moduli[1]; /* XXX */
     127          77 :         if (m == NULL)
     128           0 :             m = moduli[0]; /* XXX */
     129             :     } else {
     130             :         int i;
     131           0 :         for (i = 0; moduli[i] != NULL; i++) {
     132           0 :             if (bits < moduli[i]->bits)
     133           0 :                 break;
     134             :         }
     135           0 :         if (moduli[i] == NULL) {
     136           0 :             krb5_set_error_message(context, EINVAL,
     137           0 :                                    N_("Did not find a DH group parameter "
     138             :                                       "matching requirement of %lu bits", ""),
     139             :                                    bits);
     140           0 :             return EINVAL;
     141             :         }
     142           0 :         m = moduli[i];
     143             :     }
     144             : 
     145          77 :     dh->p = integer_to_BN(context, "p", &m->p);
     146          77 :     if (dh->p == NULL)
     147           0 :         return ENOMEM;
     148          77 :     dh->g = integer_to_BN(context, "g", &m->g);
     149          77 :     if (dh->g == NULL)
     150           0 :         return ENOMEM;
     151          77 :     dh->q = integer_to_BN(context, "q", &m->q);
     152          77 :     if (dh->q == NULL)
     153           0 :         return ENOMEM;
     154             : 
     155          77 :     return 0;
     156             : }
     157             : 
     158             : struct certfind {
     159             :     const char *type;
     160             :     const heim_oid *oid;
     161             : };
     162             : 
     163             : /*
     164             :  * Try searchin the key by to use by first looking for for PK-INIT
     165             :  * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
     166             :  */
     167             : 
     168             : static krb5_error_code
     169           0 : find_cert(krb5_context context, struct krb5_pk_identity *id,
     170             :           hx509_query *q, hx509_cert *cert)
     171             : {
     172           0 :     struct certfind cf[4] = {
     173             :         { "MobileMe EKU", NULL },
     174             :         { "PKINIT EKU", NULL },
     175             :         { "MS EKU", NULL },
     176             :         { "any (or no)", NULL }
     177             :     };
     178           0 :     int ret = HX509_CERT_NOT_FOUND;
     179           0 :     size_t i, start = 1;
     180           0 :     unsigned oids[] = { 1, 2, 840, 113635, 100, 3, 2, 1 };
     181           0 :     const heim_oid mobileMe = { sizeof(oids)/sizeof(oids[0]), oids };
     182             : 
     183             : 
     184           0 :     if (id->flags & PKINIT_BTMM)
     185           0 :         start = 0;
     186             : 
     187           0 :     cf[0].oid = &mobileMe;
     188           0 :     cf[1].oid = &asn1_oid_id_pkekuoid;
     189           0 :     cf[2].oid = &asn1_oid_id_pkinit_ms_eku;
     190           0 :     cf[3].oid = NULL;
     191             : 
     192           0 :     for (i = start; i < sizeof(cf)/sizeof(cf[0]); i++) {
     193           0 :         ret = hx509_query_match_eku(q, cf[i].oid);
     194           0 :         if (ret) {
     195           0 :             pk_copy_error(context, context->hx509ctx, ret,
     196             :                           "Failed setting %s OID", cf[i].type);
     197           0 :             return ret;
     198             :         }
     199             : 
     200           0 :         ret = hx509_certs_find(context->hx509ctx, id->certs, q, cert);
     201           0 :         if (ret == 0)
     202           0 :             break;
     203           0 :         pk_copy_error(context, context->hx509ctx, ret,
     204             :                       "Failed finding certificate with %s OID", cf[i].type);
     205             :     }
     206           0 :     return ret;
     207             : }
     208             : 
     209             : 
     210             : static krb5_error_code
     211          77 : create_signature(krb5_context context,
     212             :                  const heim_oid *eContentType,
     213             :                  krb5_data *eContent,
     214             :                  struct krb5_pk_identity *id,
     215             :                  hx509_peer_info peer,
     216             :                  krb5_data *sd_data)
     217             : {
     218          77 :     int ret, flags = 0;
     219             : 
     220          77 :     if (id->cert == NULL)
     221          77 :         flags |= HX509_CMS_SIGNATURE_NO_SIGNER;
     222             : 
     223         154 :     ret = hx509_cms_create_signed_1(context->hx509ctx,
     224             :                                     flags,
     225             :                                     eContentType,
     226          77 :                                     eContent->data,
     227             :                                     eContent->length,
     228             :                                     NULL,
     229             :                                     id->cert,
     230             :                                     peer,
     231             :                                     NULL,
     232             :                                     id->certs,
     233             :                                     sd_data);
     234          77 :     if (ret) {
     235           0 :         pk_copy_error(context, context->hx509ctx, ret,
     236             :                       "Create CMS signedData");
     237           0 :         return ret;
     238             :     }
     239             : 
     240          77 :     return 0;
     241             : }
     242             : 
     243             : static int KRB5_LIB_CALL
     244          75 : cert2epi(hx509_context context, void *ctx, hx509_cert c)
     245             : {
     246          75 :     ExternalPrincipalIdentifiers *ids = ctx;
     247             :     ExternalPrincipalIdentifier id;
     248          75 :     hx509_name subject = NULL;
     249             :     void *p;
     250             :     int ret;
     251             : 
     252          75 :     if (ids->len > 10)
     253           0 :         return 0;
     254             : 
     255          75 :     memset(&id, 0, sizeof(id));
     256             : 
     257          75 :     ret = hx509_cert_get_subject(c, &subject);
     258          75 :     if (ret)
     259           0 :         return ret;
     260             : 
     261          75 :     if (hx509_name_is_null_p(subject) != 0) {
     262             : 
     263           0 :         id.subjectName = calloc(1, sizeof(*id.subjectName));
     264           0 :         if (id.subjectName == NULL) {
     265           0 :             hx509_name_free(&subject);
     266           0 :             free_ExternalPrincipalIdentifier(&id);
     267           0 :             return ENOMEM;
     268             :         }
     269             : 
     270           0 :         ret = hx509_name_binary(subject, id.subjectName);
     271           0 :         if (ret) {
     272           0 :             hx509_name_free(&subject);
     273           0 :             free_ExternalPrincipalIdentifier(&id);
     274           0 :             return ret;
     275             :         }
     276             :     }
     277          75 :     hx509_name_free(&subject);
     278             : 
     279             : 
     280          75 :     id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber));
     281          75 :     if (id.issuerAndSerialNumber == NULL) {
     282           0 :         free_ExternalPrincipalIdentifier(&id);
     283           0 :         return ENOMEM;
     284             :     }
     285             : 
     286             :     {
     287             :         IssuerAndSerialNumber iasn;
     288             :         hx509_name issuer;
     289          75 :         size_t size = 0;
     290             : 
     291          75 :         memset(&iasn, 0, sizeof(iasn));
     292             : 
     293          75 :         ret = hx509_cert_get_issuer(c, &issuer);
     294          75 :         if (ret) {
     295           0 :             free_ExternalPrincipalIdentifier(&id);
     296           0 :             return ret;
     297             :         }
     298             : 
     299          75 :         ret = hx509_name_to_Name(issuer, &iasn.issuer);
     300          75 :         hx509_name_free(&issuer);
     301          75 :         if (ret) {
     302           0 :             free_ExternalPrincipalIdentifier(&id);
     303           0 :             return ret;
     304             :         }
     305             : 
     306          75 :         ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber);
     307          75 :         if (ret) {
     308           0 :             free_IssuerAndSerialNumber(&iasn);
     309           0 :             free_ExternalPrincipalIdentifier(&id);
     310           0 :             return ret;
     311             :         }
     312             : 
     313          75 :         ASN1_MALLOC_ENCODE(IssuerAndSerialNumber,
     314             :                            id.issuerAndSerialNumber->data,
     315             :                            id.issuerAndSerialNumber->length,
     316             :                            &iasn, &size, ret);
     317          75 :         free_IssuerAndSerialNumber(&iasn);
     318          75 :         if (ret) {
     319           0 :             free_ExternalPrincipalIdentifier(&id);
     320           0 :             return ret;
     321             :         }
     322          75 :         if (id.issuerAndSerialNumber->length != size)
     323           0 :             abort();
     324             :     }
     325             : 
     326          75 :     id.subjectKeyIdentifier = NULL;
     327             : 
     328          75 :     p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1));
     329          75 :     if (p == NULL) {
     330           0 :         free_ExternalPrincipalIdentifier(&id);
     331           0 :         return ENOMEM;
     332             :     }
     333             : 
     334          75 :     ids->val = p;
     335          75 :     ids->val[ids->len] = id;
     336          75 :     ids->len++;
     337             : 
     338          75 :     return 0;
     339             : }
     340             : 
     341             : static krb5_error_code
     342          77 : build_edi(krb5_context context,
     343             :           hx509_context hx509ctx,
     344             :           hx509_certs certs,
     345             :           ExternalPrincipalIdentifiers *ids)
     346             : {
     347          77 :     return hx509_certs_iter_f(hx509ctx, certs, cert2epi, ids);
     348             : }
     349             : 
     350             : static krb5_error_code
     351          77 : build_auth_pack(krb5_context context,
     352             :                 unsigned nonce,
     353             :                 krb5_pk_init_ctx ctx,
     354             :                 const KDC_REQ_BODY *body,
     355             :                 AuthPack *a)
     356             : {
     357          77 :     size_t buf_size, len = 0;
     358             :     krb5_error_code ret;
     359             :     void *buf;
     360             :     krb5_timestamp sec;
     361             :     int32_t usec;
     362             :     Checksum checksum;
     363             : 
     364          77 :     krb5_clear_error_message(context);
     365             : 
     366          77 :     memset(&checksum, 0, sizeof(checksum));
     367             : 
     368          77 :     krb5_us_timeofday(context, &sec, &usec);
     369          77 :     a->pkAuthenticator.ctime = sec;
     370          77 :     a->pkAuthenticator.nonce = nonce;
     371             : 
     372          77 :     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
     373          77 :     if (ret)
     374           0 :         return ret;
     375          77 :     if (buf_size != len)
     376           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
     377             : 
     378          77 :     ret = krb5_create_checksum(context,
     379             :                                NULL,
     380             :                                0,
     381             :                                CKSUMTYPE_SHA1,
     382             :                                buf,
     383             :                                len,
     384             :                                &checksum);
     385          77 :     free(buf);
     386          77 :     if (ret)
     387           0 :         return ret;
     388             : 
     389          77 :     ALLOC(a->pkAuthenticator.paChecksum, 1);
     390          77 :     if (a->pkAuthenticator.paChecksum == NULL) {
     391           0 :         return krb5_enomem(context);
     392             :     }
     393             : 
     394         154 :     ret = krb5_data_copy(a->pkAuthenticator.paChecksum,
     395          77 :                          checksum.checksum.data, checksum.checksum.length);
     396          77 :     free_Checksum(&checksum);
     397          77 :     if (ret)
     398           0 :         return ret;
     399             : 
     400          77 :     if (ctx->keyex == USE_DH || ctx->keyex == USE_ECDH) {
     401             :         const char *moduli_file;
     402             :         unsigned long dh_min_bits;
     403             :         krb5_data dhbuf;
     404          77 :         size_t size = 0;
     405             : 
     406          77 :         krb5_data_zero(&dhbuf);
     407             : 
     408             : 
     409             : 
     410          77 :         moduli_file = krb5_config_get_string(context, NULL,
     411             :                                              "libdefaults",
     412             :                                              "moduli",
     413             :                                              NULL);
     414             : 
     415          77 :         dh_min_bits =
     416          77 :             krb5_config_get_int_default(context, NULL, 0,
     417             :                                         "libdefaults",
     418             :                                         "pkinit_dh_min_bits",
     419             :                                         NULL);
     420             : 
     421          77 :         ret = _krb5_parse_moduli(context, moduli_file, &ctx->m);
     422          77 :         if (ret)
     423           0 :             return ret;
     424             : 
     425          77 :         ctx->u.dh = DH_new();
     426          77 :         if (ctx->u.dh == NULL)
     427           0 :             return krb5_enomem(context);
     428             : 
     429          77 :         ret = select_dh_group(context, ctx->u.dh, dh_min_bits, ctx->m);
     430          77 :         if (ret)
     431           0 :             return ret;
     432             : 
     433          77 :         if (DH_generate_key(ctx->u.dh) != 1) {
     434           0 :             krb5_set_error_message(context, ENOMEM,
     435           0 :                                    N_("pkinit: failed to generate DH key", ""));
     436           0 :             return ENOMEM;
     437             :         }
     438             : 
     439             : 
     440             :         if (1 /* support_cached_dh */) {
     441          77 :             ALLOC(a->clientDHNonce, 1);
     442          77 :             if (a->clientDHNonce == NULL) {
     443           0 :                 krb5_clear_error_message(context);
     444           0 :                 return ENOMEM;
     445             :             }
     446          77 :             ret = krb5_data_alloc(a->clientDHNonce, 40);
     447          77 :             if (a->clientDHNonce == NULL) {
     448           0 :                 krb5_clear_error_message(context);
     449           0 :                 return ret;
     450             :             }
     451          77 :             RAND_bytes(a->clientDHNonce->data, a->clientDHNonce->length);
     452          77 :             ret = krb5_copy_data(context, a->clientDHNonce,
     453             :                                  &ctx->clientDHNonce);
     454          77 :             if (ret)
     455           0 :                 return ret;
     456             :         }
     457             : 
     458          77 :         ALLOC(a->clientPublicValue, 1);
     459          77 :         if (a->clientPublicValue == NULL)
     460           0 :             return ENOMEM;
     461             : 
     462          77 :         if (ctx->keyex == USE_DH) {
     463          77 :             DH *dh = ctx->u.dh;
     464             :             DomainParameters dp;
     465             :             heim_integer dh_pub_key;
     466             : 
     467          77 :             ret = der_copy_oid(&asn1_oid_id_dhpublicnumber,
     468          77 :                                &a->clientPublicValue->algorithm.algorithm);
     469          77 :             if (ret)
     470           0 :                 return ret;
     471             : 
     472          77 :             memset(&dp, 0, sizeof(dp));
     473             : 
     474          77 :             ret = BN_to_integer(context, dh->p, &dp.p);
     475          77 :             if (ret) {
     476           0 :                 free_DomainParameters(&dp);
     477           0 :                 return ret;
     478             :             }
     479          77 :             ret = BN_to_integer(context, dh->g, &dp.g);
     480          77 :             if (ret) {
     481           0 :                 free_DomainParameters(&dp);
     482           0 :                 return ret;
     483             :             }
     484          77 :             if (dh->q && BN_num_bits(dh->q)) {
     485             :                 /*
     486             :                  * The q parameter is required, but MSFT made it optional.
     487             :                  * It's only required in order to verify the domain parameters
     488             :                  * -- the security of the DH group --, but we validate groups
     489             :                  * against known groups rather than accepting arbitrary groups
     490             :                  * chosen by the peer, so we really don't need to have put it
     491             :                  * on the wire.  Because these are Oakley groups, and the
     492             :                  * primes are Sophie Germain primes, q is p>>1 and we can
     493             :                  * compute it on the fly like MIT Kerberos does, but we'd have
     494             :                  * to implement BN_rshift1().
     495             :                  */
     496          77 :                 dp.q = calloc(1, sizeof(*dp.q));
     497          77 :                 if (dp.q == NULL) {
     498           0 :                     free_DomainParameters(&dp);
     499           0 :                     return ENOMEM;
     500             :                 }
     501          77 :                 ret = BN_to_integer(context, dh->q, dp.q);
     502          77 :                 if (ret) {
     503           0 :                     free_DomainParameters(&dp);
     504           0 :                     return ret;
     505             :                 }
     506             :             }
     507          77 :             dp.j = NULL;
     508          77 :             dp.validationParms = NULL;
     509             : 
     510         154 :             a->clientPublicValue->algorithm.parameters =
     511          77 :                 malloc(sizeof(*a->clientPublicValue->algorithm.parameters));
     512          77 :             if (a->clientPublicValue->algorithm.parameters == NULL) {
     513           0 :                 free_DomainParameters(&dp);
     514           0 :                 return ret;
     515             :             }
     516             : 
     517          77 :             ASN1_MALLOC_ENCODE(DomainParameters,
     518             :                                a->clientPublicValue->algorithm.parameters->data,
     519             :                                a->clientPublicValue->algorithm.parameters->length,
     520             :                                &dp, &size, ret);
     521          77 :             free_DomainParameters(&dp);
     522          77 :             if (ret)
     523           0 :                 return ret;
     524          77 :             if (size != a->clientPublicValue->algorithm.parameters->length)
     525           0 :                 krb5_abortx(context, "Internal ASN1 encoder error");
     526             : 
     527          77 :             ret = BN_to_integer(context, dh->pub_key, &dh_pub_key);
     528          77 :             if (ret)
     529           0 :                 return ret;
     530             : 
     531          77 :             ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length,
     532             :                                &dh_pub_key, &size, ret);
     533          77 :             der_free_heim_integer(&dh_pub_key);
     534          77 :             if (ret)
     535           0 :                 return ret;
     536          77 :             if (size != dhbuf.length)
     537           0 :                 krb5_abortx(context, "asn1 internal error");
     538          77 :             a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8;
     539          77 :             a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
     540           0 :         } else if (ctx->keyex == USE_ECDH) {
     541           0 :             ret = _krb5_build_authpack_subjectPK_EC(context, ctx, a);
     542           0 :             if (ret)
     543           0 :                 return ret;
     544             :         } else
     545           0 :             krb5_abortx(context, "internal error");
     546             :     }
     547             : 
     548             :     {
     549          77 :         a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes));
     550          77 :         if (a->supportedCMSTypes == NULL)
     551           0 :             return ENOMEM;
     552             : 
     553         231 :         ret = hx509_crypto_available(context->hx509ctx, HX509_SELECT_ALL,
     554          77 :                                      ctx->id->cert,
     555          77 :                                      &a->supportedCMSTypes->val,
     556          77 :                                      &a->supportedCMSTypes->len);
     557          77 :         if (ret)
     558           0 :             return ret;
     559             :     }
     560             : 
     561          77 :     return ret;
     562             : }
     563             : 
     564             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     565           0 : _krb5_pk_mk_ContentInfo(krb5_context context,
     566             :                         const krb5_data *buf,
     567             :                         const heim_oid *oid,
     568             :                         struct ContentInfo *content_info)
     569             : {
     570             :     krb5_error_code ret;
     571             : 
     572           0 :     ret = der_copy_oid(oid, &content_info->contentType);
     573           0 :     if (ret)
     574           0 :         return ret;
     575           0 :     ALLOC(content_info->content, 1);
     576           0 :     if (content_info->content == NULL)
     577           0 :         return ENOMEM;
     578           0 :     content_info->content->data = malloc(buf->length);
     579           0 :     if (content_info->content->data == NULL)
     580           0 :         return ENOMEM;
     581           0 :     memcpy(content_info->content->data, buf->data, buf->length);
     582           0 :     content_info->content->length = buf->length;
     583           0 :     return 0;
     584             : }
     585             : 
     586             : static krb5_error_code
     587          77 : pk_mk_padata(krb5_context context,
     588             :              krb5_pk_init_ctx ctx,
     589             :              const KDC_REQ_BODY *req_body,
     590             :              unsigned nonce,
     591             :              METHOD_DATA *md)
     592             : {
     593             :     struct ContentInfo content_info;
     594             :     krb5_error_code ret;
     595          77 :     const heim_oid *oid = NULL;
     596          77 :     size_t size = 0;
     597             :     krb5_data buf, sd_buf;
     598          77 :     int pa_type = -1;
     599             : 
     600          77 :     krb5_data_zero(&buf);
     601          77 :     krb5_data_zero(&sd_buf);
     602          77 :     memset(&content_info, 0, sizeof(content_info));
     603             : 
     604          77 :     if (ctx->type == PKINIT_WIN2K) {
     605             :         AuthPack_Win2k ap;
     606             :         krb5_timestamp sec;
     607             :         int32_t usec;
     608             : 
     609           0 :         memset(&ap, 0, sizeof(ap));
     610             : 
     611             :         /* fill in PKAuthenticator */
     612           0 :         ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName);
     613           0 :         if (ret) {
     614           0 :             free_AuthPack_Win2k(&ap);
     615           0 :             krb5_clear_error_message(context);
     616           0 :             goto out;
     617             :         }
     618           0 :         ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm);
     619           0 :         if (ret) {
     620           0 :             free_AuthPack_Win2k(&ap);
     621           0 :             krb5_clear_error_message(context);
     622           0 :             goto out;
     623             :         }
     624             : 
     625           0 :         krb5_us_timeofday(context, &sec, &usec);
     626           0 :         ap.pkAuthenticator.ctime = sec;
     627           0 :         ap.pkAuthenticator.cusec = usec;
     628           0 :         ap.pkAuthenticator.nonce = nonce;
     629             : 
     630           0 :         ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length,
     631             :                            &ap, &size, ret);
     632           0 :         free_AuthPack_Win2k(&ap);
     633           0 :         if (ret) {
     634           0 :             krb5_set_error_message(context, ret,
     635           0 :                                    N_("Failed encoding AuthPackWin: %d", ""),
     636             :                                    (int)ret);
     637           0 :             goto out;
     638             :         }
     639           0 :         if (buf.length != size)
     640           0 :             krb5_abortx(context, "internal ASN1 encoder error");
     641             : 
     642           0 :         oid = &asn1_oid_id_pkcs7_data;
     643          77 :     } else if (ctx->type == PKINIT_27) {
     644             :         AuthPack ap;
     645             : 
     646          77 :         memset(&ap, 0, sizeof(ap));
     647             : 
     648          77 :         ret = build_auth_pack(context, nonce, ctx, req_body, &ap);
     649          77 :         if (ret) {
     650           0 :             free_AuthPack(&ap);
     651           0 :             goto out;
     652             :         }
     653             : 
     654          77 :         ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret);
     655          77 :         free_AuthPack(&ap);
     656          77 :         if (ret) {
     657           0 :             krb5_set_error_message(context, ret,
     658           0 :                                    N_("Failed encoding AuthPack: %d", ""),
     659             :                                    (int)ret);
     660           0 :             goto out;
     661             :         }
     662          77 :         if (buf.length != size)
     663           0 :             krb5_abortx(context, "internal ASN1 encoder error");
     664             : 
     665          77 :         oid = &asn1_oid_id_pkauthdata;
     666             :     } else
     667           0 :         krb5_abortx(context, "internal pkinit error");
     668             : 
     669          77 :     ret = create_signature(context, oid, &buf, ctx->id,
     670             :                            ctx->peer, &sd_buf);
     671          77 :     krb5_data_free(&buf);
     672          77 :     if (ret)
     673           0 :         goto out;
     674             : 
     675          77 :     ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData, &sd_buf, &buf);
     676          77 :     krb5_data_free(&sd_buf);
     677          77 :     if (ret) {
     678           0 :         krb5_set_error_message(context, ret,
     679           0 :                                N_("ContentInfo wrapping of signedData failed",""));
     680           0 :         goto out;
     681             :     }
     682             : 
     683          77 :     if (ctx->type == PKINIT_WIN2K) {
     684             :         PA_PK_AS_REQ_Win2k winreq;
     685             : 
     686           0 :         pa_type = KRB5_PADATA_PK_AS_REQ_WIN;
     687             : 
     688           0 :         memset(&winreq, 0, sizeof(winreq));
     689             : 
     690           0 :         winreq.signed_auth_pack = buf;
     691             : 
     692           0 :         ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length,
     693             :                            &winreq, &size, ret);
     694           0 :         free_PA_PK_AS_REQ_Win2k(&winreq);
     695             : 
     696          77 :     } else if (ctx->type == PKINIT_27) {
     697             :         PA_PK_AS_REQ req;
     698             : 
     699          77 :         pa_type = KRB5_PADATA_PK_AS_REQ;
     700             : 
     701          77 :         memset(&req, 0, sizeof(req));
     702          77 :         req.signedAuthPack = buf;
     703             : 
     704          77 :         if (ctx->trustedCertifiers) {
     705             : 
     706          77 :             req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers));
     707          77 :             if (req.trustedCertifiers == NULL) {
     708           0 :                 ret = krb5_enomem(context);
     709           0 :                 free_PA_PK_AS_REQ(&req);
     710           0 :                 goto out;
     711             :             }
     712         154 :             ret = build_edi(context, context->hx509ctx,
     713          77 :                             ctx->id->anchors, req.trustedCertifiers);
     714          77 :             if (ret) {
     715           0 :                 krb5_set_error_message(context, ret,
     716           0 :                                        N_("pk-init: failed to build "
     717             :                                           "trustedCertifiers", ""));
     718           0 :                 free_PA_PK_AS_REQ(&req);
     719           0 :                 goto out;
     720             :             }
     721             :         }
     722          77 :         req.kdcPkId = NULL;
     723             : 
     724          77 :         ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length,
     725             :                            &req, &size, ret);
     726             : 
     727          77 :         free_PA_PK_AS_REQ(&req);
     728             : 
     729             :     } else
     730           0 :         krb5_abortx(context, "internal pkinit error");
     731          77 :     if (ret) {
     732           0 :         krb5_set_error_message(context, ret, "PA-PK-AS-REQ %d", (int)ret);
     733           0 :         goto out;
     734             :     }
     735          77 :     if (buf.length != size)
     736           0 :         krb5_abortx(context, "Internal ASN1 encoder error");
     737             : 
     738          77 :     ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length);
     739          77 :     if (ret)
     740           0 :         free(buf.data);
     741             : 
     742          77 :     if (ret == 0)
     743          77 :         ret = krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
     744             : 
     745          77 :  out:
     746          77 :     free_ContentInfo(&content_info);
     747             : 
     748          77 :     return ret;
     749             : }
     750             : 
     751             : 
     752             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     753          77 : _krb5_pk_mk_padata(krb5_context context,
     754             :                    void *c,
     755             :                    int ic_flags,
     756             :                    int win2k,
     757             :                    const KDC_REQ_BODY *req_body,
     758             :                    unsigned nonce,
     759             :                    METHOD_DATA *md)
     760             : {
     761          77 :     krb5_pk_init_ctx ctx = c;
     762             :     int win2k_compat;
     763             : 
     764          77 :     if (ctx->id->certs == NULL && ctx->anonymous == 0) {
     765           0 :         krb5_set_error_message(context, HEIM_PKINIT_NO_PRIVATE_KEY,
     766           0 :                                N_("PKINIT: No user certificate given", ""));
     767           0 :         return HEIM_PKINIT_NO_PRIVATE_KEY;
     768             :     }
     769             : 
     770          77 :     win2k_compat = krb5_config_get_bool_default(context, NULL,
     771             :                                                 win2k,
     772             :                                                 "realms",
     773             :                                                 req_body->realm,
     774             :                                                 "pkinit_win2k",
     775             :                                                 NULL);
     776             : 
     777          77 :     if (win2k_compat) {
     778           0 :         ctx->require_binding =
     779           0 :             krb5_config_get_bool_default(context, NULL,
     780             :                                          TRUE,
     781             :                                          "realms",
     782             :                                          req_body->realm,
     783             :                                          "pkinit_win2k_require_binding",
     784             :                                          NULL);
     785           0 :         ctx->type = PKINIT_WIN2K;
     786             :     } else
     787          77 :         ctx->type = PKINIT_27;
     788             : 
     789          77 :     ctx->require_eku =
     790          77 :         krb5_config_get_bool_default(context, NULL,
     791             :                                      TRUE,
     792             :                                      "realms",
     793             :                                      req_body->realm,
     794             :                                      "pkinit_require_eku",
     795             :                                      NULL);
     796          77 :     if (ic_flags & KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK)
     797           0 :         ctx->require_eku = 0;
     798          77 :     if (ctx->id->flags & (PKINIT_BTMM | PKINIT_NO_KDC_ANCHOR))
     799          77 :         ctx->require_eku = 0;
     800             : 
     801          77 :     ctx->require_krbtgt_otherName =
     802          77 :         krb5_config_get_bool_default(context, NULL,
     803             :                                      TRUE,
     804             :                                      "realms",
     805             :                                      req_body->realm,
     806             :                                      "pkinit_require_krbtgt_otherName",
     807             :                                      NULL);
     808          77 :     if (ic_flags & KRB5_INIT_CREDS_PKINIT_NO_KRBTGT_OTHERNAME_CHECK)
     809           0 :         ctx->require_krbtgt_otherName = FALSE;
     810             : 
     811          77 :     ctx->require_hostname_match =
     812          77 :         krb5_config_get_bool_default(context, NULL,
     813             :                                      FALSE,
     814             :                                      "realms",
     815             :                                      req_body->realm,
     816             :                                      "pkinit_require_hostname_match",
     817             :                                      NULL);
     818             : 
     819          77 :     ctx->trustedCertifiers =
     820          77 :         krb5_config_get_bool_default(context, NULL,
     821             :                                      TRUE,
     822             :                                      "realms",
     823             :                                      req_body->realm,
     824             :                                      "pkinit_trustedCertifiers",
     825             :                                      NULL);
     826             : 
     827          77 :     return pk_mk_padata(context, ctx, req_body, nonce, md);
     828             : }
     829             : 
     830             : static krb5_error_code
     831           0 : pk_verify_sign(krb5_context context,
     832             :                const void *data,
     833             :                size_t length,
     834             :                struct krb5_pk_identity *id,
     835             :                heim_oid *contentType,
     836             :                krb5_data *content,
     837             :                struct krb5_pk_cert **signer)
     838             : {
     839             :     hx509_certs signer_certs;
     840             :     int ret;
     841           0 :     unsigned flags = 0, verify_flags = 0;
     842             : 
     843           0 :     *signer = NULL;
     844             : 
     845           0 :     if (id->flags & PKINIT_BTMM) {
     846           0 :         flags |= HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH;
     847           0 :         flags |= HX509_CMS_VS_NO_KU_CHECK;
     848           0 :         flags |= HX509_CMS_VS_NO_VALIDATE;
     849             :     }
     850           0 :     if (id->flags & PKINIT_NO_KDC_ANCHOR)
     851           0 :         flags |= HX509_CMS_VS_NO_VALIDATE;
     852             : 
     853           0 :     ret = hx509_cms_verify_signed_ext(context->hx509ctx,
     854             :                                       id->verify_ctx,
     855             :                                       flags,
     856             :                                       data,
     857             :                                       length,
     858             :                                       NULL,
     859             :                                       id->certpool,
     860             :                                       contentType,
     861             :                                       content,
     862             :                                       &signer_certs,
     863             :                                       &verify_flags);
     864           0 :     if (ret) {
     865           0 :         pk_copy_error(context, context->hx509ctx, ret,
     866             :                       "CMS verify signed failed");
     867           0 :         return ret;
     868             :     }
     869             : 
     870           0 :     heim_assert((verify_flags & HX509_CMS_VSE_VALIDATED) ||
     871             :         (id->flags & PKINIT_NO_KDC_ANCHOR),
     872             :         "Either PKINIT signer must be validated, or NO_KDC_ANCHOR must be set");
     873             : 
     874           0 :     if ((verify_flags & HX509_CMS_VSE_VALIDATED) == 0)
     875           0 :         goto out;
     876             : 
     877           0 :     *signer = calloc(1, sizeof(**signer));
     878           0 :     if (*signer == NULL) {
     879           0 :         krb5_clear_error_message(context);
     880           0 :         ret = ENOMEM;
     881           0 :         goto out;
     882             :     }
     883             : 
     884           0 :     ret = hx509_get_one_cert(context->hx509ctx, signer_certs, &(*signer)->cert);
     885           0 :     if (ret) {
     886           0 :         pk_copy_error(context, context->hx509ctx, ret,
     887             :                       "Failed to get on of the signer certs");
     888           0 :         goto out;
     889             :     }
     890             : 
     891           0 :  out:
     892           0 :     hx509_certs_free(&signer_certs);
     893           0 :     if (ret) {
     894           0 :         if (*signer) {
     895           0 :             hx509_cert_free((*signer)->cert);
     896           0 :             free(*signer);
     897           0 :             *signer = NULL;
     898             :         }
     899             :     }
     900             : 
     901           0 :     return ret;
     902             : }
     903             : 
     904             : static krb5_error_code
     905           0 : get_reply_key_win(krb5_context context,
     906             :                   const krb5_data *content,
     907             :                   unsigned nonce,
     908             :                   krb5_keyblock **key)
     909             : {
     910             :     ReplyKeyPack_Win2k key_pack;
     911             :     krb5_error_code ret;
     912             :     size_t size;
     913             : 
     914           0 :     ret = decode_ReplyKeyPack_Win2k(content->data,
     915             :                                     content->length,
     916             :                                     &key_pack,
     917             :                                     &size);
     918           0 :     if (ret) {
     919           0 :         krb5_set_error_message(context, ret,
     920           0 :                                N_("PKINIT decoding reply key failed", ""));
     921           0 :         free_ReplyKeyPack_Win2k(&key_pack);
     922           0 :         return ret;
     923             :     }
     924             : 
     925           0 :     if ((unsigned)key_pack.nonce != nonce) {
     926           0 :         krb5_set_error_message(context, ret,
     927           0 :                                N_("PKINIT enckey nonce is wrong", ""));
     928           0 :         free_ReplyKeyPack_Win2k(&key_pack);
     929           0 :         return KRB5KRB_AP_ERR_MODIFIED;
     930             :     }
     931             : 
     932           0 :     *key = malloc (sizeof (**key));
     933           0 :     if (*key == NULL) {
     934           0 :         free_ReplyKeyPack_Win2k(&key_pack);
     935           0 :         return krb5_enomem(context);
     936             :     }
     937             : 
     938           0 :     ret = copy_EncryptionKey(&key_pack.replyKey, *key);
     939           0 :     free_ReplyKeyPack_Win2k(&key_pack);
     940           0 :     if (ret) {
     941           0 :         krb5_set_error_message(context, ret,
     942           0 :                                N_("PKINIT failed copying reply key", ""));
     943           0 :         free(*key);
     944           0 :         *key = NULL;
     945             :     }
     946             : 
     947           0 :     return ret;
     948             : }
     949             : 
     950             : static krb5_error_code
     951           0 : get_reply_key(krb5_context context,
     952             :               const krb5_data *content,
     953             :               const krb5_data *req_buffer,
     954             :               krb5_keyblock **key)
     955             : {
     956             :     ReplyKeyPack key_pack;
     957             :     krb5_error_code ret;
     958             :     size_t size;
     959             : 
     960           0 :     ret = decode_ReplyKeyPack(content->data,
     961             :                               content->length,
     962             :                               &key_pack,
     963             :                               &size);
     964           0 :     if (ret) {
     965           0 :         krb5_set_error_message(context, ret,
     966           0 :                                N_("PKINIT decoding reply key failed", ""));
     967           0 :         free_ReplyKeyPack(&key_pack);
     968           0 :         return ret;
     969             :     }
     970             : 
     971             :     {
     972             :         krb5_crypto crypto;
     973             : 
     974             :         /*
     975             :          * XXX Verify kp.replyKey is a allowed enctype in the
     976             :          * configuration file
     977             :          */
     978             : 
     979           0 :         ret = krb5_crypto_init(context, &key_pack.replyKey, 0, &crypto);
     980           0 :         if (ret) {
     981           0 :             free_ReplyKeyPack(&key_pack);
     982           0 :             return ret;
     983             :         }
     984             : 
     985           0 :         ret = krb5_verify_checksum(context, crypto, 6,
     986             :                                    req_buffer->data, req_buffer->length,
     987             :                                    &key_pack.asChecksum);
     988           0 :         krb5_crypto_destroy(context, crypto);
     989           0 :         if (ret) {
     990           0 :             free_ReplyKeyPack(&key_pack);
     991           0 :             return ret;
     992             :         }
     993             :     }
     994             : 
     995           0 :     *key = malloc (sizeof (**key));
     996           0 :     if (*key == NULL) {
     997           0 :         free_ReplyKeyPack(&key_pack);
     998           0 :         return krb5_enomem(context);
     999             :     }
    1000             : 
    1001           0 :     ret = copy_EncryptionKey(&key_pack.replyKey, *key);
    1002           0 :     free_ReplyKeyPack(&key_pack);
    1003           0 :     if (ret) {
    1004           0 :         krb5_set_error_message(context, ret,
    1005           0 :                                N_("PKINIT failed copying reply key", ""));
    1006           0 :         free(*key);
    1007           0 :         *key = NULL;
    1008             :     }
    1009             : 
    1010           0 :     return ret;
    1011             : }
    1012             : 
    1013             : 
    1014             : static krb5_error_code
    1015           0 : pk_verify_host(krb5_context context,
    1016             :                const char *realm,
    1017             :                const krb5_krbhst_info *hi,
    1018             :                struct krb5_pk_init_ctx_data *ctx,
    1019             :                struct krb5_pk_cert *host)
    1020             : {
    1021           0 :     krb5_error_code ret = 0;
    1022             : 
    1023           0 :     if (ctx->require_eku) {
    1024           0 :         ret = hx509_cert_check_eku(context->hx509ctx, host->cert,
    1025             :                                    &asn1_oid_id_pkkdcekuoid, 0);
    1026           0 :         if (ret) {
    1027           0 :             krb5_set_error_message(context, ret,
    1028           0 :                                    N_("No PK-INIT KDC EKU in kdc certificate", ""));
    1029           0 :             return ret;
    1030             :         }
    1031             :     }
    1032           0 :     if (ctx->require_krbtgt_otherName) {
    1033             :         hx509_octet_string_list list;
    1034             :         size_t i;
    1035           0 :         int matched = 0;
    1036             : 
    1037           0 :         ret = hx509_cert_find_subjectAltName_otherName(context->hx509ctx,
    1038             :                                                        host->cert,
    1039             :                                                        &asn1_oid_id_pkinit_san,
    1040             :                                                        &list);
    1041           0 :         if (ret) {
    1042           0 :             krb5_set_error_message(context, ret,
    1043           0 :                                    N_("Failed to find the PK-INIT "
    1044             :                                       "subjectAltName in the KDC "
    1045             :                                       "certificate", ""));
    1046             : 
    1047           0 :             return ret;
    1048             :         }
    1049             : 
    1050             :         /*
    1051             :          * subjectAltNames are multi-valued, and a single KDC may serve
    1052             :          * multiple realms. The SAN validation here must accept
    1053             :          * the KDC's cert if *any* of the SANs match the expected KDC.
    1054             :          * It is OK for *some* of the SANs to not match, provided at least
    1055             :          * one does.
    1056             :          */
    1057           0 :         for (i = 0; matched == 0 && i < list.len; i++) {
    1058             :             KRB5PrincipalName r;
    1059             : 
    1060           0 :             ret = decode_KRB5PrincipalName(list.val[i].data,
    1061           0 :                                            list.val[i].length,
    1062             :                                            &r,
    1063             :                                            NULL);
    1064           0 :             if (ret) {
    1065           0 :                 krb5_set_error_message(context, ret,
    1066           0 :                                        N_("Failed to decode the PK-INIT "
    1067             :                                           "subjectAltName in the "
    1068             :                                           "KDC certificate", ""));
    1069             : 
    1070           0 :                 break;
    1071             :             }
    1072             : 
    1073           0 :             if (r.principalName.name_string.len == 2 &&
    1074           0 :                 strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) == 0
    1075           0 :                 && strcmp(r.principalName.name_string.val[1], realm) == 0
    1076           0 :                 && strcmp(r.realm, realm) == 0)
    1077           0 :                 matched = 1;
    1078             : 
    1079           0 :             free_KRB5PrincipalName(&r);
    1080             :         }
    1081           0 :         hx509_free_octet_string_list(&list);
    1082             : 
    1083           0 :         if (matched == 0 &&
    1084           0 :             (ctx->id->flags & PKINIT_NO_KDC_ANCHOR) == 0) {
    1085           0 :             ret = KRB5_KDC_ERR_INVALID_CERTIFICATE;
    1086             :             /* XXX: Lost in translation... */
    1087           0 :             krb5_set_error_message(context, ret,
    1088           0 :                                    N_("KDC have wrong realm name in "
    1089             :                                       "the certificate", ""));
    1090             :         }
    1091             :     }
    1092           0 :     if (ret)
    1093           0 :         return ret;
    1094             : 
    1095           0 :     if (hi) {
    1096           0 :         ret = hx509_verify_hostname(context->hx509ctx, host->cert,
    1097           0 :                                     ctx->require_hostname_match,
    1098             :                                     HX509_HN_HOSTNAME,
    1099           0 :                                     hi->hostname,
    1100           0 :                                     hi->ai->ai_addr, hi->ai->ai_addrlen);
    1101             : 
    1102           0 :         if (ret)
    1103           0 :             krb5_set_error_message(context, ret,
    1104           0 :                                    N_("Address mismatch in "
    1105             :                                       "the KDC certificate", ""));
    1106             :     }
    1107           0 :     return ret;
    1108             : }
    1109             : 
    1110             : static krb5_error_code
    1111           0 : pk_rd_pa_reply_enckey(krb5_context context,
    1112             :                       int type,
    1113             :                       const heim_octet_string *indata,
    1114             :                       const heim_oid *dataType,
    1115             :                       const char *realm,
    1116             :                       krb5_pk_init_ctx ctx,
    1117             :                       krb5_enctype etype,
    1118             :                       const krb5_krbhst_info *hi,
    1119             :                       unsigned nonce,
    1120             :                       const krb5_data *req_buffer,
    1121             :                       PA_DATA *pa,
    1122             :                       krb5_keyblock **key)
    1123             : {
    1124             :     krb5_error_code ret;
    1125           0 :     struct krb5_pk_cert *host = NULL;
    1126             :     krb5_data content;
    1127             :     heim_octet_string unwrapped;
    1128           0 :     heim_oid contentType = { 0, NULL };
    1129           0 :     int flags = HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT;
    1130             : 
    1131           0 :     if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_envelopedData, dataType)) {
    1132           0 :         krb5_set_error_message(context, EINVAL,
    1133           0 :                                N_("PKINIT: Invalid content type", ""));
    1134           0 :         return EINVAL;
    1135             :     }
    1136             : 
    1137           0 :     if (ctx->type == PKINIT_WIN2K)
    1138           0 :         flags |= HX509_CMS_UE_ALLOW_WEAK;
    1139             : 
    1140           0 :     ret = hx509_cms_unenvelope(context->hx509ctx,
    1141           0 :                                ctx->id->certs,
    1142             :                                flags,
    1143           0 :                                indata->data,
    1144             :                                indata->length,
    1145             :                                NULL,
    1146             :                                0,
    1147             :                                &contentType,
    1148             :                                &content);
    1149           0 :     if (ret) {
    1150           0 :         pk_copy_error(context, context->hx509ctx, ret,
    1151             :                       "Failed to unenvelope CMS data in PK-INIT reply");
    1152           0 :         return ret;
    1153             :     }
    1154           0 :     der_free_oid(&contentType);
    1155             : 
    1156             :     /* win2k uses ContentInfo */
    1157           0 :     if (type == PKINIT_WIN2K) {
    1158             :         heim_oid type2;
    1159             : 
    1160           0 :         ret = hx509_cms_unwrap_ContentInfo(&content, &type2, &unwrapped, NULL);
    1161           0 :         if (ret) {
    1162             :             /* windows LH with interesting CMS packets */
    1163           0 :             size_t ph = 1 + der_length_len(content.length);
    1164           0 :             unsigned char *ptr = malloc(content.length + ph);
    1165             :             size_t l;
    1166             : 
    1167           0 :             memcpy(ptr + ph, content.data, content.length);
    1168             : 
    1169           0 :             ret = der_put_length_and_tag (ptr + ph - 1, ph, content.length,
    1170             :                                           ASN1_C_UNIV, CONS, UT_Sequence, &l);
    1171           0 :             if (ret) {
    1172           0 :                 free(ptr);
    1173           0 :                 return ret;
    1174             :             }
    1175           0 :             free(content.data);
    1176           0 :             content.data = ptr;
    1177           0 :             content.length += ph;
    1178             : 
    1179           0 :             ret = hx509_cms_unwrap_ContentInfo(&content, &type2, &unwrapped, NULL);
    1180           0 :             if (ret)
    1181           0 :                 goto out;
    1182             :         }
    1183           0 :         if (der_heim_oid_cmp(&type2, &asn1_oid_id_pkcs7_signedData)) {
    1184           0 :             ret = EINVAL; /* XXX */
    1185           0 :             krb5_set_error_message(context, ret,
    1186           0 :                                    N_("PKINIT: Invalid content type", ""));
    1187           0 :             der_free_oid(&type2);
    1188           0 :             der_free_octet_string(&unwrapped);
    1189           0 :             goto out;
    1190             :         }
    1191           0 :         der_free_oid(&type2);
    1192           0 :         krb5_data_free(&content);
    1193           0 :         ret = krb5_data_copy(&content, unwrapped.data, unwrapped.length);
    1194           0 :         der_free_octet_string(&unwrapped);
    1195           0 :         if (ret) {
    1196           0 :             krb5_set_error_message(context, ret,
    1197           0 :                                    N_("malloc: out of memory", ""));
    1198           0 :             goto out;
    1199             :         }
    1200             :     }
    1201             : 
    1202           0 :     ret = pk_verify_sign(context,
    1203           0 :                          content.data,
    1204             :                          content.length,
    1205             :                          ctx->id,
    1206             :                          &contentType,
    1207             :                          &unwrapped,
    1208             :                          &host);
    1209           0 :     if (ret == 0) {
    1210           0 :         krb5_data_free(&content);
    1211           0 :         ret = krb5_data_copy(&content, unwrapped.data, unwrapped.length);
    1212           0 :         der_free_octet_string(&unwrapped);
    1213             :     }
    1214           0 :     if (ret)
    1215           0 :         goto out;
    1216             : 
    1217           0 :     heim_assert(host || (ctx->id->flags & PKINIT_NO_KDC_ANCHOR),
    1218             :                 "KDC signature must be verified unless PKINIT_NO_KDC_ANCHOR set");
    1219             : 
    1220           0 :     if (host) {
    1221             :         /* make sure that it is the kdc's certificate */
    1222           0 :         ret = pk_verify_host(context, realm, hi, ctx, host);
    1223           0 :         if (ret)
    1224           0 :             goto out;
    1225             : 
    1226           0 :         ctx->kdc_verified = 1;
    1227             :     }
    1228             : 
    1229             : #if 0
    1230             :     if (type == PKINIT_WIN2K) {
    1231             :         if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) != 0) {
    1232             :             ret = KRB5KRB_AP_ERR_MSG_TYPE;
    1233             :             krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
    1234             :             goto out;
    1235             :         }
    1236             :     } else {
    1237             :         if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkrkeydata) != 0) {
    1238             :             ret = KRB5KRB_AP_ERR_MSG_TYPE;
    1239             :             krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
    1240             :             goto out;
    1241             :         }
    1242             :     }
    1243             : #endif
    1244             : 
    1245           0 :     switch(type) {
    1246           0 :     case PKINIT_WIN2K:
    1247           0 :         ret = get_reply_key(context, &content, req_buffer, key);
    1248           0 :         if (ret != 0 && ctx->require_binding == 0)
    1249           0 :             ret = get_reply_key_win(context, &content, nonce, key);
    1250           0 :         break;
    1251           0 :     case PKINIT_27:
    1252           0 :         ret = get_reply_key(context, &content, req_buffer, key);
    1253           0 :         break;
    1254             :     }
    1255           0 :     if (ret)
    1256           0 :         goto out;
    1257             : 
    1258             :     /* XXX compare given etype with key->etype */
    1259             : 
    1260           0 :  out:
    1261           0 :     if (host)
    1262           0 :         _krb5_pk_cert_free(host);
    1263           0 :     der_free_oid(&contentType);
    1264           0 :     krb5_data_free(&content);
    1265             : 
    1266           0 :     return ret;
    1267             : }
    1268             : 
    1269             : /*
    1270             :  * RFC 8062 section 7:
    1271             :  *
    1272             :  *  The client then decrypts the KDC contribution key and verifies that
    1273             :  *  the ticket session key in the returned ticket is the combined key of
    1274             :  *  the KDC contribution key and the reply key.
    1275             :  */
    1276             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1277           0 : _krb5_pk_kx_confirm(krb5_context context,
    1278             :                     krb5_pk_init_ctx ctx,
    1279             :                     krb5_keyblock *reply_key,
    1280             :                     krb5_keyblock *session_key,
    1281             :                     PA_DATA *pa_pkinit_kx)
    1282             : {
    1283             :     krb5_error_code ret;
    1284             :     EncryptedData ed;
    1285             :     krb5_keyblock ck, sk_verify;
    1286           0 :     krb5_crypto ck_crypto = NULL;
    1287           0 :     krb5_crypto rk_crypto = NULL;
    1288             :     size_t len;
    1289             :     krb5_data data;
    1290           0 :     krb5_data p1 = { sizeof("PKINIT") - 1, "PKINIT" };
    1291           0 :     krb5_data p2 = { sizeof("KEYEXCHANGE") - 1, "KEYEXCHANGE" };
    1292             : 
    1293           0 :     heim_assert(ctx != NULL, "PKINIT context is non-NULL");
    1294           0 :     heim_assert(reply_key != NULL, "reply key is non-NULL");
    1295           0 :     heim_assert(session_key != NULL, "session key is non-NULL");
    1296             : 
    1297             :     /* PA-PKINIT-KX is optional unless anonymous */
    1298           0 :     if (pa_pkinit_kx == NULL)
    1299           0 :         return ctx->anonymous ? KRB5_KDCREP_MODIFIED : 0;
    1300             : 
    1301           0 :     memset(&ed, 0, sizeof(ed));
    1302           0 :     krb5_keyblock_zero(&ck);
    1303           0 :     krb5_keyblock_zero(&sk_verify);
    1304           0 :     krb5_data_zero(&data);
    1305             : 
    1306           0 :     ret = decode_EncryptedData(pa_pkinit_kx->padata_value.data,
    1307             :                                pa_pkinit_kx->padata_value.length,
    1308             :                                &ed, &len);
    1309           0 :     if (ret)
    1310           0 :         goto out;
    1311             : 
    1312           0 :     if (len != pa_pkinit_kx->padata_value.length) {
    1313           0 :         ret = KRB5_KDCREP_MODIFIED;
    1314           0 :         goto out;
    1315             :     }
    1316             : 
    1317           0 :     ret = krb5_crypto_init(context, reply_key, 0, &rk_crypto);
    1318           0 :     if (ret)
    1319           0 :         goto out;
    1320             : 
    1321           0 :     ret = krb5_decrypt_EncryptedData(context, rk_crypto,
    1322             :                                      KRB5_KU_PA_PKINIT_KX,
    1323             :                                      &ed, &data);
    1324           0 :     if (ret)
    1325           0 :         goto out;
    1326             : 
    1327           0 :     ret = decode_EncryptionKey(data.data, data.length,
    1328             :                                &ck, &len);
    1329           0 :     if (ret)
    1330           0 :         goto out;
    1331             : 
    1332           0 :     ret = krb5_crypto_init(context, &ck, 0, &ck_crypto);
    1333           0 :     if (ret)
    1334           0 :         goto out;
    1335             : 
    1336           0 :     ret = krb5_crypto_fx_cf2(context, ck_crypto, rk_crypto,
    1337           0 :                              &p1, &p2, session_key->keytype,
    1338             :                              &sk_verify);
    1339           0 :     if (ret)
    1340           0 :         goto out;
    1341             : 
    1342           0 :     if (sk_verify.keytype != session_key->keytype ||
    1343           0 :         krb5_data_ct_cmp(&sk_verify.keyvalue, &session_key->keyvalue) != 0) {
    1344           0 :         ret = KRB5_KDCREP_MODIFIED;
    1345           0 :         goto out;
    1346             :     }
    1347             : 
    1348           0 : out:
    1349           0 :     free_EncryptedData(&ed);
    1350           0 :     krb5_free_keyblock_contents(context, &ck);
    1351           0 :     krb5_free_keyblock_contents(context, &sk_verify);
    1352           0 :     if (ck_crypto)
    1353           0 :         krb5_crypto_destroy(context, ck_crypto);
    1354           0 :     if (rk_crypto)
    1355           0 :         krb5_crypto_destroy(context, rk_crypto);
    1356           0 :     krb5_data_free(&data);
    1357             : 
    1358           0 :     return ret;
    1359             : }
    1360             : 
    1361             : static krb5_error_code
    1362           0 : pk_rd_pa_reply_dh(krb5_context context,
    1363             :                   const heim_octet_string *indata,
    1364             :                   const heim_oid *dataType,
    1365             :                   const char *realm,
    1366             :                   krb5_pk_init_ctx ctx,
    1367             :                   krb5_enctype etype,
    1368             :                   const krb5_krbhst_info *hi,
    1369             :                   const DHNonce *c_n,
    1370             :                   const DHNonce *k_n,
    1371             :                   unsigned nonce,
    1372             :                   PA_DATA *pa,
    1373             :                   krb5_keyblock **key)
    1374             : {
    1375             :     const unsigned char *p;
    1376           0 :     unsigned char *dh_gen_key = NULL;
    1377           0 :     struct krb5_pk_cert *host = NULL;
    1378           0 :     BIGNUM *kdc_dh_pubkey = NULL;
    1379             :     KDCDHKeyInfo kdc_dh_info;
    1380           0 :     heim_oid contentType = { 0, NULL };
    1381             :     krb5_data content;
    1382             :     krb5_error_code ret;
    1383           0 :     int dh_gen_keylen = 0;
    1384             :     size_t size;
    1385             : 
    1386           0 :     krb5_data_zero(&content);
    1387           0 :     memset(&kdc_dh_info, 0, sizeof(kdc_dh_info));
    1388             : 
    1389           0 :     if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_signedData, dataType)) {
    1390           0 :         krb5_set_error_message(context, EINVAL,
    1391           0 :                                N_("PKINIT: Invalid content type", ""));
    1392           0 :         return EINVAL;
    1393             :     }
    1394             : 
    1395           0 :     ret = pk_verify_sign(context,
    1396           0 :                          indata->data,
    1397             :                          indata->length,
    1398             :                          ctx->id,
    1399             :                          &contentType,
    1400             :                          &content,
    1401             :                          &host);
    1402           0 :     if (ret)
    1403           0 :         goto out;
    1404             : 
    1405           0 :     heim_assert(host || (ctx->id->flags & PKINIT_NO_KDC_ANCHOR),
    1406             :                 "KDC signature must be verified unless PKINIT_NO_KDC_ANCHOR set");
    1407             : 
    1408           0 :     if (host) {
    1409             :         /* make sure that it is the kdc's certificate */
    1410           0 :         ret = pk_verify_host(context, realm, hi, ctx, host);
    1411           0 :         if (ret)
    1412           0 :             goto out;
    1413             : 
    1414           0 :         ctx->kdc_verified = 1;
    1415             :     }
    1416             : 
    1417           0 :     if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkdhkeydata)) {
    1418           0 :         ret = KRB5KRB_AP_ERR_MSG_TYPE;
    1419           0 :         krb5_set_error_message(context, ret,
    1420           0 :                                N_("pkinit - dh reply contains wrong oid", ""));
    1421           0 :         goto out;
    1422             :     }
    1423             : 
    1424           0 :     ret = decode_KDCDHKeyInfo(content.data,
    1425             :                               content.length,
    1426             :                               &kdc_dh_info,
    1427             :                               &size);
    1428             : 
    1429           0 :     if (ret) {
    1430           0 :         krb5_set_error_message(context, ret,
    1431           0 :                                N_("pkinit - failed to decode "
    1432             :                                   "KDC DH Key Info", ""));
    1433           0 :         goto out;
    1434             :     }
    1435             : 
    1436           0 :     if (kdc_dh_info.nonce != nonce) {
    1437           0 :         ret = KRB5KRB_AP_ERR_MODIFIED;
    1438           0 :         krb5_set_error_message(context, ret,
    1439           0 :                                N_("PKINIT: DH nonce is wrong", ""));
    1440           0 :         goto out;
    1441             :     }
    1442             : 
    1443           0 :     if (kdc_dh_info.dhKeyExpiration) {
    1444           0 :         if (k_n == NULL) {
    1445           0 :             ret = KRB5KRB_ERR_GENERIC;
    1446           0 :             krb5_set_error_message(context, ret,
    1447           0 :                                    N_("pkinit; got key expiration "
    1448             :                                       "without server nonce", ""));
    1449           0 :             goto out;
    1450             :         }
    1451           0 :         if (c_n == NULL) {
    1452           0 :             ret = KRB5KRB_ERR_GENERIC;
    1453           0 :             krb5_set_error_message(context, ret,
    1454           0 :                                    N_("pkinit; got DH reuse but no "
    1455             :                                       "client nonce", ""));
    1456           0 :             goto out;
    1457             :         }
    1458             :     } else {
    1459           0 :         if (k_n) {
    1460           0 :             ret = KRB5KRB_ERR_GENERIC;
    1461           0 :             krb5_set_error_message(context, ret,
    1462           0 :                                    N_("pkinit: got server nonce "
    1463             :                                       "without key expiration", ""));
    1464           0 :             goto out;
    1465             :         }
    1466           0 :         c_n = NULL;
    1467             :     }
    1468             : 
    1469             : 
    1470           0 :     p = kdc_dh_info.subjectPublicKey.data;
    1471           0 :     size = (kdc_dh_info.subjectPublicKey.length + 7) / 8;
    1472             : 
    1473           0 :     if (ctx->keyex == USE_DH) {
    1474             :         DHPublicKey k;
    1475           0 :         ret = decode_DHPublicKey(p, size, &k, NULL);
    1476           0 :         if (ret) {
    1477           0 :             krb5_set_error_message(context, ret,
    1478           0 :                                    N_("pkinit: can't decode "
    1479             :                                       "without key expiration", ""));
    1480           0 :             goto out;
    1481             :         }
    1482             : 
    1483           0 :         kdc_dh_pubkey = integer_to_BN(context, "DHPublicKey", &k);
    1484           0 :         free_DHPublicKey(&k);
    1485           0 :         if (kdc_dh_pubkey == NULL) {
    1486           0 :             ret = ENOMEM;
    1487           0 :             goto out;
    1488             :         }
    1489             : 
    1490             : 
    1491           0 :         size = DH_size(ctx->u.dh);
    1492             : 
    1493           0 :         dh_gen_key = malloc(size);
    1494           0 :         if (dh_gen_key == NULL) {
    1495           0 :             ret = krb5_enomem(context);
    1496           0 :             goto out;
    1497             :         }
    1498             : 
    1499           0 :         dh_gen_keylen = DH_compute_key(dh_gen_key, kdc_dh_pubkey, ctx->u.dh);
    1500           0 :         if (dh_gen_keylen == -1) {
    1501           0 :             ret = KRB5KRB_ERR_GENERIC;
    1502           0 :             dh_gen_keylen = 0;
    1503           0 :             krb5_set_error_message(context, ret,
    1504           0 :                                    N_("PKINIT: Can't compute Diffie-Hellman key", ""));
    1505           0 :             goto out;
    1506             :         }
    1507           0 :         if (dh_gen_keylen < (int)size) {
    1508           0 :             size -= dh_gen_keylen;
    1509           0 :             memmove(dh_gen_key + size, dh_gen_key, dh_gen_keylen);
    1510           0 :             memset(dh_gen_key, 0, size);
    1511             :         }
    1512             : 
    1513             :     } else {
    1514           0 :         ret = _krb5_pk_rd_pa_reply_ecdh_compute_key(context, ctx, p,
    1515             :                                                     size, &dh_gen_key,
    1516             :                                                     &dh_gen_keylen);
    1517           0 :         if (ret)
    1518           0 :           goto out;
    1519             :     }
    1520             : 
    1521           0 :     if (dh_gen_keylen <= 0) {
    1522           0 :         ret = EINVAL;
    1523           0 :         krb5_set_error_message(context, ret,
    1524           0 :                                N_("PKINIT: resulting DH key <= 0", ""));
    1525           0 :         dh_gen_keylen = 0;
    1526           0 :         goto out;
    1527             :     }
    1528             : 
    1529           0 :     *key = malloc (sizeof (**key));
    1530           0 :     if (*key == NULL) {
    1531           0 :         ret = krb5_enomem(context);
    1532           0 :         goto out;
    1533             :     }
    1534             : 
    1535           0 :     ret = _krb5_pk_octetstring2key(context,
    1536             :                                    etype,
    1537             :                                    dh_gen_key, dh_gen_keylen,
    1538             :                                    c_n, k_n,
    1539             :                                    *key);
    1540           0 :     if (ret) {
    1541           0 :         krb5_set_error_message(context, ret,
    1542           0 :                                N_("PKINIT: can't create key from DH key", ""));
    1543           0 :         free(*key);
    1544           0 :         *key = NULL;
    1545           0 :         goto out;
    1546             :     }
    1547             : 
    1548           0 :  out:
    1549           0 :     if (kdc_dh_pubkey)
    1550           0 :         BN_free(kdc_dh_pubkey);
    1551           0 :     if (dh_gen_key) {
    1552           0 :         memset(dh_gen_key, 0, dh_gen_keylen);
    1553           0 :         free(dh_gen_key);
    1554             :     }
    1555           0 :     if (host)
    1556           0 :         _krb5_pk_cert_free(host);
    1557           0 :     if (content.data)
    1558           0 :         krb5_data_free(&content);
    1559           0 :     der_free_oid(&contentType);
    1560           0 :     free_KDCDHKeyInfo(&kdc_dh_info);
    1561             : 
    1562           0 :     return ret;
    1563             : }
    1564             : 
    1565             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1566           0 : _krb5_pk_rd_pa_reply(krb5_context context,
    1567             :                      const char *realm,
    1568             :                      void *c,
    1569             :                      krb5_enctype etype,
    1570             :                      const krb5_krbhst_info *hi,
    1571             :                      unsigned nonce,
    1572             :                      const krb5_data *req_buffer,
    1573             :                      PA_DATA *pa,
    1574             :                      krb5_keyblock **key)
    1575             : {
    1576           0 :     krb5_pk_init_ctx ctx = c;
    1577             :     krb5_error_code ret;
    1578             :     size_t size;
    1579             : 
    1580             :     /* Check for IETF PK-INIT first */
    1581           0 :     if (ctx->type == PKINIT_27) {
    1582             :         PA_PK_AS_REP rep;
    1583             :         heim_octet_string os, data;
    1584             :         heim_oid oid;
    1585             : 
    1586           0 :         if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
    1587           0 :             krb5_set_error_message(context, EINVAL,
    1588           0 :                                    N_("PKINIT: wrong padata recv", ""));
    1589           0 :             return EINVAL;
    1590             :         }
    1591             : 
    1592           0 :         ret = decode_PA_PK_AS_REP(pa->padata_value.data,
    1593             :                                   pa->padata_value.length,
    1594             :                                   &rep,
    1595             :                                   &size);
    1596           0 :         if (ret) {
    1597           0 :             krb5_set_error_message(context, ret,
    1598           0 :                                    N_("Failed to decode pkinit AS rep", ""));
    1599           0 :             return ret;
    1600             :         }
    1601             : 
    1602           0 :         switch (rep.element) {
    1603           0 :         case choice_PA_PK_AS_REP_dhInfo:
    1604           0 :             _krb5_debug(context, 5, "krb5_get_init_creds: using pkinit dh");
    1605           0 :             os = rep.u.dhInfo.dhSignedData;
    1606           0 :             break;
    1607           0 :         case choice_PA_PK_AS_REP_encKeyPack:
    1608           0 :             _krb5_debug(context, 5, "krb5_get_init_creds: using kinit enc reply key");
    1609           0 :             os = rep.u.encKeyPack;
    1610           0 :             break;
    1611           0 :         default: {
    1612             :             PA_PK_AS_REP_BTMM btmm;
    1613           0 :             free_PA_PK_AS_REP(&rep);
    1614           0 :             memset(&rep, 0, sizeof(rep));
    1615             : 
    1616           0 :             _krb5_debug(context, 5, "krb5_get_init_creds: using BTMM kinit enc reply key");
    1617             : 
    1618           0 :             ret = decode_PA_PK_AS_REP_BTMM(pa->padata_value.data,
    1619             :                                            pa->padata_value.length,
    1620             :                                            &btmm,
    1621             :                                            &size);
    1622           0 :             if (ret) {
    1623           0 :                 krb5_set_error_message(context, EINVAL,
    1624           0 :                                        N_("PKINIT: -27 reply "
    1625             :                                           "invalid content type", ""));
    1626           0 :                 return EINVAL;
    1627             :             }
    1628             : 
    1629           0 :             if (btmm.dhSignedData || btmm.encKeyPack == NULL) {
    1630           0 :                 free_PA_PK_AS_REP_BTMM(&btmm);
    1631           0 :                 ret = EINVAL;
    1632           0 :                 krb5_set_error_message(context, ret,
    1633           0 :                                        N_("DH mode not supported for BTMM mode", ""));
    1634           0 :                 return ret;
    1635             :             }
    1636             : 
    1637             :             /*
    1638             :              * Transform to IETF style PK-INIT reply so that free works below
    1639             :              */
    1640             : 
    1641           0 :             rep.element = choice_PA_PK_AS_REP_encKeyPack;
    1642           0 :             rep.u.encKeyPack.data = btmm.encKeyPack->data;
    1643           0 :             rep.u.encKeyPack.length = btmm.encKeyPack->length;
    1644           0 :             btmm.encKeyPack->data = NULL;
    1645           0 :             btmm.encKeyPack->length = 0;
    1646           0 :             free_PA_PK_AS_REP_BTMM(&btmm);
    1647           0 :             os = rep.u.encKeyPack;
    1648             :         }
    1649             :         }
    1650             : 
    1651           0 :         ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL);
    1652           0 :         if (ret) {
    1653           0 :             free_PA_PK_AS_REP(&rep);
    1654           0 :             krb5_set_error_message(context, ret,
    1655           0 :                                    N_("PKINIT: failed to unwrap CI", ""));
    1656           0 :             return ret;
    1657             :         }
    1658             : 
    1659           0 :         switch (rep.element) {
    1660           0 :         case choice_PA_PK_AS_REP_dhInfo:
    1661           0 :             ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi,
    1662           0 :                                     ctx->clientDHNonce,
    1663           0 :                                     rep.u.dhInfo.serverDHNonce,
    1664             :                                     nonce, pa, key);
    1665           0 :             break;
    1666           0 :         case choice_PA_PK_AS_REP_encKeyPack:
    1667           0 :             ret = pk_rd_pa_reply_enckey(context, PKINIT_27, &data, &oid, realm,
    1668             :                                         ctx, etype, hi, nonce, req_buffer, pa, key);
    1669           0 :             break;
    1670           0 :         default:
    1671           0 :             krb5_abortx(context, "pk-init as-rep case not possible to happen");
    1672             :         }
    1673           0 :         der_free_octet_string(&data);
    1674           0 :         der_free_oid(&oid);
    1675           0 :         free_PA_PK_AS_REP(&rep);
    1676             : 
    1677           0 :     } else if (ctx->type == PKINIT_WIN2K) {
    1678             :         PA_PK_AS_REP_Win2k w2krep;
    1679             : 
    1680             :         /* Check for Windows encoding of the AS-REP pa data */
    1681             : 
    1682             : #if 0 /* should this be ? */
    1683             :         if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
    1684             :             krb5_set_error_message(context, EINVAL,
    1685             :                                    "PKINIT: wrong padata recv");
    1686             :             return EINVAL;
    1687             :         }
    1688             : #endif
    1689             : 
    1690           0 :         memset(&w2krep, 0, sizeof(w2krep));
    1691             : 
    1692           0 :         ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data,
    1693             :                                         pa->padata_value.length,
    1694             :                                         &w2krep,
    1695             :                                         &size);
    1696           0 :         if (ret) {
    1697           0 :             krb5_set_error_message(context, ret,
    1698           0 :                                    N_("PKINIT: Failed decoding windows "
    1699             :                                       "pkinit reply %d", ""), (int)ret);
    1700           0 :             return ret;
    1701             :         }
    1702             : 
    1703           0 :         krb5_clear_error_message(context);
    1704             : 
    1705           0 :         switch (w2krep.element) {
    1706           0 :         case choice_PA_PK_AS_REP_Win2k_encKeyPack: {
    1707             :             heim_octet_string data;
    1708             :             heim_oid oid;
    1709             : 
    1710           0 :             ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack,
    1711             :                                                &oid, &data, NULL);
    1712           0 :             free_PA_PK_AS_REP_Win2k(&w2krep);
    1713           0 :             if (ret) {
    1714           0 :                 krb5_set_error_message(context, ret,
    1715           0 :                                        N_("PKINIT: failed to unwrap CI", ""));
    1716           0 :                 return ret;
    1717             :             }
    1718             : 
    1719           0 :             ret = pk_rd_pa_reply_enckey(context, PKINIT_WIN2K, &data, &oid, realm,
    1720             :                                         ctx, etype, hi, nonce, req_buffer, pa, key);
    1721           0 :             der_free_octet_string(&data);
    1722           0 :             der_free_oid(&oid);
    1723             : 
    1724           0 :             break;
    1725             :         }
    1726           0 :         default:
    1727           0 :             free_PA_PK_AS_REP_Win2k(&w2krep);
    1728           0 :             ret = EINVAL;
    1729           0 :             krb5_set_error_message(context, ret,
    1730           0 :                                    N_("PKINIT: win2k reply invalid "
    1731             :                                       "content type", ""));
    1732           0 :             break;
    1733             :         }
    1734             : 
    1735             :     } else {
    1736           0 :         ret = EINVAL;
    1737           0 :         krb5_set_error_message(context, ret,
    1738           0 :                                N_("PKINIT: unknown reply type", ""));
    1739             :     }
    1740             : 
    1741           0 :     return ret;
    1742             : }
    1743             : 
    1744             : struct prompter {
    1745             :     krb5_context context;
    1746             :     krb5_prompter_fct prompter;
    1747             :     void *prompter_data;
    1748             : };
    1749             : 
    1750             : static int
    1751           0 : hx_pass_prompter(void *data, const hx509_prompt *prompter)
    1752             : {
    1753             :     krb5_error_code ret;
    1754             :     krb5_prompt prompt;
    1755             :     krb5_data password_data;
    1756           0 :     struct prompter *p = data;
    1757             : 
    1758           0 :     password_data.data   = prompter->reply.data;
    1759           0 :     password_data.length = prompter->reply.length;
    1760             : 
    1761           0 :     prompt.prompt = prompter->prompt;
    1762           0 :     prompt.hidden = hx509_prompt_hidden(prompter->type);
    1763           0 :     prompt.reply  = &password_data;
    1764             : 
    1765           0 :     switch (prompter->type) {
    1766           0 :     case HX509_PROMPT_TYPE_INFO:
    1767           0 :         prompt.type   = KRB5_PROMPT_TYPE_INFO;
    1768           0 :         break;
    1769           0 :     case HX509_PROMPT_TYPE_PASSWORD:
    1770             :     case HX509_PROMPT_TYPE_QUESTION:
    1771             :     default:
    1772           0 :         prompt.type   = KRB5_PROMPT_TYPE_PASSWORD;
    1773           0 :         break;
    1774             :     }
    1775             : 
    1776           0 :     ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt);
    1777           0 :     if (ret) {
    1778           0 :         memset (prompter->reply.data, 0, prompter->reply.length);
    1779           0 :         return 1;
    1780             :     }
    1781           0 :     return 0;
    1782             : }
    1783             : 
    1784             : static krb5_error_code
    1785           0 : _krb5_pk_set_user_id(krb5_context context,
    1786             :                      krb5_principal principal,
    1787             :                      krb5_pk_init_ctx ctx,
    1788             :                      struct hx509_certs_data *certs)
    1789             : {
    1790           0 :     hx509_certs c = hx509_certs_ref(certs);
    1791           0 :     hx509_query *q = NULL;
    1792             :     int ret;
    1793             : 
    1794           0 :     if (ctx->id->certs)
    1795           0 :         hx509_certs_free(&ctx->id->certs);
    1796           0 :     if (ctx->id->cert) {
    1797           0 :         hx509_cert_free(ctx->id->cert);
    1798           0 :         ctx->id->cert = NULL;
    1799             :     }
    1800             : 
    1801           0 :     ctx->id->certs = c;
    1802           0 :     ctx->anonymous = 0;
    1803             : 
    1804           0 :     ret = hx509_query_alloc(context->hx509ctx, &q);
    1805           0 :     if (ret) {
    1806           0 :         pk_copy_error(context, context->hx509ctx, ret,
    1807             :                       "Allocate query to find signing certificate");
    1808           0 :         return ret;
    1809             :     }
    1810             : 
    1811           0 :     hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
    1812           0 :     hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
    1813             : 
    1814           0 :     if (principal && strncmp("LKDC:SHA1.", krb5_principal_get_realm(context, principal), 9) == 0) {
    1815           0 :         ctx->id->flags |= PKINIT_BTMM;
    1816             :     }
    1817             : 
    1818           0 :     ret = find_cert(context, ctx->id, q, &ctx->id->cert);
    1819           0 :     hx509_query_free(context->hx509ctx, q);
    1820             : 
    1821           0 :     if (ret == 0 && _krb5_have_debug(context, 2)) {
    1822             :         hx509_name name;
    1823             :         char *str, *sn;
    1824             :         heim_integer i;
    1825             : 
    1826           0 :         ret = hx509_cert_get_subject(ctx->id->cert, &name);
    1827           0 :         if (ret)
    1828           0 :             goto out;
    1829             : 
    1830           0 :         ret = hx509_name_to_string(name, &str);
    1831           0 :         hx509_name_free(&name);
    1832           0 :         if (ret)
    1833           0 :             goto out;
    1834             : 
    1835           0 :         ret = hx509_cert_get_serialnumber(ctx->id->cert, &i);
    1836           0 :         if (ret) {
    1837           0 :             free(str);
    1838           0 :             goto out;
    1839             :         }
    1840             : 
    1841           0 :         ret = der_print_hex_heim_integer(&i, &sn);
    1842           0 :         der_free_heim_integer(&i);
    1843           0 :         if (ret) {
    1844           0 :             free(str);
    1845           0 :             goto out;
    1846             :         }
    1847             : 
    1848           0 :         _krb5_debug(context, 2, "using cert: subject: %s sn: %s", str, sn);
    1849           0 :         free(str);
    1850           0 :         free(sn);
    1851             :     }
    1852           0 :  out:
    1853             : 
    1854           0 :     return ret;
    1855             : }
    1856             : 
    1857             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1858         148 : _krb5_pk_load_id(krb5_context context,
    1859             :                  struct krb5_pk_identity **ret_id,
    1860             :                  const char *user_id,
    1861             :                  const char *anchor_id,
    1862             :                  char * const *chain_list,
    1863             :                  char * const *revoke_list,
    1864             :                  krb5_prompter_fct prompter,
    1865             :                  void *prompter_data,
    1866             :                  char *password)
    1867             : {
    1868         148 :     struct krb5_pk_identity *id = NULL;
    1869             :     struct prompter p;
    1870             :     krb5_error_code ret;
    1871             : 
    1872         148 :     *ret_id = NULL;
    1873             : 
    1874             :     /* load cert */
    1875             : 
    1876         148 :     id = calloc(1, sizeof(*id));
    1877         148 :     if (id == NULL)
    1878           0 :         return krb5_enomem(context);
    1879             : 
    1880         148 :     if (user_id) {
    1881             :         hx509_lock lock;
    1882             : 
    1883          71 :         ret = hx509_lock_init(context->hx509ctx, &lock);
    1884          71 :         if (ret) {
    1885           0 :             pk_copy_error(context, context->hx509ctx, ret, "Failed init lock");
    1886           0 :             goto out;
    1887             :         }
    1888             : 
    1889          71 :         if (password && password[0])
    1890           0 :             hx509_lock_add_password(lock, password);
    1891             : 
    1892          71 :         if (prompter) {
    1893           0 :             p.context = context;
    1894           0 :             p.prompter = prompter;
    1895           0 :             p.prompter_data = prompter_data;
    1896             : 
    1897           0 :             ret = hx509_lock_set_prompter(lock, hx_pass_prompter, &p);
    1898           0 :             if (ret) {
    1899           0 :                 hx509_lock_free(lock);
    1900           0 :                 goto out;
    1901             :             }
    1902             :         }
    1903             : 
    1904          71 :         ret = hx509_certs_init(context->hx509ctx, user_id, 0, lock, &id->certs);
    1905          71 :         hx509_lock_free(lock);
    1906          71 :         if (ret) {
    1907          33 :             pk_copy_error(context, context->hx509ctx, ret,
    1908             :                           "Failed to init cert certs");
    1909          33 :             goto out;
    1910             :         }
    1911             :     } else {
    1912          77 :         id->certs = NULL;
    1913             :     }
    1914             : 
    1915         115 :     ret = hx509_certs_init(context->hx509ctx, anchor_id, 0, NULL, &id->anchors);
    1916         115 :     if (ret) {
    1917           0 :         pk_copy_error(context, context->hx509ctx, ret,
    1918             :                       "Failed to init anchors");
    1919           0 :         goto out;
    1920             :     }
    1921             : 
    1922         115 :     ret = hx509_certs_init(context->hx509ctx, "MEMORY:pkinit-cert-chain",
    1923             :                            0, NULL, &id->certpool);
    1924         115 :     if (ret) {
    1925           0 :         pk_copy_error(context, context->hx509ctx, ret,
    1926             :                       "Failed to init chain");
    1927           0 :         goto out;
    1928             :     }
    1929             : 
    1930         230 :     while (chain_list && *chain_list) {
    1931           0 :         ret = hx509_certs_append(context->hx509ctx, id->certpool,
    1932             :                                  NULL, *chain_list);
    1933           0 :         if (ret) {
    1934           0 :             pk_copy_error(context, context->hx509ctx, ret,
    1935             :                           "Failed to load chain %s",
    1936             :                           *chain_list);
    1937           0 :             goto out;
    1938             :         }
    1939           0 :         chain_list++;
    1940             :     }
    1941             : 
    1942         115 :     if (revoke_list) {
    1943           0 :         ret = hx509_revoke_init(context->hx509ctx, &id->revokectx);
    1944           0 :         if (ret) {
    1945           0 :             pk_copy_error(context, context->hx509ctx, ret,
    1946             :                           "Failed init revoke list");
    1947           0 :             goto out;
    1948             :         }
    1949             : 
    1950           0 :         while (*revoke_list) {
    1951           0 :             ret = hx509_revoke_add_crl(context->hx509ctx,
    1952             :                                        id->revokectx,
    1953             :                                        *revoke_list);
    1954           0 :             if (ret) {
    1955           0 :                 pk_copy_error(context, context->hx509ctx, ret,
    1956             :                               "Failed load revoke list");
    1957           0 :                 goto out;
    1958             :             }
    1959           0 :             revoke_list++;
    1960             :         }
    1961             :     } else
    1962         115 :         hx509_context_set_missing_revoke(context->hx509ctx, 1);
    1963             : 
    1964         115 :     ret = hx509_verify_init_ctx(context->hx509ctx, &id->verify_ctx);
    1965         115 :     if (ret) {
    1966           0 :         pk_copy_error(context, context->hx509ctx, ret,
    1967             :                       "Failed init verify context");
    1968           0 :         goto out;
    1969             :     }
    1970             : 
    1971         115 :     hx509_verify_attach_anchors(id->verify_ctx, id->anchors);
    1972         115 :     hx509_verify_attach_revoke(id->verify_ctx, id->revokectx);
    1973             : 
    1974         148 :  out:
    1975         148 :     if (ret) {
    1976          33 :         hx509_verify_destroy_ctx(id->verify_ctx);
    1977          33 :         hx509_certs_free(&id->certs);
    1978          33 :         hx509_certs_free(&id->anchors);
    1979          33 :         hx509_certs_free(&id->certpool);
    1980          33 :         hx509_revoke_free(&id->revokectx);
    1981          33 :         free(id);
    1982             :     } else
    1983         115 :         *ret_id = id;
    1984             : 
    1985         148 :     return ret;
    1986             : }
    1987             : 
    1988             : /*
    1989             :  *
    1990             :  */
    1991             : 
    1992             : static void
    1993          33 : pk_copy_error(krb5_context context,
    1994             :               hx509_context hx509ctx,
    1995             :               int hxret,
    1996             :               const char *fmt,
    1997             :               ...)
    1998             : {
    1999             :     va_list va;
    2000             :     char *s, *f;
    2001             :     int ret;
    2002             : 
    2003          33 :     va_start(va, fmt);
    2004          33 :     ret = vasprintf(&f, fmt, va);
    2005          33 :     va_end(va);
    2006          33 :     if (ret == -1 || f == NULL) {
    2007           0 :         krb5_clear_error_message(context);
    2008           0 :         return;
    2009             :     }
    2010             : 
    2011          33 :     s = hx509_get_error_string(hx509ctx, hxret);
    2012          33 :     if (s == NULL) {
    2013           0 :         krb5_clear_error_message(context);
    2014           0 :         free(f);
    2015           0 :         return;
    2016             :     }
    2017          33 :     krb5_set_error_message(context, hxret, "%s: %s", f, s);
    2018          33 :     free(s);
    2019          33 :     free(f);
    2020             : }
    2021             : 
    2022             : static int
    2023         888 : parse_integer(krb5_context context, char **p, const char *file, int lineno,
    2024             :               const char *name, heim_integer *integer)
    2025             : {
    2026             :     int ret;
    2027             :     char *p1;
    2028         888 :     p1 = strsep(p, " \t");
    2029         888 :     if (p1 == NULL) {
    2030           0 :         krb5_set_error_message(context, EINVAL,
    2031           0 :                                N_("moduli file %s missing %s on line %d", ""),
    2032             :                                file, name, lineno);
    2033           0 :         return EINVAL;
    2034             :     }
    2035         888 :     ret = der_parse_hex_heim_integer(p1, integer);
    2036         888 :     if (ret) {
    2037           0 :         krb5_set_error_message(context, ret,
    2038           0 :                                N_("moduli file %s failed parsing %s "
    2039             :                                   "on line %d", ""),
    2040             :                                file, name, lineno);
    2041           0 :         return ret;
    2042             :     }
    2043             : 
    2044         888 :     return 0;
    2045             : }
    2046             : 
    2047             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2048         296 : _krb5_parse_moduli_line(krb5_context context,
    2049             :                         const char *file,
    2050             :                         int lineno,
    2051             :                         char *p,
    2052             :                         struct krb5_dh_moduli **m)
    2053             : {
    2054             :     struct krb5_dh_moduli *m1;
    2055             :     char *p1;
    2056             :     int ret;
    2057             : 
    2058         296 :     *m = NULL;
    2059             : 
    2060         296 :     m1 = calloc(1, sizeof(*m1));
    2061         296 :     if (m1 == NULL)
    2062           0 :         return krb5_enomem(context);
    2063             : 
    2064         592 :     while (isspace((unsigned char)*p))
    2065           0 :         p++;
    2066         296 :     if (*p  == '#') {
    2067           0 :         free(m1);
    2068           0 :         return 0;
    2069             :     }
    2070         296 :     ret = EINVAL;
    2071             : 
    2072         296 :     p1 = strsep(&p, " \t");
    2073         296 :     if (p1 == NULL) {
    2074           0 :         krb5_set_error_message(context, ret,
    2075           0 :                                N_("moduli file %s missing name on line %d", ""),
    2076             :                                file, lineno);
    2077           0 :         goto out;
    2078             :     }
    2079         296 :     m1->name = strdup(p1);
    2080         296 :     if (m1->name == NULL) {
    2081           0 :         ret = krb5_enomem(context);
    2082           0 :         goto out;
    2083             :     }
    2084             : 
    2085         296 :     p1 = strsep(&p, " \t");
    2086         296 :     if (p1 == NULL) {
    2087           0 :         krb5_set_error_message(context, ret,
    2088           0 :                                N_("moduli file %s missing bits on line %d", ""),
    2089             :                                file, lineno);
    2090           0 :         goto out;
    2091             :     }
    2092             : 
    2093         296 :     m1->bits = atoi(p1);
    2094         296 :     if (m1->bits == 0) {
    2095           0 :         krb5_set_error_message(context, ret,
    2096           0 :                                N_("moduli file %s have un-parsable "
    2097             :                                   "bits on line %d", ""), file, lineno);
    2098           0 :         goto out;
    2099             :     }
    2100             : 
    2101         296 :     ret = parse_integer(context, &p, file, lineno, "p", &m1->p);
    2102         296 :     if (ret)
    2103           0 :         goto out;
    2104         296 :     ret = parse_integer(context, &p, file, lineno, "g", &m1->g);
    2105         296 :     if (ret)
    2106           0 :         goto out;
    2107         296 :     ret = parse_integer(context, &p, file, lineno, "q", &m1->q);
    2108         296 :     if (ret) {
    2109           0 :         m1->q.negative = 0;
    2110           0 :         m1->q.length = 0;
    2111           0 :         m1->q.data = 0;
    2112           0 :         krb5_clear_error_message(context);
    2113             :     }
    2114             : 
    2115         296 :     *m = m1;
    2116             : 
    2117         296 :     return 0;
    2118           0 :  out:
    2119           0 :     free(m1->name);
    2120           0 :     der_free_heim_integer(&m1->p);
    2121           0 :     der_free_heim_integer(&m1->g);
    2122           0 :     der_free_heim_integer(&m1->q);
    2123           0 :     free(m1);
    2124           0 :     return ret;
    2125             : }
    2126             : 
    2127             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    2128          77 : _krb5_free_moduli(struct krb5_dh_moduli **moduli)
    2129             : {
    2130             :     int i;
    2131         231 :     for (i = 0; moduli[i] != NULL; i++) {
    2132         154 :         free(moduli[i]->name);
    2133         154 :         der_free_heim_integer(&moduli[i]->p);
    2134         154 :         der_free_heim_integer(&moduli[i]->g);
    2135         154 :         der_free_heim_integer(&moduli[i]->q);
    2136         154 :         free(moduli[i]);
    2137             :     }
    2138          77 :     free(moduli);
    2139          77 : }
    2140             : 
    2141             : static const char *default_moduli_RFC2412_MODP_group2 =
    2142             :     /* name */
    2143             :     "RFC2412-MODP-group2 "
    2144             :     /* bits */
    2145             :     "1024 "
    2146             :     /* p */
    2147             :     "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
    2148             :     "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
    2149             :     "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
    2150             :     "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
    2151             :     "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
    2152             :     "FFFFFFFF" "FFFFFFFF "
    2153             :     /* g */
    2154             :     "02 "
    2155             :     /* q */
    2156             :     "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
    2157             :     "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
    2158             :     "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
    2159             :     "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
    2160             :     "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
    2161             :     "FFFFFFFF" "FFFFFFFF";
    2162             : 
    2163             : static const char *default_moduli_rfc3526_MODP_group14 =
    2164             :     /* name */
    2165             :     "rfc3526-MODP-group14 "
    2166             :     /* bits */
    2167             :     "1760 "
    2168             :     /* p */
    2169             :     "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
    2170             :     "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
    2171             :     "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
    2172             :     "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
    2173             :     "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
    2174             :     "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
    2175             :     "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
    2176             :     "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
    2177             :     "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
    2178             :     "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
    2179             :     "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
    2180             :     /* g */
    2181             :     "02 "
    2182             :     /* q */
    2183             :     "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
    2184             :     "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
    2185             :     "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
    2186             :     "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
    2187             :     "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
    2188             :     "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
    2189             :     "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
    2190             :     "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
    2191             :     "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
    2192             :     "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
    2193             :     "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
    2194             : 
    2195             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2196         148 : _krb5_parse_moduli(krb5_context context, const char *file,
    2197             :                    struct krb5_dh_moduli ***moduli)
    2198             : {
    2199             :     /* name bits P G Q */
    2200             :     krb5_error_code ret;
    2201         148 :     struct krb5_dh_moduli **m = NULL, **m2;
    2202             :     char buf[4096];
    2203             :     FILE *f;
    2204         148 :     int lineno = 0, n = 0;
    2205             : 
    2206         148 :     *moduli = NULL;
    2207             : 
    2208         148 :     m = calloc(1, sizeof(m[0]) * 3);
    2209         148 :     if (m == NULL)
    2210           0 :         return krb5_enomem(context);
    2211             : 
    2212         148 :     strlcpy(buf, default_moduli_rfc3526_MODP_group14, sizeof(buf));
    2213         148 :     ret = _krb5_parse_moduli_line(context, "builtin", 1, buf,  &m[0]);
    2214         148 :     if (ret) {
    2215           0 :         _krb5_free_moduli(m);
    2216           0 :         return ret;
    2217             :     }
    2218         148 :     n++;
    2219             : 
    2220         148 :     strlcpy(buf, default_moduli_RFC2412_MODP_group2, sizeof(buf));
    2221         148 :     ret = _krb5_parse_moduli_line(context, "builtin", 1, buf,  &m[1]);
    2222         148 :     if (ret) {
    2223           0 :         _krb5_free_moduli(m);
    2224           0 :         return ret;
    2225             :     }
    2226         148 :     n++;
    2227             : 
    2228             : 
    2229         148 :     if (file == NULL)
    2230         148 :         file = MODULI_FILE;
    2231             : 
    2232             :     {
    2233             :         char *exp_file;
    2234             : 
    2235         148 :         if (_krb5_expand_path_tokens(context, file, 1, &exp_file) == 0) {
    2236         148 :             f = fopen(exp_file, "r");
    2237         148 :             krb5_xfree(exp_file);
    2238             :         } else {
    2239           0 :             f = NULL;
    2240             :         }
    2241             :     }
    2242             : 
    2243         148 :     if (f == NULL) {
    2244         148 :         *moduli = m;
    2245         148 :         return 0;
    2246             :     }
    2247           0 :     rk_cloexec_file(f);
    2248             : 
    2249           0 :     while(fgets(buf, sizeof(buf), f) != NULL) {
    2250             :         struct krb5_dh_moduli *element;
    2251             : 
    2252           0 :         buf[strcspn(buf, "\n")] = '\0';
    2253           0 :         lineno++;
    2254             : 
    2255           0 :         m2 = realloc(m, (n + 2) * sizeof(m[0]));
    2256           0 :         if (m2 == NULL) {
    2257           0 :             _krb5_free_moduli(m);
    2258           0 :             return krb5_enomem(context);
    2259             :         }
    2260           0 :         m = m2;
    2261             : 
    2262           0 :         m[n] = NULL;
    2263             : 
    2264           0 :         ret = _krb5_parse_moduli_line(context, file, lineno, buf,  &element);
    2265           0 :         if (ret) {
    2266           0 :             _krb5_free_moduli(m);
    2267           0 :             return ret;
    2268             :         }
    2269           0 :         if (element == NULL)
    2270           0 :             continue;
    2271             : 
    2272           0 :         m[n] = element;
    2273           0 :         m[n + 1] = NULL;
    2274           0 :         n++;
    2275             :     }
    2276           0 :     *moduli = m;
    2277           0 :     return 0;
    2278             : }
    2279             : 
    2280             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2281           0 : _krb5_dh_group_ok(krb5_context context, unsigned long bits,
    2282             :                   heim_integer *p, heim_integer *g, heim_integer *q,
    2283             :                   struct krb5_dh_moduli **moduli,
    2284             :                   char **name)
    2285             : {
    2286             :     int i;
    2287             : 
    2288           0 :     if (name)
    2289           0 :         *name = NULL;
    2290             : 
    2291           0 :     for (i = 0; moduli[i] != NULL; i++) {
    2292           0 :         if (der_heim_integer_cmp(&moduli[i]->g, g) == 0 &&
    2293           0 :             der_heim_integer_cmp(&moduli[i]->p, p) == 0 &&
    2294           0 :             (q == NULL || moduli[i]->q.length == 0 ||
    2295           0 :              der_heim_integer_cmp(&moduli[i]->q, q) == 0))
    2296             :             {
    2297           0 :                 if (bits && bits > moduli[i]->bits) {
    2298           0 :                     krb5_set_error_message(context,
    2299             :                                            KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
    2300           0 :                                            N_("PKINIT: DH group parameter %s "
    2301             :                                               "no accepted, not enough bits "
    2302             :                                               "generated", ""),
    2303           0 :                                            moduli[i]->name);
    2304           0 :                     return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
    2305             :                 }
    2306           0 :                 if (name)
    2307           0 :                     *name = strdup(moduli[i]->name);
    2308           0 :                 return 0;
    2309             :             }
    2310             :     }
    2311           0 :     krb5_set_error_message(context,
    2312             :                            KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
    2313           0 :                            N_("PKINIT: DH group parameter no ok", ""));
    2314           0 :     return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
    2315             : }
    2316             : #endif /* PKINIT */
    2317             : 
    2318             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    2319        9858 : _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt)
    2320             : {
    2321             : #ifdef PKINIT
    2322             :     krb5_pk_init_ctx ctx;
    2323             : 
    2324        9858 :     if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL)
    2325        9781 :         return;
    2326          77 :     ctx = opt->opt_private->pk_init_ctx;
    2327          77 :     switch (ctx->keyex) {
    2328          77 :     case USE_DH:
    2329          77 :         if (ctx->u.dh)
    2330          77 :             DH_free(ctx->u.dh);
    2331          77 :         break;
    2332           0 :     case USE_RSA:
    2333           0 :         break;
    2334           0 :     case USE_ECDH:
    2335           0 :         if (ctx->u.eckey)
    2336           0 :             _krb5_pk_eckey_free(ctx->u.eckey);
    2337           0 :         break;
    2338             :     }
    2339          77 :     if (ctx->id) {
    2340          77 :         hx509_verify_destroy_ctx(ctx->id->verify_ctx);
    2341          77 :         hx509_certs_free(&ctx->id->certs);
    2342          77 :         hx509_cert_free(ctx->id->cert);
    2343          77 :         hx509_certs_free(&ctx->id->anchors);
    2344          77 :         hx509_certs_free(&ctx->id->certpool);
    2345             : 
    2346          77 :         if (ctx->clientDHNonce) {
    2347          77 :             krb5_free_data(NULL, ctx->clientDHNonce);
    2348          77 :             ctx->clientDHNonce = NULL;
    2349             :         }
    2350          77 :         if (ctx->m)
    2351          77 :             _krb5_free_moduli(ctx->m);
    2352          77 :         free(ctx->id);
    2353          77 :         ctx->id = NULL;
    2354             :     }
    2355          77 :     free(opt->opt_private->pk_init_ctx);
    2356          77 :     opt->opt_private->pk_init_ctx = NULL;
    2357             : #endif
    2358             : }
    2359             : 
    2360             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2361          77 : krb5_get_init_creds_opt_set_pkinit(krb5_context context,
    2362             :                                    krb5_get_init_creds_opt *opt,
    2363             :                                    krb5_principal principal,
    2364             :                                    const char *user_id,
    2365             :                                    const char *x509_anchors,
    2366             :                                    char * const * pool,
    2367             :                                    char * const * pki_revoke,
    2368             :                                    int flags,
    2369             :                                    krb5_prompter_fct prompter,
    2370             :                                    void *prompter_data,
    2371             :                                    char *password)
    2372             : {
    2373             : #ifdef PKINIT
    2374             :     krb5_error_code ret;
    2375          77 :     char **freeme1 = NULL;
    2376          77 :     char **freeme2 = NULL;
    2377          77 :     char *anchors = NULL;
    2378             : 
    2379          77 :     if (opt->opt_private == NULL) {
    2380           0 :         krb5_set_error_message(context, EINVAL,
    2381           0 :                                N_("PKINIT: on non extendable opt", ""));
    2382           0 :         return EINVAL;
    2383             :     }
    2384             : 
    2385         154 :     opt->opt_private->pk_init_ctx =
    2386          77 :         calloc(1, sizeof(*opt->opt_private->pk_init_ctx));
    2387          77 :     if (opt->opt_private->pk_init_ctx == NULL)
    2388           0 :         return krb5_enomem(context);
    2389          77 :     opt->opt_private->pk_init_ctx->require_binding = 0;
    2390          77 :     opt->opt_private->pk_init_ctx->require_eku = 1;
    2391          77 :     opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1;
    2392          77 :     opt->opt_private->pk_init_ctx->peer = NULL;
    2393             : 
    2394             :     /* XXX implement krb5_appdefault_strings  */
    2395          77 :     if (pool == NULL)
    2396          77 :         pool = freeme1 = krb5_config_get_strings(context, NULL, "appdefaults",
    2397             :                                                  "pkinit_pool", NULL);
    2398             : 
    2399          77 :     if (pki_revoke == NULL)
    2400          77 :         pki_revoke = freeme2 = krb5_config_get_strings(context, NULL,
    2401             :                                                        "appdefaults",
    2402             :                                                        "pkinit_revoke", NULL);
    2403             : 
    2404          77 :     if (x509_anchors == NULL) {
    2405          77 :         krb5_appdefault_string(context, "kinit",
    2406             :                                krb5_principal_get_realm(context, principal),
    2407             :                                "pkinit_anchors", NULL, &anchors);
    2408          77 :         x509_anchors = anchors;
    2409             :     }
    2410             : 
    2411          77 :     if (flags & KRB5_GIC_OPT_PKINIT_ANONYMOUS)
    2412          77 :         opt->opt_private->pk_init_ctx->anonymous = 1;
    2413             : 
    2414          77 :     if ((flags & KRB5_GIC_OPT_PKINIT_NO_KDC_ANCHOR) == 0 &&
    2415             :         x509_anchors == NULL) {
    2416           0 :         krb5_set_error_message(context, HEIM_PKINIT_NO_VALID_CA,
    2417           0 :                                N_("PKINIT: No anchor given", ""));
    2418           0 :         return HEIM_PKINIT_NO_VALID_CA;
    2419             :     }
    2420             : 
    2421          77 :     ret = _krb5_pk_load_id(context,
    2422          77 :                            &opt->opt_private->pk_init_ctx->id,
    2423             :                            user_id,
    2424             :                            x509_anchors,
    2425             :                            pool,
    2426             :                            pki_revoke,
    2427             :                            prompter,
    2428             :                            prompter_data,
    2429             :                            password);
    2430          77 :     krb5_config_free_strings(freeme2);
    2431          77 :     krb5_config_free_strings(freeme1);
    2432          77 :     free(anchors);
    2433          77 :     if (ret) {
    2434           0 :         free(opt->opt_private->pk_init_ctx);
    2435           0 :         opt->opt_private->pk_init_ctx = NULL;
    2436           0 :         return ret;
    2437             :     }
    2438          77 :     if (flags & KRB5_GIC_OPT_PKINIT_BTMM)
    2439           0 :         opt->opt_private->pk_init_ctx->id->flags |= PKINIT_BTMM;
    2440          77 :     if (principal && krb5_principal_is_lkdc(context, principal))
    2441           0 :         opt->opt_private->pk_init_ctx->id->flags |= PKINIT_BTMM;
    2442          77 :     if (flags & KRB5_GIC_OPT_PKINIT_NO_KDC_ANCHOR)
    2443          77 :         opt->opt_private->pk_init_ctx->id->flags |= PKINIT_NO_KDC_ANCHOR;
    2444             : 
    2445          77 :     if (opt->opt_private->pk_init_ctx->id->certs) {
    2446           0 :         ret = _krb5_pk_set_user_id(context,
    2447             :                                    principal,
    2448           0 :                                    opt->opt_private->pk_init_ctx,
    2449           0 :                                    opt->opt_private->pk_init_ctx->id->certs);
    2450           0 :         if (ret) {
    2451           0 :             free(opt->opt_private->pk_init_ctx);
    2452           0 :             opt->opt_private->pk_init_ctx = NULL;
    2453           0 :             return ret;
    2454             :         }
    2455             :     } else
    2456          77 :         opt->opt_private->pk_init_ctx->id->cert = NULL;
    2457             : 
    2458          77 :     if ((flags & KRB5_GIC_OPT_PKINIT_USE_ENCKEY) == 0) {
    2459          77 :         hx509_context hx509ctx = context->hx509ctx;
    2460          77 :         hx509_cert cert = opt->opt_private->pk_init_ctx->id->cert;
    2461             : 
    2462          77 :         opt->opt_private->pk_init_ctx->keyex = USE_DH;
    2463             : 
    2464             :         /*
    2465             :          * If its a ECDSA certs, lets select ECDSA as the keyex algorithm.
    2466             :          */
    2467          77 :         if (cert) {
    2468             :             AlgorithmIdentifier alg;
    2469             : 
    2470           0 :             ret = hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx, cert, &alg);
    2471           0 :             if (ret == 0) {
    2472           0 :                 if (der_heim_oid_cmp(&alg.algorithm, &asn1_oid_id_ecPublicKey) == 0)
    2473           0 :                     opt->opt_private->pk_init_ctx->keyex = USE_ECDH;
    2474           0 :                 free_AlgorithmIdentifier(&alg);
    2475             :             }
    2476             :         }
    2477             : 
    2478             :     } else {
    2479           0 :         opt->opt_private->pk_init_ctx->keyex = USE_RSA;
    2480             : 
    2481           0 :         if (opt->opt_private->pk_init_ctx->id->certs == NULL) {
    2482           0 :             krb5_set_error_message(context, EINVAL,
    2483           0 :                                    N_("No anonymous pkinit support in RSA mode", ""));
    2484           0 :             return EINVAL;
    2485             :         }
    2486             :     }
    2487             : 
    2488          77 :     return 0;
    2489             : #else
    2490             :     krb5_set_error_message(context, EINVAL,
    2491             :                            N_("no support for PKINIT compiled in", ""));
    2492             :     return EINVAL;
    2493             : #endif
    2494             : }
    2495             : 
    2496             : krb5_error_code KRB5_LIB_FUNCTION
    2497           0 : krb5_get_init_creds_opt_set_pkinit_user_certs(krb5_context context,
    2498             :                                               krb5_get_init_creds_opt *opt,
    2499             :                                               struct hx509_certs_data *certs)
    2500             : {
    2501             : #ifdef PKINIT
    2502           0 :     if (opt->opt_private == NULL) {
    2503           0 :         krb5_set_error_message(context, EINVAL,
    2504           0 :                                N_("PKINIT: on non extendable opt", ""));
    2505           0 :         return EINVAL;
    2506             :     }
    2507           0 :     if (opt->opt_private->pk_init_ctx == NULL) {
    2508           0 :         krb5_set_error_message(context, EINVAL,
    2509           0 :                                N_("PKINIT: on pkinit context", ""));
    2510           0 :         return EINVAL;
    2511             :     }
    2512             : 
    2513           0 :     return _krb5_pk_set_user_id(context, NULL, opt->opt_private->pk_init_ctx, certs);
    2514             : #else
    2515             :     krb5_set_error_message(context, EINVAL,
    2516             :                            N_("no support for PKINIT compiled in", ""));
    2517             :     return EINVAL;
    2518             : #endif
    2519             : }
    2520             : 
    2521             : #ifdef PKINIT
    2522             : 
    2523             : static int
    2524           0 : get_ms_san(hx509_context context, hx509_cert cert, char **upn)
    2525             : {
    2526             :     hx509_octet_string_list list;
    2527             :     int ret;
    2528             : 
    2529           0 :     *upn = NULL;
    2530             : 
    2531           0 :     ret = hx509_cert_find_subjectAltName_otherName(context,
    2532             :                                                    cert,
    2533             :                                                    &asn1_oid_id_pkinit_ms_san,
    2534             :                                                    &list);
    2535           0 :     if (ret)
    2536           0 :         return 0;
    2537             : 
    2538           0 :     if (list.len > 0 && list.val[0].length > 0)
    2539           0 :         ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length,
    2540             :                                 upn, NULL);
    2541             :     else
    2542           0 :         ret = 1;
    2543           0 :     hx509_free_octet_string_list(&list);
    2544             : 
    2545           0 :     return ret;
    2546             : }
    2547             : 
    2548             : static int
    2549           0 : find_ms_san(hx509_context context, hx509_cert cert, void *ctx)
    2550             : {
    2551             :     char *upn;
    2552             :     int ret;
    2553             : 
    2554           0 :     ret = get_ms_san(context, cert, &upn);
    2555           0 :     if (ret == 0)
    2556           0 :         free(upn);
    2557           0 :     return ret;
    2558             : }
    2559             : 
    2560             : 
    2561             : 
    2562             : #endif
    2563             : 
    2564             : /*
    2565             :  * Private since it need to be redesigned using krb5_get_init_creds()
    2566             :  */
    2567             : 
    2568             : KRB5_LIB_FUNCTION krb5_error_code  KRB5_LIB_CALL
    2569           0 : krb5_pk_enterprise_cert(krb5_context context,
    2570             :                         const char *user_id,
    2571             :                         krb5_const_realm realm,
    2572             :                         krb5_principal *principal,
    2573             :                         struct hx509_certs_data **res)
    2574             : {
    2575             : #ifdef PKINIT
    2576             :     krb5_error_code ret;
    2577             :     hx509_certs certs, result;
    2578           0 :     hx509_cert cert = NULL;
    2579             :     hx509_query *q;
    2580             :     char *name;
    2581             : 
    2582           0 :     *principal = NULL;
    2583           0 :     if (res)
    2584           0 :         *res = NULL;
    2585             : 
    2586           0 :     if (user_id == NULL) {
    2587           0 :         krb5_set_error_message(context, ENOENT, "no user id");
    2588           0 :         return ENOENT;
    2589             :     }
    2590             : 
    2591           0 :     ret = hx509_certs_init(context->hx509ctx, user_id, 0, NULL, &certs);
    2592           0 :     if (ret) {
    2593           0 :         pk_copy_error(context, context->hx509ctx, ret,
    2594             :                       "Failed to init cert certs");
    2595           0 :         goto out;
    2596             :     }
    2597             : 
    2598           0 :     ret = hx509_query_alloc(context->hx509ctx, &q);
    2599           0 :     if (ret) {
    2600           0 :         krb5_set_error_message(context, ret, "out of memory");
    2601           0 :         hx509_certs_free(&certs);
    2602           0 :         goto out;
    2603             :     }
    2604             : 
    2605           0 :     hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
    2606           0 :     hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
    2607           0 :     hx509_query_match_eku(q, &asn1_oid_id_pkinit_ms_eku);
    2608           0 :     hx509_query_match_cmp_func(q, find_ms_san, NULL);
    2609             : 
    2610           0 :     ret = hx509_certs_filter(context->hx509ctx, certs, q, &result);
    2611           0 :     hx509_query_free(context->hx509ctx, q);
    2612           0 :     hx509_certs_free(&certs);
    2613           0 :     if (ret) {
    2614           0 :         pk_copy_error(context, context->hx509ctx, ret,
    2615             :                       "Failed to find PKINIT certificate");
    2616           0 :         return ret;
    2617             :     }
    2618             : 
    2619           0 :     ret = hx509_get_one_cert(context->hx509ctx, result, &cert);
    2620           0 :     hx509_certs_free(&result);
    2621           0 :     if (ret) {
    2622           0 :         pk_copy_error(context, context->hx509ctx, ret,
    2623             :                       "Failed to get one cert");
    2624           0 :         goto out;
    2625             :     }
    2626             : 
    2627           0 :     ret = get_ms_san(context->hx509ctx, cert, &name);
    2628           0 :     if (ret) {
    2629           0 :         pk_copy_error(context, context->hx509ctx, ret,
    2630             :                       "Failed to get MS SAN");
    2631           0 :         goto out;
    2632             :     }
    2633             : 
    2634           0 :     ret = krb5_make_principal(context, principal, realm, name, NULL);
    2635           0 :     free(name);
    2636           0 :     if (ret)
    2637           0 :         goto out;
    2638             : 
    2639           0 :     krb5_principal_set_type(context, *principal, KRB5_NT_ENTERPRISE_PRINCIPAL);
    2640             : 
    2641           0 :     if (res) {
    2642           0 :         ret = hx509_certs_init(context->hx509ctx, "MEMORY:", 0, NULL, res);
    2643           0 :         if (ret)
    2644           0 :             goto out;
    2645             : 
    2646           0 :         ret = hx509_certs_add(context->hx509ctx, *res, cert);
    2647           0 :         if (ret) {
    2648           0 :             hx509_certs_free(res);
    2649           0 :             goto out;
    2650             :         }
    2651             :     }
    2652             : 
    2653           0 :  out:
    2654           0 :     hx509_cert_free(cert);
    2655             : 
    2656           0 :     return ret;
    2657             : #else
    2658             :     krb5_set_error_message(context, EINVAL,
    2659             :                            N_("no support for PKINIT compiled in", ""));
    2660             :     return EINVAL;
    2661             : #endif
    2662             : }
    2663             : 
    2664             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
    2665           0 : _krb5_pk_is_kdc_verified(krb5_context context,
    2666             :                          krb5_get_init_creds_opt *opt)
    2667             : {
    2668           0 :     if (opt == NULL ||
    2669           0 :         opt->opt_private == NULL ||
    2670           0 :         opt->opt_private->pk_init_ctx == NULL)
    2671           0 :         return FALSE;
    2672             : 
    2673           0 :     return opt->opt_private->pk_init_ctx->kdc_verified;
    2674             : }

Generated by: LCOV version 1.13