LCOV - code coverage report
Current view: top level - source4/heimdal/lib/krb5 - pkinit.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 593 1249 47.5 %
Date: 2021-09-23 10:06:22 Functions: 30 38 78.9 %

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

Generated by: LCOV version 1.13