Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,8 @@ private synchronized int DoHandshake(boolean fromWrap) throws SSLException {
}

} catch (SocketTimeoutException | SocketException e) {
throw new SSLException(e);
throw new SSLHandshakeException(
"Socket error during SSL/TLS handshake: " + e.getMessage());
}

return ret;
Expand Down Expand Up @@ -1058,6 +1059,12 @@ private synchronized int RecvAppData(ByteBuffer[] out, int ofst, int length)
}
break;
default:
/* Throw SSLHandshakeException if handshake not finished */
if (!this.handshakeFinished) {
throw new SSLHandshakeException(
"SSL/TLS handshake error in read: " + ret +
" , err = " + err);
}
throw new SSLException(
"wolfSSL_read() error: " + ret + " , err = " + err);
}
Expand Down Expand Up @@ -1393,6 +1400,14 @@ else if (ret < 0 &&
* any more data */
this.outBoundOpen = false;
}
/* Throw SSLHandshakeException if handshake not
* finished, otherwise throw SSLException for
* post-handshake errors */
if (!this.handshakeFinished) {
throw new SSLHandshakeException(
"SSL/TLS handshake error, ret:err = " +
ret + " : " + err);
}
throw new SSLException(
"wolfSSL error, ret:err = " + ret + " : " +
err);
Expand Down
5 changes: 5 additions & 0 deletions src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,11 @@ private void initHandshakeInternal(SSLSocket socket, SSLEngine engine)
else {
this.session.setSessionContext(authStore.getServerContext());
this.session.setSide(WolfSSL.WOLFSSL_SERVER_END);
/* Track client auth state for getPeerCertificates() */
boolean clientAuthRequested =
this.params.getNeedClientAuth() ||
this.params.getWantClientAuth();
this.session.setClientAuthRequested(clientAuthRequested);
}

if (this.sessionCreation == false && !this.session.isFromTable) {
Expand Down
45 changes: 41 additions & 4 deletions src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession {
byte[] pseudoSessionID = null; /* used with TLS 1.3*/
private int side = 0;

/* Track if client auth was requested, for getPeerCertificates() behavior */
private volatile boolean clientAuthRequested = false;

/* Cache peer certificates after received. Applications assume that
* SSLSocket.getSession().getPeerCertificates() will return the peer
* certificate even on a resumed connection where the cert has not been
Expand Down Expand Up @@ -260,6 +263,7 @@ public WolfSSLImplementSSLSession (WolfSSLImplementSSLSession orig) {
this.pseudoSessionID = orig.pseudoSessionID.clone();
}
this.side = orig.side;
this.clientAuthRequested = orig.clientAuthRequested;
if (orig.peerCerts != null) {
this.peerCerts = orig.peerCerts.clone();
}
Expand Down Expand Up @@ -519,6 +523,15 @@ public synchronized Certificate[] getPeerCertificates()
"SSLSocket/Engine closed");
}

/* Throw if server side with no client auth requested */
if (this.side == WolfSSL.WOLFSSL_SERVER_END &&
!this.clientAuthRequested) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
() -> "Server side, no client auth, throwing exception");
throw new SSLPeerUnverifiedException(
"peer not authenticated (no client auth requested)");
}

