]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Rework statefull session resumption so that the session-state list is part of the...
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 24 Jun 2021 00:07:05 +0000 (19:07 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 24 Jun 2021 00:12:36 +0000 (19:12 -0500)
Invert verb order for TLS packet-types so that it matches the sections

Disable the old X509 stack based method of doing stateful revalidation, it wouldn't have worked if the peer included intermediaries, and it caused issues with newer versions of OpenSSL.

16 files changed:
raddb/mods-available/cache_tls
share/dictionary/tls/dictionary.freeradius
src/lib/tls/attrs.h
src/lib/tls/base.c
src/lib/tls/cache.c
src/lib/tls/conf.c
src/lib/tls/session.c
src/lib/tls/verify.c
src/lib/tls/verify.h
src/lib/util/pair.h
src/modules/rlm_eap/types/rlm_eap_fast/rlm_eap_fast.c
src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c
src/modules/rlm_eap/types/rlm_eap_ttls/rlm_eap_ttls.c
src/process/tls/base.c
src/tests/eapol_test/config/tls/mods-enabled/cache [new file with mode: 0644]
src/tests/eapol_test/config/tls/sites-enabled/tls

index 2281c6d4edbadcaf3e7422d84a8f65dc48840747..0b06db3e1ae5eb68093d36fde549f1f6e78b6fe1 100644 (file)
@@ -54,20 +54,7 @@ cache cache_tls_session {
        #  update <section> { ... }::
        #
        update {
-               &session-state.Session-Data := &session-state.Session-Data
-
-               #
-               #  NOTE: If you want to store authorization attributes too, consider
-               #  performing LDAP/SQL lookups in the tls-cache virtual server and
-               #  storing the results in `&session-state`.
-               #
-               #  The complete list can then be restored along with the
-               #  `Session-Data` using the entry below.
-               #
-               #  Policies run in `post-auth` then have access to the same data
-               #  irrespective of whether the session is being resumed.
-               #
-#              &session-state += &session-state
+               &reply.Session-Data := &Session-Data
        }
 }
 
index 79f853868519d1c21c8429e61defea6db351877f..aa8ec41adb9af24bc398f66295431af9f600feee 100644 (file)
 
 ATTRIBUTE      Packet-Type                             1       uint32
 
-VALUE  Packet-Type                     Session-Load            1
-VALUE  Packet-Type                     Session-Store           2
-VALUE  Packet-Type                     Session-Clear           3
-VALUE  Packet-Type                     Certificate-Validate    4
+VALUE  Packet-Type                     Load-Session            1
+VALUE  Packet-Type                     Store-Session           2
+VALUE  Packet-Type                     Clear-Session           3
+VALUE  Packet-Type                     Verify-Certificate      4
 
 #
 #  We use response packet types instead of rcodes so that
@@ -25,3 +25,5 @@ VALUE Packet-Type                     notfound                12
 
 ATTRIBUTE      Session-Id                              10      octets
 ATTRIBUTE      Session-Data                            11      octets
+ATTRIBUTE      Session-Resumed                         12      bool
+ATTRIBUTE      Session-TTL                             13      time_delta
index f54efe5b6d84133590e0366262bd224bdb6cf8d4..b7730400b6fb5c88b83774021179ac350831f80d 100644 (file)
@@ -63,13 +63,15 @@ extern fr_dict_attr_t const *attr_tls_session_version;
 extern fr_dict_attr_t const *attr_tls_packet_type;
 extern fr_dict_attr_t const *attr_tls_session_data;
 extern fr_dict_attr_t const *attr_tls_session_id;
+extern fr_dict_attr_t const *attr_tls_session_resumed;
+extern fr_dict_attr_t const *attr_tls_session_ttl;
 
 extern fr_dict_attr_t const *attr_framed_mtu;
 
-extern fr_value_box_t const *enum_tls_packet_type_session_load;
-extern fr_value_box_t const *enum_tls_packet_type_session_store;
-extern fr_value_box_t const *enum_tls_packet_type_session_clear;
-extern fr_value_box_t const *enum_tls_packet_type_certificate_validate;
+extern fr_value_box_t const *enum_tls_packet_type_load_session;
+extern fr_value_box_t const *enum_tls_packet_type_store_session;
+extern fr_value_box_t const *enum_tls_packet_type_clear_session;
+extern fr_value_box_t const *enum_tls_packet_type_verify_certificate;
 
 extern fr_value_box_t const *enum_tls_packet_type_success;
 extern fr_value_box_t const *enum_tls_packet_type_failure;
index 92103efff3357520631e30f7202a3437078eb5d8..4efe8cbcc808e27af808f2b3d4227c9c3fcfc4e6 100644 (file)
@@ -105,6 +105,8 @@ fr_dict_attr_t const *attr_framed_mtu;
 fr_dict_attr_t const *attr_tls_packet_type;
 fr_dict_attr_t const *attr_tls_session_data;
 fr_dict_attr_t const *attr_tls_session_id;
+fr_dict_attr_t const *attr_tls_session_resumed;
+fr_dict_attr_t const *attr_tls_session_ttl;
 
 extern fr_dict_attr_autoload_t tls_dict_attr[];
 fr_dict_attr_autoload_t tls_dict_attr[] = {
@@ -149,16 +151,18 @@ fr_dict_attr_autoload_t tls_dict_attr[] = {
        { .out = &attr_tls_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_tls },
        { .out = &attr_tls_session_data, .name = "Session-Data", .type = FR_TYPE_OCTETS, .dict = &dict_tls },
        { .out = &attr_tls_session_id, .name = "Session-Id", .type = FR_TYPE_OCTETS, .dict = &dict_tls },
+       { .out = &attr_tls_session_resumed, .name = "Session-Resumed", .type = FR_TYPE_BOOL, .dict = &dict_tls },
+       { .out = &attr_tls_session_ttl, .name = "Session-TTL", .type = FR_TYPE_TIME_DELTA, .dict = &dict_tls },
        { NULL }
 };
 
 /*
  *     request types
  */
-fr_value_box_t const   *enum_tls_packet_type_session_load;
-fr_value_box_t const   *enum_tls_packet_type_session_store;
-fr_value_box_t const   *enum_tls_packet_type_session_clear;
-fr_value_box_t const   *enum_tls_packet_type_certificate_validate;
+fr_value_box_t const   *enum_tls_packet_type_load_session;
+fr_value_box_t const   *enum_tls_packet_type_store_session;
+fr_value_box_t const   *enum_tls_packet_type_clear_session;
+fr_value_box_t const   *enum_tls_packet_type_verify_certificate;
 
 /*
  *     response types
@@ -169,10 +173,10 @@ fr_value_box_t const      *enum_tls_packet_type_notfound;
 
 extern fr_dict_enum_autoload_t tls_dict_enum[];
 fr_dict_enum_autoload_t tls_dict_enum[] = {
-       { .out = &enum_tls_packet_type_session_load, .name = "Session-Load", .attr = &attr_tls_packet_type },
-       { .out = &enum_tls_packet_type_session_store, .name = "Session-Store", .attr = &attr_tls_packet_type },
-       { .out = &enum_tls_packet_type_session_clear, .name = "Session-Clear", .attr = &attr_tls_packet_type },
-       { .out = &enum_tls_packet_type_certificate_validate, .name = "Certificate-Validate", .attr = &attr_tls_packet_type },
+       { .out = &enum_tls_packet_type_load_session, .name = "Load-Session", .attr = &attr_tls_packet_type },
+       { .out = &enum_tls_packet_type_store_session, .name = "Store-Session", .attr = &attr_tls_packet_type },
+       { .out = &enum_tls_packet_type_clear_session, .name = "Clear-Session", .attr = &attr_tls_packet_type },
+       { .out = &enum_tls_packet_type_verify_certificate, .name = "Verify-Certificate", .attr = &attr_tls_packet_type },
 
        { .out = &enum_tls_packet_type_success, .name = "Success", .attr = &attr_tls_packet_type },
        { .out = &enum_tls_packet_type_failure, .name = "Failure", .attr = &attr_tls_packet_type },
index 522511b0bfe97348b5b0953f54abcd4a4e0fd44c..61404f10ccb68debc018d262b801d9c2e21fef07 100644 (file)
@@ -29,6 +29,8 @@ USES_APPLE_DEPRECATED_API     /* OpenSSL API has been deprecated by Apple */
 #ifdef WITH_TLS
 #define LOG_PREFIX "tls - "
 
+#include <openssl/ssl.h>
+
 #include <freeradius-devel/internal/internal.h>
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/server/module.h>
@@ -105,6 +107,143 @@ void tls_cache_clear_state_reset(fr_tls_cache_t *cache)
        cache->clear.state = FR_TLS_CACHE_CLEAR_INIT;
 }
 
+/** Serialize the session-state list and store it in the SSL_SESSION *
+ *
+ */
+static int tls_cache_app_data_set(request_t *request, SSL_SESSION *sess)
+{
+       fr_dbuff_t              dbuff;
+       fr_dbuff_uctx_talloc_t  tctx;
+       fr_dcursor_t            dcursor;
+       fr_pair_t               *vp;
+       ssize_t                 slen;
+       int                     ret;
+
+       RDEBUG2("Adding &session-state[*] to session-ticket");
+       RINDENT();
+       log_request_pair_list(L_DBG_LVL_2, request, NULL, &request->session_state_pairs, NULL);
+       REXDENT();
+
+       /*
+        *      Absolute maximum is `0..2^16-1`.
+        *
+        *      We leave OpenSSL 2k to add anything else
+        */
+       MEM(fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 1024, 1024 * 62));
+
+       /*
+        *      Encode the session-state contents and
+        *      add it to the ticket.
+        */
+       for (vp = fr_dcursor_init(&dcursor, &request->session_state_pairs);
+            vp;
+            vp = fr_dcursor_current(&dcursor)) {
+               slen = fr_internal_encode_pair(&dbuff, &dcursor, NULL);
+               if (slen < 0) {
+                       RPERROR("Failed serialising session-state list");
+                       fr_dbuff_free_talloc(&dbuff);
+                       return 0;
+               }
+       }
+
+       RHEXDUMP4(fr_dbuff_start(&dbuff), fr_dbuff_used(&dbuff), "session-ticket application data");
+
+       /*
+        *      Pass the serialized session-state list
+        *      over to OpenSSL.
+        */
+       ret = SSL_SESSION_set1_ticket_appdata(sess, fr_dbuff_start(&dbuff), fr_dbuff_used(&dbuff));
+       fr_dbuff_free_talloc(&dbuff);   /* OpenSSL memdups the data */
+       if (ret != 1) {
+               fr_tls_log_error(request, "Failed setting application data for session-ticket");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int tls_cache_app_data_get(request_t *request, SSL_SESSION *sess)
+{
+       uint8_t                 *data;
+       size_t                  data_len;
+       fr_dbuff_t              dbuff;
+       fr_pair_list_t          tmp;
+       fr_dcursor_t            cursor;
+
+       /*
+        *      Extract the session-state list from the ticket.
+        */
+       if (SSL_SESSION_get0_ticket_appdata(sess, (void **)&data, &data_len) != 1) {
+               fr_tls_log_error(request, "Failed retrieving application data from session");
+               return -1;
+       }
+
+       fr_pair_list_init(&tmp);
+       fr_dcursor_init(&cursor, &tmp);
+       fr_dbuff_init(&dbuff, data, data_len);
+
+       RHEXDUMP4(fr_dbuff_start(&dbuff), fr_dbuff_len(&dbuff), "session application data");
+
+       /*
+        *      Decode the session-state data into a temporary list.
+        *
+        *      It's very important that we decode _all_ attributes,
+        *      or disallow session resumption.
+        */
+       while (fr_dbuff_remaining(&dbuff) > 0) {
+               if (fr_internal_decode_pair_dbuff(request->session_state_ctx, &cursor,
+                                                 request->dict, &dbuff, NULL) < 0) {
+                       fr_pair_list_free(&tmp);
+                       RPEDEBUG("Failed decoding session-state");
+                       return -1;
+               }
+       }
+
+       RDEBUG2("Restoring &session-state[*] from session");
+       RINDENT();
+       log_request_pair_list(L_DBG_LVL_2, request, NULL, &tmp, "&session-state.");
+       REXDENT();
+
+       fr_pair_list_append(&request->session_state_pairs, &tmp);
+
+       return 0;
+}
+
+/** Delete session data be deleted from the cache
+ *
+ * @param[in] sess to be deleted.
+ */
+static void tls_cache_delete_request(SSL_SESSION *sess)
+{
+       fr_tls_session_t        *tls_session;
+       fr_tls_cache_t          *tls_cache;
+       request_t               *request;
+
+       tls_session = talloc_get_type_abort(SSL_SESSION_get_ex_data(sess, FR_TLS_EX_INDEX_TLS_SESSION), fr_tls_session_t);
+
+       if (!tls_session->cache) return;
+
+       request = fr_tls_session_request(tls_session->ssl);
+       tls_cache = tls_session->cache;
+
+       fr_assert(tls_cache->clear.state == FR_TLS_CACHE_CLEAR_INIT);
+
+       /*
+        *      Record the session to delete
+        */
+       tls_cache->clear.id = fr_tls_cache_id(tls_cache, sess);
+       if (!tls_cache->clear.id) {
+               RWDEBUG("Error retrieving Session ID");
+               return;
+       }
+
+       RDEBUG3("Requested session delete - ID %pV", fr_box_octets_buffer(tls_cache->clear.id));
+
+       tls_cache->clear.state = FR_TLS_CACHE_CLEAR_REQUESTED;
+
+       ASYNC_pause_job();      /* Go do the delete _now_ */
+}
+
 /** Process the result of `session load { ... }`
  */
 static unlang_action_t tls_cache_load_result(UNUSED rlm_rcode_t *p_result, UNUSED int *priority,
@@ -124,7 +263,7 @@ static unlang_action_t tls_cache_load_result(UNUSED rlm_rcode_t *p_result, UNUSE
                return UNLANG_ACTION_CALCULATE_RESULT;
        }
 
-       vp = fr_pair_find_by_da(&request->session_state_pairs, attr_tls_session_data, 0);
+       vp = fr_pair_find_by_da(&request->reply_pairs, attr_tls_session_data, 0);
        if (!vp) {
                RWDEBUG("No cached session found");
                goto error;
@@ -139,6 +278,7 @@ static unlang_action_t tls_cache_load_result(UNUSED rlm_rcode_t *p_result, UNUSE
                goto error;
        }
        RDEBUG3("Read %zu bytes of session data.  Session deserialized successfully", vp->vp_length);
+       if (RDEBUG_ENABLED3) SSL_SESSION_print(fr_tls_request_log_bio(request, L_DBG, L_DBG_LVL_3), sess);
 
        /*
         *      OpenSSL's API is very inconsistent.
@@ -149,29 +289,11 @@ static unlang_action_t tls_cache_load_result(UNUSED rlm_rcode_t *p_result, UNUSE
         *      ex_data is not serialised in i2d_SSL_SESSION
         *      so we don't have to bother unsetting it.
         */
-       SSL_SESSION_set_ex_data(sess, FR_TLS_EX_INDEX_TLS_SESSION,
-                               SSL_get_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_TLS_SESSION));
+       SSL_SESSION_set_ex_data(sess, FR_TLS_EX_INDEX_TLS_SESSION, fr_tls_session(tls_session->ssl));
 
        tls_cache->load.state = FR_TLS_CACHE_LOAD_RETRIEVED;
        tls_cache->load.sess = sess;    /* This is consumed in tls_cache_load_cb */
 
-#if 0
-       /*
-        *      We set the session here temporarily so that
-        *      the certificate validation can run.
-        *
-        *      FIXME - Do ASYNC session cert validation.
-        */
-       SSL_set_session(ssl, sess);             /* Increases ref count */
-
-       if (fr_tls_verify_client_cert_chain(ssl) != 1) {
-               RWDEBUG("Validation failed, forcefully expiring resumed session");
-               SSL_SESSION_set_timeout(sess, 0);
-       }
-
-       SSL_remove_session(ssl, sess);          /* Decreases ref count */
-#endif
-
        return UNLANG_ACTION_CALCULATE_RESULT;
 }
 
@@ -190,6 +312,7 @@ static unlang_action_t tls_cache_load_push(request_t *request, fr_tls_session_t
        fr_tls_conf_t           *conf = fr_tls_session_conf(tls_session->ssl);
        request_t               *child;
        fr_pair_t               *vp;
+       unlang_action_t         ua;
 
        if (tls_cache->load.state != FR_TLS_CACHE_LOAD_REQUESTED) return UNLANG_ACTION_CALCULATE_RESULT;
 
@@ -203,7 +326,7 @@ static unlang_action_t tls_cache_load_push(request_t *request, fr_tls_session_t
         *      session resumption data.
         */
        MEM(pair_prepend_request(&vp, attr_tls_packet_type) >= 0);
-       vp->vp_uint32 = enum_tls_packet_type_session_load->vb_uint32;
+       vp->vp_uint32 = enum_tls_packet_type_load_session->vb_uint32;
 
        /*
         *      Add the session identifier we're
@@ -215,13 +338,14 @@ static unlang_action_t tls_cache_load_push(request_t *request, fr_tls_session_t
         *      Allocate a child, and set it up to call
         *      the TLS virtual server.
         */
-       if (fr_tls_call_push(child, tls_cache_load_result, conf, tls_session) < 0) {
+       ua = fr_tls_call_push(child, tls_cache_load_result, conf, tls_session);
+       if (ua < 0) {
                talloc_free(child);
                tls_cache_load_state_reset(tls_cache);
                return UNLANG_ACTION_FAIL;
        }
 
-       return UNLANG_ACTION_CALCULATE_RESULT;
+       return ua;
 }
 
 /** Process the result of `session store { ... }`
@@ -267,10 +391,24 @@ unlang_action_t tls_cache_store_push(request_t *request, fr_tls_conf_t *conf, fr
        request_t               *child;
        fr_pair_t               *vp;
        SSL_SESSION             *sess = tls_session->cache->store.sess;
+       unlang_action_t         ua;
+       fr_time_t               expires = fr_time_from_sec((time_t)(SSL_SESSION_get_time(sess) + SSL_get_timeout(sess)));
+       fr_time_t               now = fr_time();
 
        fr_assert(tls_cache->store.sess);
        fr_assert(tls_cache->store.state == FR_TLS_CACHE_STORE_REQUESTED);
 
+       if (expires <= now) {
+               RWDEBUG("Session has already expired, not storing");
+               return UNLANG_ACTION_CALCULATE_RESULT;
+       }
+
+       /*
+        *      Add the current session-state list
+        *      contents to the ssl-data
+        */
+       if (tls_cache_app_data_set(request, sess) < 0) return UNLANG_ACTION_FAIL;
+
        MEM(child = unlang_subrequest_alloc(request, dict_tls));
        request = child;
 
@@ -279,7 +417,7 @@ unlang_action_t tls_cache_store_push(request_t *request, fr_tls_conf_t *conf, fr
         *      session resumption data.
         */
        MEM(pair_prepend_request(&vp, attr_tls_packet_type) >= 0);
-       vp->vp_uint32 = enum_tls_packet_type_session_store->vb_uint32;
+       vp->vp_uint32 = enum_tls_packet_type_store_session->vb_uint32;
 
        /*
         *      Add the session identifier we're trying
@@ -288,6 +426,12 @@ unlang_action_t tls_cache_store_push(request_t *request, fr_tls_conf_t *conf, fr
        MEM(pair_update_request(&vp, attr_tls_session_id) >= 0);
        fr_pair_value_memdup_buffer_shallow(vp, fr_tls_cache_id(vp, sess), true);
 
+       /*
+        *      How long the session has to live
+        */
+       MEM(pair_update_request(&vp, attr_tls_session_ttl) >= 0);
+       vp->vp_time_delta = fr_time_delta_from_nsec(expires - now);
+
        /*
         *      Serialize the session
         */
@@ -304,6 +448,7 @@ unlang_action_t tls_cache_store_push(request_t *request, fr_tls_conf_t *conf, fr
 
        MEM(pair_update_request(&vp, attr_tls_session_data) >= 0);
        MEM(data = talloc_array(vp, uint8_t, len));
+
        /* openssl mutates &p */
        p = data;
        ret = i2d_SSL_SESSION(sess, &p);        /* Serialize as ASN.1 */
@@ -319,9 +464,10 @@ unlang_action_t tls_cache_store_push(request_t *request, fr_tls_conf_t *conf, fr
         *      Allocate a child, and set it up to call
         *      the TLS virtual server.
         */
-       if (fr_tls_call_push(child, tls_cache_store_result, conf, tls_session) < 0) goto error;
+       ua = fr_tls_call_push(child, tls_cache_store_result, conf, tls_session);
+       if (ua < 0) goto error;
 
-       return UNLANG_ACTION_PUSHED_CHILD;
+       return ua;
 }
 
 /** Process the result of `session clear { ... }`
@@ -362,6 +508,7 @@ unlang_action_t tls_cache_clear_push(request_t *request, fr_tls_conf_t *conf, fr
        request_t       *child;
        fr_pair_t       *vp;
        fr_tls_cache_t  *tls_cache = tls_session->cache;
+       unlang_action_t ua;
 
        fr_assert(tls_cache->clear.state == FR_TLS_CACHE_CLEAR_REQUESTED);
        fr_assert(tls_cache->clear.id);
@@ -369,21 +516,12 @@ unlang_action_t tls_cache_clear_push(request_t *request, fr_tls_conf_t *conf, fr
        MEM(child = unlang_subrequest_alloc(request, dict_tls));
        request = child;
 
-       /*
-        *      We never managed to store the session
-        *      so don't bother trying to clear it.
-        */
-       if (tls_cache->store.state != FR_TLS_CACHE_STORE_PERSISTED) {
-               tls_cache_clear_state_reset(tls_cache);
-               return UNLANG_ACTION_CALCULATE_RESULT;
-       }
-
        /*
         *      Setup the child request for loading
         *      session resumption data.
         */
        MEM(pair_prepend_request(&vp, attr_tls_packet_type) >= 0);
-       vp->vp_uint32 = enum_tls_packet_type_session_clear->vb_uint32;
+       vp->vp_uint32 = enum_tls_packet_type_clear_session->vb_uint32;
 
        /*
         *      Add the session identifier we're
@@ -395,13 +533,14 @@ unlang_action_t tls_cache_clear_push(request_t *request, fr_tls_conf_t *conf, fr
         *      Allocate a child, and set it up to call
         *      the TLS virtual server.
         */
-       if (fr_tls_call_push(child, tls_cache_clear_result, conf, tls_session) < 0) {
+       ua = fr_tls_call_push(child, tls_cache_clear_result, conf, tls_session);
+       if (ua < 0) {
                talloc_free(child);
                tls_cache_clear_state_reset(tls_cache);
                return UNLANG_ACTION_FAIL;
        }
 
-       return UNLANG_ACTION_CALCULATE_RESULT;
+       return ua;
 }
 
 /** Push a `session store { ... }` or session clear { ... }` or `session load { ... }` depending on what operations are pending
@@ -433,8 +572,18 @@ unlang_action_t fr_tls_cache_pending_push(request_t *request, fr_tls_session_t *
        if (tls_cache->clear.state == FR_TLS_CACHE_CLEAR_REQUESTED) {
                /*
                 *      Abort any pending store operations
+                *      if they were for the same ID as
+                *      we're now trying to clear.
                 */
-               if (tls_cache->store.state == FR_TLS_CACHE_STORE_REQUESTED) tls_cache_store_state_reset(tls_cache);
+               if (tls_cache->store.state == FR_TLS_CACHE_STORE_REQUESTED) {
+                       unsigned int    len;
+                       uint8_t const   *id;
+
+                       id = SSL_SESSION_get_id(tls_cache->store.sess, &len);
+                       if ((len == talloc_array_length(tls_cache->clear.id)) &&
+                           (memcmp(tls_cache->clear.id, id, len) == 0)) tls_cache_store_state_reset(tls_cache);
+               }
+
                return tls_cache_clear_push(request, conf, tls_session);
        }
 
@@ -471,7 +620,7 @@ static int tls_cache_store_cb(SSL *ssl, SSL_SESSION *sess)
         *      of the tls_session, as the fields aren't re-populated on
         *      resumption.
         */
-       tls_session = talloc_get_type_abort(SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TLS_SESSION), fr_tls_session_t);
+       tls_session = fr_tls_session(ssl);
        request = fr_tls_session_request(tls_session->ssl);
        tls_cache = tls_session->cache;
 
@@ -506,9 +655,8 @@ static SSL_SESSION *tls_cache_load_cb(SSL *ssl,
        fr_tls_session_t        *tls_session;
        fr_tls_cache_t          *tls_cache;
        request_t               *request;
-       SSL_SESSION             *sess;
 
-       tls_session = talloc_get_type_abort(SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TLS_SESSION), fr_tls_session_t);
+       tls_session = fr_tls_session(ssl);
        request = fr_tls_session_request(tls_session->ssl);
        tls_cache = tls_session->cache;
 
@@ -536,7 +684,7 @@ again:
                fr_assert(!tls_cache->load.id);
 
                tls_cache->load.state = FR_TLS_CACHE_LOAD_REQUESTED;
-               MEM(tls_cache->load.id = talloc_memdup(tls_cache, (uint8_t const *)key, key_len));
+               MEM(tls_cache->load.id = talloc_typed_memdup(tls_cache, (uint8_t const *)key, key_len));
 
                RDEBUG3("Requested session load - ID %pV", fr_box_octets_buffer(tls_cache->load.id));
                ASYNC_pause_job();
@@ -548,15 +696,57 @@ again:
                break;
 
        case FR_TLS_CACHE_LOAD_RETRIEVED:
+       {
                TALLOC_FREE(tls_cache->load.id);
 
                RDEBUG3("Setting session data");
 
+               /*
+                *      This restores the contents of &session-state[*]
+                *      which hopefully still contains all the certificate
+                *      pairs.
+                *
+                *      Although the SSL_SESSION does contain a copy of
+                *      the peer's certificate, it does not contain the
+                *      peer's certificate chain, and so isn't reliable
+                *      for performing re-validation.
+                */
+               if (tls_cache_app_data_get(request, tls_cache->load.sess) < 0) {
+                       REDEBUG("Denying session resumption via session-id");
+               verify_error:
+                       /*
+                        *      Request the session be deleted the next
+                        *      time something calls cache action pending.
+                        */
+                       tls_cache_delete_request(tls_cache->load.sess);
+                       tls_cache_load_state_reset(tls_session->cache); /* Free the session */
+                       return NULL;
+               }
+
+               /*
+                *      This sets the validation state of the tls_session
+                *      so that when we call ASYNC_pause_job(), and execution
+                *      jumps back to tls_session_async_handshake_cont
+                *      (just under SSL_read())
+                *      the code there knows what job it needs to push onto
+                *      the unlang stack.
+                */
+               fr_tls_verify_client_cert_request(tls_session, true);
+
+               ASYNC_pause_job();
+
+               /*
+                *      If we couldn't validate the client certificate
+                *      then validation overall fails.
+                */
+               if (!fr_tls_verify_client_cert_result(tls_session)) {
+                       RDEBUG2("Certificate re-validation failed, denying session resumption via session-id");
+                       goto verify_error;
+               }
+
                *copy = 0;
-               tls_cache->load.state = FR_TLS_CACHE_LOAD_INIT; /* Reset state */
-               sess = tls_cache->load.sess;
-               tls_cache->load.sess = NULL;
-               return sess;
+       }
+               return tls_cache->load.sess;
 
        case FR_TLS_CACHE_LOAD_FAILED:
                RDEBUG3("Session data load failed");
@@ -576,31 +766,14 @@ again:
  */
 static void tls_cache_delete_cb(UNUSED SSL_CTX *ctx, SSL_SESSION *sess)
 {
-       fr_tls_session_t        *tls_session;
-       fr_tls_cache_t          *tls_cache;
-       request_t               *request;
-
-       tls_session = talloc_get_type_abort(SSL_SESSION_get_ex_data(sess, FR_TLS_EX_INDEX_TLS_SESSION), fr_tls_session_t);
-
-       if (!tls_session->cache) return;
-
-       request = fr_tls_session_request(tls_session->ssl);
-       tls_cache = tls_session->cache;
-
-       fr_assert(tls_cache->clear.state == FR_TLS_CACHE_CLEAR_INIT);
-
-       RDEBUG3("Requested session delete - ID %pV", fr_box_octets_buffer(tls_cache->clear.id));
-
        /*
-        *      Record the session to delete
+        *      Not sure why this happens, but sometimes SSL_SESSION *s
+        *      make it here without the correct ex data.
+        *
+        *      Maybe it's one OpenSSL created internally?
         */
-       tls_cache->clear.id = fr_tls_cache_id(tls_cache, sess);
-       if (!tls_cache->clear.id) {
-               RWDEBUG("Error retrieving Session ID");
-               return;
-       }
-
-       tls_cache->clear.state = FR_TLS_CACHE_CLEAR_REQUESTED;
+       if (!SSL_SESSION_get_ex_data(sess, FR_TLS_EX_INDEX_TLS_SESSION)) return;
+       tls_cache_delete_request(sess);
 }
 
 /** Prevent a TLS session from being resumed in future
@@ -621,14 +794,14 @@ int fr_tls_cache_disable_cb(SSL *ssl, int is_forward_secure)
        fr_tls_session_t        *tls_session;
        fr_pair_t               *vp;
 
-       tls_session = talloc_get_type_abort(SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TLS_SESSION), fr_tls_session_t);
+       tls_session = fr_tls_session(ssl);
        request = fr_tls_session_request(tls_session->ssl);
 
        {
                fr_tls_conf_t *conf;
 
                conf = talloc_get_type_abort(SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF), fr_tls_conf_t);
-               if (conf->cache.require_extms && (SSL_get_extms_support(tls_session->ssl) != 1)) {
+               if (conf->cache.require_extms && (SSL_get_extms_support(tls_session->ssl) == 0)) {
                        RDEBUG2("Client does not support the Extended Master Secret extension, "
                                "denying session resumption");
                        goto disable;
@@ -774,12 +947,6 @@ static int tls_cache_session_ticket_app_data_set(SSL *ssl, void *arg)
        fr_tls_cache_conf_t     *tls_cache_conf = arg;  /* Not talloced */
        SSL_SESSION             *sess;
        request_t               *request;
-       ssize_t                 slen;
-       fr_dbuff_t              dbuff;
-       fr_dbuff_uctx_talloc_t  tctx;
-       fr_dcursor_t            dcursor;
-       fr_pair_t               *vp;
-       int                     ret;
 
        /*
         *      Check to see if we have a request bound
@@ -814,45 +981,7 @@ static int tls_cache_session_ticket_app_data_set(SSL *ssl, void *arg)
                return 0;
        }
 
-       RDEBUG2("Adding &session-state[*] to session-ticket");
-       RINDENT();
-       log_request_pair_list(L_DBG_LVL_2, request, NULL, &request->session_state_pairs, NULL);
-       REXDENT();
-
-       /*
-        *      Absolute maximum is `0..2^16-1`.
-        *
-        *      We leave OpenSSL 2k to add anything else
-        */
-       MEM(fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 1024, 1024 * 62));
-
-       /*
-        *      Encode the session-state contents and
-        *      add it to the ticket.
-        */
-       for (vp = fr_dcursor_init(&dcursor, &request->session_state_pairs);
-            vp;
-            vp = fr_dcursor_current(&dcursor)) {
-               slen = fr_internal_encode_pair(&dbuff, &dcursor, NULL);
-               if (slen < 0) {
-                       RPERROR("Failed serialising session-state list");
-                       fr_dbuff_free_talloc(&dbuff);
-                       return 0;
-               }
-       }
-
-       RHEXDUMP4(fr_dbuff_start(&dbuff), fr_dbuff_used(&dbuff), "session-ticket application data");
-
-       /*
-        *      Pass the serialized session-state list
-        *      over to OpenSSL.
-        */
-       ret = SSL_SESSION_set1_ticket_appdata(sess, fr_dbuff_start(&dbuff), fr_dbuff_used(&dbuff));
-       fr_dbuff_free_talloc(&dbuff);   /* OpenSSL memdups the data */
-       if (ret != 1) {
-               fr_tls_log_error(request, "Failed setting application data for session-ticket");
-               return 0;
-       }
+       if (tls_cache_app_data_set(request, sess) < 0) return 0;
 
        return 1;
 }
@@ -871,11 +1000,6 @@ static SSL_TICKET_RETURN tls_cache_session_ticket_app_data_get(SSL *ssl, SSL_SES
        fr_tls_conf_t           *conf = fr_tls_session_conf(tls_session->ssl);
        fr_tls_cache_conf_t     *tls_cache_conf = arg;  /* Not talloced */
        request_t               *request = NULL;
-       uint8_t                 *data;
-       size_t                  data_len;
-       fr_dbuff_t              dbuff;
-       fr_pair_list_t          tmp;
-       fr_dcursor_t            cursor;
 
        if (fr_tls_session_request_bound(ssl)) request = fr_tls_session_request(ssl);
 
@@ -904,53 +1028,31 @@ static SSL_TICKET_RETURN tls_cache_session_ticket_app_data_get(SSL *ssl, SSL_SES
        }
 
        /*
-        *      Extract the session-state list from the ticket.
-        */
-       if (SSL_SESSION_get0_ticket_appdata(sess, (void **)&data, &data_len) != 1) {
-               fr_tls_log_error(request, "Failed retrieving application data from session-ticket, "
-                                "denying session resumption via session-ticket");
-               return SSL_TICKET_RETURN_IGNORE_RENEW;
-       }
-
-       fr_pair_list_init(&tmp);
-       fr_dcursor_init(&cursor, &tmp);
-       fr_dbuff_init(&dbuff, data, data_len);
-
-       RHEXDUMP4(fr_dbuff_start(&dbuff), fr_dbuff_len(&dbuff), "session-ticket application data");
-
-       /*
-        *      Decode the session-state data into a temporary list.
+        *      This restores the contents of &session-state[*]
+        *      which hopefully still contains all the certificate
+        *      pairs.
         *
-        *      It's very important that we decode _all_ attributes,
-        *      or disallow session resumption.
+        *      Although the SSL_SESSION does contain a copy of
+        *      the peer's certificate, it does not contain the
+        *      peer's certificate chain, and so isn't reliable
+        *      for performing re-validation.
         */
-       while (fr_dbuff_remaining(&dbuff) > 0) {
-               if (fr_internal_decode_pair_dbuff(request->session_state_ctx, &cursor,
-                                                 request->dict, &dbuff, NULL) < 0) {
-                       fr_pair_list_free(&tmp);
-                       RPEDEBUG("Failed decoding session-state, denying session resumption via session-ticket");
-                       return SSL_TICKET_RETURN_IGNORE_RENEW;
-               }
+       if (tls_cache_app_data_get(request, sess) < 0) {
+               REDEBUG("Denying session resumption via session-ticket");
+               return SSL_TICKET_RETURN_IGNORE_RENEW;
        }
 
-       RDEBUG2("Restoring &session-state[*] from session-ticket");
-       RINDENT();
-       log_request_pair_list(L_DBG_LVL_2, request, NULL, &tmp, "&session-state.");
-       REXDENT();
-
-       fr_pair_list_append(&request->session_state_pairs, &tmp);
-
        if (conf->virtual_server && tls_session->verify_client_cert) {
                RDEBUG2("Requesting certificate re-validation for session-ticket");
                /*
                 *      This sets the validation state of the tls_session
                 *      so that when we call ASYNC_pause_job(), and execution
                 *      jumps back to tls_session_async_handshake_cont
-                *      (just under SSL_read())
+                *      (just under SSL_read())
                 *      the code there knows what job it needs to push onto
                 *      the unlang stack.
                 */
-               fr_tls_verify_client_cert_request(tls_session);
+               fr_tls_verify_client_cert_request(tls_session, true);
 
                ASYNC_pause_job();
 
@@ -959,7 +1061,7 @@ static SSL_TICKET_RETURN tls_cache_session_ticket_app_data_get(SSL *ssl, SSL_SES
                 *      give the client the opportunity to send a new
                 *      one, but _don't_ allow session resumption.
                 */
-               if (!fr_tls_verify_client_cert_successful(tls_session)) {
+               if (!fr_tls_verify_client_cert_result(tls_session)) {
                        RDEBUG2("Certificate re-validation failed, denying session resumption via session-ticket");
                        return SSL_TICKET_RETURN_IGNORE_RENEW;
                }
index 3a1fd29e3093f559b5a131fe629225ce72fe9866..b1b7940044199a5c022a6eaf06ef1e8e5ba9e1de 100644 (file)
@@ -90,7 +90,7 @@ static CONF_PARSER tls_cache_config[] = {
        { FR_CONF_OFFSET("lifetime", FR_TYPE_UINT32, fr_tls_cache_conf_t, lifetime), .dflt = "86400" },
 
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
-       { FR_CONF_OFFSET("require_extended_master_secret", FR_TYPE_BOOL, fr_tls_cache_conf_t, require_extms), .dflt = "no" },
+       { FR_CONF_OFFSET("require_extended_master_secret", FR_TYPE_BOOL, fr_tls_cache_conf_t, require_extms), .dflt = "yes" },
        { FR_CONF_OFFSET("require_perfect_forward_secrecy", FR_TYPE_BOOL, fr_tls_cache_conf_t, require_pfs), .dflt = "no" },
 #endif
 
@@ -190,7 +190,7 @@ CONF_PARSER fr_tls_server_config[] = {
 
        { FR_CONF_OFFSET("tls_min_version", FR_TYPE_FLOAT32, fr_tls_conf_t, tls_min_version), .dflt = "1.2" },
 
-       { FR_CONF_OFFSET("cache", FR_TYPE_SUBSECTION, fr_tls_conf_t, cache), .subcs = (void const *) tls_cache_config },
+       { FR_CONF_OFFSET("session", FR_TYPE_SUBSECTION, fr_tls_conf_t, cache), .subcs = (void const *) tls_cache_config },
 
        { FR_CONF_OFFSET("verify", FR_TYPE_SUBSECTION, fr_tls_conf_t, verify), .subcs = (void const *) tls_verify_config },
 
@@ -404,20 +404,20 @@ fr_tls_conf_t *fr_tls_conf_parse_server(CONF_SECTION *cs)
                        goto error;
                }
 
-               if (!cf_section_find(conf->virtual_server, "load", "cache")) {
-                       ERROR("Specified virtual_server must contain a \"load cache { ... }\" section "
+               if (!cf_section_find(conf->virtual_server, "load", "session")) {
+                       ERROR("Specified virtual_server must contain a \"load session { ... }\" section "
                              "when cache.mode = \"stateful\"");
                        goto error;
                }
 
-               if (!cf_section_find(conf->virtual_server, "store", "cache")) {
-                       ERROR("Specified virtual_server must contain a \"store cache { ... }\" section "
+               if (!cf_section_find(conf->virtual_server, "store", "session")) {
+                       ERROR("Specified virtual_server must contain a \"store session { ... }\" section "
                              "when cache.mode = \"stateful\"");
                        goto error;
                }
 
-               if (!cf_section_find(conf->virtual_server, "clear", "cache")) {
-                       ERROR("Specified virtual_server must contain a \"clear cache { ... }\" section "
+               if (!cf_section_find(conf->virtual_server, "clear", "session")) {
+                       ERROR("Specified virtual_server must contain a \"clear session { ... }\" section "
                              "when cache.mode = \"stateful\"");
                        goto error;
                }
@@ -437,19 +437,19 @@ fr_tls_conf_t *fr_tls_conf_parse_server(CONF_SECTION *cs)
                        break;
                }
 
-               if (!cf_section_find(conf->virtual_server, "load", "cache")) {
-                       WARN("Specified virtual_server missing \"load cache { ... }\" section. "
+               if (!cf_section_find(conf->virtual_server, "load", "session")) {
+                       WARN("Specified virtual_server missing \"load session { ... }\" section. "
                             "cache.mode = \"auto\" rewritten to cache.mode = \"stateless\"");
                        goto cache_stateless;
                }
 
-               if (!cf_section_find(conf->virtual_server, "store", "cache")) {
-                       WARN("Specified virtual_server missing \"store cache { ... }\" section. "
+               if (!cf_section_find(conf->virtual_server, "store", "session")) {
+                       WARN("Specified virtual_server missing \"store session { ... }\" section. "
                             "cache.mode = \"auto\" rewritten to cache.mode = \"stateless\"");
                        goto cache_stateless;
                }
 
-               if (!cf_section_find(conf->virtual_server, "clear", "cache")) {
+               if (!cf_section_find(conf->virtual_server, "clear", "session")) {
                        WARN("Specified virtual_server missing \"clear cache { ... }\" section. "
                             "cache.mode = \"auto\" rewritten to cache.mode = \"stateless\"");
                        goto cache_stateless;
index 6653ca5032eeab90846c6ecd290bdf5dcbb443dc..d0a59491619363b0fc523605655744190a769451 100644 (file)
@@ -1034,6 +1034,9 @@ static unlang_action_t tls_session_async_handshake_done_round(UNUSED rlm_rcode_t
 {
        fr_tls_session_t        *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
        int                     ret;
+
+       RDEBUG3("entered state %s", __FUNCTION__);
+
        /*
         *      This only occurs once per session, where calling
         *      SSL_read updates the state of the SSL session, setting
@@ -1191,6 +1194,8 @@ static unlang_action_t tls_session_async_handshake_cont(rlm_rcode_t *p_result, i
        fr_tls_session_t        *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
        int                     ret;
 
+       RDEBUG3("(re-)entered state %s", __FUNCTION__);
+
        /*
         *      Magic/More magic? Although SSL_read is normally
         *      used to read application data, it will also
@@ -1237,6 +1242,9 @@ static unlang_action_t tls_session_async_handshake_cont(rlm_rcode_t *p_result, i
        case SSL_ERROR_WANT_ASYNC:      /* Certification validation or cache loads */
        {
                unlang_action_t ua;
+
+               RDEBUG3("Performing async action for OpenSSL");
+
                /*
                 *      Call this function again once we're done
                 *      asynchronously satisfying the load request.
@@ -1311,6 +1319,8 @@ static unlang_action_t tls_session_async_handshake(rlm_rcode_t *p_result, int *p
        fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
        int ret;
 
+       RDEBUG3("entered state %s", __FUNCTION__);
+
        tls_session->result = FR_TLS_RESULT_IN_PROGRESS;
 
        fr_tls_session_request_bind(tls_session->ssl, request);
index d305d9cb73786643841ede6ecd8b525b0809e03e..ef84b576f7c56834208893f981a9174da33c9802 100644 (file)
@@ -199,11 +199,39 @@ int fr_tls_verify_cert_cb(int ok, X509_STORE_CTX *x509_ctx)
        }
 done:
        /*
-        *      This is a client cert
+        *      This is a client cert, call our
+        *      virtual server here.
         */
-       if (depth == 0) tls_session->client_cert_ok = (my_ok > 0);
+       if (depth == 0) {
+               if (conf->virtual_server && tls_session->verify_client_cert) {
+                       RDEBUG2("Requesting certificate validation");
 
-       RDEBUG2("[verify] = %s", my_ok ? "ok" : "invalid");
+                       /*
+                        *      This sets the validation state of the tls_session
+                        *      so that when we call ASYNC_pause_job(), and execution
+                        *      jumps back to tls_session_async_handshake_cont
+                        *      (just under SSL_read())
+                        *      the code there knows what job it needs to push onto
+                        *      the unlang stack.
+                        */
+                       fr_tls_verify_client_cert_request(tls_session, SSL_session_reused(tls_session->ssl));
+
+                       ASYNC_pause_job();
+
+                       /*
+                        *      If we couldn't validate the client certificate
+                        *      then validation overall fails.
+                        */
+                       if (!fr_tls_verify_client_cert_result(tls_session)) {
+                               REDEBUG("Certificate validation failed");
+                               my_ok = 0;
+                               X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_APPLICATION_VERIFICATION);
+                       }
+               }
+
+               tls_session->client_cert_ok = (my_ok > 0);
+               RDEBUG2("[verify] = %s", my_ok ? "ok" : "invalid");
+       }
 
        return my_ok;
 }
@@ -222,7 +250,7 @@ DIAG_ON(DIAG_UNKNOWN_PRAGMAS)
  *     - 1 if the chain could be validated.
  *     - 0 if the chain failed validation.
  */
-int fr_tls_verify_client_cert_chain(SSL *ssl)
+int fr_tls_verify_client_cert_chain(request_t *request, SSL *ssl)
 {
        int             err;
        int             verify;
@@ -233,8 +261,6 @@ int fr_tls_verify_client_cert_chain(SSL *ssl)
        X509_STORE      *store;
        X509_STORE_CTX  *store_ctx;
 
-       request_t       *request = fr_tls_session_request(ssl);
-
        /*
         *      If there's no client certificate, we just return OK.
         */
@@ -319,7 +345,10 @@ static unlang_action_t tls_verify_client_cert_push(request_t *request, fr_tls_se
         *      session resumption data.
         */
        MEM(pair_prepend_request(&vp, attr_tls_packet_type) >= 0);
-       vp->vp_uint32 = enum_tls_packet_type_certificate_validate->vb_uint32;
+       vp->vp_uint32 = enum_tls_packet_type_verify_certificate->vb_uint32;
+
+       MEM(pair_append_request(&vp, attr_tls_session_resumed) >= 0);
+       vp->vp_bool = tls_session->validate.resumed;
 
        /*
         *      Allocate a child, and set it up to call
@@ -335,22 +364,38 @@ static unlang_action_t tls_verify_client_cert_push(request_t *request, fr_tls_se
        return ua;
 }
 
-/** Check we validated the client cert successfully
+/** Clear any previous validation result
  *
+ * Should be called by the validation requestor to get the result and reset
+ * the validation state.
+ *
+ * @return
+ *     - true if the certificate chain was validated.
+ *     - false if the certificate chain failed validation.
  */
-bool fr_tls_verify_client_cert_successful(fr_tls_session_t *tls_session)
+bool fr_tls_verify_client_cert_result(fr_tls_session_t *tls_session)
 {
-       return tls_session->validate.state == FR_TLS_VALIDATION_SUCCESS;
+       bool result;
+
+       fr_assert(tls_session->validate.state != FR_TLS_VALIDATION_INIT);
+
+       result = tls_session->validate.state == FR_TLS_VALIDATION_SUCCESS;
+
+       tls_session->validate.state = FR_TLS_VALIDATION_INIT;
+       tls_session->validate.resumed = false;
+
+       return result;
 }
 
 /** Setup a validation request
  *
  */
-void fr_tls_verify_client_cert_request(fr_tls_session_t *tls_session)
+void fr_tls_verify_client_cert_request(fr_tls_session_t *tls_session, bool session_resumed)
 {
        fr_assert(tls_session->validate.state == FR_TLS_VALIDATION_INIT);
 
        tls_session->validate.state = FR_TLS_VALIDATION_REQUESTED;
+       tls_session->validate.resumed = session_resumed;
 }
 
 /** Push a `verify certificate { ... }` section
index e18cf28a28f32fe871b8942e977f4b57c0406746..309099473cfd4150c735bccf0def91f754935e36 100644 (file)
@@ -61,11 +61,7 @@ typedef struct {
        fr_tls_validation_state_t       state;          //!< Whether OpenSSL has requested
                                                        ///< certificate validation.
 
-       bool                            first_call;     //!< Is this the first call into the validation
-                                                       ///< routine.
-       bool                            have_pairs;     //!< When we entered the validation call we found
-                                                       ///< pre-existing pairs in the session-state list
-                                                       ///< so we will not regenerate the c
+       bool                            resumed;        //!< Whether we're validating a resumed session.
 } fr_tls_verify_t;
 
 #ifdef __cplusplus
@@ -80,11 +76,11 @@ extern "C" {
 
 int            fr_tls_verify_cert_cb(int ok, X509_STORE_CTX *ctx);
 
-int            fr_tls_verify_client_cert_chain(SSL *ssl);
+int            fr_tls_verify_client_cert_chain(request_t *request, SSL *ssl);
 
-bool           fr_tls_verify_client_cert_successful(fr_tls_session_t *tls_session);
+bool           fr_tls_verify_client_cert_result(fr_tls_session_t *tls_session);
 
-void           fr_tls_verify_client_cert_request(fr_tls_session_t *tls_session);
+void           fr_tls_verify_client_cert_request(fr_tls_session_t *tls_session, bool resumed);
 
 unlang_action_t fr_tls_verify_client_cert_pending_push(request_t *request, fr_tls_session_t *tls_session);
 
index ec859e2dfcb962e057dab0160d0001a992af67f7..be80e24a6b86efa27bb45838e55bbed49ddf4853 100644 (file)
@@ -137,6 +137,7 @@ typedef struct {
 #define vp_float64             data.vb_float64
 
 #define vp_date                        data.vb_date
+#define vp_time_delta          data.vb_time_delta
 
 #define vp_group               children
 
index a65b3a01dca94c843154fd5d16a105f188de237b..7ee73822ad9ad9e83baf8872226f26b61293c146 100644 (file)
@@ -463,6 +463,12 @@ static unlang_action_t mod_handshake_resume(rlm_rcode_t *p_result, UNUSED module
                 *      @todo - generate MPPE keys, which have their own magical deriviation.
                 */
 
+               /*
+                *      Result is always OK, even if we fail to persist the
+                *      session data.
+                */
+               *p_result = RLM_MODULE_OK;
+
                /*
                 *      Write the session to the session cache
                 *
index 2075ea211978301fb669ab7515c950dbee43d66e..d1d2d2312dc5decd28bde5131ea4a92e540bdaef 100644 (file)
@@ -72,6 +72,12 @@ fr_dict_attr_autoload_t rlm_eap_tls_dict_attr[] = {
        { NULL }
 };
 
+static unlang_action_t mod_handshake_done(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx,
+                                         UNUSED request_t *request, UNUSED void *rctx)
+{
+       RETURN_MODULE_OK;
+}
+
 static unlang_action_t mod_handshake_resume(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx,
                                            request_t *request, void *rctx)
 {
@@ -103,6 +109,11 @@ static unlang_action_t mod_handshake_resume(rlm_rcode_t *p_result, UNUSED module
 
                if (eap_tls_success(request, eap_session, &prf_label) < 0) RETURN_MODULE_FAIL;
 
+               /*
+                *      Result is always OK, even if we fail to persist the
+                *      session data.
+                */
+               unlang_module_yield(request, mod_handshake_done, NULL, NULL);
                /*
                 *      Write the session to the session cache
                 *
index ca8ff8ec83dffca33eef5c27d45b0d8a6fb95208..e68ab0391398fa2dd856ca462be28d0f1ec4c147 100644 (file)
@@ -170,6 +170,11 @@ static unlang_action_t mod_handshake_resume(rlm_rcode_t *p_result, UNUSED module
                         *      Success: Automatically return MPPE keys.
                         */
                        if (eap_tls_success(request, eap_session, &prf_label) < 0) RETURN_MODULE_FAIL;
+
+                       /*
+                        *      Result is always OK, even if we fail to persist the
+                        *      session data.
+                        */
                        *p_result = RLM_MODULE_OK;
 
                        /*
index bdcc23bf24ac9cf67b17e372c6b163e37e3d5aca..abf440e7bcd0921f098d4b8c46ee621d38265cbe 100644 (file)
@@ -43,10 +43,10 @@ fr_dict_attr_autoload_t process_tls_dict_attr[] = {
 };
 
 typedef struct {
-       CONF_SECTION    *session_load;
-       CONF_SECTION    *session_store;
-       CONF_SECTION    *session_clear;
-       CONF_SECTION    *certificate_validate;
+       CONF_SECTION    *load_session;
+       CONF_SECTION    *store_session;
+       CONF_SECTION    *clear_session;
+       CONF_SECTION    *verify_certificate;
 } process_tls_sections_t;
 
 typedef struct {
@@ -62,7 +62,7 @@ typedef struct {
 #include <freeradius-devel/server/process.h>
 
 static fr_process_state_t const process_state[] = {
-       [FR_PACKET_TYPE_VALUE_SESSION_LOAD] = {
+       [FR_PACKET_TYPE_VALUE_LOAD_SESSION] = {
                .packet_type = {
                        [RLM_MODULE_OK] =       FR_PACKET_TYPE_VALUE_SUCCESS,
                        [RLM_MODULE_UPDATED] =  FR_PACKET_TYPE_VALUE_SUCCESS,
@@ -77,9 +77,9 @@ static fr_process_state_t const process_state[] = {
                .rcode = RLM_MODULE_NOOP,
                .recv = recv_generic,
                .resume = resume_recv_no_send,
-               .section_offset = PROCESS_CONF_OFFSET(session_load),
+               .section_offset = PROCESS_CONF_OFFSET(load_session),
        },
-       [FR_PACKET_TYPE_VALUE_SESSION_STORE] = {
+       [FR_PACKET_TYPE_VALUE_STORE_SESSION] = {
                .packet_type = {
                        [RLM_MODULE_OK] =       FR_PACKET_TYPE_VALUE_SUCCESS,
                        [RLM_MODULE_UPDATED] =  FR_PACKET_TYPE_VALUE_SUCCESS,
@@ -94,9 +94,9 @@ static fr_process_state_t const process_state[] = {
                .rcode = RLM_MODULE_NOOP,
                .recv = recv_generic,
                .resume = resume_recv_no_send,
-               .section_offset = PROCESS_CONF_OFFSET(session_store),
+               .section_offset = PROCESS_CONF_OFFSET(store_session),
        },
-       [FR_PACKET_TYPE_VALUE_SESSION_CLEAR] = {
+       [FR_PACKET_TYPE_VALUE_CLEAR_SESSION] = {
                .packet_type = {
                        [RLM_MODULE_OK] =       FR_PACKET_TYPE_VALUE_SUCCESS,
                        [RLM_MODULE_UPDATED] =  FR_PACKET_TYPE_VALUE_SUCCESS,
@@ -111,14 +111,14 @@ static fr_process_state_t const process_state[] = {
                .rcode = RLM_MODULE_NOOP,
                .recv = recv_generic,
                .resume = resume_recv_no_send,
-               .section_offset = PROCESS_CONF_OFFSET(session_clear),
+               .section_offset = PROCESS_CONF_OFFSET(clear_session),
        },
-       [FR_PACKET_TYPE_VALUE_CERTIFICATE_VALIDATE] = {
+       [FR_PACKET_TYPE_VALUE_VERIFY_CERTIFICATE] = {
                .packet_type = {
                        [RLM_MODULE_OK] =       FR_PACKET_TYPE_VALUE_SUCCESS,
+                       [RLM_MODULE_UPDATED] =  FR_PACKET_TYPE_VALUE_SUCCESS,
+                       [RLM_MODULE_NOOP] =     FR_PACKET_TYPE_VALUE_SUCCESS,
 
-                       [RLM_MODULE_UPDATED] =  FR_PACKET_TYPE_VALUE_FAILURE,
-                       [RLM_MODULE_NOOP] =     FR_PACKET_TYPE_VALUE_FAILURE,
                        [RLM_MODULE_REJECT] =   FR_PACKET_TYPE_VALUE_FAILURE,
                        [RLM_MODULE_FAIL] =     FR_PACKET_TYPE_VALUE_FAILURE,
                        [RLM_MODULE_INVALID] =  FR_PACKET_TYPE_VALUE_FAILURE,
@@ -128,7 +128,7 @@ static fr_process_state_t const process_state[] = {
                .rcode = RLM_MODULE_NOOP,
                .recv = recv_generic,
                .resume = resume_recv_no_send,
-               .section_offset = PROCESS_CONF_OFFSET(certificate_validate),
+               .section_offset = PROCESS_CONF_OFFSET(verify_certificate),
        },
 };
 
@@ -156,25 +156,25 @@ static const virtual_server_compile_t compile_list[] = {
                .name = "store",
                .name2 = "session",
                .component = MOD_AUTHORIZE,
-               .offset = PROCESS_CONF_OFFSET(session_store)
+               .offset = PROCESS_CONF_OFFSET(store_session)
        },
        {
                .name = "load",
                .name2 = "session",
                .component = MOD_AUTHORIZE,
-               .offset = PROCESS_CONF_OFFSET(session_load)
+               .offset = PROCESS_CONF_OFFSET(load_session)
        },
        {
                .name = "clear",
                .name2 = "session",
                .component = MOD_AUTHORIZE,
-               .offset = PROCESS_CONF_OFFSET(session_clear)
+               .offset = PROCESS_CONF_OFFSET(clear_session)
        },
        {
                .name = "verify",
                .name2 = "certificate",
                .component = MOD_AUTHORIZE,
-               .offset = PROCESS_CONF_OFFSET(certificate_validate)
+               .offset = PROCESS_CONF_OFFSET(verify_certificate)
        },
        COMPILE_TERMINATOR
 };
diff --git a/src/tests/eapol_test/config/tls/mods-enabled/cache b/src/tests/eapol_test/config/tls/mods-enabled/cache
new file mode 100644 (file)
index 0000000..fb20ae4
--- /dev/null
@@ -0,0 +1,23 @@
+cache cache_tls_session {
+       #
+       #  driver:: `cache` driver.
+       #
+       driver = "rlm_cache_rbtree"
+
+       #
+       #  key:: The `cache` key.
+       #
+       key = &Session-Id
+
+       #
+       #  ttl:: TTL for `cache` entries.
+       #
+       ttl = 3600
+
+       #
+       #  update <section> { ... }::
+       #
+       update {
+               &reply.Session-Data := &Session-Data
+       }
+}
index 8e0d616935c0c547f23aec16a9669d6efa9aeaf0..c12636a21d68d77278fe0464c36a1aec1ded4acc 100644 (file)
@@ -1,7 +1,29 @@
 server eap-tls-test {
        namespace = tls
 
+       load session {
+               update control {
+                       &control.Cache-Allow-Insert := no
+               }
+               cache_tls_session
+       }
+
+       store session {
+               cache_tls_session
+       }
+
+       clear session {
+               update control {
+                       &control.Cache-Allow-Insert := no
+                       &control.Cache-Allow-Merge := no
+                       &control.Cache-TTL := 0
+               }
+               cache_tls_session
+       }
+
        verify certificate {
-               ok
+               if (&Session-Resumed == true) {
+                       reject
+               }
        }
 }