LCOV - code coverage report
Current view: top level - third_party/heimdal/kdc - fast.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 272 429 63.4 %
Date: 2024-06-13 04:01:37 Functions: 10 11 90.9 %

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

Generated by: LCOV version 1.13