diff --git a/native/com_wolfssl_WolfSSLSession.c b/native/com_wolfssl_WolfSSLSession.c
index ba8bb1df..5ed693cd 100644
--- a/native/com_wolfssl_WolfSSLSession.c
+++ b/native/com_wolfssl_WolfSSLSession.c
@@ -2358,6 +2358,33 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useCertificateChainBuffer
return ret;
}
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useCertificateChainBufferFormat
+ (JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray in, jlong sz, jint format)
+{
+ int ret = WOLFSSL_FAILURE;
+ byte* buff = NULL;
+ word32 buffSz = 0;
+ WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
+ (void)jcl;
+ (void)sz;
+
+ if (jenv == NULL || ssl == NULL || in == NULL) {
+ return (jint)BAD_FUNC_ARG;
+ }
+
+ buff = (byte*)(*jenv)->GetByteArrayElements(jenv, in, NULL);
+ buffSz = (*jenv)->GetArrayLength(jenv, in);
+
+ if (buff != NULL && buffSz > 0) {
+ ret = wolfSSL_use_certificate_chain_buffer_format(
+ ssl, buff, buffSz, format);
+ }
+
+ (*jenv)->ReleaseByteArrayElements(jenv, in, (jbyte*)buff, JNI_ABORT);
+
+ return (jint)ret;
+}
+
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setGroupMessages
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
diff --git a/native/com_wolfssl_WolfSSLSession.h b/native/com_wolfssl_WolfSSLSession.h
index 47fb578f..4368d994 100644
--- a/native/com_wolfssl_WolfSSLSession.h
+++ b/native/com_wolfssl_WolfSSLSession.h
@@ -367,6 +367,14 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_usePrivateKeyBuffer
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useCertificateChainBuffer
(JNIEnv *, jobject, jlong, jbyteArray, jlong);
+/*
+ * Class: com_wolfssl_WolfSSLSession
+ * Method: useCertificateChainBufferFormat
+ * Signature: (J[BJI)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useCertificateChainBufferFormat
+ (JNIEnv *, jobject, jlong, jbyteArray, jlong, jint);
+
/*
* Class: com_wolfssl_WolfSSLSession
* Method: setGroupMessages
diff --git a/src/java/com/wolfssl/WolfSSLContext.java b/src/java/com/wolfssl/WolfSSLContext.java
index 5448e3c4..81f65fb0 100644
--- a/src/java/com/wolfssl/WolfSSLContext.java
+++ b/src/java/com/wolfssl/WolfSSLContext.java
@@ -1052,7 +1052,7 @@ public int useCertificateChainBuffer(byte[] in, long sz)
* and start with the subject's certificate, ending with the root
* certificate.
*
- * @param in the input buffer containing the PEM-formatted
+ * @param in the input buffer containing the PEM or DER formatted
* certificate chain to be loaded.
* @param sz the size of the input buffer, in
* @param format format of the certificate buffer being loaded - either
diff --git a/src/java/com/wolfssl/WolfSSLSession.java b/src/java/com/wolfssl/WolfSSLSession.java
index e41f209c..7e6fa80b 100644
--- a/src/java/com/wolfssl/WolfSSLSession.java
+++ b/src/java/com/wolfssl/WolfSSLSession.java
@@ -297,6 +297,8 @@ private native int usePrivateKeyBuffer(long ssl, byte[] in, long sz,
int format);
private native int useCertificateChainBuffer(long ssl, byte[] in,
long sz);
+ private native int useCertificateChainBufferFormat(
+ long ssl, byte[] in, long sz, int format);
private native int setGroupMessages(long ssl);
private native int enableCRL(long ssl, int options);
private native int disableCRL(long ssl);
@@ -2008,6 +2010,52 @@ public int useCertificateChainBuffer(byte[] in, long sz)
}
}
+ /**
+ * Loads a certificate chain buffer into the SSL object in specific format.
+ * This method behaves like the non-buffered version, only differing
+ * in its ability to be called with a buffer as input instead of a file.
+ * This function is similar to useCertificateChainBuffer(), but allows
+ * the input format to be specified. The format must be either DER or PEM,
+ * and start with the subject's certificate, ending with the root
+ * certificate.
+ *
+ * @param in the input buffer containing the PEM or DER formatted
+ * certificate chain to be loaded.
+ * @param sz the size of the input buffer, in
+ * @param format format of the certificate buffer being loaded - either
+ * SSL_FILETYPE_PEM or SSL_FILETYPE_ASN1
+ * @return SSL_SUCCESS
upon success,
+ * SSL_FAILURE
upon general failure,
+ * SSL_BAD_FILETYPE
if the file is
+ * in the wrong format, SSL_BAD_FILE
+ * if the file doesn't exist, can't be read, or is
+ * corrupted. MEMORY_E
if an out of
+ * memory condition occurs, ASN_INPUT_E
+ * if Base16 decoding fails on the file,
+ * BUFFER_E
if a chain buffer is
+ * bigger than the receiving buffer, and
+ * BAD_FUNC_ARG
if invalid input arguments
+ * are provided.
+ * @throws IllegalStateException WolfSSLContext has been freed
+ * @throws WolfSSLJNIException Internal JNI error
+ * @see #useCertificateBuffer(byte[], long, int)
+ * @see #usePrivateKeyBuffer(byte[], long, int)
+ * @see WolfSSLSession#useCertificateBuffer(byte[], long, int)
+ * @see WolfSSLSession#usePrivateKeyBuffer(byte[], long, int)
+ * @see WolfSSLSession#useCertificateChainBuffer(byte[], long)
+ */
+ public int useCertificateChainBufferFormat(byte[] in, long sz, int format)
+ throws IllegalStateException, WolfSSLJNIException {
+
+ confirmObjectIsActive();
+
+ synchronized (sslLock) {
+ return useCertificateChainBufferFormat(
+ getSessionPtr(), in, sz, format);
+ }
+ }
+
+
/**
* Turns on grouping of the handshake messages where possible using the
* SSL session.
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java b/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java
index 1ed146ba..5dd164ac 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java
@@ -178,7 +178,6 @@ private void createCtx() throws WolfSSLException {
try {
LoadTrustedRootCerts();
- LoadClientKeyAndCertChain();
} catch (Exception e) {
throw new IllegalArgumentException(e);
@@ -369,101 +368,6 @@ private void LoadTrustedRootCerts() {
}
}
- private void LoadClientKeyAndCertChain() throws Exception {
-
- int ret;
- int offset;
- X509KeyManager km = authStore.getX509KeyManager();
- String javaVersion = System.getProperty("java.version");
-
- if (km == null) {
- WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
- "internal KeyManager is null, no cert/key to load");
- return;
- }
-
- /* We only load keys from algorithms enabled in native wolfSSL,
- * and in the priority order of ECC first, then RSA. JDK 1.7.0_201
- * and 1.7.0_171 have a bug that causes PrivateKey.getEncoded() to
- * fail for EC keys. This has been fixed in later JDK versions,
- * but skip adding EC here if we're running on those versions . */
- ArrayList keyAlgos = new ArrayList();
- if (WolfSSL.EccEnabled() &&
- (!javaVersion.equals("1.7.0_201") &&
- !javaVersion.equals("1.7.0_171"))) {
- keyAlgos.add("EC");
- }
- if (WolfSSL.RsaEnabled()) {
- keyAlgos.add("RSA");
- }
-
- String[] keyStrings = new String[keyAlgos.size()];
- keyStrings = keyAlgos.toArray(keyStrings);
-
- String alias = km.chooseClientAlias(keyStrings, null, null);
- authStore.setCertAlias(alias);
-
- /* client private key */
- PrivateKey privKey = km.getPrivateKey(alias);
-
- if (privKey != null) {
- byte[] privKeyEncoded = privKey.getEncoded();
- if (!privKey.getFormat().equals("PKCS#8")) {
- throw new Exception("Private key is not in PKCS#8 format");
- }
-
- /* skip past PKCS#8 offset */
- offset = WolfSSL.getPkcs8TraditionalOffset(privKeyEncoded, 0,
- privKeyEncoded.length);
-
- byte[] privKeyTraditional = Arrays.copyOfRange(privKeyEncoded,
- offset, privKeyEncoded.length);
-
- ret = ctx.usePrivateKeyBuffer(privKeyTraditional,
- privKeyTraditional.length, WolfSSL.SSL_FILETYPE_ASN1);
-
- if (ret != WolfSSL.SSL_SUCCESS) {
- throw new WolfSSLJNIException("Failed to load private key " +
- "buffer, err = " + ret);
- }
- WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "loaded private key from KeyManager (alias: " + alias +
- ")");
- } else {
- WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "no private key found, skipped loading");
- }
-
- /* client certificate chain */
- X509Certificate[] cert = km.getCertificateChain(alias);
-
- if (cert != null) {
- ByteArrayOutputStream certStream = new ByteArrayOutputStream();
- int chainLength = 0;
- for (int i = 0; i < cert.length; i++) {
- /* concatenate certs into single byte array */
- certStream.write(cert[i].getEncoded());
- chainLength++;
- }
- byte[] certChain = certStream.toByteArray();
- certStream.close();
-
- ret = ctx.useCertificateChainBufferFormat(certChain,
- certChain.length, WolfSSL.SSL_FILETYPE_ASN1);
-
- if (ret != WolfSSL.SSL_SUCCESS) {
- throw new WolfSSLJNIException("Failed to load certificate " +
- "chain buffer, err = " + ret);
- }
- WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "loaded certificate chain from KeyManager (length: " +
- chainLength + ")");
- } else {
- WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "no certificate or chain found, skipped loading");
- }
- }
-
/**
* Initializes a SSLContext.
*
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java b/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
index 512412ab..f0a3f065 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
@@ -28,6 +28,7 @@
import com.wolfssl.WolfSSLJNIException;
import com.wolfssl.WolfSSLSession;
import com.wolfssl.WolfSSLALPNSelectCallback;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ReadOnlyBufferException;
import java.util.function.BiFunction;
@@ -36,6 +37,7 @@
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
+import java.security.cert.CertificateEncodingException;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
@@ -164,6 +166,14 @@ protected WolfSSLEngine(com.wolfssl.WolfSSLContext ctx,
}
EngineHelper = new WolfSSLEngineHelper(this.ssl, this.authStore,
this.params);
+
+ try {
+ EngineHelper.LoadKeyAndCertChain(null, this);
+ } catch (CertificateEncodingException | IOException e) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "failed to load private key and/or cert chain");
+ throw new WolfSSLException(e);
+ }
}
/**
@@ -192,6 +202,14 @@ protected WolfSSLEngine(com.wolfssl.WolfSSLContext ctx,
}
EngineHelper = new WolfSSLEngineHelper(this.ssl, this.authStore,
this.params, port, host);
+
+ try {
+ EngineHelper.LoadKeyAndCertChain(null, this);
+ } catch (CertificateEncodingException | IOException e) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "failed to load private key and/or cert chain");
+ throw new WolfSSLException(e);
+ }
}
/**
@@ -350,6 +368,13 @@ private synchronized int ClosingConnection() throws SocketException {
/* send/recv close_notify as needed */
synchronized (ioLock) {
ret = ssl.shutdownSSL();
+ if (ssl.getError(ret) == WolfSSL.SSL_ERROR_ZERO_RETURN) {
+ /* got close_notify alert, reset ret to 0 to continue
+ * and let corresponding close_notify to be sent */
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "ClosingConnection(), ssl.getError() is ZERO_RETURN");
+ ret = 0;
+ }
}
UpdateCloseNotifyStatus();
@@ -757,6 +782,8 @@ private synchronized int RecvAppData(ByteBuffer[] out, int ofst, int length)
synchronized (ioLock) {
if (ssl.getShutdown() ==
WolfSSL.SSL_RECEIVED_SHUTDOWN) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "RecvAppData(), received shutdown message");
try {
ret = ClosingConnection();
if (ret > 0) {
@@ -1381,7 +1408,7 @@ public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
@Override
public synchronized void setUseClientMode(boolean mode) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "entered setUseClientMode()");
+ "entered setUseClientMode(" + mode + ")");
EngineHelper.setUseClientMode(mode);
this.clientModeSet = true;
}
@@ -1396,7 +1423,7 @@ public synchronized boolean getUseClientMode() {
@Override
public synchronized void setNeedClientAuth(boolean need) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "entered setNeedClientAuth()");
+ "entered setNeedClientAuth(" + need + ")");
EngineHelper.setNeedClientAuth(need);
}
@@ -1410,7 +1437,7 @@ public synchronized boolean getNeedClientAuth() {
@Override
public synchronized void setWantClientAuth(boolean want) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "entered setWantClientAuth()");
+ "entered setWantClientAuth(" + want + ")");
EngineHelper.setWantClientAuth(want);
}
@@ -1424,7 +1451,7 @@ public synchronized boolean getWantClientAuth() {
@Override
public synchronized void setEnableSessionCreation(boolean flag) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "entered setEnableSessionCreation()");
+ "entered setEnableSessionCreation(" + flag + ")");
EngineHelper.setEnableSessionCreation(flag);
}
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java
index 09bb63e2..95dc5faa 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java
@@ -20,12 +20,12 @@
*/
package com.wolfssl.provider.jsse;
-import com.wolfssl.WolfSSL;
-import com.wolfssl.WolfSSLException;
-import com.wolfssl.WolfSSLSession;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.Socket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
@@ -33,8 +33,18 @@
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.SSLHandshakeException;
import java.security.Security;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateEncodingException;
+
+import com.wolfssl.WolfSSL;
+import com.wolfssl.WolfSSLSession;
+import com.wolfssl.WolfSSLException;
+import com.wolfssl.WolfSSLJNIException;
/**
* This is a helper class to account for similar methods between SSLSocket
@@ -168,6 +178,206 @@ protected WolfSSLEngineHelper(WolfSSLSession ssl, WolfSSLAuthStore store,
", peer IP: " + peerAddr.getHostAddress() + ")");
}
+ /**
+ * Get the alias from the X509KeyManager to use for finding and loading
+ * the private key and certificate chain for this endpoint.
+ *
+ * @param km X509KeyManager or X509ExtendedKeyManager to poll for
+ * client/server alias name
+ * @param socket Socket or SSLSocket from which this peer is being
+ * created, may be null if engine is being used instead
+ * @param engine SSLEngine from which this peer is being created, may be
+ * null if socket is being used instead
+ *
+ * @return alias String, or null if none found
+ */
+ private String GetKeyAndCertChainAlias(X509KeyManager km, Socket sock,
+ SSLEngine engine) {
+
+ String alias = null;
+ String javaVersion = System.getProperty("java.version");
+
+ if (sock == null && engine == null) {
+ return null;
+ }
+
+ /* We only load keys from algorithms enabled in native wolfSSL,
+ * and in the priority order of ECC first, then RSA. JDK 1.7.0_201
+ * and 1.7.0_171 have a bug that causes PrivateKey.getEncoded() to
+ * fail for EC keys. This has been fixed in later JDK versions,
+ * but skip adding EC here if we're running on those versions . */
+ ArrayList keyAlgos = new ArrayList();
+ if (WolfSSL.EccEnabled() &&
+ (!javaVersion.equals("1.7.0_201") &&
+ !javaVersion.equals("1.7.0_171"))) {
+ keyAlgos.add("EC");
+ }
+ if (WolfSSL.RsaEnabled()) {
+ keyAlgos.add("RSA");
+ }
+
+ String[] keyTypes = new String[keyAlgos.size()];
+ keyTypes = keyAlgos.toArray(keyTypes);
+
+ if (clientMode) {
+ if (sock != null) {
+ alias = km.chooseClientAlias(keyTypes, null, sock);
+ }
+ else if (engine != null) {
+ if (km instanceof X509ExtendedKeyManager) {
+ alias = ((X509ExtendedKeyManager)km).
+ chooseEngineClientAlias(keyTypes, null, engine);
+ }
+ else {
+ alias = km.chooseClientAlias(keyTypes, null, null);
+ }
+ }
+ }
+ else {
+ /* Loop through available key types until we find an alias
+ * that works, or none that do and return null */
+ for (String type : keyTypes) {
+ if (sock != null) {
+ alias = km.chooseServerAlias(type, null, sock);
+ }
+ else if (engine != null) {
+ if (km instanceof X509ExtendedKeyManager) {
+ alias = ((X509ExtendedKeyManager)km).
+ chooseEngineServerAlias(type, null, engine);
+ }
+ else {
+ alias = km.chooseServerAlias(type, null, null);
+ }
+ }
+
+ if (alias != null) {
+ break;
+ }
+ }
+ }
+
+ return alias;
+ }
+
+ /**
+ * Loads the private key and certificate chain for this
+ * SSLSocket/SSLEngine to be used for performing authentication of
+ * this peer during the handshake.
+ *
+ * If there is no X509KeyManager in our WolfSSLAuthStore, skips loading
+ * private key and certificate. This means SSLContext.init() was
+ * initialized with a null KeyManager.
+ *
+ * @param sock Socket or SSLSocket associated with this connection, may
+ * be null if engine is used instead
+ * @param engine SSLEngine associated with this connection, may be null
+ * if sock used instead
+ *
+ * @throws WolfSSLException if private key is not correct format,
+ * WolfSSLAuthStore is null, or native error when loading
+ * private key or certificate.
+ * @throws CertificateEncodingException on error getting Certificate
+ * encoding before loading into native WOLFSSL
+ * @throws IOException on error concatenating certificate chain into
+ * single byte array
+ */
+ protected void LoadKeyAndCertChain(Socket sock, SSLEngine engine)
+ throws WolfSSLException, CertificateEncodingException, IOException {
+
+ int ret;
+ int offset;
+ String alias = null; /* KeyStore alias holding private key */
+ X509KeyManager km = null; /* X509KeyManager from KeyStore */
+
+ if (this.authStore == null) {
+ throw new WolfSSLException("WolfSSLAuthStore is null");
+ }
+
+ km = this.authStore.getX509KeyManager();
+ if (km == null) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
+ "internal KeyManager is null, no cert/key to load");
+ return;
+ }
+
+ /* Ask X509KeyManager to choose correct client alias from which
+ * to load private key / cert chain */
+ alias = GetKeyAndCertChainAlias(km, sock, engine);
+ authStore.setCertAlias(alias);
+
+ /* Load private key into WOLFSSL session */
+ PrivateKey privKey = km.getPrivateKey(alias);
+
+ if (privKey != null) {
+ byte[] privKeyEncoded = privKey.getEncoded();
+ if (!privKey.getFormat().equals("PKCS#8")) {
+ throw new WolfSSLException(
+ "Private key is not in PKCS#8 format");
+ }
+
+ /* Skip past PKCS#8 offset */
+ offset = WolfSSL.getPkcs8TraditionalOffset(privKeyEncoded, 0,
+ privKeyEncoded.length);
+
+ byte[] privKeyTraditional = Arrays.copyOfRange(privKeyEncoded,
+ offset, privKeyEncoded.length);
+
+ try {
+ ret = this.ssl.usePrivateKeyBuffer(privKeyTraditional,
+ privKeyTraditional.length, WolfSSL.SSL_FILETYPE_ASN1);
+ } catch (WolfSSLJNIException e) {
+ throw new WolfSSLException(e);
+ }
+
+ if (ret != WolfSSL.SSL_SUCCESS) {
+ throw new WolfSSLException("Failed to load private key " +
+ "buffer into WOLFSSL, err = " + ret);
+ }
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "loaded private key from X509KeyManager " +
+ "(alias: " + alias + ")");
+ } else {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "no private key found in X509KeyManager " +
+ "(alias: " + alias + "), skipped loading");
+ }
+
+ /* Load certificate chain */
+ X509Certificate[] cert = km.getCertificateChain(alias);
+
+ if (cert != null) {
+ ByteArrayOutputStream certStream = new ByteArrayOutputStream();
+ int chainLength = 0;
+ for (int i = 0; i < cert.length; i++) {
+ /* concatenate certs into single byte array */
+ certStream.write(cert[i].getEncoded());
+ chainLength++;
+ }
+ byte[] certChain = certStream.toByteArray();
+ certStream.close();
+
+ try {
+ ret = this.ssl.useCertificateChainBufferFormat(certChain,
+ certChain.length, WolfSSL.SSL_FILETYPE_ASN1);
+ } catch (WolfSSLJNIException e) {
+ throw new WolfSSLException(e);
+ }
+
+ if (ret != WolfSSL.SSL_SUCCESS) {
+ throw new WolfSSLException("Failed to load certificate " +
+ "chain buffer into WOLFSSL, err = " + ret);
+ }
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "loaded certificate chain from KeyManager (alias: " +
+ alias + ", length: " +
+ chainLength + ")");
+ } else {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "no certificate or chain found " +
+ "(alias: " + alias + "), skipped loading");
+ }
+ }
+
/**
* Set hostname and port
* Used internally by SSLSocket.connect(SocketAddress)
@@ -580,7 +790,8 @@ private void setLocalAuth(SSLSocket socket, SSLEngine engine) {
X509TrustManager tm = authStore.getX509TrustManager();
wicb = new WolfSSLInternalVerifyCb(authStore.getX509TrustManager(),
- this.clientMode, socket, engine);
+ this.clientMode, socket, engine,
+ this.params);
if (tm instanceof com.wolfssl.provider.jsse.WolfSSLTrustX509) {
/* use internal peer verification logic */
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLInternalVerifyCb.java b/src/java/com/wolfssl/provider/jsse/WolfSSLInternalVerifyCb.java
index dd54a36d..b394af45 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLInternalVerifyCb.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLInternalVerifyCb.java
@@ -48,6 +48,7 @@ public class WolfSSLInternalVerifyCb implements WolfSSLVerifyCallback {
private boolean clientMode;
private SSLSocket callingSocket = null;
private SSLEngine callingEngine = null;
+ private WolfSSLParameters params = null;
/**
* Create new WolfSSLInternalVerifyCb
@@ -56,13 +57,15 @@ public class WolfSSLInternalVerifyCb implements WolfSSLVerifyCallback {
* @param client boolean representing if this is client side
* @param socket SSLSocket associated with this callback, or null
* @param engine SSLEngine associated with this callback, or null
+ * @param params WolfSSLParameters associated with this callback
*/
public WolfSSLInternalVerifyCb(X509TrustManager xtm, boolean client,
- SSLSocket socket, SSLEngine engine) {
+ SSLSocket socket, SSLEngine engine, WolfSSLParameters params) {
this.tm = xtm;
this.clientMode = client;
this.callingSocket = socket;
this.callingEngine = engine;
+ this.params = params;
}
/**
@@ -114,6 +117,97 @@ else if (this.callingEngine != null) {
return 1;
}
+ /**
+ * Calls registered X509TrustManager / X509ExtendedTrustManager to
+ * verify certificate chain.
+ *
+ * @param certs Peer certificate chain to validate
+ * @param authType Authentication type
+ *
+ * @return true on successful validation, otherwise false on failure
+ */
+ private boolean VerifyCertChainWithTrustManager(X509Certificate[] certs,
+ String authType) {
+
+ try {
+ /* Call TrustManager to do cert verification, should throw
+ * CertificateException if verification fails */
+ if (this.clientMode) {
+ if (this.tm instanceof X509ExtendedTrustManager) {
+ X509ExtendedTrustManager xtm =
+ (X509ExtendedTrustManager)this.tm;
+ if (this.callingSocket != null) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "Calling TrustManager.checkServerTrusted(SSLSocket)");
+ xtm.checkServerTrusted(certs, authType,
+ this.callingSocket);
+ }
+ else if (this.callingEngine != null) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "Calling TrustManager.checkServerTrusted(SSLEngine)");
+ xtm.checkServerTrusted(certs, authType,
+ this.callingEngine);
+ }
+ else {
+ /* If we do have access to X509ExtendedTrustManager,
+ * but don't have SSLSocket/Engine, error out instead
+ * of falling back to verify without hostname. */
+ throw new Exception(
+ "SSLSocket/SSLEngine null during server peer " +
+ "verification, failed to verify");
+ }
+ }
+ else {
+ /* Basic X509TrustManager does not support HTTPS
+ * hostname verification, no SSLSocket/Engine needed */
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "Calling TrustManager.checkServerTrusted()");
+ this.tm.checkServerTrusted(certs, authType);
+ }
+
+ } else {
+ if (this.tm instanceof X509ExtendedTrustManager) {
+ X509ExtendedTrustManager xtm =
+ (X509ExtendedTrustManager)this.tm;
+ if (this.callingSocket != null) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "Calling TrustManager.checkClientTrusted(SSLSocket)");
+ xtm.checkClientTrusted(certs, authType,
+ this.callingSocket);
+ }
+ else if (this.callingEngine != null) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "Calling TrustManager.checkClientTrusted(SSLEngine)");
+ xtm.checkClientTrusted(certs, authType,
+ this.callingEngine);
+ }
+ else {
+ /* If we do have access to X509ExtendedTrustManager,
+ * but don't have SSLSocket/Engine, error out instead
+ * of falling back to verify without hostname. */
+ throw new Exception(
+ "SSLSocket/SSLEngine null during client peer " +
+ "verification, failed to verify");
+ }
+ }
+ else {
+ /* Basic X509TrustManager does not support HTTPS
+ * hostname verification, no SSLSocket/Engine needed */
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "Calling TrustManager.checkClientTrusted()");
+ this.tm.checkClientTrusted(certs, authType);
+ }
+ }
+ } catch (Exception e) {
+ /* TrustManager rejected certificate, not valid */
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "TrustManager rejected certificates, verification failed");
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Native wolfSSL verify callback.
*
@@ -128,8 +222,8 @@ else if (this.callingEngine != null) {
public int verifyCallback(int preverify_ok, long x509StorePtr) {
WolfSSLCertificate[] certs = null;
- X509Certificate[] x509certs = null;
String authType = null;
+ X509Certificate[] x509certs = new X509Certificate[0];
if (preverify_ok == 1) {
/* When using WolfSSLTrustX509 implementation of
@@ -141,10 +235,12 @@ public int verifyCallback(int preverify_ok, long x509StorePtr) {
* passed if preverify_ok == 1, so we skip doing it again here
* later on for this case */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "Native wolfSSL peer verification passed");
+ "Native wolfSSL peer verification passed (clientMode: " +
+ this.clientMode + ")");
} else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "NOTE: Native wolfSSL peer verification failed");
+ "NOTE: Native wolfSSL peer verification failed " +
+ "(clientMode: " + this.clientMode + ")");
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
" Continuing with X509TrustManager verification");
}
@@ -173,10 +269,11 @@ public int verifyCallback(int preverify_ok, long x509StorePtr) {
}
} catch (CertificateException | IOException |
WolfSSLJNIException ce) {
- /* failed to get cert array, give app null array */
+ /* failed to get cert array, give app empty array */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "Failed to get X509Certificate[] array, set to null");
- x509certs = null;
+ "Failed to get X509Certificate[] array, set to " +
+ "empty array");
+ x509certs = new X509Certificate[0];
}
/* get authType, use first cert */
@@ -205,87 +302,51 @@ public int verifyCallback(int preverify_ok, long x509StorePtr) {
* We do that here and return before going on to additional
* checkServerTrusted/checkClientTrusted() so that we do not
* duplicate verification. */
- if (preverify_ok == 1 && (tm instanceof WolfSSLTrustX509)) {
+ if ((preverify_ok == 1) && (x509certs.length > 0) &&
+ (tm instanceof WolfSSLTrustX509)) {
return verifyHostnameOnly(x509certs[0]);
}
- try {
- /* poll TrustManager for cert verification, should throw
- * CertificateException if verification fails */
- if (clientMode) {
- if (tm instanceof X509ExtendedTrustManager) {
- X509ExtendedTrustManager xtm = (X509ExtendedTrustManager)tm;
- if (this.callingSocket != null) {
- WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "Calling TrustManager.checkServerTrusted(SSLSocket)");
- xtm.checkServerTrusted(x509certs, authType,
- this.callingSocket);
- }
- else if (this.callingEngine != null) {
- WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "Calling TrustManager.checkServerTrusted(SSLEngine)");
- xtm.checkServerTrusted(x509certs, authType,
- this.callingEngine);
- }
- else {
- /* If we do have access to X509ExtendedTrustManager,
- * but don't have SSLSocket/Engine, error out instead
- * of falling back to verify without hostname. */
- throw new Exception(
- "SSLSocket/SSLEngine null during server peer " +
- "verification, failed to verify");
- }
- }
- else {
- /* Basic X509TrustManager does not support HTTPS
- * hostname verification, no SSLSocket/Engine needed */
- WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "Calling TrustManager.checkServerTrusted()");
- tm.checkServerTrusted(x509certs, authType);
- }
-
- } else {
- if (tm instanceof X509ExtendedTrustManager) {
- X509ExtendedTrustManager xtm = (X509ExtendedTrustManager)tm;
- if (this.callingSocket != null) {
- WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "Calling TrustManager.checkClientTrusted(SSLSocket)");
- xtm.checkClientTrusted(x509certs, authType,
- this.callingSocket);
- }
- else if (this.callingEngine != null) {
- WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "Calling TrustManager.checkClientTrusted(SSLEngine)");
- xtm.checkClientTrusted(x509certs, authType,
- this.callingEngine);
- }
- else {
- /* If we do have access to X509ExtendedTrustManager,
- * but don't have SSLSocket/Engine, error out instead
- * of falling back to verify without hostname. */
- throw new Exception(
- "SSLSocket/SSLEngine null during client peer " +
- "verification, failed to verify");
- }
- }
- else {
- /* Basic X509TrustManager does not support HTTPS
- * hostname verification, no SSLSocket/Engine needed */
- WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "Calling TrustManager.checkClientTrusted()");
- tm.checkClientTrusted(x509certs, authType);
- }
- }
- } catch (Exception e) {
- /* TrustManager rejected certificate, not valid */
+ /* If server-side application has explicitly disabled client
+ * authentication, return as success and skip X509TrustManager
+ * verification */
+ if ((!this.clientMode) && (this.params != null) &&
+ (!this.params.getNeedClientAuth())) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
- "TrustManager rejected certificates, verification failed");
- return 0;
+ "Application has disabled client verification with " +
+ "setNeedClientAuth(false), skipping verification");
+ return 1;
+ }
+ else if ((preverify_ok == 1) && (x509certs.length == 0) &&
+ (!this.clientMode) && (this.params != null) &&
+ this.params.getWantClientAuth() &&
+ (!this.params.getNeedClientAuth())) {
+ /* If native wolfSSL verification has passed, and we have no peer
+ * certificates, if application has set client authentication be
+ * requested (wantClientAuth == true), but not fatal if no
+ * certificate was sent (needClientAuth == false), don't call
+ * TrustManager with empty certificate chain just consider
+ * verification successful at this point */
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "No client cert sent and client auth marked optional, not " +
+ "calling TrustManager for hostname verification");
+ }
+ else {
+ /* Poll X509TrustManager / X509ExtendedTrustManager for certificate
+ * verification status. Returns 0 if certificates are rejected,
+ * otherwise 1 on successful verification */
+ if (VerifyCertChainWithTrustManager(x509certs, authType) == false) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
+ "TrustManager verification failed");
+ /* Abort handshake, verification failed */
+ return 0;
+ }
}
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"TrustManager verification successful");
- /* continue handshake, verification succeeded */
+
+ /* Continue handshake, verification succeeded */
return 1;
}
}
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java b/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java
index a9a96dc2..5fb3eb06 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java
@@ -106,9 +106,11 @@ boolean getWantClientAuth() {
}
void setWantClientAuth(boolean wantClientAuth) {
- /* wantClientAuth OR needClientAuth can be set, not both */
+ /* wantClientAuth OR needClientAuth can be set true, not both */
this.wantClientAuth = wantClientAuth;
- this.needClientAuth = false;
+ if (this.wantClientAuth) {
+ this.needClientAuth = false;
+ }
}
boolean getNeedClientAuth() {
@@ -116,9 +118,11 @@ boolean getNeedClientAuth() {
}
void setNeedClientAuth(boolean needClientAuth) {
- /* wantClientAuth OR needClientAuth can be set, not both */
+ /* wantClientAuth OR needClientAuth can be set true, not both */
this.needClientAuth = needClientAuth;
- this.wantClientAuth = false;
+ if (this.needClientAuth) {
+ this.wantClientAuth = false;
+ }
}
String getEndpointIdentificationAlgorithm() {
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java b/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java
index f1925267..13ada725 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java
@@ -36,6 +36,7 @@
import java.util.List;
import java.util.Arrays;
import java.nio.channels.SocketChannel;
+import java.security.cert.CertificateEncodingException;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
@@ -131,8 +132,10 @@ public WolfSSLSocket(com.wolfssl.WolfSSLContext context,
EngineHelper = new WolfSSLEngineHelper(this.ssl, this.authStore,
this.params);
EngineHelper.setUseClientMode(clientMode);
+ EngineHelper.LoadKeyAndCertChain(this, null);
- } catch (WolfSSLException e) {
+ } catch (WolfSSLException | CertificateEncodingException |
+ IOException e) {
throw new IOException(e);
}
}
@@ -173,8 +176,10 @@ public WolfSSLSocket(com.wolfssl.WolfSSLContext context,
EngineHelper = new WolfSSLEngineHelper(this.ssl, this.authStore,
this.params, port, host);
EngineHelper.setUseClientMode(clientMode);
+ EngineHelper.LoadKeyAndCertChain(this, null);
- } catch (WolfSSLException e) {
+ } catch (WolfSSLException | CertificateEncodingException |
+ IOException e) {
throw new IOException(e);
}
}
@@ -218,8 +223,10 @@ public WolfSSLSocket(com.wolfssl.WolfSSLContext context,
EngineHelper = new WolfSSLEngineHelper(this.ssl, this.authStore,
this.params, port, address);
EngineHelper.setUseClientMode(clientMode);
+ EngineHelper.LoadKeyAndCertChain(this, null);
- } catch (WolfSSLException e) {
+ } catch (WolfSSLException | CertificateEncodingException |
+ IOException e) {
throw new IOException(e);
}
}
@@ -260,8 +267,10 @@ public WolfSSLSocket(com.wolfssl.WolfSSLContext context,
EngineHelper = new WolfSSLEngineHelper(this.ssl, this.authStore,
this.params, port, host);
EngineHelper.setUseClientMode(clientMode);
+ EngineHelper.LoadKeyAndCertChain(this, null);
- } catch (WolfSSLException e) {
+ } catch (WolfSSLException | CertificateEncodingException |
+ IOException e) {
throw new IOException(e);
}
}
@@ -305,8 +314,10 @@ public WolfSSLSocket(com.wolfssl.WolfSSLContext context,
EngineHelper = new WolfSSLEngineHelper(this.ssl, this.authStore,
this.params, port, host);
EngineHelper.setUseClientMode(clientMode);
+ EngineHelper.LoadKeyAndCertChain(this, null);
- } catch (WolfSSLException e) {
+ } catch (WolfSSLException | CertificateEncodingException |
+ IOException e) {
throw new IOException(e);
}
}
@@ -364,8 +375,10 @@ public WolfSSLSocket(com.wolfssl.WolfSSLContext context,
EngineHelper = new WolfSSLEngineHelper(this.ssl, this.authStore,
this.params, port, host);
EngineHelper.setUseClientMode(clientMode);
+ EngineHelper.LoadKeyAndCertChain(this.socket, null);
- } catch (WolfSSLException e) {
+ } catch (WolfSSLException | CertificateEncodingException |
+ IOException e) {
throw new IOException(e);
}
}
@@ -799,8 +812,9 @@ public WolfSSLSocket(com.wolfssl.WolfSSLContext context,
EngineHelper = new WolfSSLEngineHelper(this.ssl, this.authStore,
this.params, s.getPort(), s.getInetAddress());
EngineHelper.setUseClientMode(clientMode);
+ EngineHelper.LoadKeyAndCertChain(s, null);
- } catch (WolfSSLException e) {
+ } catch (WolfSSLException | CertificateEncodingException e) {
throw new IOException(e);
}
}
@@ -850,6 +864,7 @@ public WolfSSLSocket(com.wolfssl.WolfSSLContext context,
EngineHelper = new WolfSSLEngineHelper(this.ssl, this.authStore,
this.params, s.getPort(), s.getInetAddress());
EngineHelper.setUseClientMode(false);
+ EngineHelper.LoadKeyAndCertChain(s, null);
/* register custom receive callback to read consumed first */
if (consumed != null) {
@@ -859,10 +874,9 @@ public WolfSSLSocket(com.wolfssl.WolfSSLContext context,
this.ssl.setIOReadCtx(recvCtx);
}
- } catch (WolfSSLException e) {
+ } catch (WolfSSLException | WolfSSLJNIException |
+ CertificateEncodingException e) {
throw new IOException(e);
- } catch (WolfSSLJNIException jnie) {
- throw new IOException(jnie);
}
}
diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java
index 4717fbe5..638fa3ec 100644
--- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java
+++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java
@@ -34,11 +34,13 @@
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
+import java.security.cert.CertificateException;
import java.security.KeyStore;
import java.util.Random;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
+import java.net.Socket;
import java.net.InetSocketAddress;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
@@ -46,6 +48,8 @@
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
@@ -122,7 +126,7 @@ public void testSSLEngine()
SSLEngine e;
/* create new SSLEngine */
- System.out.print("\tTesting creation");
+ System.out.print("\tSSLEngine creation");
for (int i = 0; i < enabledProtocols.size(); i++) {
this.ctx = tf.createSSLContext(enabledProtocols.get(i),
@@ -143,7 +147,7 @@ public void testSSLEngineSetCipher()
String sup[];
boolean ok = false;
- System.out.print("\tTesting setting cipher");
+ System.out.print("\tSetting ciphersuite");
if (!WolfSSL.TLSv12Enabled()) {
pass("\t\t... skipped");
@@ -203,7 +207,7 @@ public void testCipherConnection()
Certificate[] certs;
/* create new SSLEngine */
- System.out.print("\tTesting cipher connection");
+ System.out.print("\tBasic ciphersuiet connection");
this.ctx = tf.createSSLContext("TLS", engineProvider);
server = this.ctx.createSSLEngine();
@@ -262,24 +266,24 @@ public void testCipherConnection()
}
pass("\t... passed");
- System.out.print("\tTesting close connection");
+ System.out.print("\tclose connection");
try {
/* test close connection */
tf.CloseConnection(server, client, false);
} catch (SSLException ex) {
- error("\t... failed");
+ error("\t\t... failed");
fail("failed to create engine");
}
/* check if inbound is still open */
if (!server.isInboundDone() || !client.isInboundDone()) {
- error("\t... failed");
+ error("\t\t... failed");
fail("inbound is not done");
}
/* check if outbound is still open */
if (!server.isOutboundDone() || !client.isOutboundDone()) {
- error("\t... failed");
+ error("\t\t... failed");
fail("outbound is not done");
}
@@ -287,11 +291,11 @@ public void testCipherConnection()
try {
server.closeInbound();
} catch (SSLException ex) {
- error("\t... failed");
+ error("\t\t... failed");
fail("close inbound failure");
}
- pass("\t... passed");
+ pass("\t\t... passed");
}
@Test
@@ -302,7 +306,7 @@ public void testBeginHandshake()
int ret;
/* create new SSLEngine */
- System.out.print("\tTesting begin handshake");
+ System.out.print("\tbeginHandshake()");
this.ctx = tf.createSSLContext("TLS", engineProvider);
server = this.ctx.createSSLEngine();
@@ -336,7 +340,7 @@ public void testConnectionOutIn()
int ret;
/* create new SSLEngine */
- System.out.print("\tTesting out/in bound");
+ System.out.print("\tisIn/OutboundDone()");
this.ctx = tf.createSSLContext("TLS", engineProvider);
server = this.ctx.createSSLEngine();
@@ -383,7 +387,7 @@ public void testSetUseClientMode()
SSLEngine client;
SSLEngine server;
- System.out.print("\tTesting setUseClientMode()");
+ System.out.print("\tsetUseClientMode()");
/* expected to fail, not calling setUseClientMode() */
this.ctx = tf.createSSLContext("TLS", engineProvider);
@@ -393,7 +397,7 @@ public void testSetUseClientMode()
server.setNeedClientAuth(false);
try {
ret = tf.testConnection(server, client, null, null, "Testing");
- error("\t... failed");
+ error("\t\t... failed");
fail("did not fail without setUseClientMode()");
} catch (IllegalStateException e) {
/* expected */
@@ -407,7 +411,7 @@ public void testSetUseClientMode()
client.setUseClientMode(true);
try {
ret = tf.testConnection(server, client, null, null, "Testing");
- error("\t... failed");
+ error("\t\t... failed");
fail("did not fail without server.setUseClientMode()");
} catch (IllegalStateException e) {
/* expected */
@@ -421,7 +425,7 @@ public void testSetUseClientMode()
server.setUseClientMode(false);
try {
ret = tf.testConnection(server, client, null, null, "Testing");
- error("\t... failed");
+ error("\t\t... failed");
fail("did not fail without client.setUseClientMode()");
} catch (IllegalStateException e) {
/* expected */
@@ -438,11 +442,11 @@ public void testSetUseClientMode()
ret = tf.testConnection(server, client, null, null, "Testing");
} catch (IllegalStateException e) {
e.printStackTrace();
- error("\t... failed");
+ error("\t\t... failed");
fail("failed with setUseClientMode(), should succeed");
}
- pass("\t... passed");
+ pass("\t\t... passed");
}
@Test
@@ -453,7 +457,7 @@ public void testMutualAuth()
int ret;
/* create new SSLEngine */
- System.out.print("\tTesting mutual auth");
+ System.out.print("\tMutual authentication");
/* success case */
this.ctx = tf.createSSLContext("TLS", engineProvider);
@@ -496,6 +500,437 @@ public void testMutualAuth()
pass("\t\t... passed");
}
+ /**
+ * Helper class used with below setWant/NeedClientAuth() test methods.
+ *
+ * Note that setWantClientAuth() and setNeedClientAuth() are only
+ * applicable when called on the server side. But including testing
+ * then when called on the client side here as well, for sanity.
+ */
+ private static class PeerAuthConfig {
+ boolean clientWantClientAuth;
+ boolean clientNeedClientAuth;
+ boolean serverWantClientAuth;
+ boolean serverNeedClientAuth;
+ boolean expectSuccess;
+
+ public PeerAuthConfig(boolean cwca, boolean cnca, boolean swca,
+ boolean snca, boolean ex) {
+ this.clientWantClientAuth = cwca;
+ this.clientNeedClientAuth = cnca;
+ this.serverWantClientAuth = swca;
+ this.serverNeedClientAuth = snca;
+ this.expectSuccess = ex;
+ }
+ }
+
+ @Test
+ public void testSetWantNeedClientAuth_ClientServerDefaultKeyManager()
+ throws NoSuchProviderException, NoSuchAlgorithmException {
+
+ int ret = 0;
+ SSLContext cCtx = null;
+ SSLContext sCtx = null;
+ SSLEngine client = null;
+ SSLEngine server = null;
+
+ /* All combinations using DEFAULT X509TrustManager/X509KeyManager
+ * from WolfSSLTestFactory. All expected to pass since each since has
+ * certs/keys loaded no matter if verify is being done */
+ PeerAuthConfig[] configsDefaultManagers = new PeerAuthConfig[] {
+ new PeerAuthConfig(true, true, true, true, true),
+ new PeerAuthConfig(true, true, true, false, true),
+ new PeerAuthConfig(true, true, false, true, true),
+ new PeerAuthConfig(true, true, false, false, true),
+ new PeerAuthConfig(true, false, true, true, true),
+ new PeerAuthConfig(true, false, true, false, true),
+ new PeerAuthConfig(true, false, false, true, true),
+ new PeerAuthConfig(true, false, false, false, true),
+ new PeerAuthConfig(false, true, true, true, true),
+ new PeerAuthConfig(false, true, true, false, true),
+ new PeerAuthConfig(false, true, false, true, true),
+ new PeerAuthConfig(false, true, false, false, true),
+ new PeerAuthConfig(false, false, true, true, true),
+ new PeerAuthConfig(false, false, true, false, true),
+ new PeerAuthConfig(false, false, false, true, true),
+ new PeerAuthConfig(false, false, false, false, true)
+ };
+
+ System.out.print("\tsetWantClientAuth(default KM)");
+
+ for (PeerAuthConfig c : configsDefaultManagers) {
+
+ sCtx = tf.createSSLContext("TLS", engineProvider);
+ server = sCtx.createSSLEngine();
+ server.setUseClientMode(false);
+ server.setWantClientAuth(c.serverWantClientAuth);
+ server.setNeedClientAuth(c.serverNeedClientAuth);
+
+ cCtx = tf.createSSLContext("TLS", engineProvider);
+ client = cCtx.createSSLEngine("wolfSSL test case", 11111);
+ client.setUseClientMode(true);
+ client.setWantClientAuth(c.clientWantClientAuth);
+ client.setNeedClientAuth(c.clientNeedClientAuth);
+
+ ret = tf.testConnection(server, client, null, null, "Test");
+ if ((c.expectSuccess && ret != 0) ||
+ (!c.expectSuccess && ret == 0)) {
+ error("\t... failed");
+ fail("SSLEngine want/needClientAuth failed: \n" +
+ "\n cWantClientAuth = " + c.clientWantClientAuth +
+ "\n cNeedClientAuth = " + c.clientNeedClientAuth +
+ "\n sWantClientAuth = " + c.serverWantClientAuth +
+ "\n sNeedClientAuth = " + c.serverNeedClientAuth +
+ "\n expectSuccess = " + c.expectSuccess +
+ "\n got ret = " + ret);
+ }
+ }
+
+ pass("\t... passed");
+ }
+
+ @Test
+ public void testSetWantNeedClientAuth_ClientNoKeyManager()
+ throws NoSuchProviderException, NoSuchAlgorithmException {
+
+ int ret = 0;
+ SSLContext cCtx = null;
+ SSLContext sCtx = null;
+ SSLEngine client = null;
+ SSLEngine server = null;
+
+ /* All combinations using 'null' as client KeyManager, so client
+ * will not have cert or private key loaded, but server will */
+ PeerAuthConfig[] configs = new PeerAuthConfig[] {
+ new PeerAuthConfig(true, true, true, true, false),
+ new PeerAuthConfig(true, true, true, false, true),
+ new PeerAuthConfig(true, true, false, true, false),
+ new PeerAuthConfig(true, true, false, false, true),
+ new PeerAuthConfig(true, false, true, true, false),
+ new PeerAuthConfig(true, false, true, false, true),
+ new PeerAuthConfig(true, false, false, true, false),
+ new PeerAuthConfig(true, false, false, false, true),
+ new PeerAuthConfig(false, true, true, true, false),
+ new PeerAuthConfig(false, true, true, false, true),
+ new PeerAuthConfig(false, true, false, true, false),
+ new PeerAuthConfig(false, true, false, false, true),
+ new PeerAuthConfig(false, false, true, true, false),
+ new PeerAuthConfig(false, false, true, false, true),
+ new PeerAuthConfig(false, false, false, true, false),
+ new PeerAuthConfig(false, false, false, false, true)
+ };
+
+ System.out.print("\tsetWantClientAuth(no client KM)");
+
+ for (PeerAuthConfig c : configs) {
+
+ sCtx = tf.createSSLContext("TLS", engineProvider);
+ server = sCtx.createSSLEngine();
+ server.setUseClientMode(false);
+ server.setWantClientAuth(c.serverWantClientAuth);
+ server.setNeedClientAuth(c.serverNeedClientAuth);
+
+ cCtx = tf.createSSLContextNoDefaults("TLS", engineProvider,
+ tf.createTrustManager("SunX509", tf.clientJKS, engineProvider),
+ null);
+ client = cCtx.createSSLEngine("wolfSSL test case", 11111);
+ client.setUseClientMode(true);
+ client.setWantClientAuth(c.clientWantClientAuth);
+ client.setNeedClientAuth(c.clientNeedClientAuth);
+
+ ret = tf.testConnection(server, client, null, null, "Test");
+ if ((c.expectSuccess && ret != 0) ||
+ (!c.expectSuccess && ret == 0)) {
+ error("\t... failed");
+ fail("SSLEngine want/needClientAuth failed: \n" +
+ "\n cWantClientAuth = " + c.clientWantClientAuth +
+ "\n cNeedClientAuth = " + c.clientNeedClientAuth +
+ "\n sWantClientAuth = " + c.serverWantClientAuth +
+ "\n sNeedClientAuth = " + c.serverNeedClientAuth +
+ "\n expectSuccess = " + c.expectSuccess +
+ "\n got ret = " + ret);
+ }
+ }
+
+ pass("\t... passed");
+ }
+
+ @Test
+ public void testSetWantNeedClientAuth_ServerNoKeyManager()
+ throws NoSuchProviderException, NoSuchAlgorithmException {
+
+ int ret = 0;
+ SSLContext cCtx = null;
+ SSLContext sCtx = null;
+ SSLEngine client = null;
+ SSLEngine server = null;
+
+ /* All combinations using 'null' as server KeyManager, so server
+ * will not have cert or private key loaded, but client will.
+ * All these should fail, since the server requires a private key
+ * be loaded. */
+ PeerAuthConfig[] configs = new PeerAuthConfig[] {
+ new PeerAuthConfig(true, true, true, true, false),
+ new PeerAuthConfig(true, true, true, false, false),
+ new PeerAuthConfig(true, true, false, true, false),
+ new PeerAuthConfig(true, true, false, false, false),
+ new PeerAuthConfig(true, false, true, true, false),
+ new PeerAuthConfig(true, false, true, false, false),
+ new PeerAuthConfig(true, false, false, true, false),
+ new PeerAuthConfig(true, false, false, false, false),
+ new PeerAuthConfig(false, true, true, true, false),
+ new PeerAuthConfig(false, true, true, false, false),
+ new PeerAuthConfig(false, true, false, true, false),
+ new PeerAuthConfig(false, true, false, false, false),
+ new PeerAuthConfig(false, false, true, true, false),
+ new PeerAuthConfig(false, false, true, false, false),
+ new PeerAuthConfig(false, false, false, true, false),
+ new PeerAuthConfig(false, false, false, false, false)
+ };
+
+ System.out.print("\tsetWantClientAuth(no server KM)");
+
+ for (PeerAuthConfig c : configs) {
+
+ sCtx = tf.createSSLContextNoDefaults("TLS", engineProvider,
+ tf.createTrustManager("SunX509", tf.clientJKS, engineProvider),
+ null);
+ server = sCtx.createSSLEngine();
+ server.setUseClientMode(false);
+ server.setWantClientAuth(c.serverWantClientAuth);
+ server.setNeedClientAuth(c.serverNeedClientAuth);
+
+ cCtx = tf.createSSLContext("TLS", engineProvider);
+ client = cCtx.createSSLEngine("wolfSSL test case", 11111);
+ client.setUseClientMode(true);
+ client.setWantClientAuth(c.clientWantClientAuth);
+ client.setNeedClientAuth(c.clientNeedClientAuth);
+
+ ret = tf.testConnection(server, client, null, null, "Test");
+ if ((c.expectSuccess && ret != 0) ||
+ (!c.expectSuccess && ret == 0)) {
+ error("\t... failed");
+ fail("SSLEngine want/needClientAuth failed: \n" +
+ "\n cWantClientAuth = " + c.clientWantClientAuth +
+ "\n cNeedClientAuth = " + c.clientNeedClientAuth +
+ "\n sWantClientAuth = " + c.serverWantClientAuth +
+ "\n sNeedClientAuth = " + c.serverNeedClientAuth +
+ "\n expectSuccess = " + c.expectSuccess +
+ "\n got ret = " + ret);
+ }
+ }
+
+ pass("\t... passed");
+ }
+
+ @Test
+ public void testSetWantNeedClientAuth_ClientServerExternalTrustAllCerts()
+ throws NoSuchProviderException, NoSuchAlgorithmException {
+
+ int ret = 0;
+ SSLContext cCtx = null;
+ SSLContext sCtx = null;
+ SSLEngine client = null;
+ SSLEngine server = null;
+
+ /* TrustManager that trusts all certificates */
+ TrustManager[] trustAllCerts = {
+ new X509ExtendedTrustManager() {
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+ public void checkClientTrusted(X509Certificate[] chain,
+ String authType) {
+ }
+ public void checkClientTrusted(X509Certificate[] chain,
+ String authType, Socket socket) {
+ }
+ public void checkClientTrusted(X509Certificate[] chain,
+ String authType, SSLEngine engine) {
+ }
+ public void checkServerTrusted(X509Certificate[] chain,
+ String authType) {
+ }
+ public void checkServerTrusted(X509Certificate[] chain,
+ String authType, Socket socket) {
+ }
+ public void checkServerTrusted(X509Certificate[] chain,
+ String authType, SSLEngine engine) {
+ }
+ }
+ };
+
+ /* All combinations using DEFAULT X509TrustManager/X509KeyManager
+ * from WolfSSLTestFactory. All expected to pass since each since has
+ * certs/keys loaded no matter if verify is being done */
+ PeerAuthConfig[] configsDefaultManagers = new PeerAuthConfig[] {
+ new PeerAuthConfig(true, true, true, true, true),
+ new PeerAuthConfig(true, true, true, false, true),
+ new PeerAuthConfig(true, true, false, true, true),
+ new PeerAuthConfig(true, true, false, false, true),
+ new PeerAuthConfig(true, false, true, true, true),
+ new PeerAuthConfig(true, false, true, false, true),
+ new PeerAuthConfig(true, false, false, true, true),
+ new PeerAuthConfig(true, false, false, false, true),
+ new PeerAuthConfig(false, true, true, true, true),
+ new PeerAuthConfig(false, true, true, false, true),
+ new PeerAuthConfig(false, true, false, true, true),
+ new PeerAuthConfig(false, true, false, false, true),
+ new PeerAuthConfig(false, false, true, true, true),
+ new PeerAuthConfig(false, false, true, false, true),
+ new PeerAuthConfig(false, false, false, true, true),
+ new PeerAuthConfig(false, false, false, false, true)
+ };
+
+ System.out.print("\tsetWantClientAuth(ext KM all)");
+
+ for (PeerAuthConfig c : configsDefaultManagers) {
+
+ sCtx = tf.createSSLContextNoDefaults("TLS", engineProvider,
+ trustAllCerts,
+ tf.createKeyManager("SunX509", tf.clientJKS, engineProvider));
+ server = sCtx.createSSLEngine();
+ server.setUseClientMode(false);
+ server.setWantClientAuth(c.serverWantClientAuth);
+ server.setNeedClientAuth(c.serverNeedClientAuth);
+
+ cCtx = tf.createSSLContextNoDefaults("TLS", engineProvider,
+ trustAllCerts,
+ tf.createKeyManager("SunX509", tf.clientJKS, engineProvider));
+ client = cCtx.createSSLEngine("wolfSSL test case", 11111);
+ client.setUseClientMode(true);
+ client.setWantClientAuth(c.clientWantClientAuth);
+ client.setNeedClientAuth(c.clientNeedClientAuth);
+
+ ret = tf.testConnection(server, client, null, null, "Test");
+ if ((c.expectSuccess && ret != 0) ||
+ (!c.expectSuccess && ret == 0)) {
+ error("\t... failed");
+ fail("SSLEngine want/needClientAuth failed: \n" +
+ "\n cWantClientAuth = " + c.clientWantClientAuth +
+ "\n cNeedClientAuth = " + c.clientNeedClientAuth +
+ "\n sWantClientAuth = " + c.serverWantClientAuth +
+ "\n sNeedClientAuth = " + c.serverNeedClientAuth +
+ "\n expectSuccess = " + c.expectSuccess +
+ "\n got ret = " + ret);
+ }
+ }
+
+ pass("\t... passed");
+ }
+
+ @Test
+ public void testSetWantNeedClientAuth_ExternalTrustNoClientCerts()
+ throws NoSuchProviderException, NoSuchAlgorithmException {
+
+ int ret = 0;
+ SSLContext cCtx = null;
+ SSLContext sCtx = null;
+ SSLEngine client = null;
+ SSLEngine server = null;
+
+ /* TrustManager that trusts no certificates */
+ TrustManager[] trustNoClientCerts = {
+ new X509ExtendedTrustManager() {
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+ public void checkClientTrusted(X509Certificate[] chain,
+ String authType) throws CertificateException {
+ throw new CertificateException(
+ "fail on purpose / bad cert");
+ }
+ public void checkClientTrusted(X509Certificate[] chain,
+ String authType, Socket socket)
+ throws CertificateException {
+ throw new CertificateException(
+ "fail on purpose / bad cert");
+ }
+ public void checkClientTrusted(X509Certificate[] chain,
+ String authType, SSLEngine engine)
+ throws CertificateException {
+ throw new CertificateException(
+ "fail on purpose / bad cert");
+ }
+ public void checkServerTrusted(X509Certificate[] chain,
+ String authType) throws CertificateException {
+ /* Accept all server certs, not in scope of
+ * setWant/NeedClientAuth() */
+ }
+ public void checkServerTrusted(X509Certificate[] chain,
+ String authType, Socket socket)
+ throws CertificateException {
+ /* Accept all server certs, not in scope of
+ * setWant/NeedClientAuth() */
+ }
+ public void checkServerTrusted(X509Certificate[] chain,
+ String authType, SSLEngine engine)
+ throws CertificateException {
+ /* Accept all server certs, not in scope of
+ * setWant/NeedClientAuth() */
+ }
+ }
+ };
+
+ /* All combinations with external X509ExtendedTrustManager registered
+ * which will trust NO client certs and ALL server certs */
+ PeerAuthConfig[] configsDefaultManagers = new PeerAuthConfig[] {
+ new PeerAuthConfig(true, true, true, true, false),
+ new PeerAuthConfig(true, true, true, false, true),
+ new PeerAuthConfig(true, true, false, true, false),
+ new PeerAuthConfig(true, true, false, false, true),
+ new PeerAuthConfig(true, false, true, true, false),
+ new PeerAuthConfig(true, false, true, false, true),
+ new PeerAuthConfig(true, false, false, true, false),
+ new PeerAuthConfig(true, false, false, false, true),
+ new PeerAuthConfig(false, true, true, true, false),
+ new PeerAuthConfig(false, true, true, false, true),
+ new PeerAuthConfig(false, true, false, true, false),
+ new PeerAuthConfig(false, true, false, false, true),
+ new PeerAuthConfig(false, false, true, true, false),
+ new PeerAuthConfig(false, false, true, false, true),
+ new PeerAuthConfig(false, false, false, true, false),
+ new PeerAuthConfig(false, false, false, false, true)
+ };
+
+ System.out.print("\tsetWantClientAuth(ext KM no)");
+
+ for (PeerAuthConfig c : configsDefaultManagers) {
+
+ sCtx = tf.createSSLContextNoDefaults("TLS", engineProvider,
+ trustNoClientCerts,
+ tf.createKeyManager("SunX509", tf.clientJKS, engineProvider));
+ server = sCtx.createSSLEngine();
+ server.setUseClientMode(false);
+ server.setWantClientAuth(c.serverWantClientAuth);
+ server.setNeedClientAuth(c.serverNeedClientAuth);
+
+ cCtx = tf.createSSLContextNoDefaults("TLS", engineProvider,
+ trustNoClientCerts,
+ tf.createKeyManager("SunX509", tf.clientJKS, engineProvider));
+ client = cCtx.createSSLEngine("wolfSSL test case", 11111);
+ client.setUseClientMode(true);
+ client.setWantClientAuth(c.clientWantClientAuth);
+ client.setNeedClientAuth(c.clientNeedClientAuth);
+
+ ret = tf.testConnection(server, client, null, null, "Test");
+ if ((c.expectSuccess && ret != 0) ||
+ (!c.expectSuccess && ret == 0)) {
+ error("\t... failed");
+ fail("SSLEngine want/needClientAuth failed: \n" +
+ "\n cWantClientAuth = " + c.clientWantClientAuth +
+ "\n cNeedClientAuth = " + c.clientNeedClientAuth +
+ "\n sWantClientAuth = " + c.serverWantClientAuth +
+ "\n sNeedClientAuth = " + c.serverNeedClientAuth +
+ "\n expectSuccess = " + c.expectSuccess +
+ "\n got ret = " + ret);
+ }
+ }
+
+ pass("\t... passed");
+ }
+
+
@Test
public void testReuseSession()
throws NoSuchProviderException, NoSuchAlgorithmException {
@@ -504,7 +939,7 @@ public void testReuseSession()
int ret;
/* create new SSLEngine */
- System.out.print("\tTesting reuse of session");
+ System.out.print("\tSession reuse");
this.ctx = tf.createSSLContext("TLS", engineProvider);
server = this.ctx.createSSLEngine();
@@ -515,7 +950,7 @@ public void testReuseSession()
client.setUseClientMode(true);
ret = tf.testConnection(server, client, null, null, "Test reuse");
if (ret != 0) {
- error("\t... failed");
+ error("\t\t\t... failed");
fail("failed to create engine");
}
@@ -523,7 +958,7 @@ public void testReuseSession()
/* test close connection */
tf.CloseConnection(server, client, false);
} catch (SSLException ex) {
- error("\t... failed");
+ error("\t\t\t... failed");
fail("failed to create engine");
}
@@ -535,22 +970,23 @@ public void testReuseSession()
client.setUseClientMode(true);
ret = tf.testConnection(server, client, null, null, "Test reuse");
if (ret != 0) {
- error("\t... failed");
+ error("\t\t\t... failed");
fail("failed to create engine");
}
try {
/* test close connection */
tf.CloseConnection(server, client, false);
} catch (SSLException ex) {
- error("\t... failed");
+ error("\t\t\t... failed");
fail("failed to create engine");
}
- if (client.getEnableSessionCreation() || !server.getEnableSessionCreation()) {
- error("\t... failed");
+ if (client.getEnableSessionCreation() ||
+ !server.getEnableSessionCreation()) {
+ error("\t\t\t... failed");
fail("bad enabled session creation");
}
- pass("\t... passed");
+ pass("\t\t\t... passed");
}
/**
@@ -591,7 +1027,7 @@ public void testExtendedThreadingUse()
failures.set(0, 0);
success.set(0, 0);
- System.out.print("\tTesting ExtendedThreadingUse");
+ System.out.print("\tExtended threading use");
/* Start up simple TLS test server */
CountDownLatch serverOpenLatch = new CountDownLatch(1);
@@ -627,14 +1063,16 @@ public void testExtendedThreadingUse()
/* check failure count and success count against thread count */
if (failures.get(0) == 0 && success.get(0) == numThreads) {
- pass("\t... passed");
+ pass("\t\t... passed");
} else {
if (returnWithoutTimeout == true) {
+ error("\t\t... failed");
fail("SSLEngine threading error: " +
failures.get(0) + " failures, " +
success.get(0) + " success, " +
numThreads + " num threads total");
} else {
+ error("\t\t... failed");
fail("SSLEngine threading error, threads timed out");
}
}
@@ -776,7 +1214,8 @@ public void connect() throws Exception {
case NOT_HANDSHAKING:
break;
default:
- throw new Exception("Invalid HandshakeStatus");
+ throw new Exception("Invalid HandshakeStatus: " +
+ hsStatus);
}
hsStatus = engine.getHandshakeStatus();
}
diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java
index 2d8b75f1..d8513415 100644
--- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java
+++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java
@@ -390,7 +390,9 @@ protected SSLContext createSSLContext(String protocol, String provider) {
}
/**
- * Creates a new context using provider passed in and km/tm
+ * Creates a new context using provider passed in and km/tm. Falls back
+ * and creates default TrustManager/KeyManager if those arguments are
+ * null.
*
* @param protocol to be used when creating context
* @param provider to be used when creating context (can be null)
@@ -403,6 +405,42 @@ protected SSLContext createSSLContext(String protocol, String provider,
return internalCreateSSLContext(protocol, provider, tm, km);
}
+ /**
+ * Creates a new context using provider passed in and km/tm, does not
+ * fallback and create default TrustManager/KeyManager if thoes arguments
+ * are null.
+ *
+ * @param protocol to be used when creating context
+ * @param provider to be used when creating context (can be null)
+ * @param tm trust manager to use (can be null)
+ * @param km key manager to use (can be null)
+ * @return new SSLContext on success and null on failure
+ */
+ protected SSLContext createSSLContextNoDefaults(String protocol,
+ String provider, TrustManager[] tm, KeyManager[] km) {
+
+ SSLContext ctx = null;
+
+ try {
+ if (provider != null) {
+ ctx = SSLContext.getInstance(protocol, provider);
+ } else {
+ ctx = SSLContext.getInstance(protocol);
+ }
+
+ ctx.init(km, tm, null);
+ return ctx;
+
+ } catch (NoSuchAlgorithmException ex) {
+ ex.printStackTrace();
+ } catch (KeyManagementException ex) {
+ ex.printStackTrace();
+ } catch (NoSuchProviderException ex) {
+ ex.printStackTrace();
+ }
+ return null;
+ }
+
/**
* Red coloring to fail message
* @param msg