"Fossies" - the Fresh Open Source Software Archive

Member "freeradius-server-3.0.23/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c" (10 Jun 2021, 8431 Bytes) of package /linux/misc/freeradius-server-3.0.23.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rlm_eap_tls.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.0.22_vs_3.0.23.

    1 /*
    2  * rlm_eap_tls.c  contains the interfaces that are called from eap
    3  *
    4  * Version:     $Id: d327c575fc8ff204e9f980cd64ee8bb22e716c8a $
    5  *
    6  *   This program is free software; you can redistribute it and/or modify
    7  *   it under the terms of the GNU General Public License as published by
    8  *   the Free Software Foundation; either version 2 of the License, or
    9  *   (at your option) any later version.
   10  *
   11  *   This program is distributed in the hope that it will be useful,
   12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  *   GNU General Public License for more details.
   15  *
   16  *   You should have received a copy of the GNU General Public License
   17  *   along with this program; if not, write to the Free Software
   18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
   19  *
   20  * Copyright 2001  hereUare Communications, Inc. <raghud@hereuare.com>
   21  * Copyright 2003  Alan DeKok <aland@freeradius.org>
   22  * Copyright 2006  The FreeRADIUS server project
   23  *
   24  */
   25 
   26 RCSID("$Id: d327c575fc8ff204e9f980cd64ee8bb22e716c8a $")
   27 USES_APPLE_DEPRECATED_API   /* OpenSSL API has been deprecated by Apple */
   28 
   29 #ifdef HAVE_OPENSSL_RAND_H
   30 #include <openssl/rand.h>
   31 #endif
   32 
   33 #ifdef HAVE_OPENSSL_EVP_H
   34 #include <openssl/evp.h>
   35 #endif
   36 
   37 #include "rlm_eap_tls.h"
   38 
   39 #ifdef HAVE_SYS_STAT_H
   40 #include <sys/stat.h>
   41 #endif
   42 
   43 static CONF_PARSER module_config[] = {
   44     { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_tls_t, tls_conf_name), NULL },
   45     { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_tls_t, virtual_server), NULL },
   46     { "configurable_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_tls_t, configurable_client_cert), NULL },
   47     CONF_PARSER_TERMINATOR
   48 };
   49 
   50 
   51 /*
   52  *  Attach the EAP-TLS module.
   53  */
   54 static int mod_instantiate(CONF_SECTION *cs, void **instance)
   55 {
   56     rlm_eap_tls_t       *inst;
   57 
   58     /*
   59      *  Parse the config file & get all the configured values
   60      */
   61     *instance = inst = talloc_zero(cs, rlm_eap_tls_t);
   62     if (!inst) return -1;
   63 
   64     if (cf_section_parse(cs, inst, module_config) < 0) {
   65         return -1;
   66     }
   67 
   68     inst->tls_conf = eaptls_conf_parse(cs, "tls");
   69 
   70     if (!inst->tls_conf) {
   71         ERROR("rlm_eap_tls: Failed initializing SSL context");
   72         return -1;
   73     }
   74 
   75 #ifdef TLS1_3_VERSION
   76     if ((inst->tls_conf->max_version == TLS1_3_VERSION) ||
   77         (inst->tls_conf->min_version == TLS1_3_VERSION)) {
   78         WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
   79         WARN("!! Most supplicants do not support EAP-TLS with TLS 1.3");
   80         WARN("!! Please set tls_max_version = \"1.2\"");
   81         WARN("!! FreeRADIUS only supports TLS 1.3 for special builds of wpa_supplicant and Windows");
   82         WARN("!! This limitation is likely to change in late 2021.");
   83         WARN("!! If you are using this version of FreeRADIUS after 2021, you will probably need to upgrade");
   84         WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
   85     }
   86 #endif
   87 
   88     return 0;
   89 }
   90 
   91 
   92 /*
   93  *  Send an initial eap-tls request to the peer, using the libeap functions.
   94  */
   95 static int mod_session_init(void *type_arg, eap_handler_t *handler)
   96 {
   97     int     status;
   98     tls_session_t   *ssn;
   99     rlm_eap_tls_t   *inst;
  100     REQUEST     *request = handler->request;
  101     bool        require_client_cert = true;
  102 
  103     inst = type_arg;
  104 
  105     handler->tls = true;
  106 
  107     /*
  108      *  Respect EAP-TLS-Require-Client-Cert, but only if
  109      *  enabled in the module configuration.
  110      *
  111      *  We can't change behavior of existing systems, so this
  112      *  change has to be enabled via a new configuration
  113      *  option.
  114      */
  115     if (inst->configurable_client_cert) {
  116         VALUE_PAIR *vp;
  117 
  118         vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
  119         if (vp && !vp->vp_integer) require_client_cert = false;
  120     }
  121 
  122     /*
  123      *  EAP-TLS always requires a client certificate, and
  124      *  allows for TLS 1.3 if permitted.
  125      */
  126     ssn = eaptls_session(handler, inst->tls_conf, require_client_cert, true);
  127     if (!ssn) {
  128         return 0;
  129     }
  130 
  131     handler->opaque = ((void *)ssn);
  132     ssn->quick_session_tickets = true; /* send as soon as we've seen the client cert */
  133 
  134     /*
  135      *  TLS session initialization is over.  Now handle TLS
  136      *  related handshaking or application data.
  137      */
  138     status = eaptls_start(handler->eap_ds, ssn->peap_flag);
  139     if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
  140         REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
  141     } else {
  142         RDEBUG3("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
  143     }
  144     if (status == 0) return 0;
  145 
  146     /*
  147      *  The next stage to process the packet.
  148      */
  149     handler->stage = PROCESS;
  150 
  151     return 1;
  152 }
  153 
  154 /*
  155  *  Do authentication, by letting EAP-TLS do most of the work.
  156  */
  157 static int CC_HINT(nonnull) mod_process(void *type_arg, eap_handler_t *handler)
  158 {
  159     fr_tls_status_t status;
  160     int ret;
  161     tls_session_t *tls_session = (tls_session_t *) handler->opaque;
  162     REQUEST *request = handler->request;
  163     rlm_eap_tls_t *inst;
  164 
  165     inst = type_arg;
  166 
  167     status = eaptls_process(handler);
  168     if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
  169         REDEBUG("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
  170     } else {
  171         RDEBUG3("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
  172     }
  173 
  174 
  175     /*
  176      *  Make request available to any SSL callbacks
  177      */
  178     SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request);
  179     switch (status) {
  180     /*
  181      *  EAP-TLS handshake was successful, return an
  182      *  EAP-TLS-Success packet here.
  183      *
  184      *  If a virtual server was configured, check that
  185      *  it accepts the certificates, too.
  186      */
  187     case FR_TLS_SUCCESS:
  188         if (inst->virtual_server) {
  189             VALUE_PAIR *vp;
  190             REQUEST *fake;
  191 
  192             /* create a fake request */
  193             fake = request_alloc_fake(request);
  194             rad_assert(!fake->packet->vps);
  195 
  196             fake->packet->vps = fr_pair_list_copy(fake->packet, request->packet->vps);
  197 
  198             /* set the virtual server to use */
  199             if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
  200                 fake->server = vp->vp_strvalue;
  201             } else {
  202                 fake->server = inst->virtual_server;
  203             }
  204 
  205             RDEBUG2("Validating certificate");
  206             rad_virtual_server(fake);
  207 
  208             /* copy the reply vps back to our reply */
  209             fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps,
  210                   &fake->reply->vps, 0, 0, TAG_ANY);
  211 
  212             /* reject if virtual server didn't return accept */
  213             if (fake->reply->code != PW_CODE_ACCESS_ACCEPT) {
  214                 RDEBUG2("Certificate rejected by the virtual server");
  215                 talloc_free(fake);
  216                 eaptls_fail(handler, 0);
  217                 ret = 0;
  218                 goto done;
  219             }
  220 
  221             talloc_free(fake);
  222             /* success */
  223         }
  224 
  225         /*
  226          *  Set the label to a fixed string.  For TLS 1.3,
  227          *  the label is the same for all TLS-based EAP
  228          *  methods.
  229          */
  230         tls_session->label = "client EAP encryption";
  231 
  232         /*
  233          *  Success: Automatically return MPPE keys.
  234          */
  235         ret = eaptls_success(handler, 0);
  236         break;
  237 
  238         /*
  239          *  The TLS code is still working on the TLS
  240          *  exchange, and it's a valid TLS request.
  241          *  do nothing.
  242          */
  243     case FR_TLS_HANDLED:
  244         ret = 1;
  245         break;
  246 
  247         /*
  248          *  Handshake is done, proceed with decoding tunneled
  249          *  data.
  250          */
  251     case FR_TLS_OK:
  252         RDEBUG2("Received unexpected tunneled data after successful handshake");
  253 #ifndef NDEBUG
  254         if ((rad_debug_lvl > 2) && fr_log_fp) {
  255             unsigned int i;
  256             unsigned int data_len;
  257             unsigned char buffer[1024];
  258 
  259             data_len = (tls_session->record_minus)(&tls_session->dirty_in,
  260                         buffer, sizeof(buffer));
  261             DEBUG("  Tunneled data (%u bytes)", data_len);
  262             for (i = 0; i < data_len; i++) {
  263                 if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "  %x: ", i);
  264                 if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
  265 
  266                 fprintf(fr_log_fp, "%02x ", buffer[i]);
  267             }
  268             fprintf(fr_log_fp, "\n");
  269         }
  270 #endif
  271 
  272         eaptls_fail(handler, 0);
  273         ret = 0;
  274         break;
  275 
  276         /*
  277          *  Anything else: fail.
  278          *
  279          *  Also, remove the session from the cache so that
  280          *  the client can't re-use it.
  281          */
  282     default:
  283         tls_fail(tls_session);
  284         ret = 0;
  285     }
  286 
  287 done:
  288     SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL);
  289 
  290     return ret;
  291 }
  292 
  293 /*
  294  *  The module name should be the only globally exported symbol.
  295  *  That is, everything else should be 'static'.
  296  */
  297 extern rlm_eap_module_t rlm_eap_tls;
  298 rlm_eap_module_t rlm_eap_tls = {
  299     .name       = "eap_tls",
  300     .instantiate    = mod_instantiate,  /* Create new submodule instance */
  301     .session_init   = mod_session_init, /* Initialise a new EAP session */
  302     .process    = mod_process       /* Process next round of EAP method */
  303 };