LCOV - code coverage report
Current view: top level - third_party/heimdal/kdc - pkinit.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 37 1011 3.7 %
Date: 2024-06-13 04:01:37 Functions: 2 20 10.0 %

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

Generated by: LCOV version 1.13