Bug 1308019 - Provide Tomcat support for TLS v1.1 and TLS v1.2 via NSS through JSS
authorElio Maldonado <emaldona@redhat.com>
Wed, 08 Feb 2017 18:55:43 -0800
changeset 2136 af1a5fa71a69e1f2a021764d3113d00b167b1828
parent 2135 15967d65ec7a32bd0c590dabb5f777f757918ae3
child 2137 5cd3eb611cebe7bc336446d3a0d3707c483ef2a5
push id21
push useremaldona@redhat.com
push dateThu, 09 Feb 2017 14:42:36 +0000
bugs1308019
Bug 1308019 - Provide Tomcat support for TLS v1.1 and TLS v1.2 via NSS through JSS
org/mozilla/jss/ssl/SSLSocket.c
org/mozilla/jss/ssl/SSLSocket.java
org/mozilla/jss/ssl/SocketBase.java
org/mozilla/jss/ssl/common.c
org/mozilla/jss/ssl/jssl.h
--- a/org/mozilla/jss/ssl/SSLSocket.c
+++ b/org/mozilla/jss/ssl/SSLSocket.c
@@ -12,23 +12,124 @@
 #include <java_ids.h>
 #include <pk11util.h>
 #include "_jni/org_mozilla_jss_ssl_SSLSocket.h"
 #include "jssl.h"
 
 
 #ifdef WINNT
 #include <private/pprio.h>
+#define AF_INET6 23
 #endif 
 
 #ifdef WIN32
 #include <winsock.h>
+#define AF_INET6 23
 #endif
 
 
