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
  */