LCOV - code coverage report
Current view: top level - third_party/heimdal/kdc - pkinit.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 636 1218 52.2 %
Date: 2024-04-21 15:09:00 Functions: 21 22 95.5 %

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

Generated by: LCOV version 1.14