Skip to content
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
13 changes: 13 additions & 0 deletions native/com_wolfssl_WolfSSL.c
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,19 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_trustPeerCertEnabled
#endif
}

JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_sessionCertsEnabled
(JNIEnv* jenv, jclass jcl)
{
(void)jenv;
(void)jcl;

#ifdef SESSION_CERTS
return JNI_TRUE;
#else
return JNI_FALSE;
#endif
}

JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_sessionTicketEnabled
(JNIEnv* jenv, jclass jcl)
{
Expand Down
8 changes: 8 additions & 0 deletions native/com_wolfssl_WolfSSL.h

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

78 changes: 78 additions & 0 deletions native/com_wolfssl_WolfSSLSession.c
Original file line number Diff line number Diff line change
Expand Up @@ -3412,6 +3412,84 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getPeerCertificate
#endif
}

JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_WolfSSLSession_getPeerCertificateChainDER
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifdef SESSION_CERTS
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
WOLFSSL_X509_CHAIN* chain = NULL;
jclass byteArrayClass = NULL;
jobjectArray chainArr = NULL;
jbyteArray derArr = NULL;
unsigned char* der = NULL;
int chainSz = 0;
int derSz = 0;
int i = 0;
(void)jcl;

if (jenv == NULL || ssl == NULL) {
return NULL;
}

chain = wolfSSL_get_peer_chain(ssl);
if (chain == NULL) {
return NULL;
}

chainSz = wolfSSL_get_chain_count(chain);
if (chainSz <= 0) {
return NULL;
}

byteArrayClass = (*jenv)->FindClass(jenv, "[B");
if (byteArrayClass == NULL) {
return NULL;
}

chainArr = (*jenv)->NewObjectArray(jenv, chainSz, byteArrayClass, NULL);
if (chainArr == NULL) {
return NULL;
}

/* Appended in wire order, peer cert first. Native wolfSSL drops certs
* of MAX_X509_SIZE or larger and anything past MAX_CHAIN_DEPTH, so the
* chain can be incomplete and may not start with the peer cert. */
for (i = 0; i < chainSz; i++) {

der = wolfSSL_get_chain_cert(chain, i);
derSz = wolfSSL_get_chain_length(chain, i);

if (der == NULL || derSz <= 0) {
/* Chain not usable if any entry is missing */
return NULL;
}

derArr = (*jenv)->NewByteArray(jenv, derSz);
if (derArr == NULL) {
return NULL;
}

(*jenv)->SetByteArrayRegion(jenv, derArr, 0, derSz, (jbyte*)der);
if ((*jenv)->ExceptionCheck(jenv)) {
return NULL;
}

(*jenv)->SetObjectArrayElement(jenv, chainArr, i, derArr);
(*jenv)->DeleteLocalRef(jenv, derArr);
if ((*jenv)->ExceptionCheck(jenv)) {
return NULL;
}
}

return chainArr;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NULL;
#endif
}

JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_getPeerX509Issuer
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jlong x509Ptr)
{
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.

11 changes: 11 additions & 0 deletions src/java/com/wolfssl/WolfSSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,17 @@ protected static byte[] fileToBytes(File file)
*/
public static native boolean trustPeerCertEnabled();

/**
* Tests if native wolfSSL has been compiled with SESSION_CERTS.
* If defined, wolfSSL stores the cert chain sent by the peer, allowing
* full chain to be returned from
* WolfSSLSession.getPeerCertificateChainDER().
*
* @return true if enabled, otherwise false if SESSION_CERTS has not
* been defined.
*/
public static native boolean sessionCertsEnabled();

/**
* Tests if native session ticket support has been compiled into wolfSSL
* with HAVE_SESSION_TICKET.
Expand Down
157 changes: 157 additions & 0 deletions src/java/com/wolfssl/WolfSSLSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ private static native byte[] dtlsCidParseNative(byte[] msg, int msgSz,
private native InetSocketAddress dtlsGetPeer(long ssl);
private native int sessionReused(long ssl);
private native long getPeerCertificate(long ssl);
private native byte[][] getPeerCertificateChainDER(long ssl);
private native String getPeerX509Issuer(long ssl, long x509);
private native String getPeerX509Subject(long ssl, long x509);
private native String getPeerX509AltName(long ssl, long x509);
Expand Down Expand Up @@ -3341,6 +3342,162 @@ public long getPeerCertificate()
}
}

/**
* Gets the DER encoding of the peer certificate.
*
* Requires native wolfSSL to be compiled with KEEP_PEER_CERT,
* auto defined by "--enable-jni".
*
* @return DER encoding of the peer cert, or null if the peer did not send
* a certificate or it is not available. Returned encoding is a
* copy, no native memory needs to be freed by caller.
* @throws IllegalStateException WolfSSLSession has been freed
* @throws WolfSSLJNIException Internal JNI error
* @see WolfSSLSession#getPeerCertificateChainDER()
*/
public byte[] getPeerCertificateDER()
throws IllegalStateException, WolfSSLJNIException {

confirmObjectIsActive();

synchronized (sslLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.sslPtr,
() -> "entered getPeerCertificateDER()");

return getPeerCertificateDERLocked();
}
}

