Skip to content

Commit

Permalink
Workaround for SSL events in JSSEngine
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
edewata committed Aug 20, 2024
1 parent 5eac839 commit 42a7dee
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 17 deletions.
34 changes: 34 additions & 0 deletions base/src/main/java/org/mozilla/jss/nss/SSLFDProxy.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -53,11 +61,37 @@ 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);
}

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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/*
Expand All @@ -30,6 +31,10 @@ public SSLHandshakeCompletedEvent(SSLSocket socket) {
super(socket);
}

public SSLHandshakeCompletedEvent(SSLFDProxy proxy) {
super(proxy);
}

public SSLHandshakeCompletedEvent(JSSEngine engine) {
super(engine);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -285,6 +286,8 @@ private void init() throws SSLException {
// certificate.
applyTrustManagers();

configureSocketListener();

// Finally, set up any debug logging necessary.
createLoggingSocket();
}
Expand Down Expand Up @@ -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()");

Expand Down
121 changes: 107 additions & 14 deletions native/src/main/native/org/mozilla/jss/nss/SSLFDProxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}
Expand All @@ -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
Expand All @@ -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;
}
Expand All @@ -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
Expand Down Expand Up @@ -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;
}
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion native/src/main/native/org/mozilla/jss/nss/SSLFDProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
5 changes: 5 additions & 0 deletions native/src/main/native/org/mozilla/jss/util/java_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down

0 comments on commit 42a7dee

Please sign in to comment.