Author: markt
Date: Wed Oct 10 21:49:55 2018
New Revision: 1843514

URL: http://svn.apache.org/viewvc?rev=1843514&view=rev
Log:
Implement TLS 1.3 support for CLIENT-CERT when the APR/native connector is not 
configured with certificateVerification="required" (i.e. the equivalent of 
server initiated renegotiation to obtain a client cert)

Modified:
    tomcat/native/trunk/native/include/ssl_private.h
    tomcat/native/trunk/native/src/sslnetwork.c
    tomcat/native/trunk/native/src/sslutils.c

Modified: tomcat/native/trunk/native/include/ssl_private.h
URL: 
http://svn.apache.org/viewvc/tomcat/native/trunk/native/include/ssl_private.h?rev=1843514&r1=1843513&r2=1843514&view=diff
==============================================================================
--- tomcat/native/trunk/native/include/ssl_private.h (original)
+++ tomcat/native/trunk/native/include/ssl_private.h Wed Oct 10 21:49:55 2018
@@ -324,7 +324,7 @@ struct tcn_ssl_conf_ctxt_t {
     SSL_CONF_CTX    *cctx;
 };
 #endif
-  
+
 typedef struct {
     apr_pool_t     *pool;
     tcn_ssl_ctxt_t *ctx;
@@ -335,7 +335,7 @@ typedef struct {
      * that all client-initiated renegotiations can be rejected, as a
      * partial fix for CVE-2009-3555.
      */
-    enum { 
+    enum {
         RENEG_INIT = 0, /* Before initial handshake */
         RENEG_REJECT,   /* After initial handshake; any client-initiated
                          * renegotiation should be rejected
@@ -347,6 +347,13 @@ typedef struct {
                          * connection
                          */
     } reneg_state;
+#if defined(SSL_OP_NO_TLSv1_3)
+    enum {
+       PHA_NONE = 0,   /* Before PHA */
+               PHA_STARTED,    /* PHA req sent to client but no response */
+               PHA_COMPLETE    /* Client has returned cert */
+    } pha_state;
+#endif
     apr_socket_t   *sock;
     apr_pollset_t  *pollset;
 } tcn_ssl_conn_t;
@@ -356,7 +363,7 @@ typedef struct {
  *  Additional Functions
  */
 void        SSL_init_app_data2_3_idx(void);
-/* The app_data2 is used to store the tcn_ssl_ctxt_t pointer for the SSL 
instance. */ 
+/* The app_data2 is used to store the tcn_ssl_ctxt_t pointer for the SSL 
instance. */
 void       *SSL_get_app_data2(SSL *);
 void        SSL_set_app_data2(SSL *, void *);
 /* The app_data3 is used to store the handshakeCount pointer for the SSL 
instance. */

Modified: tomcat/native/trunk/native/src/sslnetwork.c
URL: 
http://svn.apache.org/viewvc/tomcat/native/trunk/native/src/sslnetwork.c?rev=1843514&r1=1843513&r2=1843514&view=diff
==============================================================================
--- tomcat/native/trunk/native/src/sslnetwork.c (original)
+++ tomcat/native/trunk/native/src/sslnetwork.c Wed Oct 10 21:49:55 2018
@@ -625,69 +625,130 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, rene
     int error = 0;
     char peekbuf[1];
     apr_interval_time_t timeout;
+    const SSL_SESSION *session;
 
     UNREFERENCED_STDARGS;
     TCN_ASSERT(sock != 0);
     con = (tcn_ssl_conn_t *)s->opaque;
+    session  = SSL_get_session(con->ssl);
+       apr_socket_timeout_get(con->sock, &timeout);
 
-    /* Toggle the renegotiation state to allow the new
-     * handshake to proceed.
-     */
-    con->reneg_state = RENEG_ALLOW;
-
-    // Schedule a renegotiation request
-    retVal = SSL_renegotiate(con->ssl);
-    if (retVal <= 0)
-        return APR_EGENERAL;
-
-    /* Need to trigger the renegotiation handshake by reading.
-     * Peeking 0 bytes actually works.
-     * See: http://marc.info/?t=145493359200002&r=1&w=2
-     *
-     * This will normally return SSL_ERROR_WANT_READ whether the renegotiation
-     * has been completed or not. Afterwards, need to determine if I/O needs to
-     * be triggered or not.
-     */
-    retVal = SSL_peek(con->ssl, peekbuf, 0);
-    if (retVal < 1) {
-        error = SSL_get_error(con->ssl, retVal);
-    }
+#if defined(SSL_OP_NO_TLSv1_3)
+    if (SSL_SESSION_get_protocol_version(session) == TLS1_3_VERSION) {
+       // TLS 1.3 renegotiation
+       retVal = SSL_verify_client_post_handshake(con->ssl);
+               if (retVal <= 0) {
+                       return APR_EGENERAL;
+               }
+
+               con->pha_state = PHA_STARTED;
+
+               // Need to trigger a write operation to sent the cert request 
to the
+               // client. As per OpenSSL docs, use SSL_do_handshake() for this.
+               retVal = SSL_do_handshake(con->ssl);
+               if (retVal <= 0) {
+                       return APR_EGENERAL;
+               }
+
+               // Trigger reading of the certs from the client
+               retVal = SSL_peek(con->ssl, peekbuf, 0);
+               if (retVal < 1) {
+                       error = SSL_get_error(con->ssl, retVal);
+               }
+
+               // If the certs have not been received, then need to wait for 
I/O
+               while (con->pha_state == PHA_STARTED) {
+                       // SSL_ERROR_WANT_READ is expected. Anything else is an 
error.
+                       if (error == SSL_ERROR_WANT_READ) {
+                               retVal = wait_for_io_or_timeout(con, error, 
timeout);
+                               /*
+                                * Since this is blocking I/O, anything other 
than APR_SUCCESS is an
+                                * error.
+                                */
+                               if (retVal != APR_SUCCESS) {
+                                       con->shutdown_type = 
SSL_SHUTDOWN_TYPE_UNCLEAN;
+                                       return retVal;
+                               }
+                       } else {
+                               return APR_EGENERAL;
+                       }
+
+                       // Re-try SSL_peek after I/O
+                       retVal = SSL_peek(con->ssl, peekbuf, 0);
+                       if (retVal < 1) {
+                               error = SSL_get_error(con->ssl, retVal);
+                       } else {
+                               /*
+                                * Reset error to handle case where SSL_Peek 
returns 0 but
+                                * con->pha_state has not changed. This will 
trigger an error
+                                * to be returned.
+                                */
+                               error = 0;
+                       }
+               }
+    } else {
+#endif
+       // TLS 1.2 and earlier renegotiation
+
+               /* Toggle the renegotiation state to allow the new
+                * handshake to proceed.
+                */
+               con->reneg_state = RENEG_ALLOW;
+
+               // Schedule a renegotiation request
+               retVal = SSL_renegotiate(con->ssl);
+               if (retVal <= 0) {
+                       return APR_EGENERAL;
+               }
+
+               /* Need to trigger the renegotiation handshake by reading.
+                * Peeking 0 bytes actually works.
+                * See: http://marc.info/?t=145493359200002&r=1&w=2
+                *
+                * This will normally return SSL_ERROR_WANT_READ whether the 
renegotiation
+                * has been completed or not. Afterwards, need to determine if 
I/O needs to
+                * be triggered or not.
+                */
+               retVal = SSL_peek(con->ssl, peekbuf, 0);
+               if (retVal < 1) {
+                       error = SSL_get_error(con->ssl, retVal);
+               }
+
+               // If the renegotiation is still pending, then I/O needs to be 
triggered
+               while (SSL_renegotiate_pending(con->ssl)) {
+                       // SSL_ERROR_WANT_READ is expected. Anything else is an 
error.
+                       if (error == SSL_ERROR_WANT_READ) {
+                               retVal = wait_for_io_or_timeout(con, error, 
timeout);
+                               /*
+                                * Since this is blocking I/O, anything other 
than APR_SUCCESS is an
+                                * error.
+                                */
+                               if (retVal != APR_SUCCESS) {
+                                       con->shutdown_type = 
SSL_SHUTDOWN_TYPE_UNCLEAN;
+                                       return retVal;
+                               }
+                       } else {
+                               return APR_EGENERAL;
+                       }
+
+                       // Re-try SSL_peek after I/O
+                       retVal = SSL_peek(con->ssl, peekbuf, 0);
+                       if (retVal < 1) {
+                               error = SSL_get_error(con->ssl, retVal);
+                       } else {
+                               /*
+                                * Reset error to handle case where SSL_Peek 
returns 0 but
+                                * SSL_renegotiate_pending returns true. This 
will trigger an error
+                                * to be returned.
+                                */
+                               error = 0;
+                       }
+               }
 
-    apr_socket_timeout_get(con->sock, &timeout);
-    // If the renegotiation is still pending, then I/O needs to be triggered
-    while (SSL_renegotiate_pending(con->ssl)) {
-        // SSL_ERROR_WANT_READ is expected. Anything else is an error.
-        if (error == SSL_ERROR_WANT_READ) {
-            retVal = wait_for_io_or_timeout(con, error, timeout);
-            /*
-             * Since this is blocking I/O, anything other than APR_SUCCESS is 
an
-             * error.
-             */
-            if (retVal != APR_SUCCESS) {
-                printf("ERROR\n");
-                con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
-                return retVal;
-            }
-        } else {
-            return APR_EGENERAL;
-        }
-
-        // Re-try SSL_peek after I/O
-        retVal = SSL_peek(con->ssl, peekbuf, 0);
-        if (retVal < 1) {
-            error = SSL_get_error(con->ssl, retVal);
-        } else {
-            /*
-             * Reset error to handle case where SSL_Peek returns 0 but
-             * SSL_renegotiate_pending returns true. This will trigger an error
-             * to be returned.
-             */
-            error = 0;
-        }
+               con->reneg_state = RENEG_REJECT;
+#if defined(SSL_OP_NO_TLSv1_3)
     }
-    
-    con->reneg_state = RENEG_REJECT;
-
+#endif
     return APR_SUCCESS;
 }
 

Modified: tomcat/native/trunk/native/src/sslutils.c
URL: 
http://svn.apache.org/viewvc/tomcat/native/trunk/native/src/sslutils.c?rev=1843514&r1=1843513&r2=1843514&view=diff
==============================================================================
--- tomcat/native/trunk/native/src/sslutils.c (original)
+++ tomcat/native/trunk/native/src/sslutils.c Wed Oct 10 21:49:55 2018
@@ -305,6 +305,10 @@ int SSL_callback_SSL_verify(int ok, X509
     int verify   = con->ctx->verify_mode;
     int depth    = con->ctx->verify_depth;
 
+#if defined(SSL_OP_NO_TLSv1_3)
+    con->pha_state = PHA_COMPLETE;
+#endif
+
     if (verify == SSL_CVERIFY_UNSET ||
         verify == SSL_CVERIFY_NONE)
         return 1;



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to