]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Make the TLS alert record generate code less crappy...
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sun, 20 Jan 2019 09:56:56 +0000 (16:56 +0700)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sun, 20 Jan 2019 14:44:10 +0000 (21:44 +0700)
Alert fixup

src/lib/tls/base-h
src/lib/tls/session.c

index d1c7f7fa056746b96a04653cd1190c54415d26cb..61bba49f310d70e6feeda7ad6cb0540867491b1d 100644 (file)
@@ -125,6 +125,11 @@ typedef struct _tls_record_t {
        size_t  used;
 } tls_record_t;
 
+typedef enum {
+       TLS_INFO_ORIGIN_RECORD_RECEIVED,
+       TLS_INFO_ORIGIN_RECORD_SENT
+} tls_info_origin_t;
+
 typedef struct _tls_info_t {
        int             origin;
        int             content_type;
@@ -185,11 +190,10 @@ typedef struct _tls_session_t {
 
        void            *opaque;                        //!< Used to store module specific data.
 
-       struct {
-               unsigned int    count;
-               unsigned int    level;
-               unsigned int    description;
-       } handshake_alert;
+       uint8_t         alerts_sent;
+       bool            pending_alert;
+       uint8_t         pending_alert_level;
+       uint8_t         pending_alert_description;
 } tls_session_t;
 
 #ifdef HAVE_OPENSSL_OCSP_H
@@ -573,7 +577,7 @@ int                 tls_session_send(REQUEST *request, tls_session_t *tls_session);
 
 int            tls_session_handshake(REQUEST *request, tls_session_t *tls_session);
 
-int            tls_session_handshake_alert(REQUEST *request, tls_session_t *tls_session, uint8_t level, uint8_t description);
+int            tls_session_alert(REQUEST *request, tls_session_t *tls_session, uint8_t level, uint8_t description);
 
 tls_session_t  *tls_session_init_client(TALLOC_CTX *ctx, fr_tls_conf_t *conf);
 
index b5b9ec91e608aadf59a17c6fa4fe7c76f808bd23..2d8e073e4dab06fc9d8f6d479f63fb02282f8d98 100644 (file)
@@ -1156,16 +1156,21 @@ int tls_session_send(REQUEST *request, tls_session_t *session)
        return 1;
 }
 
+/** Instruct tls_session_handshake to create a synthesised TLS alert record and send it to the peer
+ *
+ */
 int tls_session_handshake_alert(UNUSED REQUEST *request, tls_session_t *session, uint8_t level, uint8_t description)
 {
-       rad_assert(session->handshake_alert.level == 0);
+       if (session->alerts_sent > 3) return -1;                /* Some kind of sate machine brokenness */
 
-       session->handshake_alert.count++;
-       if (session->handshake_alert.count > 3)
-               return -1;
+       /*
+        *      Ignore less severe alerts
+        */
+       if (session->pending_alert && (level < session->pending_alert_level)) return 0;
 
-       session->handshake_alert.level = level;
-       session->handshake_alert.description = description;
+       session->pending_alert = true;
+       session->pending_alert_level = level;
+       session->pending_alert_description = description;
 
        return 0;
 }
@@ -1371,32 +1376,46 @@ int tls_session_handshake(REQUEST *request, tls_session_t *session)
        }
 
        /*
-        *      W would prefer to latch on info.content_type but
-        *      (I think its...) tls_session_msg_cb() updates it
-        *      after the call to tls_session_handshake_alert()
+        *      Trash the current data in dirty_out, and synthesize
+        *      a TLS error record.
+        *
+        *      OpensSL annoyingly provides no mechanism for us to
+        *      do this, and we need to send alerts as part of
+        *      RFC 5216, so this is our only option.
         */
-       if (session->handshake_alert.level) {
+       if (session->pending_alert) {
                /*
                 * FIXME RFC 4851 section 3.6.1 - peer might ACK alert and include a restarted ClientHello
                 *                                 which eap_tls_session_status() will fail on
                 */
+
+               /*
+                *      Update our internal view of the session
+                */
+               session->info.origin = TLS_INFO_ORIGIN_RECORD_SENT;
                session->info.content_type = SSL3_RT_ALERT;
+               session->info.alert_level = session->pending_alert_level;
+               session->info.alert_description = session->pending_alert_description;
 
                session->dirty_out.data[0] = session->info.content_type;
                session->dirty_out.data[1] = 3;
                session->dirty_out.data[2] = 1;
                session->dirty_out.data[3] = 0;
                session->dirty_out.data[4] = 2;
-               session->dirty_out.data[5] = session->handshake_alert.level;
-               session->dirty_out.data[6] = session->handshake_alert.description;
+               session->dirty_out.data[5] = session->pending_alert_level;
+               session->dirty_out.data[6] = session->pending_alert_description;
 
                session->dirty_out.used = 7;
 
-               session->handshake_alert.level = 0;
+               session->pending_alert = false;
+               session->alerts_sent++;
+
+               session_msg_log(request, session);
        }
 
        /* We are done with dirty_in, reinitialize it */
        record_init(&session->dirty_in);
+
        return 1;
 }