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<SSLAlertEvent> inboundAlerts; public int inboundOffset; public ArrayList<SSLAlertEvent> outboundAlerts; public int outboundOffset; + // temporary workaround for inboundAlerts and outboundAlerts + public List<SSLSocketListener> 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, "<init>", "(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, "<init>", + "(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 */