[Pkg-freeipa-devel] [Git][freeipa-team/jss][upstream] 10 commits: Add NSS stubs for BadCertHandler

Timo Aaltonen gitlab at salsa.debian.org
Mon Sep 14 12:30:04 BST 2020



Timo Aaltonen pushed to branch upstream at FreeIPA packaging / jss


Commits:
44a454d8 by Alexander Scheel at 2020-09-01T07:56:58-04:00
Add NSS stubs for BadCertHandler

The JDK's SSL interfaces under javax.net.ssl do not provide a way for
the SSLSocket/SSLEngine instance to validate hostname during the
handshake. Instead, the accepted way of doing hostname verification
(using a HostnameVerifier) is after the handshake is completed. This
causes problems with NSS, because they assume the hostname is available
for validation at handshake time.

In order to support this use case, when the hostname is `null` on a
client SSL socket, we will attach using SSL_BadCertHook and give the
JSSEngine a chance to bypass this value.

Signed-off-by: Alexander Scheel <ascheel at redhat.com>

- - - - -
20765fc7 by Alexander Scheel at 2020-09-01T07:56:58-04:00
Add SSLErrors with SSL_ERROR_BAD_CERT_DOMAIN

This is the only SSLError we wish to allow through in regular JSSEngine
client operations.

Signed-off-by: Alexander Scheel <ascheel at redhat.com>

- - - - -
826943f8 by Alexander Scheel at 2020-09-01T07:56:58-04:00
Bypass SSL_ERRORS_BAD_CERT_DOMAIN for JDK

When JSSEngine is used via the provider interface, most callers won't be
aware that they're using JSSEngine. As a side effect, they won't be
using JSSEngine's setHostname() to validate the server's SSL
certificate. This means NSS has no knowledge of the hostname, throwing
an error like:

    Caused by: javax.net.ssl.SSLHandshakeException: Error duing SSL.ForceHandshake() :: SSL_ERROR_BAD_CERT_DOMAIN (-12276)
            at org.mozilla.jss.ssl.javax.JSSEngineReferenceImpl.updateHandshakeState(JSSEngineReferenceImpl.java:856)
            at org.mozilla.jss.ssl.javax.JSSEngineReferenceImpl.unwrap(JSSEngineReferenceImpl.java:1037)
            at org.mozilla.jss.ssl.javax.JSSSocketChannel.read(JSSSocketChannel.java:272)

We need to provide a mechanism to bypass this by default for these
connections, in order to stay compatible with the JCA. This approach was
suggested by Bob Relyea.

Signed-off-by: Alexander Scheel <ascheel at redhat.com>

- - - - -
8d5266b4 by Alexander Scheel at 2020-09-01T19:42:26-04:00
Disable ENABLE_FALLBACK_SCSV for JCA compatibility

Signed-off-by: Alexander Scheel <ascheel at redhat.com>

- - - - -
7a1d17c3 by Alexander Scheel at 2020-09-01T19:42:26-04:00
Add Post-Handshake Auth to legacy SSLSocket

Signed-off-by: Alexander Scheel <ascheel at redhat.com>

- - - - -
0d633086 by Alexander Scheel at 2020-09-02T20:21:50-04:00
Fix JNI function misname

Signed-off-by: Alexander Scheel <ascheel at redhat.com>

- - - - -
76e38c67 by Alexander Scheel at 2020-09-10T16:17:17-04:00
Add CryptoManager.isInitialized()

This prevents Java from thinking we're trying to recursively load the
JSSProvider. We kinda are, but we just really need to trigger it to load
in more instances.

In particular, in JSSProvider, we need to check if CryptoManager is
already initialized, and if not, initialize it. We used
CryptoManager.getInstance() for this, which in turn tries to load the
provider if it isn't already loaded. This resulted in a recursive
initialization. By using CryptoManager.isInitialized(), we can avoid the
call to CryptoManager.getInstance() and avoid this recursion.

Signed-off-by: Alexander Scheel <ascheel at redhat.com>

- - - - -
4c1d8872 by Alexander Scheel at 2020-09-10T16:17:17-04:00
Add SNI to all socket connections

