LCOV - code coverage report
Current view: top level - third_party/heimdal/kdc - fast.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 295 512 57.6 %
Date: 2024-01-11 09:59:51 Functions: 9 13 69.2 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997-2011 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Portions Copyright (c) 2010 - 2011 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             : static krb5_error_code
      39           0 : salt_fastuser_crypto(astgs_request_t r,
      40             :                      krb5_const_principal salt_principal,
      41             :                      krb5_enctype enctype,
      42             :                      krb5_crypto fast_crypto,
      43             :                      krb5_crypto *salted_crypto)
      44             : {
      45           0 :     krb5_error_code ret;
      46           0 :     krb5_principal client_princ = NULL;
      47           0 :     krb5_data salt;
      48           0 :     krb5_keyblock dkey;
      49           0 :     size_t size;
      50             : 
      51           0 :     *salted_crypto = NULL;
      52             : 
      53           0 :     krb5_data_zero(&salt);
      54           0 :     krb5_keyblock_zero(&dkey);
      55             : 
      56           0 :     if (salt_principal == NULL) {
      57           0 :         if (r->req.req_body.cname == NULL) {
      58           0 :             ret = KRB5KRB_ERR_GENERIC;
      59           0 :             goto out;
      60             :         }
      61             : 
      62           0 :         ret = _krb5_principalname2krb5_principal(r->context, &client_princ,
      63           0 :                                                  *(r->req.req_body.cname),
      64             :                                                  r->req.req_body.realm);
      65           0 :         if (ret)
      66           0 :             goto out;
      67             : 
      68           0 :         salt_principal = client_princ;
      69             :     }
      70             : 
      71           0 :     ret = krb5_unparse_name(r->context, salt_principal, (char **)&salt.data);
      72           0 :     if (ret)
      73           0 :         goto out;
      74             : 
      75           0 :     salt.length = strlen(salt.data);
      76             : 
      77           0 :     kdc_log(r->context, r->config, 10,
      78             :             "salt_fastuser_crypto: salt principal is %s (%d)",
      79           0 :             (char *)salt.data, enctype);
      80             : 
      81           0 :     ret = krb5_enctype_keysize(r->context, enctype, &size);
      82           0 :     if (ret)
      83           0 :         goto out;
      84             : 
      85           0 :     ret = krb5_crypto_prfplus(r->context, fast_crypto, &salt,
      86             :                               size, &dkey.keyvalue);
      87           0 :     if (ret)
      88           0 :         goto out;
      89             : 
      90           0 :     dkey.keytype = enctype;
      91             : 
      92           0 :     ret = krb5_crypto_init(r->context, &dkey, ENCTYPE_NULL, salted_crypto);
      93           0 :     if (ret)
      94           0 :         goto out;
      95             : 
      96           0 : out:
      97           0 :     krb5_free_keyblock_contents(r->context, &dkey);
      98           0 :     krb5_data_free(&salt);
      99           0 :     krb5_free_principal(r->context, client_princ);
     100             : 
     101           0 :     return ret;
     102             : }
     103             : 
     104             : static krb5_error_code
     105           0 : get_fastuser_crypto(astgs_request_t r,
     106             :                     krb5_const_principal ticket_client,
     107             :                     krb5_enctype enctype,
     108             :                     krb5_crypto *crypto)
     109             : {
     110           0 :     krb5_principal fast_princ;
     111           0 :     HDB *fast_db;
     112           0 :     hdb_entry *fast_user = NULL;
     113           0 :     Key *cookie_key = NULL;
     114           0 :     krb5_crypto fast_crypto = NULL;
     115           0 :     krb5_error_code ret;
     116             : 
     117           0 :     *crypto = NULL;
     118             : 
     119           0 :     ret = krb5_make_principal(r->context, &fast_princ,
     120             :                               KRB5_WELLKNOWN_ORG_H5L_REALM,
     121             :                               KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL);
     122           0 :     if (ret)
     123           0 :         goto out;
     124             : 
     125           0 :     ret = _kdc_db_fetch(r->context, r->config, fast_princ,
     126             :                         HDB_F_GET_FAST_COOKIE, NULL, &fast_db, &fast_user);
     127           0 :     if (ret)
     128           0 :         goto out;
     129             : 
     130           0 :     if (enctype == KRB5_ENCTYPE_NULL)
     131           0 :         ret = _kdc_get_preferred_key(r->context, r->config, fast_user,
     132             :                                      "fast-cookie", &enctype, &cookie_key);
     133             :     else
     134           0 :         ret = hdb_enctype2key(r->context, fast_user, NULL,
     135             :                               enctype, &cookie_key);
     136           0 :     if (ret)
     137           0 :         goto out;
     138             : 
     139           0 :     ret = krb5_crypto_init(r->context, &cookie_key->key,
     140             :                            ENCTYPE_NULL, &fast_crypto);
     141           0 :     if (ret)
     142           0 :         goto out;
     143             : 
     144           0 :     ret = salt_fastuser_crypto(r, ticket_client,
     145           0 :                                cookie_key->key.keytype,
     146             :                                fast_crypto, crypto);
     147           0 :     if (ret)
     148           0 :         goto out;
     149             : 
     150           0 :  out:
     151           0 :     if (fast_user)
     152           0 :         _kdc_free_ent(r->context, fast_db, fast_user);
     153           0 :     if (fast_crypto)
     154           0 :         krb5_crypto_destroy(r->context, fast_crypto);
     155           0 :     krb5_free_principal(r->context, fast_princ);
     156             : 
     157           0 :     return ret;
     158             : }
     159             : 
     160             : 
     161             : static krb5_error_code
     162           0 : fast_parse_cookie(astgs_request_t r,
     163             :                   krb5_const_principal ticket_client,
     164             :                   const PA_DATA *pa)
     165             : {
     166           0 :     krb5_crypto crypto = NULL;
     167           0 :     krb5_error_code ret;
     168           0 :     KDCFastCookie data;
     169           0 :     krb5_data d1;
     170           0 :     size_t len;
     171             : 
     172           0 :     ret = decode_KDCFastCookie(pa->padata_value.data,
     173           0 :                                pa->padata_value.length,
     174             :                                &data, &len);
     175           0 :     if (ret)
     176           0 :         return ret;
     177             : 
     178           0 :     if (len != pa->padata_value.length || strcmp("H5L1", data.version) != 0) {
     179           0 :         free_KDCFastCookie(&data);
     180           0 :         return KRB5KDC_ERR_POLICY;
     181             :     }
     182             : 
     183           0 :     ret = get_fastuser_crypto(r, ticket_client, data.cookie.etype, &crypto);
     184           0 :     if (ret)
     185           0 :         goto out;
     186             : 
     187           0 :     ret = krb5_decrypt_EncryptedData(r->context, crypto,
     188             :                                      KRB5_KU_H5L_COOKIE,
     189             :                                      &data.cookie, &d1);
     190           0 :     krb5_crypto_destroy(r->context, crypto);
     191           0 :     if (ret)
     192           0 :         goto out;
     193             : 
     194           0 :     ret = decode_KDCFastState(d1.data, d1.length, &r->fast, &len);
     195           0 :     krb5_data_free(&d1);
     196           0 :     if (ret)
     197           0 :         goto out;
     198             : 
     199           0 :     if (r->fast.expiration < kdc_time) {
     200           0 :         kdc_log(r->context, r->config, 2, "FAST cookie expired");
     201           0 :         ret = KRB5KDC_ERR_POLICY;
     202           0 :         goto out;
     203             :     }
     204             : 
     205           0 :  out:
     206           0 :     free_KDCFastCookie(&data);
     207             : 
     208           0 :     return ret;
     209             : }
     210             : 
     211             : static krb5_error_code
     212           0 : fast_add_cookie(astgs_request_t r,
     213             :                 krb5_const_principal ticket_client,
     214             :                 METHOD_DATA *method_data)
     215             : {
     216           0 :     krb5_crypto crypto = NULL;
     217           0 :     KDCFastCookie shell;
     218           0 :     krb5_error_code ret;
     219           0 :     krb5_data data;
     220           0 :     size_t size;
     221             : 
     222           0 :     memset(&shell, 0, sizeof(shell));
     223             : 
     224           0 :     r->fast.expiration = kdc_time + FAST_EXPIRATION_TIME;
     225             : 
     226           0 :     ASN1_MALLOC_ENCODE(KDCFastState, data.data, data.length,
     227             :                        &r->fast, &size, ret);
     228           0 :     if (ret)
     229           0 :         return ret;
     230           0 :     heim_assert(size == data.length, "internal asn.1 encoder error");
     231             : 
     232           0 :     ret = get_fastuser_crypto(r, ticket_client, KRB5_ENCTYPE_NULL, &crypto);
     233           0 :     if (ret) {
     234           0 :         kdc_log(r->context, r->config, 0,
     235             :                 "Failed to find FAST principal for cookie encryption: %d", ret);
     236           0 :         goto out;
     237             :     }
     238             : 
     239           0 :     ret = krb5_encrypt_EncryptedData(r->context, crypto,
     240             :                                      KRB5_KU_H5L_COOKIE,
     241             :                                      data.data, data.length, 0,
     242             :                                      &shell.cookie);
     243           0 :     krb5_crypto_destroy(r->context, crypto);
     244           0 :     if (ret)
     245           0 :         goto out;
     246             : 
     247           0 :     krb5_data_free(&data);
     248             : 
     249           0 :     shell.version = "H5L1";
     250             : 
     251           0 :     ASN1_MALLOC_ENCODE(KDCFastCookie, data.data, data.length,
     252             :                        &shell, &size, ret);
     253           0 :     free_EncryptedData(&shell.cookie);
     254           0 :     if (ret)
     255           0 :         goto out;
     256           0 :     heim_assert(size == data.length, "internal asn.1 encoder error");
     257             : 
     258           0 :     ret = krb5_padata_add(r->context, method_data,
     259             :                           KRB5_PADATA_FX_COOKIE,
     260             :                           data.data, data.length);
     261           0 :     if (ret == 0)
     262           0 :         krb5_data_zero(&data);
     263             : 
     264           0 :  out:
     265           0 :     krb5_data_free(&data);
     266           0 :     return ret;
     267             : }
     268             : 
     269             : static krb5_error_code
     270        1425 : fast_add_dummy_cookie(astgs_request_t r,
     271             :                       METHOD_DATA *method_data)
     272             : {
     273           0 :     krb5_error_code ret;
     274           0 :     krb5_data data;
     275        1425 :     const krb5_data *dummy_fast_cookie = &r->config->dummy_fast_cookie;
     276             : 
     277        1425 :     if (dummy_fast_cookie->data == NULL)
     278           0 :         return 0;
     279             : 
     280        1425 :     ret = krb5_data_copy(&data,
     281        1425 :                          dummy_fast_cookie->data,
     282        1425 :                          dummy_fast_cookie->length);
     283        1425 :     if (ret)
     284           0 :         return ret;
     285             : 
     286        1425 :     ret = krb5_padata_add(r->context, method_data,
     287             :                           KRB5_PADATA_FX_COOKIE,
     288             :                           data.data, data.length);
     289        1425 :     if (ret) {
     290           0 :         krb5_data_free(&data);
     291             :     }
     292             : 
     293        1425 :     return ret;
     294             : }
     295             : 
     296             : krb5_error_code
     297       43427 : _kdc_fast_mk_response(krb5_context context,
     298             :                       krb5_crypto armor_crypto,
     299             :                       METHOD_DATA *pa_data,
     300             :                       krb5_keyblock *strengthen_key,
     301             :                       KrbFastFinished *finished,
     302             :                       krb5uint32 nonce,
     303             :                       krb5_data *data)
     304             : {
     305        1658 :     PA_FX_FAST_REPLY fxfastrep;
     306        1658 :     KrbFastResponse fastrep;
     307        1658 :     krb5_error_code ret;
     308        1658 :     krb5_data buf;
     309        1658 :     size_t size;
     310             : 
     311       43427 :     memset(&fxfastrep, 0, sizeof(fxfastrep));
     312       43427 :     memset(&fastrep, 0, sizeof(fastrep));
     313       43427 :     krb5_data_zero(data);
     314             : 
     315       43427 :     if (pa_data) {
     316       43427 :         fastrep.padata.val = pa_data->val;
     317       43427 :         fastrep.padata.len = pa_data->len;
     318             :     }
     319       43427 :     fastrep.strengthen_key = strengthen_key;
     320       43427 :     fastrep.finished = finished;
     321       43427 :     fastrep.nonce = nonce;
     322             : 
     323       43427 :     ASN1_MALLOC_ENCODE(KrbFastResponse, buf.data, buf.length,
     324             :                        &fastrep, &size, ret);
     325       43427 :     if (ret)
     326           0 :         return ret;
     327       43427 :     heim_assert(size == buf.length, "internal asn.1 encoder error");
     328             : 
     329       43427 :     fxfastrep.element = choice_PA_FX_FAST_REPLY_armored_data;
     330             : 
     331       43427 :     ret = krb5_encrypt_EncryptedData(context,
     332             :                                      armor_crypto,
     333             :                                      KRB5_KU_FAST_REP,
     334             :                                      buf.data,
     335             :                                      buf.length,
     336             :                                      0,
     337             :                                      &fxfastrep.u.armored_data.enc_fast_rep);
     338       43427 :     krb5_data_free(&buf);
     339       43427 :     if (ret)
     340           0 :         return ret;
     341             : 
     342       43427 :     ASN1_MALLOC_ENCODE(PA_FX_FAST_REPLY, data->data, data->length,
     343             :                        &fxfastrep, &size, ret);
     344       43427 :     free_PA_FX_FAST_REPLY(&fxfastrep);
     345       43427 :     if (ret)
     346           0 :         return ret;
     347       43427 :     heim_assert(size == data->length, "internal asn.1 encoder error");
     348             : 
     349       41769 :     return 0;
     350             : }
     351             : 
     352             : 
     353             : static krb5_error_code
     354       33365 : _kdc_fast_mk_e_data(astgs_request_t r,
     355             :                    METHOD_DATA *error_method,
     356             :                    krb5_crypto armor_crypto,
     357             :                    const KDC_REQ_BODY *req_body,
     358             :                    krb5_error_code outer_error,
     359             :                    krb5_principal error_client,
     360             :                    krb5_principal error_server,
     361             :                    time_t *csec, int *cusec,
     362             :                    krb5_data *e_data)
     363             : {
     364       33365 :     krb5_error_code ret = 0;
     365        1170 :     size_t size;
     366             : 
     367             :     /*
     368             :      * FX-COOKIE can be used outside of FAST, e.g. SRP or GSS.
     369             :      */
     370       33365 :     if (armor_crypto || r->fast.fast_state.len) {
     371        1425 :         if (r->config->enable_fast_cookie) {
     372           0 :             kdc_log(r->context, r->config, 5, "Adding FAST cookie for KRB-ERROR");
     373           0 :             ret = fast_add_cookie(r, error_client, error_method);
     374           0 :             if (ret) {
     375           0 :                 kdc_log(r->context, r->config, 1,
     376             :                         "Failed to add FAST cookie: %d", ret);
     377           0 :                 free_METHOD_DATA(error_method);
     378           0 :                 return ret;
     379             :             }
     380             :         } else {
     381        1425 :             kdc_log(r->context, r->config, 5, "Adding dummy FAST cookie for KRB-ERROR");
     382        1425 :             ret = fast_add_dummy_cookie(r, error_method);
     383        1425 :             if (ret) {
     384           0 :                 kdc_log(r->context, r->config, 1,
     385             :                         "Failed to add dummy FAST cookie: %d", ret);
     386           0 :                 free_METHOD_DATA(error_method);
     387           0 :                 return ret;
     388             :             }
     389             :         }
     390             :     }
     391             : 
     392       33365 :     if (armor_crypto) {
     393           0 :         PA_FX_FAST_REPLY fxfastrep;
     394           0 :         KrbFastResponse fastrep;
     395             : 
     396        1425 :         memset(&fxfastrep, 0, sizeof(fxfastrep));
     397        1425 :         memset(&fastrep, 0, sizeof(fastrep));
     398             : 
     399        1425 :         kdc_log(r->context, r->config, 5, "Making FAST inner KRB-ERROR");
     400             : 
     401             :         /* first add the KRB-ERROR to the fast errors */
     402             : 
     403        1425 :         ret = krb5_mk_error(r->context,
     404             :                             outer_error,
     405             :                             r->e_text,
     406             :                             NULL,
     407             :                             error_client,
     408             :                             error_server,
     409             :                             csec,
     410             :                             cusec,
     411             :                             e_data);
     412        1425 :         if (ret) {
     413           0 :             kdc_log(r->context, r->config, 1,
     414             :                     "Failed to make inner KRB-ERROR: %d", ret);
     415           0 :             return ret;
     416             :         }
     417             : 
     418        1425 :         ret = krb5_padata_add(r->context, error_method,
     419             :                               KRB5_PADATA_FX_ERROR,
     420             :                               e_data->data, e_data->length);
     421        1425 :         if (ret) {
     422           0 :             kdc_log(r->context, r->config, 1,
     423             :                     "Failed to make add FAST PADATA to inner KRB-ERROR: %d", ret);
     424           0 :             krb5_data_free(e_data);
     425           0 :             return ret;
     426             :         }
     427             : 
     428        1425 :         r->e_text = NULL;
     429             : 
     430        1425 :         ret = _kdc_fast_mk_response(r->context, armor_crypto,
     431             :                                     error_method, NULL, NULL,
     432        1425 :                                     req_body->nonce, e_data);
     433        1425 :         free_METHOD_DATA(error_method);
     434        1425 :         if (ret) {
     435           0 :             kdc_log(r->context, r->config, 1,
     436             :                     "Failed to make outer KRB-ERROR: %d", ret);
     437           0 :             return ret;
     438             :         }
     439             : 
     440        1425 :         ret = krb5_padata_add(r->context, error_method,
     441             :                               KRB5_PADATA_FX_FAST,
     442             :                               e_data->data, e_data->length);
     443        1425 :         if (ret) {
     444           0 :             kdc_log(r->context, r->config, 1,
     445             :                     "Failed to make add FAST PADATA to outer KRB-ERROR: %d", ret);
     446           0 :             return ret;
     447             :         }
     448             :     } else
     449       31940 :         kdc_log(r->context, r->config, 5, "Making non-FAST KRB-ERROR");
     450             : 
     451       33365 :     if (error_method && error_method->len) {
     452       31388 :         ASN1_MALLOC_ENCODE(METHOD_DATA, e_data->data, e_data->length,
     453             :                            error_method, &size, ret);
     454       31388 :         if (ret) {
     455           0 :             kdc_log(r->context, r->config, 1,
     456             :                     "Failed to make encode METHOD-DATA: %d", ret);
     457           0 :             return ret;
     458             :         }
     459       31388 :         heim_assert(size == e_data->length, "internal asn.1 encoder error");
     460             :     }
     461             : 
     462       32195 :     return ret;
     463             : }
     464             : 
     465             : 
     466             : krb5_error_code
     467       33472 : _kdc_fast_mk_error(astgs_request_t r,
     468             :                    METHOD_DATA *error_method,
     469             :                    krb5_crypto armor_crypto,
     470             :                    const KDC_REQ_BODY *req_body,
     471             :                    krb5_error_code outer_error,
     472             :                    krb5_principal error_client,
     473             :                    krb5_principal error_server,
     474             :                    time_t *csec, int *cusec,
     475             :                    krb5_data *error_msg)
     476             : {
     477        1170 :     krb5_error_code ret;
     478        1170 :     krb5_data _e_data;
     479       33472 :     krb5_data *e_data = NULL;
     480             : 
     481       33472 :     krb5_data_zero(&_e_data);
     482             : 
     483       33472 :     heim_assert(r != NULL, "invalid request in _kdc_fast_mk_error");
     484             : 
     485       33472 :     if (r->e_data.length) {
     486         107 :         e_data = &r->e_data;
     487             :     } else {
     488       33365 :         ret = _kdc_fast_mk_e_data(r,
     489             :                                   error_method,
     490             :                                   armor_crypto,
     491             :                                   req_body,
     492             :                                   outer_error,
     493             :                                   error_client,
     494             :                                   error_server,
     495             :                                   csec, cusec,
     496             :                                   &_e_data);
     497       33365 :         if (ret) {
     498           0 :             kdc_log(r->context, r->config, 1,
     499             :                     "Failed to make FAST e-data: %d", ret);
     500           0 :             return ret;
     501             :         }
     502             : 
     503       32195 :         e_data = &_e_data;
     504             :     }
     505             : 
     506       33472 :     if (armor_crypto) {
     507        1487 :         if (r->fast.flags.requested_hidden_names) {
     508        1095 :             error_client = NULL;
     509        1095 :             error_server = NULL;
     510             :         }
     511        1487 :         csec = NULL;
     512        1487 :         cusec = NULL;
     513             :     }
     514             : 
     515       33472 :     ret = krb5_mk_error(r->context,
     516             :                         outer_error,
     517             :                         r->e_text,
     518       33472 :                         (e_data->length ? e_data : NULL),
     519             :                         error_client,
     520             :                         error_server,
     521             :                         csec,
     522             :                         cusec,
     523             :                         error_msg);
     524       33472 :     krb5_data_free(&_e_data);
     525             : 
     526       33472 :     if (ret)
     527           0 :         kdc_log(r->context, r->config, 1,
     528             :                 "Failed to make encode KRB-ERROR: %d", ret);
     529             : 
     530       32302 :     return ret;
     531             : }
     532             : 
     533             : static krb5_error_code
     534       95074 : fast_unwrap_request(astgs_request_t r,
     535             :                     krb5_ticket *tgs_ticket,
     536             :                     krb5_auth_context tgs_ac)
     537             : {
     538       95074 :     krb5_principal armor_server_principal = NULL;
     539       95074 :     char *armor_client_principal_name = NULL;
     540       95074 :     char *armor_server_principal_name = NULL;
     541        3413 :     PA_FX_FAST_REQUEST fxreq;
     542       95074 :     krb5_auth_context ac = NULL;
     543       95074 :     krb5_ticket *ticket = NULL;
     544        3413 :     krb5_flags ap_req_options;
     545        3413 :     krb5_keyblock armorkey;
     546        3413 :     krb5_keyblock explicit_armorkey;
     547        3413 :     krb5_error_code ret;
     548        3413 :     krb5_ap_req ap_req;
     549        3413 :     KrbFastReq fastreq;
     550        3413 :     const PA_DATA *pa;
     551        3413 :     krb5_data data;
     552        3413 :     size_t len;
     553       95074 :     int i = 0;
     554             : 
     555       95074 :     memset(&fxreq, 0, sizeof(fxreq));
     556       95074 :     memset(&fastreq, 0, sizeof(fastreq));
     557             : 
     558       95074 :     pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST);
     559       95074 :     if (pa == NULL) {
     560       51532 :         if (tgs_ac && r->fast_asserted) {
     561           1 :             kdc_log(r->context, r->config, 1,
     562             :                     "Client asserted FAST but did not include FX-FAST pa-data");
     563           1 :             ret = KRB5KRB_AP_ERR_MODIFIED;
     564           1 :             goto out;
     565             :         }
     566             : 
     567       51531 :         kdc_log(r->context, r->config, 10, "Not a FAST request");
     568       51531 :         return 0;
     569             :     }
     570             : 
     571       45200 :     ret = decode_PA_FX_FAST_REQUEST(pa->padata_value.data,
     572       43542 :                                     pa->padata_value.length,
     573             :                                     &fxreq,
     574             :                                     &len);
     575       43542 :     if (ret) {
     576           0 :         kdc_log(r->context, r->config, 4,
     577             :                 "Failed to decode PA-FX-FAST-REQUEST: %d", ret);
     578           0 :         goto out;
     579             :     }
     580             : 
     581       43542 :     if (fxreq.element != choice_PA_FX_FAST_REQUEST_armored_data) {
     582           1 :         kdc_log(r->context, r->config, 4,
     583             :                 "PA-FX-FAST-REQUEST contains unknown type: %d",
     584           1 :                 (int)fxreq.element);
     585           1 :         ret = KRB5KDC_ERR_PREAUTH_FAILED;
     586           1 :         goto out;
     587             :     }
     588             : 
     589             :     /*
     590             :      * If check for armor data or it's not a TGS-REQ with implicit
     591             :      * armor.
     592             :      */
     593       43541 :     if (fxreq.u.armored_data.armor == NULL && tgs_ac == NULL) {
     594           1 :         kdc_log(r->context, r->config, 4,
     595             :                 "AS-REQ armor missing");
     596           1 :         ret = KRB5KDC_ERR_PREAUTH_FAILED;
     597           1 :         goto out;
     598             :     }
     599             : 
     600       43540 :     r->explicit_armor_present = fxreq.u.armored_data.armor != NULL && tgs_ac != NULL;
     601             : 
     602             :     /*
     603             :      *
     604             :      */
     605       43540 :     if (fxreq.u.armored_data.armor != NULL) {
     606           0 :         krb5uint32 kvno;
     607         795 :         krb5uint32 *kvno_ptr = NULL;
     608             : 
     609         795 :         if (fxreq.u.armored_data.armor->armor_type != 1) {
     610           2 :             kdc_log(r->context, r->config, 4,
     611             :                     "Incorrect AS-REQ armor type");
     612           2 :             ret = KRB5KDC_ERR_PREAUTH_FAILED;
     613           8 :             goto out;
     614             :         }
     615             : 
     616         793 :         ret = krb5_decode_ap_req(r->context,
     617         793 :                                  &fxreq.u.armored_data.armor->armor_value,
     618             :                                  &ap_req);
     619         793 :         if(ret) {
     620           0 :             kdc_log(r->context, r->config, 4, "Failed to decode AP-REQ");
     621           0 :             goto out;
     622             :         }
     623             : 
     624             :         /* Save that principal that was in the request */
     625         793 :         ret = _krb5_principalname2krb5_principal(r->context,
     626             :                                                  &armor_server_principal,
     627             :                                                  ap_req.ticket.sname,
     628             :                                                  ap_req.ticket.realm);
     629         793 :         if (ret) {
     630           0 :             free_AP_REQ(&ap_req);
     631           0 :             goto out;
     632             :         }
     633             : 
     634         793 :         if (ap_req.ticket.enc_part.kvno != NULL) {
     635         793 :             kvno = *ap_req.ticket.enc_part.kvno;
     636         793 :             kvno_ptr = &kvno;
     637             :         }
     638             : 
     639         793 :         ret = _kdc_db_fetch(r->context, r->config, armor_server_principal,
     640             :                             HDB_F_GET_KRBTGT | HDB_F_DELAY_NEW_KEYS,
     641             :                             kvno_ptr,
     642             :                             &r->armor_serverdb, &r->armor_server);
     643         793 :         if(ret == HDB_ERR_NOT_FOUND_HERE) {
     644           0 :             free_AP_REQ(&ap_req);
     645           0 :             kdc_log(r->context, r->config, 5,
     646             :                     "Armor key does not have secrets at this KDC, "
     647             :                     "need to proxy");
     648           0 :             goto out;
     649         793 :         } else if (ret) {
     650           4 :             free_AP_REQ(&ap_req);
     651           4 :             ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
     652           4 :             goto out;
     653             :         }
     654             : 
     655         789 :         ret = hdb_enctype2key(r->context, r->armor_server, NULL,
     656             :                               ap_req.ticket.enc_part.etype,
     657             :                               &r->armor_key);
     658         789 :         if (ret) {
     659           1 :             free_AP_REQ(&ap_req);
     660           1 :             goto out;
     661             :         }
     662             : 
     663         788 :         ret = krb5_verify_ap_req2(r->context, &ac,
     664             :                                   &ap_req,
     665             :                                   armor_server_principal,
     666         788 :                                   &r->armor_key->key,
     667             :                                   0,
     668             :                                   &ap_req_options,
     669             :                                   &r->armor_ticket,
     670             :                                   KRB5_KU_AP_REQ_AUTH);
     671         788 :         free_AP_REQ(&ap_req);
     672         788 :         if (ret)
     673           1 :             goto out;
     674             : 
     675         787 :         ret = krb5_unparse_name(r->context, armor_server_principal,
     676             :                                 &armor_server_principal_name);
     677         787 :         if (ret)
     678           0 :             goto out;
     679             : 
     680             :         /* FIXME krb5_verify_ap_req2() also checks this */
     681         787 :         ret = _kdc_verify_flags(r->context, r->config,
     682         787 :                                 &r->armor_ticket->ticket,
     683             :                                 armor_server_principal_name);
     684         787 :         if (ret) {
     685           0 :             kdc_audit_addreason((kdc_request_t)r,
     686             :                                 "Armor TGT expired or invalid");
     687           0 :             goto out;
     688             :         }
     689         787 :         ticket = r->armor_ticket;
     690             :     } else {
     691       42745 :         heim_assert(tgs_ticket != NULL, "TGS authentication context without ticket");
     692       42745 :         ac = tgs_ac;
     693       42745 :         ticket = tgs_ticket;
     694             :     }
     695             : 
     696       43532 :     (void) krb5_unparse_name(r->context, ticket->client, &armor_client_principal_name);
     697       43532 :     kdc_audit_addkv((kdc_request_t)r, 0, "armor_client_name", "%s",
     698       43532 :                     armor_client_principal_name ?
     699             :                         armor_client_principal_name :
     700             :                         "<out of memory>");
     701             : 
     702       43532 :     if (ac->remote_subkey == NULL) {
     703           1 :         krb5_auth_con_free(r->context, ac);
     704           1 :         kdc_log(r->context, r->config, 2,
     705             :                 "FAST AP-REQ remote subkey missing");
     706           1 :         ret = KRB5KDC_ERR_PREAUTH_FAILED;
     707           1 :         goto out;
     708             :     }
     709             : 
     710       45189 :     r->fast.flags.kdc_verified =
     711       43531 :         !_kdc_is_anonymous_pkinit(r->context, ticket->client);
     712             : 
     713       43531 :     ret = _krb5_fast_armor_key(r->context,
     714       43531 :                                ac->remote_subkey,
     715       43531 :                                &ticket->ticket.key,
     716             :                                &armorkey,
     717       43531 :                                r->explicit_armor_present ? NULL : &r->armor_crypto);
     718       43531 :     if (ret)
     719           0 :         goto out;
     720             : 
     721       43531 :     if (r->explicit_armor_present) {
     722         324 :         ret = _krb5_fast_explicit_armor_key(r->context,
     723             :                                             &armorkey,
     724             :                                             tgs_ac->remote_subkey,
     725             :                                             &explicit_armorkey,
     726             :                                             &r->armor_crypto);
     727         324 :         if (ret)
     728           0 :             goto out;
     729             : 
     730         324 :         krb5_free_keyblock_contents(r->context, &explicit_armorkey);
     731             :     }
     732             : 
     733       43531 :     krb5_free_keyblock_contents(r->context, &armorkey);
     734             : 
     735       43531 :     ret = krb5_decrypt_EncryptedData(r->context, r->armor_crypto,
     736             :                                      KRB5_KU_FAST_ENC,
     737             :                                      &fxreq.u.armored_data.enc_fast_req,
     738             :                                      &data);
     739       43531 :     if (ret) {
     740           0 :         kdc_log(r->context, r->config, 2,
     741             :                 "Failed to decrypt FAST request");
     742           0 :         goto out;
     743             :     }
     744             : 
     745       43531 :     ret = decode_KrbFastReq(data.data, data.length, &fastreq, NULL);
     746       43531 :     krb5_data_free(&data);
     747       43531 :     if (ret)
     748           0 :         goto out;
     749             : 
     750             :     /*
     751             :      * verify req-checksum of the outer body
     752             :      */
     753       43531 :     if (tgs_ac) {
     754             :         /*
     755             :          * -- For TGS, contains the checksum performed over the type
     756             :          * -- AP-REQ in the PA-TGS-REQ padata.
     757             :          */
     758       43068 :         i = 0;
     759       43068 :         pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_TGS_REQ);
     760       43068 :         if (pa == NULL) {
     761           0 :             kdc_log(r->context, r->config, 4,
     762             :                     "FAST TGS request missing TGS-REQ padata");
     763           0 :             ret = KRB5KRB_ERR_GENERIC;
     764           0 :             goto out;
     765             :         }
     766             : 
     767       44726 :         ret = _kdc_verify_checksum(r->context, r->armor_crypto,
     768             :                                    KRB5_KU_FAST_REQ_CHKSUM,
     769       43068 :                                    &pa->padata_value,
     770             :                                    &fxreq.u.armored_data.req_checksum);
     771       43068 :         if (ret) {
     772           0 :             kdc_log(r->context, r->config, 2,
     773             :                     "Bad checksum in FAST TGS request");
     774           0 :             goto out;
     775             :         }
     776             :     } else {
     777             :         /*
     778             :          * -- For AS, contains the checksum performed over the type
     779             :          * -- KDC-REQ-BODY for the req-body field of the KDC-REQ
     780             :          * -- structure;
     781             :          */
     782         463 :         ret = _kdc_verify_checksum(r->context, r->armor_crypto,
     783             :                                    KRB5_KU_FAST_REQ_CHKSUM,
     784         463 :                                    &r->req.req_body._save,
     785             :                                    &fxreq.u.armored_data.req_checksum);
     786         463 :         if (ret) {
     787           0 :             kdc_log(r->context, r->config, 2,
     788             :                     "Bad checksum in FAST AS request");
     789           0 :             goto out;
     790             :         }
     791             :     }
     792             : 
     793             :     /*
     794             :      * check for unsupported mandatory options
     795             :      */
     796       43531 :     if (FastOptions2int(fastreq.fast_options) & 0xfffc) {
     797           1 :         kdc_log(r->context, r->config, 2,
     798             :                 "FAST unsupported mandatory option set");
     799           1 :         ret = KRB5_KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS;
     800           1 :         goto out;
     801             :     }
     802             : 
     803       43530 :     r->fast.flags.requested_hidden_names = fastreq.fast_options.hide_client_names;
     804             : 
     805             :     /* KDC MUST ignore outer pa data preauth-14 - 6.5.5 */
     806       43530 :     if (r->req.padata)
     807       43530 :         free_METHOD_DATA(r->req.padata);
     808             :     else
     809           0 :         ALLOC(r->req.padata);
     810             : 
     811       43530 :     ret = copy_METHOD_DATA(&fastreq.padata, r->req.padata);
     812       43530 :     if (ret)
     813           0 :         goto out;
     814             : 
     815       43530 :     free_KDC_REQ_BODY(&r->req.req_body);
     816       43530 :     ret = copy_KDC_REQ_BODY(&fastreq.req_body, &r->req.req_body);
     817       43530 :     if (ret)
     818           0 :         goto out;
     819             : 
     820       43530 :     kdc_log(r->context, r->config, 5, "Client selected FAST");
     821             : 
     822       43543 :  out:
     823       43543 :     if (ac && ac != tgs_ac)
     824         787 :         krb5_auth_con_free(r->context, ac);
     825             : 
     826       43543 :     krb5_free_principal(r->context, armor_server_principal);
     827       43543 :     krb5_xfree(armor_client_principal_name);
     828       43543 :     krb5_xfree(armor_server_principal_name);
     829             : 
     830       43543 :     free_KrbFastReq(&fastreq);
     831       43543 :     free_PA_FX_FAST_REQUEST(&fxreq);
     832             : 
     833       43543 :     return ret;
     834             : }
     835             : 
     836             : /*
     837             :  *
     838             :  */
     839             : krb5_error_code
     840      100730 : _kdc_fast_unwrap_request(astgs_request_t r,
     841             :                          krb5_ticket *tgs_ticket,
     842             :                          krb5_auth_context tgs_ac)
     843             : {
     844        3413 :     krb5_error_code ret;
     845        3413 :     const PA_DATA *pa;
     846      100730 :     int i = 0;
     847             : 
     848      100730 :     if (!r->config->enable_fast)
     849        5656 :         return 0;
     850             : 
     851       95074 :     ret = fast_unwrap_request(r, tgs_ticket, tgs_ac);
     852       95074 :     if (ret)
     853          13 :         return ret;
     854             : 
     855       95061 :     if (r->config->enable_fast_cookie) {
     856             :         /*
     857             :          * FX-COOKIE can be used outside of FAST, e.g. SRP or GSS.
     858             :          */
     859           0 :         pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_COOKIE);
     860           0 :         if (pa) {
     861           0 :             krb5_const_principal ticket_client = NULL;
     862             : 
     863           0 :             if (tgs_ticket)
     864           0 :                 ticket_client = tgs_ticket->client;
     865             : 
     866           0 :             ret = fast_parse_cookie(r, ticket_client, pa);
     867             :         }
     868             :     }
     869             : 
     870       91648 :     return ret;
     871             : }
     872             : 
     873             : /*
     874             :  * Strengthen reply key by mixing with a random key that is
     875             :  * protected by FAST.
     876             :  */
     877             : krb5_error_code
     878       79615 : _kdc_fast_strengthen_reply_key(astgs_request_t r)
     879             : {
     880       79615 :     if (r->armor_crypto) {
     881        1658 :         krb5_keyblock new_reply_key;
     882        1658 :         krb5_error_code ret;
     883             : 
     884       43225 :         kdc_log(r->context, r->config, 5,
     885             :                 "FAST strengthen reply key with strengthen-key");
     886             : 
     887       43225 :         heim_assert(r->reply_key.keytype != KRB5_ENCTYPE_NULL, "NULL reply key enctype");
     888             : 
     889       43225 :         ret = krb5_generate_random_keyblock(r->context, r->reply_key.keytype,
     890             :                                             &r->strengthen_key);
     891       43225 :         if (ret) {
     892           0 :             kdc_log(r->context, r->config, 0, "failed to prepare random keyblock");
     893           0 :             return ret;
     894             :         }
     895             : 
     896       43225 :         ret = _krb5_fast_cf2(r->context,
     897             :                              &r->strengthen_key, "strengthenkey",
     898             :                              &r->reply_key, "replykey",
     899             :                              &new_reply_key, NULL);
     900       43225 :         if (ret)
     901           0 :             return ret;
     902             : 
     903       43225 :         krb5_free_keyblock_contents(r->context, &r->reply_key);
     904       43225 :         r->reply_key = new_reply_key;
     905             :     }
     906             : 
     907       76787 :     return 0;
     908             : }
     909             : 
     910             : /*
     911             :  * Zero and free KDCFastState
     912             :  */
     913             : void
     914      102098 : _kdc_free_fast_state(KDCFastState *state)
     915             : {
     916        3413 :     size_t i;
     917             : 
     918      102098 :     for (i = 0; i < state->fast_state.len; i++) {
     919           0 :         PA_DATA *pa = &state->fast_state.val[i];
     920             : 
     921           0 :         if (pa->padata_value.data)
     922           0 :             memset_s(pa->padata_value.data, 0,
     923           0 :                      pa->padata_value.length, pa->padata_value.length);
     924             :     }
     925      102098 :     free_KDCFastState(state);
     926      102098 : }
     927             : 
     928             : krb5_error_code
     929         786 : _kdc_fast_check_armor_pac(astgs_request_t r, int flags)
     930             : {
     931           0 :     krb5_error_code ret;
     932         786 :     krb5_boolean ad_kdc_issued = FALSE;
     933         786 :     krb5_pac mspac = NULL;
     934         786 :     krb5_principal armor_client_principal = NULL;
     935           0 :     HDB *armor_db;
     936         786 :     hdb_entry *armor_client = NULL;
     937         786 :     char *armor_client_principal_name = NULL;
     938             : 
     939         786 :     flags |= HDB_F_ARMOR_PRINCIPAL;
     940         786 :     if (_kdc_synthetic_princ_used_p(r->context, r->armor_ticket))
     941           0 :         flags |= HDB_F_SYNTHETIC_OK;
     942         786 :     if (r->req.req_body.kdc_options.canonicalize)
     943          71 :         flags |= HDB_F_CANON;
     944             : 
     945         786 :     ret = _krb5_principalname2krb5_principal(r->context,
     946             :                                              &armor_client_principal,
     947         786 :                                              r->armor_ticket->ticket.cname,
     948         786 :                                              r->armor_ticket->ticket.crealm);
     949         786 :     if (ret)
     950           0 :         goto out;
     951             : 
     952         786 :     ret = krb5_unparse_name(r->context, armor_client_principal,
     953             :                             &armor_client_principal_name);
     954         786 :     if (ret)
     955           0 :         goto out;
     956             : 
     957         786 :     ret = _kdc_db_fetch_client(r->context, r->config, flags,
     958             :                                armor_client_principal, armor_client_principal_name,
     959         786 :                                r->req.req_body.realm, &armor_db, &armor_client);
     960         786 :     if (ret)
     961           0 :         goto out;
     962             : 
     963         786 :     ret = kdc_check_flags(r, FALSE, armor_client, NULL);
     964         786 :     if (ret)
     965           0 :         goto out;
     966             : 
     967         786 :     ret = _kdc_check_pac(r, armor_client_principal, NULL,
     968             :                          armor_client, r->armor_server,
     969             :                          r->armor_server, r->armor_server,
     970         786 :                          &r->armor_key->key, &r->armor_key->key,
     971         786 :                          &r->armor_ticket->ticket, &ad_kdc_issued, &mspac, NULL, NULL);
     972         786 :     if (ret) {
     973          16 :         const char *msg = krb5_get_error_message(r->context, ret);
     974             : 
     975          16 :         kdc_log(r->context, r->config, 4,
     976             :                 "Verify armor PAC (%s) failed for %s (%s) from %s with %s (%s)",
     977             :                 armor_client_principal_name, r->cname, r->sname,
     978          16 :                 r->from, msg, mspac ? "Ticket unsigned" : "No PAC");
     979             : 
     980          16 :         krb5_free_error_message(r->context, msg);
     981             : 
     982          16 :         goto out;
     983             :     }
     984             : 
     985         770 :     r->armor_clientdb = armor_db;
     986         770 :     armor_db = NULL;
     987             : 
     988         770 :     r->armor_client = armor_client;
     989         770 :     armor_client = NULL;
     990             : 
     991         770 :     r->armor_pac = mspac;
     992         770 :     mspac = NULL;
     993             : 
     994         786 : out:
     995         786 :     krb5_xfree(armor_client_principal_name);
     996         786 :     if (armor_client)
     997          16 :         _kdc_free_ent(r->context, armor_db, armor_client);
     998         786 :     krb5_free_principal(r->context, armor_client_principal);
     999         786 :     krb5_pac_free(r->context, mspac);
    1000             : 
    1001         786 :     return ret;
    1002             : }

Generated by: LCOV version 1.14