Skip to content

Commit

Permalink
Merge pull request #172 from cconlon/needWantClientAuth
Browse files Browse the repository at this point in the history
Fixes for SSLEngine.setWant/NeedClientAuth() and choosing key alias chooseEngineClient/ServerAlias()
  • Loading branch information
JacobBarthelmeh authored Feb 15, 2024
2 parents 0e4953f + 1d0b807 commit ecd67a4
Show file tree
Hide file tree
Showing 12 changed files with 1,010 additions and 229 deletions.
27 changes: 27 additions & 0 deletions native/com_wolfssl_WolfSSLSession.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
8 changes: 8 additions & 0 deletions native/com_wolfssl_WolfSSLSession.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/java/com/wolfssl/WolfSSLContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -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, <b>in</b>
* @param format format of the certificate buffer being loaded - either
Expand Down
48 changes: 48 additions & 0 deletions src/java/com/wolfssl/WolfSSLSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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, <b>in</b>
* @param format format of the certificate buffer being loaded - either
* <b>SSL_FILETYPE_PEM</b> or <b>SSL_FILETYPE_ASN1</b>
* @return <b><code>SSL_SUCCESS</code></b> upon success,
* <b><code>SSL_FAILURE</code></b> upon general failure,
* <b><code>SSL_BAD_FILETYPE</code></b> if the file is
* in the wrong format, <b><code>SSL_BAD_FILE</code></b>
* if the file doesn't exist, can't be read, or is
* corrupted. <b><code>MEMORY_E</code></b> if an out of
* memory condition occurs, <b><code>ASN_INPUT_E</code></b>
* if Base16 decoding fails on the file,
* <b><code>BUFFER_E</code></b> if a chain buffer is
* bigger than the receiving buffer, and <b><code>
* BAD_FUNC_ARG</code></b> 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.
Expand Down
96 changes: 0 additions & 96 deletions src/java/com/wolfssl/provider/jsse/WolfSSLContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ private void createCtx() throws WolfSSLException {

try {
LoadTrustedRootCerts();
LoadClientKeyAndCertChain();

} catch (Exception e) {
throw new IllegalArgumentException(e);
Expand Down Expand Up @@ -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<String> keyAlgos = new ArrayList<String>();
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.
*
Expand Down
35 changes: 31 additions & 4 deletions src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
}

/**
Expand Down Expand Up @@ -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);
}
}

/**
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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);
}

Expand Down
Loading

0 comments on commit ecd67a4

Please sign in to comment.