From 60fd9b6d7fe288bb09cb6c674f949321f14f814f Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" Date: Tue, 6 Aug 2024 15:54:11 -0500 Subject: [PATCH] Workaround for SSL events in JSSEngine Currently JSSEngine does not generate SSL events although it seems to receive the alerts from NSS. As a temporary workaround, the SSLFDProxy has been updated to keep a list of SSL socket listeners, then JSSEngine will add a listener into it. When NSS generates an SSL event, it will be passed to SSLFDProxy listeners directly, then eventually to JSSEngine listeners as well. The code that creates the SSL event in JSS_NSS_addSSLAlert() has been moved into JSS_NSS_createSSLAlert() so it can be reused. --- .../java/org/mozilla/jss/nss/SSLFDProxy.java | 34 +++++ .../jss/ssl/SSLHandshakeCompletedEvent.java | 9 +- .../jss/ssl/javax/JSSEngineReferenceImpl.java | 24 ++++ .../native/org/mozilla/jss/nss/SSLFDProxy.c | 121 ++++++++++++++++-- .../native/org/mozilla/jss/nss/SSLFDProxy.h | 3 +- .../native/org/mozilla/jss/util/java_ids.h | 5 + 6 files changed, 179 insertions(+), 17 deletions(-) diff --git a/base/src/main/java/org/mozilla/jss/nss/SSLFDProxy.java b/base/src/main/java/org/mozilla/jss/nss/SSLFDProxy.java index 7cbbe2dd1..8e08f079a 100644 --- a/base/src/main/java/org/mozilla/jss/nss/SSLFDProxy.java +++ b/base/src/main/java/org/mozilla/jss/nss/SSLFDProxy.java @@ -1,22 +1,30 @@ package org.mozilla.jss.nss; import java.util.ArrayList; +import java.util.List; import org.mozilla.jss.crypto.X509Certificate; import org.mozilla.jss.pkcs11.PK11Cert; import org.mozilla.jss.ssl.SSLAlertEvent; +import org.mozilla.jss.ssl.SSLHandshakeCompletedEvent; +import org.mozilla.jss.ssl.SSLSocketListener; import org.mozilla.jss.util.GlobalRefProxy; public class SSLFDProxy extends PRFDProxy { public PK11Cert clientCert; public GlobalRefProxy globalRef; + // inboundAlerts and outboundAlerts do not seem to be working properly + // TODO: investigate the problem public ArrayList inboundAlerts; public int inboundOffset; public ArrayList outboundAlerts; public int outboundOffset; + // temporary workaround for inboundAlerts and outboundAlerts + public List socketListeners = new ArrayList<>(); + public boolean needCertValidation; public boolean needBadCertValidation; public int badCertError; @@ -53,6 +61,14 @@ protected synchronized void releaseNativeResources() throws Exception { } } + public void addSocketListener(SSLSocketListener socketListener) { + socketListeners.add(socketListener); + } + + public void removeSocketListener(SSLSocketListener socketListener) { + socketListeners.remove(socketListener); + } + public int invokeCertAuthHandler() { return certAuthHandler.check(this); } @@ -60,4 +76,22 @@ public int invokeCertAuthHandler() { public int invokeBadCertHandler(int error) { return badCertHandler.check(this, error); } + + public void fireHandshakeCompleted(SSLHandshakeCompletedEvent event) { + for (SSLSocketListener socketListener : socketListeners) { + socketListener.handshakeCompleted(event); + } + } + + public void fireAlertReceived(SSLAlertEvent event) { + for (SSLSocketListener socketListener : socketListeners) { + socketListener.alertReceived(event); + } + } + + public void fireAlertSent(SSLAlertEvent event) { + for (SSLSocketListener socketListener : socketListeners) { + socketListener.alertSent(event); + } + } } diff --git a/base/src/main/java/org/mozilla/jss/ssl/SSLHandshakeCompletedEvent.java b/base/src/main/java/org/mozilla/jss/ssl/SSLHandshakeCompletedEvent.java index 00a698be2..f6332e3ed 100644 --- a/base/src/main/java/org/mozilla/jss/ssl/SSLHandshakeCompletedEvent.java +++ b/base/src/main/java/org/mozilla/jss/ssl/SSLHandshakeCompletedEvent.java @@ -9,9 +9,10 @@ package org.mozilla.jss.ssl; -import java.net.*; -import java.util.*; +import java.net.SocketException; +import java.util.EventObject; +import org.mozilla.jss.nss.SSLFDProxy; import org.mozilla.jss.ssl.javax.JSSEngine; /* @@ -30,6 +31,10 @@ public SSLHandshakeCompletedEvent(SSLSocket socket) { super(socket); } + public SSLHandshakeCompletedEvent(SSLFDProxy proxy) { + super(proxy); + } + public SSLHandshakeCompletedEvent(JSSEngine engine) { super(engine); } diff --git a/base/src/main/java/org/mozilla/jss/ssl/javax/JSSEngineReferenceImpl.java b/base/src/main/java/org/mozilla/jss/ssl/javax/JSSEngineReferenceImpl.java index 8e7ad0f14..0d02169d7 100644 --- a/base/src/main/java/org/mozilla/jss/ssl/javax/JSSEngineReferenceImpl.java +++ b/base/src/main/java/org/mozilla/jss/ssl/javax/JSSEngineReferenceImpl.java @@ -37,6 +37,7 @@ import org.mozilla.jss.ssl.SSLAlertLevel; import org.mozilla.jss.ssl.SSLCipher; import org.mozilla.jss.ssl.SSLHandshakeCompletedEvent; +import org.mozilla.jss.ssl.SSLSocketListener; import org.mozilla.jss.ssl.SSLVersion; import org.mozilla.jss.ssl.SSLVersionRange; @@ -285,6 +286,8 @@ private void init() throws SSLException { // certificate. applyTrustManagers(); + configureSocketListener(); + // Finally, set up any debug logging necessary. createLoggingSocket(); } @@ -534,6 +537,27 @@ private void applyHosts() throws SSLException { } } + private void configureSocketListener() { + + // register a listener in SSLFDProxy + ssl_fd.addSocketListener(new SSLSocketListener() { + @Override + public void handshakeCompleted(SSLHandshakeCompletedEvent event) { + fireHandshakeComplete(event); + } + + @Override + public void alertReceived(SSLAlertEvent event) { + fireAlertReceived(event); + } + + @Override + public void alertSent(SSLAlertEvent event) { + fireAlertSent(event); + } + }); + } + private void applyTrustManagers() throws SSLException { debug("JSSEngine: applyTrustManagers()"); diff --git a/native/src/main/native/org/mozilla/jss/nss/SSLFDProxy.c b/native/src/main/native/org/mozilla/jss/nss/SSLFDProxy.c index a7ef33541..b78cf1d8a 100644 --- a/native/src/main/native/org/mozilla/jss/nss/SSLFDProxy.c +++ b/native/src/main/native/org/mozilla/jss/nss/SSLFDProxy.c @@ -104,37 +104,40 @@ JSS_NSS_getGlobalRef(JNIEnv *env, jobject sslfd_proxy, jobject *global_ref) return PR_SUCCESS; } -PRStatus -JSS_NSS_addSSLAlert(JNIEnv *env, jobject sslfd_proxy, jobject list, - const SSLAlert *alert) +jobject +JSS_NSS_createSSLAlert(JNIEnv *env, jobject sslfd_proxy, const SSLAlert *alert) { jclass eventClass; jmethodID eventConstructor; jobject event; - jclass eventListClass; - jmethodID arrayListAdd; - - PR_ASSERT(env != NULL && sslfd_proxy != NULL && list != NULL && alert != NULL); + PR_ASSERT(env != NULL && sslfd_proxy != NULL && alert != NULL); /* Build the new alert event object (org.mozilla.jss.ssl.SSLAlertEvent). */ eventClass = (*env)->FindClass(env, SSL_ALERT_EVENT_CLASS); if (eventClass == NULL) { - return PR_FAILURE; + return NULL; } eventConstructor = (*env)->GetMethodID(env, eventClass, "", "(L" SSLFD_PROXY_CLASS_NAME ";II)V"); if (eventConstructor == NULL) { - return PR_FAILURE; + return NULL; } event = (*env)->NewObject(env, eventClass, eventConstructor, sslfd_proxy, (int)alert->level, (int)alert->description); - if (event == NULL) { - return PR_FAILURE; - } + return event; +} + +PRStatus +JSS_NSS_addSSLAlert(JNIEnv *env, jobject list, jobject event) +{ + jclass eventListClass; + jmethodID arrayListAdd; + + PR_ASSERT(env != NULL && list != NULL && event != NULL); /* Add it to the event list. */ eventListClass = (*env)->GetObjectClass(env, list); @@ -160,6 +163,11 @@ JSSL_SSLFDAlertReceivedCallback(const PRFileDesc *fd, void *arg, const SSLAlert jobject sslfd_proxy = (jobject)arg; jobject list; + jobject event; + + jclass proxyClass; + jmethodID proxyFireAlertReceivedMethod; + if (fd == NULL || arg == NULL || alert == NULL || JSS_javaVM == NULL) { return; } @@ -172,9 +180,32 @@ JSSL_SSLFDAlertReceivedCallback(const PRFileDesc *fd, void *arg, const SSLAlert return; } - if (JSS_NSS_addSSLAlert(env, sslfd_proxy, list, alert) != PR_SUCCESS) { + // event = new SSLAlertEvent() + event = JSS_NSS_createSSLAlert(env, sslfd_proxy, alert); + + if (event == NULL) { + return; + } + + // sslfd_proxy.inboundAlerts.add(event) + if (JSS_NSS_addSSLAlert(env, list, event) != PR_SUCCESS) { + return; + } + + proxyClass = (*env)->GetObjectClass(env, sslfd_proxy); + if (proxyClass == NULL) { return; } + + proxyFireAlertReceivedMethod = (*env)->GetMethodID( + env, proxyClass, "fireAlertReceived", + "(L" SSL_ALERT_EVENT_CLASS ";)V"); + if (proxyFireAlertReceivedMethod == NULL) { + return; + } + + // sslfd_proxy.fireAlertReceived(event) + (void)(*env)->CallVoidMethod(env, sslfd_proxy, proxyFireAlertReceivedMethod, event); } void @@ -184,6 +215,11 @@ JSSL_SSLFDAlertSentCallback(const PRFileDesc *fd, void *arg, const SSLAlert *ale jobject sslfd_proxy = (jobject)arg; jobject list; + jobject event; + + jclass proxyClass; + jmethodID proxyFireAlertSentMethod; + if (fd == NULL || arg == NULL || alert == NULL || JSS_javaVM == NULL) { return; } @@ -196,9 +232,32 @@ JSSL_SSLFDAlertSentCallback(const PRFileDesc *fd, void *arg, const SSLAlert *ale return; } - if (JSS_NSS_addSSLAlert(env, sslfd_proxy, list, alert) != PR_SUCCESS) { + // event = new SSLAlertEvent() + event = JSS_NSS_createSSLAlert(env, sslfd_proxy, alert); + + if (event == NULL) { return; } + + // sslfd_proxy.outboundAlerts.add(event) + if (JSS_NSS_addSSLAlert(env, list, event) != PR_SUCCESS) { + return; + } + + proxyClass = (*env)->GetObjectClass(env, sslfd_proxy); + if (proxyClass == NULL) { + return; + } + + proxyFireAlertSentMethod = (*env)->GetMethodID( + env, proxyClass, "fireAlertSent", + "(L" SSL_ALERT_EVENT_CLASS ";)V"); + if (proxyFireAlertSentMethod == NULL) { + return; + } + + // sslfd_proxy.fireAlertSent(event) + (void)(*env)->CallVoidMethod(env, sslfd_proxy, proxyFireAlertSentMethod, event); } SECStatus @@ -250,6 +309,12 @@ JSSL_SSLFDHandshakeComplete(PRFileDesc *fd, void *client_data) jclass sslfdProxyClass; jfieldID handshakeCompleteField; + jclass eventClass; + jmethodID eventConstructor; + jobject event; + + jmethodID proxyFireHandshakeCompletedMethod; + if (fd == NULL || client_data == NULL || JSS_javaVM == NULL) { return; } @@ -270,6 +335,34 @@ JSSL_SSLFDHandshakeComplete(PRFileDesc *fd, void *client_data) } (*env)->SetBooleanField(env, sslfd_proxy, handshakeCompleteField, JNI_TRUE); + + eventClass = (*env)->FindClass(env, SSL_HANDSHAKE_COMPLETED_EVENT_CLASS); + if (eventClass == NULL) { + return; + } + + eventConstructor = (*env)->GetMethodID(env, eventClass, "", + "(L" SSLFD_PROXY_CLASS_NAME ";)V"); + if (eventConstructor == NULL) { + return; + } + + // event = new SSLHandshakeCompletedEvent() + event = (*env)->NewObject(env, eventClass, eventConstructor, + sslfd_proxy); + if (event == NULL) { + return; + } + + proxyFireHandshakeCompletedMethod = (*env)->GetMethodID( + env, sslfdProxyClass, "fireHandshakeCompleted", + "(L" SSL_HANDSHAKE_COMPLETED_EVENT_CLASS ";)V"); + if (proxyFireHandshakeCompletedMethod == NULL) { + return; + } + + // sslfd_proxy.fireHandshakeCompleted(event) + (void)(*env)->CallVoidMethod(env, sslfd_proxy, proxyFireHandshakeCompletedMethod, event); } SECStatus diff --git a/native/src/main/native/org/mozilla/jss/nss/SSLFDProxy.h b/native/src/main/native/org/mozilla/jss/nss/SSLFDProxy.h index 2185e802e..9fa947930 100644 --- a/native/src/main/native/org/mozilla/jss/nss/SSLFDProxy.h +++ b/native/src/main/native/org/mozilla/jss/nss/SSLFDProxy.h @@ -10,7 +10,8 @@ PRStatus JSS_NSS_getSSLAlertSentList(JNIEnv *env, jobject sslfd_proxy, jobject * PRStatus JSS_NSS_getSSLAlertReceivedList(JNIEnv *env, jobject sslfd_proxy, jobject *list); -PRStatus JSS_NSS_addSSLAlert(JNIEnv *env, jobject sslfd_proxy, jobject list, const SSLAlert *alert); +jobject JSS_NSS_createSSLAlert(JNIEnv *env, jobject sslfd_proxy, const SSLAlert *alert); +PRStatus JSS_NSS_addSSLAlert(JNIEnv *env, jobject list, jobject event); PRStatus JSS_NSS_getGlobalRef(JNIEnv *env, jobject sslfd_proxy, jobject *global_ref); diff --git a/native/src/main/native/org/mozilla/jss/util/java_ids.h b/native/src/main/native/org/mozilla/jss/util/java_ids.h index 01b165999..9b47ad273 100644 --- a/native/src/main/native/org/mozilla/jss/util/java_ids.h +++ b/native/src/main/native/org/mozilla/jss/util/java_ids.h @@ -285,6 +285,11 @@ PR_BEGIN_EXTERN_C */ #define SSL_ALERT_EVENT_CLASS "org/mozilla/jss/ssl/SSLAlertEvent" +/* + * SSLHandshakeCompletedEvent + */ +#define SSL_HANDSHAKE_COMPLETED_EVENT_CLASS "org/mozilla/jss/ssl/SSLHandshakeCompletedEvent" + /* * SSLCertificateApprovalCallback */