One limitation of NSS's SSL APIs is that client sockets cannot indicate
SNI information except via SSL_SetURL(). The downside with this approach
is that the same hostname is also used for certificate validation. In
particular, Java doesn't expose the hostname for certificate validation,
but only exposes one hostname in the SSLEngine constructor. This means
we shouldn't usually use this hostname for certificate validation, but
only for SNI.

However, some servers require SNI in order for the connection to
succeed. One example at the time of writing is google.com. By using
SSL_SetURL, we both validate the certificate and provide SNI, which is
sufficient in most instances. However, in the event the hostname is
incorrect for certificate validation, a BAD_CERT_DOMAIN error will still
raise, triggering our other checks, and return control back to Java's
hostname validation logic.

Signed-off-by: Alexander Scheel <ascheel at redhat.com>

- - - - -
90e4f05d by Alexander Scheel at 2020-09-10T16:17:17-04:00
Fix parameters on unwrap() buffer copy

When reading data from NSS during unwrap(), we get the result back as a
single byte array. However, the caller already has separate ByteBuffer
instances that we need to put data into. Because the loop incremented
the index again, we returned one extra byte. This resulted in the
JSSEngine caller thinking there was one more byte of data, usually a
NULL byte. When multiple HTTPS requests were issued on a single TLS
connection, this resulted in the caller getting a single NULL byte
between requests, causing HTTP parsing libraries to throw an
exception.

Fixing the array bounds and returning the correct size fixes the
problem.

Signed-off-by: Alexander Scheel <ascheel at redhat.com>

- - - - -
a715520a by Alexander Scheel at 2020-09-11T16:15:45-04:00
Release JSS v4.7.3

Signed-off-by: Alexander Scheel <ascheel at redhat.com>

- - - - -


20 changed files:

- cmake/JSSConfig.cmake
- jss.spec
- lib/jss.map
- org/mozilla/jss/CryptoManager.java
- org/mozilla/jss/JSSLoader.java
- org/mozilla/jss/JSSProvider.java
- + org/mozilla/jss/nss/BadCertHandler.java
- org/mozilla/jss/nss/SSL.c
- org/mozilla/jss/nss/SSL.java
- + org/mozilla/jss/nss/SSLErrors.c
- + org/mozilla/jss/nss/SSLErrors.java
- org/mozilla/jss/nss/SSLFDProxy.c
- org/mozilla/jss/nss/SSLFDProxy.h
- org/mozilla/jss/nss/SSLFDProxy.java
- org/mozilla/jss/ssl/SSLSocket.java
- org/mozilla/jss/ssl/SocketBase.java
- org/mozilla/jss/ssl/common.c
- org/mozilla/jss/ssl/javax/JSSEngine.java
- org/mozilla/jss/ssl/javax/JSSEngineReferenceImpl.java
- org/mozilla/jss/ssl/jssl.h


Changes:

=====================================
cmake/JSSConfig.cmake
=====================================
@@ -2,7 +2,7 @@ macro(jss_config)
     # Set the current JSS release number. Arguments are:
     #   MAJOR MINOR PATCH BETA
     # When BETA is zero, it isn't a beta release.
-    jss_config_version(4 7 2 0)
+    jss_config_version(4 7 3 0)
 
     # Configure output directories
     jss_config_outputs()


=====================================
jss.spec
=====================================
@@ -6,7 +6,7 @@ Summary:        Java Security Services (JSS)
 URL:            http://www.dogtagpki.org/wiki/JSS
 License:        MPLv1.1 or GPLv2+ or LGPLv2+
 
-Version:        4.7.2
+Version:        4.7.3
 Release:        1%{?_timestamp}%{?_commit_id}%{?dist}
 #global         _phase -a1
 
@@ -108,13 +108,26 @@ export CFLAGS
 # Check if we're in FIPS mode
 modutil -dbdir /etc/pki/nssdb -chkfips true | grep -q enabled && export FIPS_ENABLED=1
 
+# RHEL's CMake doesn't support -B flag.
+%if 0%{?rhel}
+%{__mkdir_p} %{_vpath_builddir}
+cd %{_vpath_builddir}
+%endif
+
 # The Makefile is not thread-safe
 %cmake \
     -DJAVA_HOME=%{java_home} \
     -DJAVA_LIB_INSTALL_DIR=%{_jnidir} \
