Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for SSLEngine.setWant/NeedClientAuth() and choosing key alias chooseEngineClient/ServerAlias() #172

Merged
merged 2 commits into from
Feb 15, 2024
Merged
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
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