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,17 +516,13 @@ 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);
x509 = 0;
}
/* if no peer cert, throw SSLPeerUnverifiedException */
if (x509 == 0) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"ssl.getPeerCertificates() returned null, trying cached cert");
@ -542,56 +538,88 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession
throw new SSLPeerUnverifiedException("No peer certificate");
}
}
X509Certificate[] certs = new X509Certificate[numCerts];
try {
/* wolfSSL starting with 5.3.0 returns a new WOLFSSL_X509
* structure from wolfSSL_get_peer_certificate(). In that case,
* we need to free the pointer when finished. Prior to 5.3.0,
* this memory was freed internally by wolfSSL since the API
* only returned a pointer to internal memory */
if (WolfSSL.getLibVersionHex() >= 0x05003000) {
cert = new WolfSSLX509(x509, true);
for (int i = 0; i < numCerts; i++) {
try {
x509 = this.ssl.getPeerCertificate(i);
} catch (IllegalStateException | WolfSSLJNIException ex) {
Logger.getLogger(
WolfSSLImplementSSLSession.class.getName()).log(
Level.SEVERE, null, ex);
x509 = 0;
}
else {
cert = new WolfSSLX509(x509, false);
/* if no peer cert, throw SSLPeerUnverifiedException */
if (x509 == 0) {
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");
}
}
} catch (WolfSSLException ex) {
throw new SSLPeerUnverifiedException("Error creating certificate");
}
/* convert WolfSSLX509 into X509Certificate so we can release
* our native memory */
try {
cf = CertificateFactory.getInstance("X.509");
} catch (CertificateException ex) {
try {
/* wolfSSL starting with 5.3.0 returns a new WOLFSSL_X509
* structure from wolfSSL_get_peer_certificate(). In that case,
* we need to free the pointer when finished. Prior to 5.3.0,
* this memory was freed internally by wolfSSL since the API
* only returned a pointer to internal memory */
if (WolfSSL.getLibVersionHex() >= 0x05003000) {
cert = new WolfSSLX509(x509, true);
}
else {
cert = new WolfSSLX509(x509, false);
}
} catch (WolfSSLException ex) {
throw new SSLPeerUnverifiedException("Error creating certificate");
}
/* convert WolfSSLX509 into X509Certificate so we can release
* our native memory */
try {
cf = CertificateFactory.getInstance("X.509");
} catch (CertificateException ex) {
cert.free();
throw new SSLPeerUnverifiedException(
"Error getting CertificateFactory instance");
}
try {
der = new ByteArrayInputStream(cert.getEncoded());
} catch (CertificateEncodingException ex) {
cert.free();
throw new SSLPeerUnverifiedException(
"Error getting encoded DER from WolfSSLX509 object");
}
try {
exportCert = (X509Certificate)cf.generateCertificate(der);
} catch (CertificateException ex) {
cert.free();
throw new SSLPeerUnverifiedException(
"Error generating X509Certificdate from DER encoding");
}
/* release native memory */
cert.free();
throw new SSLPeerUnverifiedException(
"Error getting CertificateFactory instance");
}
try {
der = new ByteArrayInputStream(cert.getEncoded());
} catch (CertificateEncodingException ex) {
cert.free();
throw new SSLPeerUnverifiedException(
"Error getting encoded DER from WolfSSLX509 object");
certs[i] = exportCert;
}
try {
exportCert = (X509Certificate)cf.generateCertificate(der);
} catch (CertificateException ex) {
cert.free();
throw new SSLPeerUnverifiedException(
"Error generating X509Certificdate from DER encoding");
}
/* release native memory */
cert.free();
/* cache peer cert for use by app in resumed session */
this.peerCerts = new X509Certificate[] { exportCert };
this.peerCerts = certs;
return this.peerCerts.clone();
return certs.clone();
}
@Override
@ -612,25 +640,30 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession
}
try {
peerX509 = this.ssl.getPeerCertificate();
if (peerX509 == 0) {
return null;
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;
}
/* wolfSSL starting with 5.3.0 returns a new WOLFSSL_X509
* structure from wolfSSL_get_peer_certificate(). In that case,
* we need to free the pointer when finished. Prior to 5.3.0,
* this memory was freed internally by wolfSSL since the API
* only returned a pointer to internal memory */
if (WolfSSL.getLibVersionHex() >= 0x05003000) {
x509 = new WolfSSLX509X(peerX509, true);
}
else {
x509 = new WolfSSLX509X(peerX509, false);
}
certs[i] = (javax.security.cert.X509Certificate)x509;
}
/* wolfSSL starting with 5.3.0 returns a new WOLFSSL_X509
* structure from wolfSSL_get_peer_certificate(). In that case,
* we need to free the pointer when finished. Prior to 5.3.0,
* this memory was freed internally by wolfSSL since the API
* only returned a pointer to internal memory */
if (WolfSSL.getLibVersionHex() >= 0x05003000) {
x509 = new WolfSSLX509X(peerX509, true);
}
else {
x509 = new WolfSSLX509X(peerX509, false);
}
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;
}