WolfSSLSession.getPeerCertificates(): provide full cert chain

This is needed for Certificate Pinning which is a common practice in
Android applications.
pull/256/head
Julian Winkler 2025-03-25 22:39:31 +01:00
parent 95bedabeb2
commit aba417593f
4 changed files with 156 additions and 72 deletions

View File

@ -2858,9 +2858,29 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_sessionReused
return wolfSSL_session_reused(ssl);
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getPeerCertificate
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getPeerCertificateCount
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifdef KEEP_PEER_CERT
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
if (ssl == NULL) {
return (jlong)0;
}
WOLFSSL_X509_CHAIN* chain = wolfSSL_get_peer_chain(ssl);
return wolfSSL_get_chain_count(chain);
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return 0;
#endif
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getPeerCertificate
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint index)
{
#ifdef KEEP_PEER_CERT
WOLFSSL_X509* x509 = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
@ -2870,8 +2890,8 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getPeerCertificate
if (ssl == NULL) {
return (jlong)0;
}
x509 = wolfSSL_get_peer_certificate(ssl);
WOLFSSL_X509_CHAIN* chain = wolfSSL_get_peer_chain(ssl);
x509 = wolfSSL_get_chain_X509(chain, index);
return (jlong)(uintptr_t)x509;
#else

View File

@ -351,13 +351,21 @@ JNIEXPORT jobject JNICALL Java_com_wolfssl_WolfSSLSession_dtlsGetPeer
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_sessionReused
(JNIEnv *, jobject, jlong);
/*
* Class: com_wolfssl_WolfSSLSession
* Method: getPeerCertificateCount
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getPeerCertificateCount
(JNIEnv *, jobject, jlong);
/*
* Class: com_wolfssl_WolfSSLSession
* Method: getPeerCertificate
* Signature: (J)J
* Signature: (JI)J
*/
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getPeerCertificate
(JNIEnv *, jobject, jlong);
(JNIEnv *, jobject, jlong, jint);
/*
* Class: com_wolfssl_WolfSSLSession

View File

@ -358,7 +358,8 @@ public class WolfSSLSession {
private native long getDtlsReplayDropCount(long ssl);
private native InetSocketAddress dtlsGetPeer(long ssl);
private native int sessionReused(long ssl);
private native long getPeerCertificate(long ssl);
private native int getPeerCertificateCount(long ssl);
private native long getPeerCertificate(long ssl, int index);
private native String getPeerX509Issuer(long ssl, long x509);
private native String getPeerX509Subject(long ssl, long x509);
private native String getPeerX509AltName(long ssl, long x509);
@ -2590,6 +2591,27 @@ public class WolfSSLSession {
return ret;
}
/**
* Returns the number of certificates in the peer's certificate chain.
*
* @return number of certificates in the peer's certificate chain.
* @throws IllegalStateException WolfSSLContext has been freed
* @throws WolfSSLJNIException Internal JNI error
* @see WolfSSLSession#getPeerCertificate(int)
*/
public int getPeerCertificateCount()
throws IllegalStateException, WolfSSLJNIException {
confirmObjectIsActive();
synchronized (sslLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.sslPtr, "entered getPeerCertificateCount()");
return getPeerCertificateCount(this.sslPtr);
}
}
/**
* Gets the native (long) WOLFSSL_X509 pointer to the peer's certificate.
* This can be used to retrieve further information about the peer's
@ -2606,6 +2628,7 @@ public class WolfSSLSession {
* Pointer should be freed by calling:
* WolfSSLCertificate.freeX509(long x509);
*
* @param index index of the certificate in the peer's certificate chain
* @return (long) WOLFSSL_X509 pointer to the peer's certificate.
* @throws IllegalStateException WolfSSLContext has been freed
* @throws WolfSSLJNIException Internal JNI error
@ -2614,7 +2637,7 @@ public class WolfSSLSession {
* @see WolfSSLSession#getVersion()
* @see WolfSSLSession#getCurrentCipher()
*/
public long getPeerCertificate()
public long getPeerCertificate(int index)
throws IllegalStateException, WolfSSLJNIException {
confirmObjectIsActive();
@ -2623,7 +2646,7 @@ public class WolfSSLSession {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.sslPtr, "entered getPeerCertificate()");
return getPeerCertificate(this.sslPtr);
return getPeerCertificate(this.sslPtr, index);
}
}

View File

@ -516,8 +516,33 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession
"SSLSocket/Engine closed");
}
int numCerts;
try {
x509 = this.ssl.getPeerCertificate();
numCerts = this.ssl.getPeerCertificateCount();
} catch (IllegalStateException | WolfSSLJNIException ex) {
Logger.getLogger(
WolfSSLImplementSSLSession.class.getName()).log(
Level.SEVERE, null, ex);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"ssl.getPeerCertificates() returned null, trying cached cert");
if (this.peerCerts != null) {
/* If peer cert is already cached, just return that */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"peer cert already cached, returning it");
return this.peerCerts.clone();
}
else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"No peer cert sent and none cached");
throw new SSLPeerUnverifiedException("No peer certificate");
}
}
X509Certificate[] certs = new X509Certificate[numCerts];
for (int i = 0; i < numCerts; i++) {
try {
x509 = this.ssl.getPeerCertificate(i);
} catch (IllegalStateException | WolfSSLJNIException ex) {
Logger.getLogger(
WolfSSLImplementSSLSession.class.getName()).log(
@ -588,10 +613,13 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession
/* release native memory */
cert.free();
/* cache peer cert for use by app in resumed session */
this.peerCerts = new X509Certificate[] { exportCert };
certs[i] = exportCert;
}
return this.peerCerts.clone();
/* cache peer cert for use by app in resumed session */
this.peerCerts = certs;
return certs.clone();
}
@Override
@ -612,7 +640,11 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession
}
try {
peerX509 = this.ssl.getPeerCertificate();
int numCerts = this.ssl.getPeerCertificateCount();
javax.security.cert.X509Certificate[] certs = new javax.security.cert.X509Certificate[numCerts];
for (int i = 0; i < numCerts; i++) {
peerX509 = this.ssl.getPeerCertificate(i);
if (peerX509 == 0) {
return null;
}
@ -628,9 +660,10 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession
else {
x509 = new WolfSSLX509X(peerX509, false);
}
certs[i] = (javax.security.cert.X509Certificate)x509;
}
return new javax.security.cert.X509Certificate[] {
(javax.security.cert.X509Certificate)x509 };
return certs;
} catch (IllegalStateException | WolfSSLJNIException |
WolfSSLException ex) {
@ -654,7 +687,7 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession
}
try {
peerX509 = this.ssl.getPeerCertificate();
peerX509 = this.ssl.getPeerCertificate(0);
if (peerX509 == 0) {
return null;
}