"Fossies" - the Fresh Open Source Software Archive

Member "freeradius-server-3.0.23/src/modules/rlm_eap/types/rlm_eap_ttls/rlm_eap_ttls.c" (10 Jun 2021, 11067 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_ttls.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_ttls.c  contains the interfaces that are called from eap
    3  *
    4  * Version:     $Id: 3c77aa48776a28fb7a23f1b53cb4d71eb289f202 $
    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: 3c77aa48776a28fb7a23f1b53cb4d71eb289f202 $")
   25 USES_APPLE_DEPRECATED_API   /* OpenSSL API has been deprecated by Apple */
   26 
   27 #include "eap_ttls.h"
   28 
   29 typedef struct rlm_eap_ttls_t {
   30     /*
   31      *  TLS configuration
   32      */
   33     char const *tls_conf_name;
   34     fr_tls_server_conf_t *tls_conf;
   35 
   36     /*
   37      *  Default tunneled EAP type
   38      */
   39     char const *default_method_name;
   40     int default_method;
   41 
   42     /*
   43      *  Use the reply attributes from the tunneled session in
   44      *  the non-tunneled reply to the client.
   45      */
   46     bool use_tunneled_reply;
   47 
   48     /*
   49      *  Use SOME of the request attributes from outside of the
   50      *  tunneled session in the tunneled request
   51      */
   52     bool copy_request_to_tunnel;
   53 
   54     /*
   55      *  RFC 5281 (TTLS) says that the length field MUST NOT be
   56      *  in fragments after the first one.  However, we've done
   57      *  it that way for years, and no one has complained.
   58      *
   59      *  In the interests of allowing the server to follow the
   60      *  RFC, we add the option here.  If set to "no", it sends
   61      *  the length field in ONLY the first fragment.
   62      */
   63     bool include_length;
   64 
   65     /*
   66      *  Virtual server for inner tunnel session.
   67      */
   68     char const *virtual_server;
   69 
   70     /*
   71      *  Do we do require a client cert?
   72      */
   73     bool req_client_cert;
   74 } rlm_eap_ttls_t;
   75 
   76 
   77 static CONF_PARSER module_config[] = {
   78     { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, tls_conf_name), NULL },
   79     { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, default_method_name), "md5" },
   80     { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, copy_request_to_tunnel), "no" },
   81     { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, use_tunneled_reply), "no" },
   82     { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, virtual_server), NULL },
   83     { "include_length", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, include_length), "yes" },
   84     { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, req_client_cert), "no" },
   85     CONF_PARSER_TERMINATOR
   86 };
   87 
   88 
   89 /*
   90  *  Attach the module.
   91  */
   92 static int mod_instantiate(CONF_SECTION *cs, void **instance)
   93 {
   94     rlm_eap_ttls_t      *inst;
   95 
   96     *instance = inst = talloc_zero(cs, rlm_eap_ttls_t);
   97     if (!inst) return -1;
   98 
   99     /*
  100      *  Parse the configuration attributes.
  101      */
  102     if (cf_section_parse(cs, inst, module_config) < 0) {
  103         return -1;
  104     }
  105 
  106     if (!inst->virtual_server) {
  107         ERROR("rlm_eap_ttls: A 'virtual_server' MUST be defined for security");
  108         return -1;
  109     }
  110 
  111     /*
  112      *  Convert the name to an integer, to make it easier to
  113      *  handle.
  114      */
  115     inst->default_method = eap_name2type(inst->default_method_name);
  116     if (inst->default_method < 0) {
  117         ERROR("rlm_eap_ttls: Unknown EAP type %s",
  118                inst->default_method_name);
  119         return -1;
  120     }
  121 
  122     /*
  123      *  Read tls configuration, either from group given by 'tls'
  124      *  option, or from the eap-tls configuration.
  125      */
  126     inst->tls_conf = eaptls_conf_parse(cs, "tls");
  127 
  128     if (!inst->tls_conf) {
  129         ERROR("rlm_eap_ttls: Failed initializing SSL context");
  130         return -1;
  131     }
  132 
  133 #ifdef TLS1_3_VERSION
  134     if ((inst->tls_conf->min_version == TLS1_3_VERSION) && !inst->tls_conf->tls13_enable_magic) {
  135         ERROR("There are no standards for using TLS 1.3 with TTLS.");
  136         ERROR("You MUST enable TLS 1.2 for TTLS to work.");
  137         return -1;
  138     }
  139 
  140     if ((inst->tls_conf->max_version == TLS1_3_VERSION) ||
  141         (inst->tls_conf->min_version == TLS1_3_VERSION)) {
  142         WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
  143         WARN("!! There is no standard for using TTLS with TLS 1.3");
  144         WARN("!! Please set tls_max_version = \"1.2\"");
  145         WARN("!! FreeRADIUS only supports TLS 1.3 for special builds of wpa_supplicant and Windows");
  146         WARN("!! This limitation is likely to change in late 2021.");
  147         WARN("!! If you are using this version of FreeRADIUS after 2021, you will probably need to upgrade");
  148         WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
  149     }
  150 #endif
  151 
  152     return 0;
  153 }
  154 
  155 /*
  156  *  Allocate the TTLS per-session data
  157  */
  158 static ttls_tunnel_t *ttls_alloc(TALLOC_CTX *ctx, rlm_eap_ttls_t *inst)
  159 {
  160     ttls_tunnel_t *t;
  161 
  162     t = talloc_zero(ctx, ttls_tunnel_t);
  163 
  164     t->default_method = inst->default_method;
  165     t->copy_request_to_tunnel = inst->copy_request_to_tunnel;
  166     t->use_tunneled_reply = inst->use_tunneled_reply;
  167     t->virtual_server = inst->virtual_server;
  168     return t;
  169 }
  170 
  171 
  172 /*
  173  *  Send an initial eap-tls request to the peer, using the libeap functions.
  174  */
  175 static int mod_session_init(void *type_arg, eap_handler_t *handler)
  176 {
  177     int     status;
  178     tls_session_t   *ssn;
  179     rlm_eap_ttls_t  *inst;
  180     VALUE_PAIR  *vp;
  181     bool        client_cert;
  182     REQUEST     *request = handler->request;
  183 
  184     inst = type_arg;
  185 
  186     handler->tls = true;
  187 
  188     /*
  189      *  Check if we need a client certificate.
  190      */
  191 
  192     /*
  193      * EAP-TLS-Require-Client-Cert attribute will override
  194      * the require_client_cert configuration option.
  195      */
  196     vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
  197     if (vp) {
  198         client_cert = vp->vp_integer ? true : false;
  199     } else {
  200         client_cert = inst->req_client_cert;
  201     }
  202 
  203     /*
  204      *  Don't allow TLS 1.3 for us, even if it's allowed
  205      *  elsewhere.
  206      */
  207     ssn = eaptls_session(handler, inst->tls_conf, client_cert, inst->tls_conf->tls13_enable_magic);
  208     if (!ssn) {
  209         return 0;
  210     }
  211 
  212     handler->opaque = ((void *)ssn);
  213 
  214     /*
  215      *  Set the label to a fixed string.  For TLS 1.3, the
  216      *  label is the same for all TLS-based EAP methods.  If
  217      *  the client is using TLS 1.3, then eaptls_success()
  218      *  will over-ride this label with the correct label for
  219      *  TLS 1.3.
  220      */
  221     ssn->label = "ttls keying material";
  222 
  223     /*
  224      *  TLS session initialization is over.  Now handle TLS
  225      *  related handshaking or application data.
  226      */
  227     status = eaptls_start(handler->eap_ds, ssn->peap_flag);
  228     if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
  229         REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
  230     } else {
  231         RDEBUG3("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
  232     }
  233     if (status == 0) return 0;
  234 
  235     /*
  236      *  The next stage to process the packet.
  237      */
  238     handler->stage = PROCESS;
  239 
  240     return 1;
  241 }
  242 
  243 
  244 /*
  245  *  Do authentication, by letting EAP-TLS do most of the work.
  246  */
  247 static int mod_process(void *arg, eap_handler_t *handler)
  248 {
  249     int rcode;
  250     int ret = 0;
  251     fr_tls_status_t status;
  252     rlm_eap_ttls_t *inst = (rlm_eap_ttls_t *) arg;
  253     tls_session_t *tls_session = (tls_session_t *) handler->opaque;
  254     ttls_tunnel_t *t = (ttls_tunnel_t *) tls_session->opaque;
  255     REQUEST *request = handler->request;
  256 
  257     RDEBUG2("Authenticate");
  258 
  259     tls_session->length_flag = inst->include_length;
  260 
  261     /*
  262      *  Process TLS layer until done.
  263      */
  264     status = eaptls_process(handler);
  265     if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
  266         REDEBUG("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
  267     } else {
  268         RDEBUG3("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
  269     }
  270 
  271     /*
  272      *  Make request available to any SSL callbacks
  273      */
  274     SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request);
  275     switch (status) {
  276     /*
  277      *  EAP-TLS handshake was successful, tell the
  278      *  client to keep talking.
  279      *
  280      *  If this was EAP-TLS, we would just return
  281      *  an EAP-TLS-Success packet here.
  282      */
  283     case FR_TLS_SUCCESS:
  284         if (SSL_session_reused(tls_session->ssl)) {
  285             RDEBUG("Skipping Phase2 due to session resumption");
  286             goto do_keys;
  287         }
  288 
  289         if (t && t->authenticated) {
  290             if (t->accept_vps) {
  291                 RDEBUG2("Using saved attributes from the original Access-Accept");
  292                 rdebug_pair_list(L_DBG_LVL_2, request, t->accept_vps, NULL);
  293                 fr_pair_list_mcopy_by_num(handler->request->reply,
  294                        &handler->request->reply->vps,
  295                        &t->accept_vps, 0, 0, TAG_ANY);
  296             } else if (t->use_tunneled_reply) {
  297                 RDEBUG2("No saved attributes in the original Access-Accept");
  298             }
  299 
  300         do_keys:
  301             /*
  302              *  Success: Automatically return MPPE keys.
  303              */
  304             ret = eaptls_success(handler, 0);
  305             goto done;
  306         } else {
  307             eaptls_request(handler->eap_ds, tls_session);
  308         }
  309         ret = 1;
  310         goto done;
  311 
  312     /*
  313      *  The TLS code is still working on the TLS
  314      *  exchange, and it's a valid TLS request.
  315      *  do nothing.
  316      */
  317     case FR_TLS_HANDLED:
  318         ret = 1;
  319         goto done;
  320 
  321     /*
  322      *  Handshake is done, proceed with decoding tunneled
  323      *  data.
  324      */
  325     case FR_TLS_OK:
  326         break;
  327 
  328     /*
  329      *  Anything else: fail.
  330      */
  331     default:
  332         ret = 0;
  333         goto done;
  334     }
  335 
  336     /*
  337      *  Session is established, proceed with decoding
  338      *  tunneled data.
  339      */
  340     RDEBUG2("Session established.  Proceeding to decode tunneled attributes");
  341 
  342     /*
  343      *  We may need TTLS data associated with the session, so
  344      *  allocate it here, if it wasn't already alloacted.
  345      */
  346     if (!tls_session->opaque) {
  347         tls_session->opaque = ttls_alloc(tls_session, inst);
  348     }
  349 
  350     /*
  351      *  Process the TTLS portion of the request.
  352      */
  353     rcode = eapttls_process(handler, tls_session);
  354     switch (rcode) {
  355     case PW_CODE_ACCESS_REJECT:
  356         eaptls_fail(handler, 0);
  357         ret = 0;
  358         goto done;
  359 
  360         /*
  361          *  Access-Challenge, continue tunneled conversation.
  362          */
  363     case PW_CODE_ACCESS_CHALLENGE:
  364         eaptls_request(handler->eap_ds, tls_session);
  365         ret = 1;
  366         goto done;
  367 
  368         /*
  369          *  Success: Automatically return MPPE keys.
  370          */
  371     case PW_CODE_ACCESS_ACCEPT:
  372         goto do_keys;
  373 
  374         /*
  375          *  No response packet, MUST be proxying it.
  376          *  The main EAP module will take care of discovering
  377          *  that the request now has a "proxy" packet, and
  378          *  will proxy it, rather than returning an EAP packet.
  379          */
  380     case PW_CODE_STATUS_CLIENT:
  381 #ifdef WITH_PROXY
  382         rad_assert(handler->request->proxy != NULL);
  383 #endif
  384         ret = 1;
  385         goto done;
  386 
  387     default:
  388         break;
  389     }
  390 
  391     /*
  392      *  Something we don't understand: Reject it.
  393      */
  394     eaptls_fail(handler, 0);
  395 
  396 done:
  397     SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL);
  398 
  399     return ret;
  400 }
  401 
  402 /*
  403  *  The module name should be the only globally exported symbol.
  404  *  That is, everything else should be 'static'.
  405  */
  406 extern rlm_eap_module_t rlm_eap_ttls;
  407 rlm_eap_module_t rlm_eap_ttls = {
  408     .name       = "eap_ttls",
  409     .instantiate    = mod_instantiate,  /* Create new submodule instance */
  410     .session_init   = mod_session_init, /* Initialise a new EAP session */
  411     .process    = mod_process       /* Process next round of EAP method */
  412 };