try {
x509 = this.ssl.getPeerCertificate();
} catch (IllegalStateException | WolfSSLJNIException ex) {
Expand Down Expand Up @@ -605,8 +618,8 @@ public Certificate[] getLocalCertificates() {
}

@Override
public synchronized javax.security.cert.X509Certificate[] getPeerCertificateChain()
throws SSLPeerUnverifiedException {
public synchronized javax.security.cert.X509Certificate[]
getPeerCertificateChain() throws SSLPeerUnverifiedException {

long peerX509 = 0;
WolfSSLX509X x509;
Expand All @@ -615,10 +628,17 @@ public synchronized javax.security.cert.X509Certificate[] getPeerCertificateChai
throw new SSLPeerUnverifiedException("handshake not done");
}

/* Throw if server side with no client auth requested */
if (this.side == WolfSSL.WOLFSSL_SERVER_END &&
!this.clientAuthRequested) {
throw new SSLPeerUnverifiedException(
"peer not authenticated (no client auth requested)");
}

try {
peerX509 = this.ssl.getPeerCertificate();
if (peerX509 == 0) {
return null;
throw new SSLPeerUnverifiedException("No peer certificate");
}

/* wolfSSL starting with 5.3.0 returns a new WOLFSSL_X509
Expand Down Expand Up @@ -657,10 +677,17 @@ public synchronized Principal getPeerPrincipal()
throw new SSLPeerUnverifiedException("handshake not done");
}

/* Throw if server side with no client auth requested */
if (this.side == WolfSSL.WOLFSSL_SERVER_END &&
!this.clientAuthRequested) {
throw new SSLPeerUnverifiedException(
"peer not authenticated (no client auth requested)");
}

try {
peerX509 = this.ssl.getPeerCertificate();
if (peerX509 == 0) {
return null;
throw new SSLPeerUnverifiedException("No peer certificate");
}

/* wolfSSL starting with 5.3.0 returns a new WOLFSSL_X509
Expand Down Expand Up @@ -1039,6 +1066,16 @@ protected int getSide() {
return this.side;
}

/**
* Set whether client auth was requested.
* Used for getPeerCertificates() behavior.
*
* @param requested true if client auth was requested, false otherwise
*/
protected void setClientAuthRequested(boolean requested) {
this.clientAuthRequested = requested;
}

/**
* Return the side session is on (server/client) as a String
* @return "client" or "server" representing the side of this session
Expand Down
26 changes: 24 additions & 2 deletions src/java/com/wolfssl/provider/jsse/WolfSSLKeyX509.java
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,18 @@ public String chooseClientAlias(String[] type, Principal[] issuers,
for (i = 0; i < type.length; i++) {
String[] all = getAliases(type[i], issuers);
if (all != null) {
return all[0];
/* Find first alias that has a private key, skip cert-only
* entries (trustedCertEntry) which have no private key */
for (String alias : all) {
PrivateKey key = getPrivateKey(alias);
if (key != null) {
final String selectedAlias = alias;
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
() -> "chooseClientAlias() returning alias " +
"with private key: " + selectedAlias);
return alias;
}
}
}
}
return null;
Expand All @@ -398,7 +409,18 @@ public String chooseEngineClientAlias(String[] type, Principal[] issuers,
for (i = 0; i < type.length; i++) {
String[] all = getAliases(type[i], issuers);
if (all != null) {
return all[0];
/* Find first alias that has a private key, skip cert-only
* entries (trustedCertEntry) which have no private key */
for (String alias : all) {
PrivateKey key = getPrivateKey(alias);
if (key != null) {
final String selectedAlias = alias;
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
() -> "chooseEngineClientAlias() returning " +
"alias with private key: " + selectedAlias);
return alias;
}
}
}
}
return null;
Expand Down
75 changes: 72 additions & 3 deletions src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -761,9 +761,78 @@ protected void engineInit(ManagerFactoryParameters arg0)
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
() -> "entered engineInit(ManagerFactoryParameters arg0)");

throw new UnsupportedOperationException(
"TrustManagerFactory.init(ManagerFactoryParameters) " +
"not supported yet");
/* Handle CertPathTrustManagerParameters (used by Tomcat, etc) */
if (arg0 instanceof javax.net.ssl.CertPathTrustManagerParameters) {
javax.net.ssl.CertPathTrustManagerParameters certPathParams =
(javax.net.ssl.CertPathTrustManagerParameters) arg0;
java.security.cert.CertPathParameters certPathParameters =
certPathParams.getParameters();

if (certPathParameters instanceof
java.security.cert.PKIXParameters) {
java.security.cert.PKIXParameters pkixParams =
(java.security.cert.PKIXParameters) certPathParameters;
java.util.Set<java.security.cert.TrustAnchor> anchors =
pkixParams.getTrustAnchors();

try {
java.security.KeyStore ks =
java.security.KeyStore.getInstance(
java.security.KeyStore.getDefaultType());
ks.load(null, null);
int count = 0;
for (java.security.cert.TrustAnchor anchor : anchors) {
java.security.cert.X509Certificate cert =
anchor.getTrustedCert();
if (cert != null) {
ks.setCertificateEntry(
"trustanchor-" + count, cert);
count++;
}
}
final int finalCount = count;
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
() -> "Initialized TrustManager from " +
"CertPathTrustManagerParameters with " +
finalCount + " anchors");
engineInit(ks);
return;
} catch (Exception e) {
throw new InvalidAlgorithmParameterException(
"Failed to create KeyStore from TrustAnchors: " +
e.getMessage(), e);
}
}
}