/**
* Get the DER encoding of the peer certificate, caller must already hold
* sslLock and have called confirmObjectIsActive(). The public method
* cannot be used from inside sslLock, confirmObjectIsActive() is
* synchronized on this object and would invert this class's lock order.
*
* @return DER encoding of the peer cert, or null if not available
*/
private byte[] getPeerCertificateDERLocked() {

long x509 = getPeerCertificate(this.sslPtr);

if (x509 == 0) {
return null;
}

try {
return WolfSSL.x509_getDer(x509);

} finally {
/* wolfSSL 5.3.0 and later hand back a new WOLFSSL_X509 the
* caller owns, earlier versions internal memory */
if (WolfSSL.getLibVersionHex() >= 0x05003000) {
WolfSSLCertificate.freeX509(x509);
}
}
}

/**
* Gets the DER encoding of each certificate in the peer cert chain,
* as sent by the peer during the handshake.
*
* Index zero holds the peer cert, followed by any intermediate CA certs
* the peer chose to send, in the order received. If native wolfSSL
* stored no chain, for example when built without SESSION_CERTS, the
* peer cert alone is returned.
*
* Native wolfSSL skips certs of MAX_X509_SIZE or larger when storing the
* peer chain, and drops anything past MAX_CHAIN_DEPTH, so an oversized
* or deep intermediate CA cert will be missing. An oversized peer cert
* is skipped too, but is restored to index zero from the separate
* KEEP_PEER_CERT copy. Without KEEP_PEER_CERT there is no copy to check
* index zero against, so null is returned rather than a chain that might
* start at a CA.
*
* On a resumed session no Certificate message is received, so native
* wolfSSL reports the chain stored in the resumed session. Callers
* needing the certs from the original handshake should cache them.
*
* This method makes several native calls, one of which copies the peer
* cert, so callers should cache the result rather than call this
* repeatedly to avoid performance penalties.
*
* @return two dimensional byte array holding the DER encoding of each
* certificate in the peer's chain, or null if the peer sent no
* certificates. Returned arrays are copies, no native memory
* needs to be freed by caller.
* @throws IllegalStateException WolfSSLSession has been freed
* @throws WolfSSLJNIException Internal JNI error
* @see WolfSSLSession#getPeerCertificateDER()
* @see WolfSSLSession#getPeerCertificate()
*/
public byte[][] getPeerCertificateChainDER()
throws IllegalStateException, WolfSSLJNIException {

byte[] peerDer = null;
byte[][] chain = null;

confirmObjectIsActive();

synchronized (sslLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.sslPtr,
() -> "entered getPeerCertificateChainDER()");

chain = getPeerCertificateChainDER(this.sslPtr);
peerDer = getPeerCertificateDERLocked();
chain = ensurePeerCertFirst(chain, peerDer);

final int chainSz = (chain == null) ? 0 : chain.length;
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.sslPtr,
() -> "peer chain size: " + chainSz);

return chain;
}
}

/**
* Place the peer certificate at index zero of the stored chain, which
* native wolfSSL leaves starting at a CA when the peer cert was too
* large to store.
*
* @param chain DER encoding of each cert in the chain stored by native
* wolfSSL, may be null or empty
* @param peerDer DER encoding of the peer's own cert, may be null
*
* @return chain holding the peer cert at index zero, or null if no cert
* is available or the peer cert cannot be confirmed to be first
*/
private static byte[][] ensurePeerCertFirst(byte[][] chain,
byte[] peerDer) {

byte[][] fullChain = null;

if (chain == null || chain.length == 0) {
if (peerDer == null) {
return null;
}
return new byte[][] { peerDer };
}

if (peerDer == null) {
/* No peer cert to check chain[0] against, fail closed rather
* than report CA as peer. */
return null;
}

if (Arrays.equals(peerDer, chain[0])) {
return chain;
}

fullChain = new byte[chain.length + 1][];
fullChain[0] = peerDer;
System.arraycopy(chain, 0, fullChain, 1, chain.length);

return fullChain;
}

/**
* Gets the peer X509 certificate's issuer information.
*
Expand Down
Loading
Loading