+/*
+ * support TLS v1.1 and v1.2
+ *   sets default SSL version range for sockets created after this call
+ */
+JNIEXPORT void JNICALL
+Java_org_mozilla_jss_ssl_SSLSocket_setSSLVersionRangeDefault(JNIEnv *env,
+    jclass clazz, jint ssl_variant, jint min, jint max)
+{
+    SECStatus status;
+    SSLVersionRange vrange;
+
+    if (ssl_variant <0 || ssl_variant >= JSSL_enums_size|| 
+            min <0 || min >= JSSL_enums_size ||
+            max <0 || max >= JSSL_enums_size) {
+        char buf[128];
+        PR_snprintf(buf, 128, "JSS setSSLVersionRangeDefault(): for variant=%d min=%d max=%d failed - out of range for array JSSL_enums size: %d", JSSL_enums[ssl_variant], min, max, JSSL_enums_size);
+        JSSL_throwSSLSocketException(env, buf);
+        goto finish;
+    }
+
+    vrange.min = JSSL_enums[min];
+    vrange.max = JSSL_enums[max];
+
+    /* get supported range */
+    SSLVersionRange supported_range;
+    status = SSL_VersionRangeGetSupported(JSSL_enums[ssl_variant],
+                &supported_range);
+    if( status != SECSuccess ) {
+        char buf[128];
+        PR_snprintf(buf, 128, "SSL_VersionRangeGetSupported() for variant=%d failed: %d", JSSL_enums[ssl_variant], PR_GetError());
+        JSSL_throwSSLSocketException(env, buf);
+        goto finish;
+    }
+    /* now check the min and max */
+    if (vrange.min < supported_range.min  ||
+                vrange.max > supported_range.max) {
+        char buf[128];
+        PR_snprintf(buf, 128, "SSL_VersionRangeSetDefault() for variant=%d with min=%d max=%d out of range (%d:%d): %d", JSSL_enums[ssl_variant], vrange.min, vrange.max, supported_range.min, supported_range.max, PR_GetError());
+        JSSL_throwSSLSocketException(env, buf);
+        goto finish;
+    }
+
+    /* set the default SSL Version Range */
+    status = SSL_VersionRangeSetDefault(JSSL_enums[ssl_variant],
+                 &vrange);
+    if( status != SECSuccess ) {
+        char buf[128];
+        PR_snprintf(buf, 128, "SSL_VersionRangeSetDefault() for variant=%d with min=%d max=%d failed: %d", JSSL_enums[ssl_variant], vrange.min, vrange.max, PR_GetError());
+        JSSL_throwSSLSocketException(env, buf);
+        goto finish;
+    }
+
+finish:
+    return;
+}
+
+/*
+ * support TLS v1.1 and v1.2
+ *   sets SSL version range for this socket
+ */
+JNIEXPORT void JNICALL
+Java_org_mozilla_jss_ssl_SocketBase_setSSLVersionRange
+    (JNIEnv *env, jobject self, jint min, jint max)
+{
+    SECStatus status;
+    JSSL_SocketData *sock = NULL;
+    SSLVersionRange vrange;
+
+    if ( min <0 || min >= JSSL_enums_size ||
+            max <0 || max >= JSSL_enums_size) {
+        char buf[128];
+        PR_snprintf(buf, 128, "JSS setSSLVersionRange(): for max=%d failed - out of range for array JSSL_enums size: %d", min, max, JSSL_enums_size);
+        JSSL_throwSSLSocketException(env, buf);
+        goto finish;
+    }
+
+    /* get my fd */
+    if( JSSL_getSockData(env, self, &sock) != PR_SUCCESS ) {
+        goto finish;
+    }
+
+    vrange.min = JSSL_enums[min];
+    vrange.max = JSSL_enums[max];
+
+    /*
+     * set the SSL Version Range 
+     * The validity of the range will be checked by this NSS call
+     */
+    status = SSL_VersionRangeSet(sock->fd, &vrange);
+    if( status != SECSuccess ) {
+        JSSL_throwSSLSocketException(env, "SSL_VersionRangeSet failed");
+        goto finish;
+    }
+
+finish:
+    EXCEPTION_CHECK(env, sock)
+    return;
+}
+
 JNIEXPORT void JNICALL
 Java_org_mozilla_jss_ssl_SSLSocket_setSSLDefaultOption(JNIEnv *env,
     jclass clazz, jint joption, jint on)
 {
     SECStatus status;
 
     /* set the option */
     status = SSL_OptionSetDefault(JSSL_enums[joption], on);
--- a/org/mozilla/jss/ssl/SSLSocket.java
+++ b/org/mozilla/jss/ssl/SSLSocket.java
@@ -1032,16 +1032,73 @@ public class SSLSocket extends java.net.
 
     /** 
      * Sets the default setting for use of the session cache.
      */
     public void useCacheDefault(boolean b) throws SocketException {
         setSSLDefaultOption(SocketBase.SSL_NO_CACHE, !b);
     }
 
+   /*
+    * _min_enum and _max_enum should be one of the following:
+    *     SocketBase.SSL_LIBRARY_VERSION_3_0
+    *     SocketBase.SSL_LIBRARY_VERSION_TLS_1_0
+    *     SocketBase.SSL_LIBRARY_VERSION_TLS_1_1
+    *     SocketBase.SSL_LIBRARY_VERSION_TLS_1_2
+    */
+    public static class SSLVersionRange {
+        private int _min_enum;
+        private int _max_enum;
+        public static final int ssl3 = SocketBase.SSL_LIBRARY_VERSION_3_0;
+        public static final int tls1_0 = SocketBase.SSL_LIBRARY_VERSION_TLS_1_0;
+        public static final int tls1_1 = SocketBase.SSL_LIBRARY_VERSION_TLS_1_1;
+        public static final int tls1_2 = SocketBase.SSL_LIBRARY_VERSION_TLS_1_2;
+        public SSLVersionRange(int min_enum, int max_enum)
+          throws IllegalArgumentException {
+            if ((min_enum >= SocketBase.SSL_LIBRARY_VERSION_3_0) &&
+                (max_enum <= SocketBase.SSL_LIBRARY_VERSION_TLS_1_2) &&
+                (min_enum <= max_enum)) {
+                _min_enum = min_enum;
+                _max_enum = max_enum;
+            } else {
+                throw new IllegalArgumentException("JSS SSLSocket SSLVersionRange: arguments out of range");
+            }
+        }
+
+        int getMinEnum() { return _min_enum; }
+        int getMaxEnum() { return _max_enum; }
+
+    }
+
+    public static class SSLProtocolVariant {
+        private int _enum;
+        private SSLProtocolVariant(int val) { _enum = val; }
+
+        int getEnum() { return _enum; }
+
+        public static final SSLProtocolVariant STREAM =
+            new SSLProtocolVariant(SocketBase.SSL_Variant_Stream);
+        public static final SSLProtocolVariant DATA_GRAM =
+            new SSLProtocolVariant(SocketBase.SSL_Variant_Datagram);
+
+    }
+
+    public static void setSSLVersionRangeDefault(SSLProtocolVariant ssl_variant, SSLVersionRange range)
+        throws SocketException
+    {
+        if (range == null)
+            throw new SocketException("setSSLVersionRangeDefault: range null");
+        setSSLVersionRangeDefault(ssl_variant.getEnum(), range.getMinEnum(), range.getMaxEnum());
+    }
+
+    /** 
+     * Sets SSL Version Range Default
+     */
+    private static native void setSSLVersionRangeDefault(int ssl_variant, int min, int max)
+        throws SocketException;
 
     private static void setSSLDefaultOption(int option, boolean on)
         throws SocketException
     {
         setSSLDefaultOption(option, on ? 1 : 0);
     }
 
     /** 
--- a/org/mozilla/jss/ssl/SocketBase.java
+++ b/org/mozilla/jss/ssl/SocketBase.java
@@ -38,21 +38,21 @@ class SocketBase {
     native byte[] socketCreate(Object socketObject,
         SSLCertificateApprovalCallback certApprovalCallback,
         SSLClientCertificateSelectionCallback clientCertSelectionCallback,
         java.net.Socket javaSock, String host,int family)
             throws SocketException;
 
     byte[] socketCreate(Object socketObject,
         SSLCertificateApprovalCallback certApprovalCallback,
-        SSLClientCertificateSelectionCallback clientCertSelectionCallback,int family)
+        SSLClientCertificateSelectionCallback clientCertSelectionCallback, int family)
             throws SocketException
     {
         return socketCreate(socketObject, certApprovalCallback,
-            clientCertSelectionCallback, null, null,family);
+            clientCertSelectionCallback, null, null, family);
     }
 
     native void socketBind(byte[] addrBA, int port) throws SocketException;
 
     /**
      * Enums. These must match the enums table in common.c. This is
      * safer than copying the values of the C constants, which are subject
      * to change, into Java code.
@@ -83,16 +83,25 @@ class SocketBase {
     static final int SSL_REQUIRE_NO_ERROR = 21;
     static final int SSL_ENABLE_SESSION_TICKETS = 22;
     static final int SSL_ENABLE_RENEGOTIATION = 23;
     static final int SSL_RENEGOTIATE_NEVER = 24;
     static final int SSL_RENEGOTIATE_UNRESTRICTED = 25;
     static final int SSL_RENEGOTIATE_REQUIRES_XTN = 26;
     static final int SSL_RENEGOTIATE_TRANSITIONAL = 27;
     static final int SSL_REQUIRE_SAFE_NEGOTIATION = 28;
+    /* ssl/sslproto.h for supporting SSLVersionRange */
+    static final int SSL_LIBRARY_VERSION_2 = 29;
+    static final int SSL_LIBRARY_VERSION_3_0 = 30;
+    static final int SSL_LIBRARY_VERSION_TLS_1_0 = 31;
+    static final int SSL_LIBRARY_VERSION_TLS_1_1 = 32;
+    static final int SSL_LIBRARY_VERSION_TLS_1_2 = 33;
+    /* ssl/sslt.h */
+    static final int SSL_Variant_Stream = 34;
+    static final int SSL_Variant_Datagram = 35;
 
 
     static final int SSL_AF_INET  = 50;
     static final int SSL_AF_INET6 = 51;
 
     void close() throws IOException {
         socketClose();
     }
@@ -169,16 +178,28 @@ class SocketBase {
 
     /** 
      * Sets SSL options for this socket that have simple 
      * enable/disable values.
      */
     native void setSSLOption(int option, int on)
         throws SocketException;
 
+    void setSSLVersionRange(org.mozilla.jss.ssl.SSLSocket.SSLVersionRange range)
+        throws SocketException
+    {
+        setSSLVersionRange(range.getMinEnum(), range.getMaxEnum());
+    }
+
+    /**
+     * Sets SSL Version Range for this socket to support TLS v1.1 and v1.2
+     */
+    native void setSSLVersionRange(int min, int max)
+        throws SocketException;
+
     /** 
      * Sets the SSL option setting mode value use for options
      * that have more values than just enable/disable.
      */
     native void setSSLOptionMode(int option, int option2)
         throws SocketException; 
 
     
--- a/org/mozilla/jss/ssl/common.c
+++ b/org/mozilla/jss/ssl/common.c
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <nspr.h>
 #include <jni.h>
 #include <pk11func.h>
 #include <ssl.h>
 #include <sslerr.h>
+#include <sslproto.h>
 
 #include <jssutil.h>
 #include <jss_exceptions.h>
 #include <java_ids.h>
 #include <pk11util.h>
 #include "_jni/org_mozilla_jss_ssl_SSLSocket.h"
 #include "jssl.h"
 
@@ -378,16 +379,23 @@ PRInt32 JSSL_enums[] = {
     SSL_REQUIRE_NO_ERROR,       /* 21 */        /* ssl.h */
     SSL_ENABLE_SESSION_TICKETS, /* 22 */        /* ssl.h */
     SSL_ENABLE_RENEGOTIATION,     /* 23 */      /* ssl.h */
     SSL_RENEGOTIATE_NEVER,        /* 24 */      /* ssl.h */
     SSL_RENEGOTIATE_UNRESTRICTED, /* 25 */      /* ssl.h */
     SSL_RENEGOTIATE_REQUIRES_XTN, /* 26 */      /* ssl.h */
     SSL_RENEGOTIATE_TRANSITIONAL, /* 27 */      /* ssl.h */
     SSL_REQUIRE_SAFE_NEGOTIATION, /* 28 */      /* ssl.h */
+    SSL_LIBRARY_VERSION_2,        /* 29 */      /* sslproto.h */
+    SSL_LIBRARY_VERSION_3_0,      /* 30 */      /* sslproto.h */
+    SSL_LIBRARY_VERSION_TLS_1_0,  /* 31 */      /* sslproto.h */
+    SSL_LIBRARY_VERSION_TLS_1_1,  /* 32 */      /* sslproto.h */
+    SSL_LIBRARY_VERSION_TLS_1_2,  /* 33 */      /* sslproto.h */
+    ssl_variant_stream,           /* 34 */      /* sslt.h */
+    ssl_variant_datagram,         /* 35 */      /* sslt.h */
     0
 };
 
 JNIEXPORT void JNICALL
 Java_org_mozilla_jss_ssl_SocketBase_socketBind
     (JNIEnv *env, jobject self, jbyteArray addrBA, jint port)
 {
     JSSL_SocketData *sock;
--- a/org/mozilla/jss/ssl/jssl.h
+++ b/org/mozilla/jss/ssl/jssl.h
@@ -74,16 +74,17 @@ JSSL_GetClientAuthData( void * arg,
         SSLSOCKET_PROXY_SIG, (void**)sdptr)
 
 
 void
 JSSL_DestroySocketData(JNIEnv *env, JSSL_SocketData *sd);
 
 
 extern PRInt32 JSSL_enums[];
+#define JSSL_enums_size 36
 
 JSSL_SocketData*
 JSSL_CreateSocketData(JNIEnv *env, jobject sockObj, PRFileDesc* newFD,
         PRFilePrivate *priv);
 
 #define SSL_POLICY_DOMESTIC 0
 #define SSL_POLICY_EXPORT 1
 #define SSL_POLICY_FRANCE 2