LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - pkinit.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 633 1448 43.7 %
Date: 2023-11-21 12:31:41 Functions: 28 37 75.7 %

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

Generated by: LCOV version 1.14