"Fossies" - the Fresh Open Source Software Archive

Member "freeradius-server-3.0.23/src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c" (10 Jun 2021, 13088 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_peap.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_peap.c  contains the interfaces that are called from eap
    3  *
    4  * Version:     $Id: 4bbf57330fb1d802f26d7637715f70ec19e2d7a6 $
    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 2003 Alan DeKok <aland@freeradius.org>
   21  * Copyright 2006 The FreeRADIUS server project
   22  */
   23 
   24 RCSID("$Id: 4bbf57330fb1d802f26d7637715f70ec19e2d7a6 $")
   25 
   26 #include "eap_peap.h"
   27 
   28 typedef struct rlm_eap_peap_t {
   29     char const *tls_conf_name;      //!< TLS configuration.
   30     fr_tls_server_conf_t *tls_conf;
   31     char const *default_method_name;    //!< Default tunneled EAP type.
   32     int default_method;
   33 
   34     char const *inner_eap_module;       //!< module name for inner EAP
   35     int auth_type_eap;
   36     bool use_tunneled_reply;        //!< Use the reply attributes from the tunneled session in
   37                         //!< the non-tunneled reply to the client.
   38 
   39     bool copy_request_to_tunnel;        //!< Use SOME of the request attributes from outside of the
   40                         //!< tunneled session in the tunneled request.
   41 #ifdef WITH_PROXY
   42     bool proxy_tunneled_request_as_eap; //!< Proxy tunneled session as EAP, or as de-capsulated
   43                         //!< protocol.
   44 #endif
   45     char const *virtual_server;     //!< Virtual server for inner tunnel session.
   46 
   47     bool soh;               //!< Do we do SoH request?
   48     char const *soh_virtual_server;
   49     bool req_client_cert;           //!< Do we do require a client cert?
   50 } rlm_eap_peap_t;
   51 
   52 
   53 static CONF_PARSER module_config[] = {
   54     { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, tls_conf_name), NULL },
   55 
   56     { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, default_method_name), "mschapv2" },
   57 
   58     { "inner_eap_module", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, inner_eap_module), NULL },
   59 
   60     { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, copy_request_to_tunnel), "no" },
   61 
   62     { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, use_tunneled_reply), "no" },
   63 
   64 #ifdef WITH_PROXY
   65     { "proxy_tunneled_request_as_eap", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, proxy_tunneled_request_as_eap), "yes" },
   66 #endif
   67 
   68     { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, virtual_server), NULL },
   69 
   70     { "soh", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, soh), "no" },
   71 
   72     { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, req_client_cert), "no" },
   73 
   74     { "soh_virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, soh_virtual_server), NULL },
   75 
   76     CONF_PARSER_TERMINATOR
   77 };
   78 
   79 
   80 /*
   81  *  Attach the module.
   82  */
   83 static int mod_instantiate(CONF_SECTION *cs, void **instance)
   84 {
   85     rlm_eap_peap_t      *inst;
   86     DICT_VALUE const    *dv;
   87 
   88     *instance = inst = talloc_zero(cs, rlm_eap_peap_t);
   89     if (!inst) return -1;
   90 
   91     /*
   92      *  Parse the configuration attributes.
   93      */
   94     if (cf_section_parse(cs, inst, module_config) < 0) {
   95         return -1;
   96     }
   97 
   98     if (!inst->virtual_server) {
   99         ERROR("rlm_eap_peap: A 'virtual_server' MUST be defined for security");
  100         return -1;
  101     }
  102 
  103     /*
  104      *  Convert the name to an integer, to make it easier to
  105      *  handle.
  106      */
  107     inst->default_method = eap_name2type(inst->default_method_name);
  108     if (inst->default_method < 0) {
  109         ERROR("rlm_eap_peap: Unknown EAP type %s",
  110                inst->default_method_name);
  111         return -1;
  112     }
  113 
  114     /*
  115      *  Read tls configuration, either from group given by 'tls'
  116      *  option, or from the eap-tls configuration.
  117      */
  118     inst->tls_conf = eaptls_conf_parse(cs, "tls");
  119 
  120     if (!inst->tls_conf) {
  121         ERROR("rlm_eap_peap: Failed initializing SSL context");
  122         return -1;
  123     }
  124 
  125     /*
  126      *  Don't expose this if we don't need it.
  127      */
  128     if (!inst->inner_eap_module) inst->inner_eap_module = "eap";
  129 
  130     dv = dict_valbyname(PW_AUTH_TYPE, 0, inst->inner_eap_module);
  131     if (!dv) {
  132         WARN("Failed to find 'Auth-Type %s' section in virtual server %s.  The server cannot proxy inner-tunnel EAP packets.",
  133              inst->inner_eap_module, inst->virtual_server);
  134     } else {
  135         inst->auth_type_eap = dv->value;
  136     }
  137 
  138 #ifdef TLS1_3_VERSION
  139     if ((inst->tls_conf->min_version == TLS1_3_VERSION) && !inst->tls_conf->tls13_enable_magic) {
  140         ERROR("There are no standards for using TLS 1.3 with PEAP.");
  141         ERROR("You MUST enable TLS 1.2 for PEAP to work.");
  142         return -1;
  143     }
  144 
  145     if ((inst->tls_conf->max_version == TLS1_3_VERSION) ||
  146         (inst->tls_conf->min_version == TLS1_3_VERSION)) {
  147         WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
  148         WARN("!! There is no standard for using PEAP with TLS 1.3");
  149         WARN("!! Please set tls_max_version = \"1.2\"");
  150         WARN("!! FreeRADIUS only supports TLS 1.3 for special builds of wpa_supplicant and Windows");
  151         WARN("!! This limitation is likely to change in late 2021.");
  152         WARN("!! If you are using this version of FreeRADIUS after 2021, you will probably need to upgrade");
  153         WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
  154 }
  155 #endif
  156 
  157     return 0;
  158 }
  159 
  160 /*
  161  *  Allocate the PEAP per-session data
  162  */
  163 static peap_tunnel_t *peap_alloc(TALLOC_CTX *ctx, rlm_eap_peap_t *inst)
  164 {
  165     peap_tunnel_t *t;
  166 
  167     t = talloc_zero(ctx, peap_tunnel_t);
  168 
  169     t->default_method = inst->default_method;
  170     t->copy_request_to_tunnel = inst->copy_request_to_tunnel;
  171     t->use_tunneled_reply = inst->use_tunneled_reply;
  172 #ifdef WITH_PROXY
  173     t->proxy_tunneled_request_as_eap = inst->proxy_tunneled_request_as_eap;
  174 #endif
  175     t->virtual_server = inst->virtual_server;
  176     t->soh = inst->soh;
  177     t->soh_virtual_server = inst->soh_virtual_server;
  178     t->session_resumption_state = PEAP_RESUMPTION_MAYBE;
  179 
  180     return t;
  181 }
  182 
  183 /*
  184  *  Send an initial eap-tls request to the peer, using the libeap functions.
  185  */
  186 static int mod_session_init(void *type_arg, eap_handler_t *handler)
  187 {
  188     int     status;
  189     tls_session_t   *ssn;
  190     rlm_eap_peap_t  *inst;
  191     VALUE_PAIR  *vp;
  192     bool        client_cert;
  193     REQUEST     *request = handler->request;
  194 
  195     inst = type_arg;
  196 
  197     handler->tls = true;
  198 
  199     /*
  200      *  Check if we need a client certificate.
  201      */
  202 
  203     /*
  204      * EAP-TLS-Require-Client-Cert attribute will override
  205      * the require_client_cert configuration option.
  206      */
  207     vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
  208     if (vp) {
  209         client_cert = vp->vp_integer ? true : false;
  210     } else {
  211         client_cert = inst->req_client_cert;
  212     }
  213 
  214     /*
  215      *  Don't allow TLS 1.3 for us, even if it's allowed
  216      *  elsewhere.
  217      */
  218     ssn = eaptls_session(handler, inst->tls_conf, client_cert, inst->tls_conf->tls13_enable_magic);
  219     if (!ssn) {
  220         return 0;
  221     }
  222 
  223     handler->opaque = ((void *)ssn);
  224 
  225     /*
  226      *  Set the label to a fixed string.  For TLS 1.3, the
  227      *  label is the same for all TLS-based EAP methods.  If
  228      *  the client is using TLS 1.3, then eaptls_success()
  229      *  will over-ride this label with the correct label for
  230      *  TLS 1.3.
  231      */
  232     ssn->label = "client EAP encryption";
  233 
  234     /*
  235      *  As it is a poorly designed protocol, PEAP uses
  236      *  bits in the TLS header to indicate PEAP
  237      *  version numbers.  For now, we only support
  238      *  PEAP version 0, so it doesn't matter too much.
  239      *  However, if we support later versions of PEAP,
  240      *  we will need this flag to indicate which
  241      *  version we're currently dealing with.
  242      */
  243     ssn->peap_flag = 0x00;
  244 
  245     /*
  246      *  PEAP version 0 requires 'include_length = no',
  247      *  so rather than hoping the user figures it out,
  248      *  we force it here.
  249      */
  250     ssn->length_flag = false;
  251 
  252     /*
  253      *  TLS session initialization is over.  Now handle TLS
  254      *  related handshaking or application data.
  255      */
  256     status = eaptls_start(handler->eap_ds, ssn->peap_flag);
  257     if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
  258         REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
  259     } else {
  260         RDEBUG3("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
  261     }
  262     if (status == 0) return 0;
  263 
  264     /*
  265      *  The next stage to process the packet.
  266      */
  267     handler->stage = PROCESS;
  268 
  269     return 1;
  270 }
  271 
  272 /*
  273  *  Do authentication, by letting EAP-TLS do most of the work.
  274  */
  275 static int mod_process(void *arg, eap_handler_t *handler)
  276 {
  277     int rcode;
  278     int ret = 0;
  279     fr_tls_status_t status;
  280     rlm_eap_peap_t *inst = (rlm_eap_peap_t *) arg;
  281     tls_session_t *tls_session = (tls_session_t *) handler->opaque;
  282     peap_tunnel_t *peap = tls_session->opaque;
  283     REQUEST *request = handler->request;
  284 
  285     /*
  286      *  Session resumption requires the storage of data, so
  287      *  allocate it if it doesn't already exist.
  288      */
  289     if (!tls_session->opaque) {
  290         peap = tls_session->opaque = peap_alloc(tls_session, inst);
  291     }
  292 
  293     /*
  294      *  Negotiate PEAP versions down.
  295      */
  296     if ((handler->eap_ds->response->type.data[0] & 0x03) < tls_session->peap_flag) {
  297         tls_session->peap_flag = handler->eap_ds->response->type.data[0] & 0x03;
  298     }
  299 
  300     status = eaptls_process(handler);
  301     if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
  302         REDEBUG("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
  303     } else {
  304         RDEBUG3("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
  305     }
  306 
  307     /*
  308      *  Make request available to any SSL callbacks
  309      */
  310     SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request);
  311     switch (status) {
  312     /*
  313      *  EAP-TLS handshake was successful, tell the
  314      *  client to keep talking.
  315      *
  316      *  If this was EAP-TLS, we would just return
  317      *  an EAP-TLS-Success packet here.
  318      */
  319     case FR_TLS_SUCCESS:
  320         peap->status = PEAP_STATUS_TUNNEL_ESTABLISHED;
  321         break;
  322 
  323     /*
  324      *  The TLS code is still working on the TLS
  325      *  exchange, and it's a valid TLS request.
  326      *  do nothing.
  327      */
  328     case FR_TLS_HANDLED:
  329         /*
  330          *  FIXME: If the SSL session is established, grab the state
  331          *  and EAP id from the inner tunnel, and update it with
  332          *  the expected EAP id!
  333          */
  334         ret = 1;
  335         goto done;
  336     /*
  337      *  Handshake is done, proceed with decoding tunneled
  338      *  data.
  339      */
  340     case FR_TLS_OK:
  341                 /*
  342                  *  TLSv1.3 makes application data immediately avaliable
  343                  */
  344         if (tls_session->is_init_finished && (peap->status == PEAP_STATUS_INVALID)) peap->status = PEAP_STATUS_TUNNEL_ESTABLISHED;
  345         break;
  346 
  347         /*
  348          *  Anything else: fail.
  349          */
  350     default:
  351         ret = 0;
  352         goto done;
  353     }
  354 
  355     /*
  356      *  Session is established, proceed with decoding
  357      *  tunneled data.
  358      */
  359     RDEBUG2("Session established.  Decoding tunneled attributes");
  360 
  361     /*
  362      *  We may need PEAP data associated with the session, so
  363      *  allocate it here, if it wasn't already alloacted.
  364      */
  365     if (!tls_session->opaque) {
  366         tls_session->opaque = peap_alloc(tls_session, inst);
  367     }
  368 
  369     /*
  370      *  Process the PEAP portion of the request.
  371      */
  372     rcode = eappeap_process(handler, tls_session, inst->auth_type_eap);
  373     switch (rcode) {
  374     case RLM_MODULE_REJECT:
  375         eaptls_fail(handler, 0);
  376         ret = 0;
  377         goto done;
  378 
  379     case RLM_MODULE_HANDLED:
  380         eaptls_request(handler->eap_ds, tls_session);
  381         ret = 1;
  382         goto done;
  383 
  384     case RLM_MODULE_OK:
  385         /*
  386          *  Move the saved VP's from the Access-Accept to
  387          *  our Access-Accept.
  388          */
  389         peap = tls_session->opaque;
  390         if (peap->soh_reply_vps) {
  391             RDEBUG2("Using saved attributes from the SoH reply");
  392             rdebug_pair_list(L_DBG_LVL_2, request, peap->soh_reply_vps, NULL);
  393             fr_pair_list_mcopy_by_num(handler->request->reply,
  394                   &handler->request->reply->vps,
  395                   &peap->soh_reply_vps, 0, 0, TAG_ANY);
  396         }
  397         if (peap->accept_vps) {
  398             RDEBUG2("Using saved attributes from the original Access-Accept");
  399             rdebug_pair_list(L_DBG_LVL_2, request, peap->accept_vps, NULL);
  400             fr_pair_list_mcopy_by_num(handler->request->reply,
  401                   &handler->request->reply->vps,
  402                   &peap->accept_vps, 0, 0, TAG_ANY);
  403         } else if (peap->use_tunneled_reply) {
  404             RDEBUG2("No saved attributes in the original Access-Accept");
  405         }
  406 
  407         /*
  408          *  Success: Automatically return MPPE keys.
  409          */
  410         ret = eaptls_success(handler, 0);
  411         goto done;
  412 
  413         /*
  414          *  No response packet, MUST be proxying it.
  415          *  The main EAP module will take care of discovering
  416          *  that the request now has a "proxy" packet, and
  417          *  will proxy it, rather than returning an EAP packet.
  418          */
  419     case RLM_MODULE_UPDATED:
  420 #ifdef WITH_PROXY
  421         rad_assert(handler->request->proxy != NULL);
  422 #endif
  423         ret = 1;
  424         goto done;
  425 
  426     default:
  427         break;
  428     }
  429 
  430     eaptls_fail(handler, 0);
  431 
  432 done:
  433     SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL);
  434 
  435     return ret;
  436 }
  437 
  438 
  439 /*
  440  *  The module name should be the only globally exported symbol.
  441  *  That is, everything else should be 'static'.
  442  */
  443 extern rlm_eap_module_t rlm_eap_peap;
  444 rlm_eap_module_t rlm_eap_peap = {
  445     .name       = "eap_peap",
  446     .instantiate    = mod_instantiate,  /* Create new submodule instance */
  447     .session_init   = mod_session_init, /* Initialise a new EAP session */
  448     .process    = mod_process       /* Process next round of EAP method */
  449 };