+%if 0%{?rhel}
+    ..
+%else
     -B %{_vpath_builddir}
+%endif
 
+%if 0%{?fedora}
 cd %{_vpath_builddir}
+%endif
+
 %{__make} all
 %{__make} javadoc
 ctest --output-on-failure


=====================================
lib/jss.map
=====================================
@@ -491,3 +491,11 @@ Java_org_mozilla_jss_nss_SSL_ImportFDNative;
     local:
         *;
 };
+JSS_4.7.3 {
+    global:
+Java_org_mozilla_jss_nss_SSL_ConfigAsyncBadCertCallback;
+Java_org_mozilla_jss_nss_SSL_ConfigSyncBadCertCallback;
+Java_org_mozilla_jss_nss_SSLErrors_getBadCertDomain;
+    local:
+        *;
+};


=====================================
org/mozilla/jss/CryptoManager.java
=====================================
@@ -330,6 +330,12 @@ public final class CryptoManager implements TokenSupplier
         reloadModules();
     }
 
+    public static boolean isInitialized() {
+        synchronized (CryptoManager.class) {
+            return instance != null;
+        }
+    }
+
     /**
      * Retrieve the single instance of CryptoManager.
      * This cannot be called before initialization.


=====================================
org/mozilla/jss/JSSLoader.java
=====================================
@@ -78,17 +78,6 @@ import org.slf4j.LoggerFactory;
 public class JSSLoader {
     public static Logger logger = LoggerFactory.getLogger(JSSLoader.class);
 
-    /**
-     * Check if this provider has been configured.
-     */
-    public static boolean loaded() {
-        try {
-            return CryptoManager.getInstance() != null;
-        } catch (Exception e) {
-            return false;
-        }
-    }
-
     /**
      * Initialize JSS from the specified path to a configuration file.
      */
