Author: markt
Date: Mon Aug 21 08:22:17 2017
New Revision: 1805606

URL: http://svn.apache.org/viewvc?rev=1805606&view=rev
Log:
Fix renegotiation to obtain a client certificate from a user agent.

Modified:
    tomcat/native/trunk/native/src/sslnetwork.c
    tomcat/native/trunk/xdocs/miscellaneous/changelog.xml

Modified: tomcat/native/trunk/native/src/sslnetwork.c
URL: 
http://svn.apache.org/viewvc/tomcat/native/trunk/native/src/sslnetwork.c?rev=1805606&r1=1805605&r2=1805606&view=diff
==============================================================================
--- tomcat/native/trunk/native/src/sslnetwork.c (original)
+++ tomcat/native/trunk/native/src/sslnetwork.c Mon Aug 21 08:22:17 2017
@@ -365,13 +365,12 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, hand
         * Check for failed client authentication
         */
         if (con->ctx->verify_mode != SSL_VERIFY_NONE &&
-           (vr = SSL_get_verify_result(con->ssl)) != X509_V_OK) {
+                (vr = SSL_get_verify_result(con->ssl)) != X509_V_OK) {
 
             if (SSL_VERIFY_ERROR_IS_OPTIONAL(vr) &&
-                con->ctx->verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA) {
+                    con->ctx->verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA) {
                 /* TODO: Log optionalNoCA */
-            }
-            else {
+            } else {
                 /* TODO: Log SSL client authentication failed */
                 con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
                 /* TODO: Figure out the correct return value */
@@ -623,7 +622,9 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, rene
     tcn_socket_t *s   = J2P(sock, tcn_socket_t *);
     tcn_ssl_conn_t *con;
     int retVal;
+    int error = 0;
     char peekbuf[1];
+    apr_interval_time_t timeout;
 
     UNREFERENCED_STDARGS;
     TCN_ASSERT(sock != 0);
@@ -633,28 +634,59 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, rene
      * handshake to proceed.
      */
     con->reneg_state = RENEG_ALLOW;
-    retVal = SSL_renegotiate(con->ssl);
-    if (retVal <= 0)
-        return APR_EGENERAL;
 
-    retVal = SSL_do_handshake(con->ssl);
+    // Schedule a renegotiation request
+    retVal = SSL_renegotiate(con->ssl);
     if (retVal <= 0)
         return APR_EGENERAL;
-    if (!SSL_is_init_finished(con->ssl)) {
-        return APR_EGENERAL;
-    }
 
-    /* Need to trigger renegotiation handshake by reading.
+    /* 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.
      */
-    SSL_peek(con->ssl, peekbuf, 0);
+    retVal = SSL_peek(con->ssl, peekbuf, 0);
+    if (retVal < 1) {
+        error = SSL_get_error(con->ssl, retVal);
+    }
 
-    con->reneg_state = RENEG_REJECT;
+    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;
+        }
 
-    if (!SSL_is_init_finished(con->ssl)) {
-        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;
 
     return APR_SUCCESS;
 }

Modified: tomcat/native/trunk/xdocs/miscellaneous/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/native/trunk/xdocs/miscellaneous/changelog.xml?rev=1805606&r1=1805605&r2=1805606&view=diff
==============================================================================
--- tomcat/native/trunk/xdocs/miscellaneous/changelog.xml (original)
+++ tomcat/native/trunk/xdocs/miscellaneous/changelog.xml Mon Aug 21 08:22:17 
2017
@@ -50,6 +50,10 @@
       Fix an error not announcing the correct CA list for client certificates
       during TLS handshake. (rjung)
     </fix>
+    <fix>
+      Fix renegotiation to obtain a client certificate from a user agent.
+      (markt)
+    </fix>
   </changelog>
 </section>
 <section name="Changes in 1.2.12">



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

Reply via email to