/* Handle KeyStoreBuilderParameters */
if (arg0 instanceof javax.net.ssl.KeyStoreBuilderParameters) {
javax.net.ssl.KeyStoreBuilderParameters ksParams =
(javax.net.ssl.KeyStoreBuilderParameters) arg0;
java.util.List<java.security.KeyStore.Builder> builders =
ksParams.getParameters();

if (builders != null && !builders.isEmpty()) {
try {
/* Use the first KeyStore builder */
java.security.KeyStore ks =
builders.get(0).getKeyStore();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
() -> "Initialized TrustManager from " +
"KeyStoreBuilderParameters");
engineInit(ks);
return;
} catch (Exception e) {
throw new InvalidAlgorithmParameterException(
"Failed to get KeyStore from Builder: " +
e.getMessage(), e);
}
}
}

throw new InvalidAlgorithmParameterException(
"Unsupported ManagerFactoryParameters type: " +
(arg0 != null ? arg0.getClass().getName() : "null"));
}

@Override
Expand Down
5 changes: 5 additions & 0 deletions src/java/com/wolfssl/provider/jsse/WolfSSLUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ public WolfSSLUtil() {
protected static String[] sanitizeProtocols(String[] protocols,
WolfSSL.TLS_VERSION currentVersion) {

/* Return null if protocols is null, let caller handle */
if (protocols == null) {
return null;
}

ArrayList<String> filtered = new ArrayList<String>();

String disabledAlgos =
Expand Down
33 changes: 33 additions & 0 deletions src/test/com/wolfssl/provider/jsse/test/WolfSSLContextTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
import com.wolfssl.WolfSSL;
import com.wolfssl.provider.jsse.WolfSSLProvider;

import java.lang.reflect.Method;

public class WolfSSLContextTest {

private static WolfSSLTestFactory tf;
Expand Down Expand Up @@ -965,5 +967,36 @@ public void testWolfJSSEEnabledCipherSuites()

System.out.println("\t... passed");
}

@Test
public void testSanitizeProtocolsNullInput() {

System.out.print("\tTesting sanitizeProtocols(null)");

try {
Class<?> utilClass = Class.forName(
"com.wolfssl.provider.jsse.WolfSSLUtil");
Method sanitizeMethod = utilClass.getDeclaredMethod(
"sanitizeProtocols",
String[].class,
WolfSSL.TLS_VERSION.class);
sanitizeMethod.setAccessible(true);

String[] result = (String[]) sanitizeMethod.invoke(
null, (String[]) null, WolfSSL.TLS_VERSION.TLSv1_2);

if (result != null) {
System.out.println("\t... failed");
fail("sanitizeProtocols(null) should return null");
return;
}

System.out.println("\t\t... passed");

} catch (Exception e) {
System.out.println("\t... failed");
fail("Exception during sanitizeProtocols test: " + e.getMessage());
}
}
}

50 changes: 50 additions & 0 deletions src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
Expand Down Expand Up @@ -2494,5 +2495,54 @@ private ByteBuffer enlargeBuffer(ByteBuffer buffer, int size) {
bb.put(buffer);
return bb;
}

/**
* Verify getPeerCertificateChain() throws SSLPeerUnverifiedException
* when no client auth requested, matching SunJSSE/Netty expectations.
*/
@Test
public void testGetPeerCertificateChainNoClientAuth() throws Exception {

System.out.print("\tgetPeerCertChain no client auth");

String protocol = null;
for (String p : enabledProtocols) {
if (!p.equals("TLS") && !p.contains("DTLS")) {
protocol = p;
break;
}
}

if (protocol == null) {
pass("\t... skipped");
return;
}

SSLContext ctx = tf.createSSLContext(protocol, engineProvider);

SSLEngine server = ctx.createSSLEngine();
SSLEngine client = ctx.createSSLEngine("localhost", 11111);

server.setUseClientMode(false);
server.setNeedClientAuth(false);
server.setWantClientAuth(false);
client.setUseClientMode(true);

tf.testConnection(server, client, null, null, "No client auth test");

SSLSession serverSession = server.getSession();

try {
javax.security.cert.X509Certificate[] certs =
serverSession.getPeerCertificateChain();
error("\t... failed");
fail("Expected SSLPeerUnverifiedException, got " +
(certs == null ? "null" : "certs"));
} catch (SSLPeerUnverifiedException e) {
/* Expected */
}

pass("\t... passed");
}
}

Loading
Loading