@@ -108,7 +97,7 @@ public class JSSLoader {
      * Initialize JSS from an InputStream.
      */
     public static CryptoManager init(InputStream istream) throws Exception {
-        if (loaded()) {
+        if (CryptoManager.isInitialized()) {
             return CryptoManager.getInstance();
         }
 


=====================================
org/mozilla/jss/JSSProvider.java
=====================================
@@ -29,7 +29,7 @@ public final class JSSProvider extends java.security.Provider {
     private static CryptoManager cm;
 
     public JSSProvider() {
-        this(loader.loaded());
+        this(CryptoManager.isInitialized());
     }
 
     public JSSProvider(boolean initialize) {


=====================================
org/mozilla/jss/nss/BadCertHandler.java
=====================================
@@ -0,0 +1,71 @@
+package org.mozilla.jss.nss;
+
+/**
+ * BadAuthHandler interface enables arbitrary certificate authentication
+ * from a NSS cert auth hook.
+ *
+ * Notably, the return code from check should be a PRErrorCode, else 0.
+ * This will be used by NSS to determine the alert to send when closing
+ * the connection (in the event of an error).
+ *
+ * The concern here is that, when this is invoked synchronously, we're
+ * called from NSS as called by Java. Certain operations may or may not
+ * succeed or work as expected (such as raising an exception, acquiring
+ * locks already held, etc.).
+ */
+public abstract class BadCertHandler implements Runnable {
+    /**
+     * When invoked via run(), the error code to pass to the
+     * check operation.
+     */
+    public int error;
+
+    /**
+     * When invoked via run(), the result of the check
+     * operation.
+     */
+    public int result;
+
+    /**
+     * Whether or not the check operation has been executed
+     * yet, when invoked via run().
+     */
+    public boolean finished;
+
+    /**
+     * SSLFDProxy instance.
+     */
+    private SSLFDProxy ssl_fd;
+
+    /**
+     * Constructor to store SSLFDProxy, error information.
+     *
+     * This is useful for implementations which expect to be used
+     * via the Runnable interface, instead of called via the
+     * synchronous certificate authentication hook in NSS.
+     */
+    public BadCertHandler(SSLFDProxy fd, int error) {
+        ssl_fd = fd;
+        this.error = error;
+    }
+
+    /**
+     * Returns the PRErrorCode the error validating certificate
+     * auth, else 0.
+     *
+     * Note that it is up to the implementer to fetch the certificates
+     * (via SSL.PeerCertificateChain(ssl_fd)) and validate them
+     * properly.
+     *
+     * Note that returning 0 here means SECis returned
+     */
+    public abstract int check(SSLFDProxy fd, int error);
+
+    public void run() {
+        try {
+            result = check(ssl_fd, error);
+        } finally {
+            finished = true;
+        }
+    }
+}


=====================================
org/mozilla/jss/nss/SSL.c
=====================================
@@ -931,6 +931,48 @@ Java_org_mozilla_jss_nss_SSL_ConfigSyncTrustManagerCertAuthCallback(JNIEnv *env,
     return SSL_AuthCertificateHook(real_fd, JSSL_SSLFDSyncCertAuthCallback, fd_ref);
 }
 
+JNIEXPORT jint JNICALL
+Java_org_mozilla_jss_nss_SSL_ConfigAsyncBadCertCallback(JNIEnv *env, jclass clazz,
+    jobject fd)
+{
+    PRFileDesc *real_fd = NULL;
+    jobject fd_ref = NULL;
+
+    PR_ASSERT(env != NULL && fd != NULL);
+    PR_SetError(0, 0);
+
+    if (JSS_PR_getPRFileDesc(env, fd, &real_fd) != PR_SUCCESS) {
+        return SECFailure;
+    }
+
+    if (JSS_NSS_getGlobalRef(env, fd, &fd_ref) != PR_SUCCESS) {
+        return SECFailure;
+    }
+
+    return SSL_BadCertHook(real_fd, JSSL_SSLFDAsyncBadCertCallback, fd_ref);
+}
+
+JNIEXPORT jint JNICALL
+Java_org_mozilla_jss_nss_SSL_ConfigSyncBadCertCallback(JNIEnv *env, jclass clazz,
+    jobject fd)
+{
+    PRFileDesc *real_fd = NULL;
+    jobject fd_ref = NULL;
+
+    PR_ASSERT(env != NULL && fd != NULL);
+    PR_SetError(0, 0);
+
+    if (JSS_PR_getPRFileDesc(env, fd, &real_fd) != PR_SUCCESS) {
+        return SECFailure;
+    }
+
+    if (JSS_NSS_getGlobalRef(env, fd, &fd_ref) != PR_SUCCESS) {
+        return SECFailure;
+    }
+
+    return SSL_BadCertHook(real_fd, JSSL_SSLFDSyncBadCertCallback, fd_ref);
+}
+
 JNIEXPORT jint JNICALL
 Java_org_mozilla_jss_nss_SSL_AuthCertificateComplete(JNIEnv *env, jclass clazz,
     jobject fd, jint error)


=====================================
org/mozilla/jss/nss/SSL.java
=====================================
@@ -471,10 +471,38 @@ public class SSL {
      */
     public static native int ConfigSyncTrustManagerCertAuthCallback(SSLFDProxy fd);
 
+    /**
+     * Use an asynchronous bad certificate handler which allows us to approve
+     * rejected certificates. This allows us to bypass the hostname check
+     * failure caused by the Java socket having no knowledge of the hostname
+     * we use for certificate validation; no HostnameVerifier is passed in.
+     * As a result, NSS has no value for the hostname and validation will fail.
+     *
+     * Note: This does NOT work for server-side connections.
+     *
+     * See also: SSL_BadCertHook in /usr/include/nss3/ssl.h and
+     *           JSSL_SSLFDAsyncBadCertCallback in jss/nss/SSLFDProxy.c
+     */
+    public static native int ConfigAsyncBadCertCallback(SSLFDProxy fd);
+
+    /**
+     * Use a synchronous bad certificate handler which allows us to approve
+     * rejected certificates. This allows us to bypass the hostname check
+     * failure caused by the Java socket having no knowledge of the hostname
+     * we use for certificate validation; no HostnameVerifier is passed in.
+     * As a result, NSS has no value for the hostname and validation will fail.
+     *
+     * See also: SSL_BadCertHook in /usr/include/nss3/ssl.h and
+     *           JSSL_SSLFDSyncBadCertCallback in jss/nss/SSLFDProxy.c
+     */
+    public static native int ConfigSyncBadCertCallback(SSLFDProxy fd);
+
     /**
      * Inform NSS that the asynchronous certificate check handler has
      * completed, allowing us to continue the handshake.
      *
+     * This is also used for the async bad certificate handler as well.
+     *
      * See also: SSL_AuthCertificateComplete in /usr/include/nss3/ssl.h
      */
     public static native int AuthCertificateComplete(SSLFDProxy fd, int error);


=====================================
org/mozilla/jss/nss/SSLErrors.c
=====================================
@@ -0,0 +1,20 @@
+#include <nspr.h>
+#include <limits.h>
+#include <stdint.h>
+#include <jni.h>
+#include <nss.h>
+#include <ssl.h>
+#include <sslerr.h>
+
+#include "jssutil.h"
+#include "PRFDProxy.h"
+#include "BufferProxy.h"
+#include "BufferPRFD.h"
+
+#include "_jni/org_mozilla_jss_nss_SECErrors.h"
+
+JNIEXPORT int JNICALL
+Java_org_mozilla_jss_nss_SSLErrors_getBadCertDomain(JNIEnv *env, jclass clazz)
+{
+    return SSL_ERROR_BAD_CERT_DOMAIN;
+}


=====================================
org/mozilla/jss/nss/SSLErrors.java
=====================================
@@ -0,0 +1,19 @@
+package org.mozilla.jss.nss;
+
+/**
+ * This class provides access to useful NSS/SSL errors, getting their values
+ * from a JNI call. Note that it *isn't* an enum as the NSS wrappers return
+ * int. This saves us from having to wrap every NSS error in a class instance
+ * only to later unwrap it to make any useful calls.
+ */
+
+public class SSLErrors {
+    /**
+     * Certificate has a bad hostname.
+     *
+     * See also:  in /usr/include/nss3/sslcerr.h
+     */
+    public static final int BAD_CERT_DOMAIN = getBadCertDomain();
+
+    private static native int getBadCertDomain();
+}


=====================================
org/mozilla/jss/nss/SSLFDProxy.c
=====================================
@@ -322,8 +322,8 @@ JSSL_SSLFDSyncCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, PRBoo
      * because we have no control over whether or not our TrustManagers do
      * signature verification (we hope they do!) we ignore checkSig as well.
      *
-     * All we need to do then is set SSLFDProxy at fd_ref's needCertValidation
-     * to true.
+     * All we need to do then is call SSLFDProxy at fd_ref's
+     * invokeCertAuthHandler() method.
      */
     JNIEnv *env = NULL;
     jobject sslfd_proxy = (jobject) arg;
@@ -367,3 +367,106 @@ JSSL_SSLFDSyncCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, PRBoo
 
     return SECFailure;
 }
+
+SECStatus
+JSSL_SSLFDAsyncBadCertCallback(void *arg, PRFileDesc *fd)
+{
+    /* We know that arg is our GlobalRefProxy instance pointing to the
+     * SSLFDProxy class instance. This lets us ignore the PRFileDesc
+     * parameter because we already have a reference to it via arg.
+     *
+     * All we need to do then is set SSLFDProxy at fd_ref's needBadCertValidation
+     * to true.
+     */
+    JNIEnv *env = NULL;
+    jobject sslfd_proxy = (jobject) arg;
+    jclass sslfdProxyClass;
+    jfieldID needBadCertValidationField;
+    jfieldID badCertErrorField;
+    int cert_error = PR_GetError();
+
+    if (arg == NULL || fd == NULL || JSS_javaVM == NULL) {
+        return SECFailure;
+    }
+
+    if ((*JSS_javaVM)->AttachCurrentThread(JSS_javaVM, (void**)&env, NULL) != JNI_OK || env == NULL) {
+        return SECFailure;
+    }
+
+    sslfdProxyClass = (*env)->GetObjectClass(env, sslfd_proxy);
+    if (sslfdProxyClass == NULL) {
+        return SECFailure;
+    }
+
+    needBadCertValidationField = (*env)->GetFieldID(env, sslfdProxyClass,
+                                                    "needBadCertValidation", "Z");
+    if (needBadCertValidationField == NULL) {
+        return SECFailure;
+    }
+
+    badCertErrorField = (*env)->GetFieldID(env, sslfdProxyClass,
+                                           "badCertError", "I");
+    if (badCertErrorField == NULL) {
+        return SECFailure;
+    }
+
+    (*env)->SetBooleanField(env, sslfd_proxy, needBadCertValidationField, JNI_TRUE);
+    (*env)->SetIntField(env, sslfd_proxy, needBadCertValidationField, cert_error);
+
+    return SECWouldBlock;
+}
+
+SECStatus
+JSSL_SSLFDSyncBadCertCallback(void *arg, PRFileDesc *fd)
+{
+    /* We know that arg is our GlobalRefProxy instance pointing to the
+     * SSLFDProxy class instance. This lets us ignore the PRFileDesc
+     * parameter because we already have a reference to it via arg.
+     *
+     * All we need to do then is call SSLFDProxy at fd_ref's
+     * invokeBadCertHandler() method.
+     */
+    JNIEnv *env = NULL;
+    jobject sslfd_proxy = (jobject) arg;
+    jclass sslfdProxyClass;
+    jmethodID badCertHandlerMethod;
+    PRErrorCode ret;
+    int cert_error = PR_GetError();
+
+    if (arg == NULL || fd == NULL || JSS_javaVM == NULL) {
+        PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
+        return SECFailure;
+    }
+
+    if ((*JSS_javaVM)->AttachCurrentThread(JSS_javaVM, (void**)&env, NULL) != JNI_OK || env == NULL) {
+        PR_SetError(PR_UNKNOWN_ERROR, 0);
+        return SECFailure;
+    }
+
+    sslfdProxyClass = (*env)->GetObjectClass(env, sslfd_proxy);
+    if (sslfdProxyClass == NULL) {
+        PR_SetError(PR_UNKNOWN_ERROR, 0);
+        return SECFailure;
+    }
+
+    badCertHandlerMethod = (*env)->GetMethodID(env, sslfdProxyClass,
+        "invokeBadCertHandler", "(I)I");
+    if (badCertHandlerMethod == NULL) {
+        PR_SetError(PR_UNKNOWN_ERROR, 0);
+        return SECFailure;
+    }
+
+    ret = (*env)->CallIntMethod(env, sslfd_proxy, badCertHandlerMethod, cert_error);
+    if ((*env)->ExceptionOccurred(env) != NULL) {
+        ret = PR_UNKNOWN_ERROR;
+    }
+
+    PR_SetError(ret, 0);
+
+    if (ret == 0) {
+        return SECSuccess;
+    }
+
+    return SECFailure;
+}
+


=====================================
org/mozilla/jss/nss/SSLFDProxy.h
=====================================
@@ -35,3 +35,9 @@ JSSL_SSLFDAsyncCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, PRBo
 
 SECStatus
 JSSL_SSLFDSyncCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer);
+
+SECStatus
+JSSL_SSLFDAsyncBadCertCallback(void *arg, PRFileDesc *fd);
+
+SECStatus
+JSSL_SSLFDSyncBadCertCallback(void *arg, PRFileDesc *fd);


=====================================
org/mozilla/jss/nss/SSLFDProxy.java
=====================================
@@ -19,9 +19,12 @@ public class SSLFDProxy extends PRFDProxy {
     public int outboundOffset;
 
     public boolean needCertValidation;
+    public boolean needBadCertValidation;
+    public int badCertError;
     public boolean handshakeComplete;
 
-    public CertAuthHandler handler;
+    public CertAuthHandler certAuthHandler;
+    public BadCertHandler badCertHandler;
 
     public SSLFDProxy(byte[] pointer) {
         super(pointer);
@@ -51,6 +54,10 @@ public class SSLFDProxy extends PRFDProxy {
     }
 
     public int invokeCertAuthHandler() {
-        return handler.check(this);
+        return certAuthHandler.check(this);
+    }
+
+    public int invokeBadCertHandler(int error) {
+        return badCertHandler.check(this, error);
     }
 }


=====================================
org/mozilla/jss/ssl/SSLSocket.java
=====================================
@@ -1094,6 +1094,24 @@ public class SSLSocket extends java.net.Socket {
         setSSLDefaultOption(SocketBase.SSL_V2_COMPATIBLE_HELLO, enable);
     }
 
+    /**
+     * Enable or disable post-handshake auth for a single socket.
+     */
+    public void enablePostHandshakeAuth(boolean enable)
+    throws SocketException
+    {
+        base.enablePostHandshakeAuth(enable);
+    }
+
+    /**
+     * Sets the default to allow post-handshake auth globally.
+     */
+    public static void enablePostHandshakeAuthDefault(boolean enable)
+    throws SocketException
+    {
+        setSSLDefaultOption(SocketBase.SSL_ENABLE_POST_HANDSHAKE_AUTH, enable);
+    }
+
     /**
      * @return a String listing the current SSLOptions for this SSLSocket.
      */


=====================================
org/mozilla/jss/ssl/SocketBase.java
=====================================
@@ -101,6 +101,7 @@ class SocketBase {
     /* ssl/sslt.h */
     static final int SSL_Variant_Stream = 33;
     static final int SSL_Variant_Datagram = 34;
+    static final int SSL_ENABLE_POST_HANDSHAKE_AUTH = 36;
 
     static final int SSL_AF_INET = 50;
     static final int SSL_AF_INET6 = 51;
@@ -175,6 +176,10 @@ class SocketBase {
         setSSLOption(SSL_V2_COMPATIBLE_HELLO, enable);
     }
 
+    void enablePostHandshakeAuth(boolean enable) throws SocketException {
+        setSSLOption(SSL_ENABLE_POST_HANDSHAKE_AUTH, enable);
+    }
+
     void setSSLOption(int option, boolean on)
             throws SocketException {
         setSSLOption(option, on ? 1 : 0);


=====================================
org/mozilla/jss/ssl/common.c
=====================================
@@ -422,6 +422,7 @@ PRInt32 JSSL_enums[] = {
     ssl_variant_stream,           /* 33 */      /* sslt.h */
     ssl_variant_datagram,         /* 34 */      /* sslt.h */
     SSL_LIBRARY_VERSION_TLS_1_3,  /* 35 */      /* sslproto.h */
+    SSL_ENABLE_POST_HANDSHAKE_AUTH, /* 36 */      /* ssl.h */
     0
 };
 


=====================================
org/mozilla/jss/ssl/javax/JSSEngine.java
=====================================
@@ -945,7 +945,6 @@ public abstract class JSSEngine extends javax.net.ssl.SSLEngine {
         // TLS < 1.3.
         result.put(SSL.ENABLE_RENEGOTIATION, SSL.RENEGOTIATE_REQUIRES_XTN);
         result.put(SSL.REQUIRE_SAFE_NEGOTIATION, 1);
-        result.put(SSL.ENABLE_FALLBACK_SCSV, 1);
         return result;
     }
 


=====================================
org/mozilla/jss/ssl/javax/JSSEngineReferenceImpl.java
=====================================
@@ -82,7 +82,33 @@ public class JSSEngineReferenceImpl extends JSSEngine {
     public JSSEngineReferenceImpl(String peerHost, int peerPort) {
         super(peerHost, peerPort);
 
-        peer_info = peerHost + ":" + peerPort;
+        // Signal host and port for session resumption. Only do it when we've
+        // been given valid information.
+        if (peerHost != null && peerPort != 0) {
+            peer_info = peerHost + ":" + peerPort;
+        }
+
+        // Massive hack for compatibility. In particular, Java usually
+        // specifies the peer information here. NSS uses SSL_SetURL not only
+        // for hostname verification, but also for SNI (!!) on the client.
+        // This means that there's no way to indicate (to those servers like
+        // google.com which require SNI) hostname for the client WITHOUT
+        // also validating the hostname at certificate verification time.
+        // Because the certificate hostname explicitly isn't provided (per
+        // JCA specification) for validation, this might break other clients
+        // which don't provide this information. However, the alternative is
+        // that we never add SNI indication, ever.
+        //
+        // Specifically, this breaks a dead-simple Apache HTTP Components
+        // client:
+        //
+        //     CloseableHttpClient client = HttpClients.createDefault();
+        //     HttpGet request = new HttpGet("https://google.com/");
+        //     HttpResponse response = client.execute(request);
+        //     System.out.println(response);
+        //
+        // Without this, we have no way for the above to work.
+        setHostname(peerHost);
 
         debug("JSSEngine: constructor(" + peerHost + ", " + peerPort + ")");
     }
@@ -92,7 +118,15 @@ public class JSSEngineReferenceImpl extends JSSEngine {
                      org.mozilla.jss.crypto.PrivateKey localKey) {
         super(peerHost, peerPort, localCert, localKey);
 
-        peer_info = peerHost + ":" + peerPort;
+        // Signal host and port for session resumption. Only do it when we've
+        // been given valid information.
+        if (peerHost != null && peerPort != 0) {
+            peer_info = peerHost + ":" + peerPort;
+        }
+
+        // See above.
+        setHostname(peerHost);
+
         prefix = prefix + "[" + peer_info + "] ";
 
         debug("JSSEngine: constructor(" + peerHost + ", " + peerPort + ", " + localCert + ", " + localKey + ")");
@@ -228,6 +262,17 @@ public class JSSEngineReferenceImpl extends JSSEngine {
                 throw new SSLException("Unable to attach client certificate auth callback.");
             }
         }
+
+        if (hostname == null) {
+            // When we're a client with no hostname, assume we're running
+            // under standard JDK JCA semantics with no hostname available.
+            // Bypass NSS's hostname check by adding a BadCertHandler, which
+            // check ONLY for the bad hostname error and allows it.
+            ssl_fd.badCertHandler = new BypassBadHostname(ssl_fd, 0);
+            if (SSL.ConfigSyncBadCertCallback(ssl_fd) != SSL.SECSuccess) {
+                throw new SSLException("Unable to attach bad cert callback.");
+            }
+        }
     }
 
     private void initServer() throws SSLException {
@@ -390,7 +435,7 @@ public class JSSEngineReferenceImpl extends JSSEngine {
             // from Runnable, so we can reuse it here as well. We can create
             // it ahead of time though. In this case, checkNeedCertValidation()
             // is never called.
-            ssl_fd.handler = new CertValidationTask(ssl_fd);
+            ssl_fd.certAuthHandler = new CertValidationTask(ssl_fd);
 
             if (SSL.ConfigSyncTrustManagerCertAuthCallback(ssl_fd) == SSL.SECFailure) {
                 throw new SSLException("Unable to configure TrustManager validation on this JSSengine: " + errorText(PR.GetError()));
@@ -734,7 +779,7 @@ public class JSSEngineReferenceImpl extends JSSEngine {
             return data_index;
         }
 
-        for (data_index = 0; data_index < data.length; data_index++) {
+        for (data_index = 0; data_index < data.length;) {
             // Ensure we have have a buffer with capacity.
             while ((buffers[buffer_index] == null || buffers[buffer_index].remaining() <= 0) &&
                     (buffer_index < offset + length)) {
@@ -1639,4 +1684,18 @@ public class JSSEngineReferenceImpl extends JSSEngine {
             return nss_code;
         }
     }
+
+    private class BypassBadHostname extends BadCertHandler {
+        public BypassBadHostname(SSLFDProxy fd, int error) {
+            super(fd, error);
+        }
+
+        public int check(SSLFDProxy fd, int error) {
+            if (error == SSLErrors.BAD_CERT_DOMAIN) {
+                return 0;
+            }
+
+            return error;
+        }
+    }
 }


=====================================
org/mozilla/jss/ssl/jssl.h
=====================================
@@ -106,7 +106,7 @@ JSSL_DestroySocketData(JNIEnv *env, JSSL_SocketData *sd);
 
 
 extern PRInt32 JSSL_enums[];
-#define JSSL_enums_size 36
+#define JSSL_enums_size 37
 int JSSL_enums_reverse(PRInt32 value);
 
 JSSL_SocketData*



View it on GitLab: https://salsa.debian.org/freeipa-team/jss/-/compare/6d788286ebf256b9365244dd3e612bec01d52532...a715520a0dc7d4ad9625bdbb1e76bc314e7ad1b9

-- 
View it on GitLab: https://salsa.debian.org/freeipa-team/jss/-/compare/6d788286ebf256b9365244dd3e612bec01d52532...a715520a0dc7d4ad9625bdbb1e76bc314e7ad1b9
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-freeipa-devel/attachments/20200914/28a00b3f/attachment-0001.html>


More information about the Pkg-freeipa-devel mailing list