Skip to content

Commit 4eb1bea

Browse files
committed
JSSE: add Android non-standard checkServerTrusted() in X509TrustManager
1 parent b2555d4 commit 4eb1bea

5 files changed

Lines changed: 625 additions & 2 deletions

File tree

native/com_wolfssl_WolfSSLCertManager.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,48 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertManager_CertManagerVerifyBuff
145145
return (jint)ret;
146146
}
147147

148+
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertManager_CertManagerCheckOCSPResponse
149+
(JNIEnv* jenv, jclass jcl, jlong cmPtr, jbyteArray response)
150+
{
151+
#ifdef HAVE_OCSP
152+
int ret = 0;
153+
jint responseSz = 0;
154+
byte* responseBuffer = NULL;
155+
WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)(uintptr_t)cmPtr;
156+
(void)jcl;
157+
158+
if (jenv == NULL || response == NULL || cm == NULL) {
159+
ret = BAD_FUNC_ARG;
160+
}
161+
162+
if (ret == 0) {
163+
responseSz = (*jenv)->GetArrayLength(jenv, response);
164+
responseBuffer = (byte*)(*jenv)->GetByteArrayElements(jenv,
165+
response, NULL);
166+
if (responseBuffer == NULL) {
167+
ret = MEMORY_E;
168+
}
169+
}
170+
171+
/* Call native wolfSSL OCSP response validation. Pass NULL for unused
172+
* parameters as we only need basic response validation. */
173+
if (ret == 0) {
174+
ret = wolfSSL_CertManagerCheckOCSPResponse(cm, responseBuffer,
175+
responseSz, NULL, NULL, NULL, NULL);
176+
}
177+
178+
if (responseBuffer != NULL) {
179+
(*jenv)->ReleaseByteArrayElements(jenv, response,
180+
(jbyte*)responseBuffer, JNI_ABORT);
181+
}
182+
183+
return (jint)ret;
184+
#else
185+
(void)jenv;
186+
(void)jcl;
187+
(void)cmPtr;
188+
(void)response;
189+
return (jint)NOT_COMPILED_IN;
190+
#endif
191+
}
192+

native/com_wolfssl_WolfSSLCertManager.h

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/java/com/wolfssl/WolfSSLCertManager.java

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,11 @@ public class WolfSSLCertManager {
4949
static native void CertManagerFree(long cm);
5050
static native int CertManagerLoadCA(long cm, String f, String d);
5151
static native int CertManagerLoadCABuffer(long cm, byte[] in, long sz,
52-
int format);
52+
int format);
5353
static native int CertManagerUnloadCAs(long cm);
5454
static native int CertManagerVerifyBuffer(long cm, byte[] in, long sz,
55-
int format);
55+
int format);
56+
static native int CertManagerCheckOCSPResponse(long cm, byte[] response);
5657

5758
/**
5859
* Create new WolfSSLCertManager object
@@ -246,6 +247,41 @@ public synchronized int CertManagerVerifyBuffer(
246247
}
247248
}
248249

250+
/**
251+
* Check OCSP response for certificate revocation status
252+
*
253+
* @param response DER-encoded OCSP response data
254+
*
255+
* @return WolfSSL.SSL_SUCCESS on success, negative on error
256+
*
257+
* @throws IllegalStateException if WolfSSLCertManager has been freed
258+
* @throws WolfSSLException if OCSP is not compiled in
259+
*/
260+
public synchronized int CertManagerCheckOCSPResponse(byte[] response)
261+
throws IllegalStateException, WolfSSLException {
262+
263+
confirmObjectIsActive();
264+
265+
if (response == null || response.length == 0) {
266+
throw new IllegalArgumentException(
267+
"OCSP response data is null or invalid size");
268+
}
269+
270+
synchronized (cmLock) {
271+
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
272+
WolfSSLDebug.INFO, this.cmPtr,
273+
() -> "entered CertManagerCheckOCSPResponse(responseSz: " +
274+
response.length + ")");
275+
276+
int ret = CertManagerCheckOCSPResponse(this.cmPtr, response);
277+
if (ret == WolfSSL.NOT_COMPILED_IN) {
278+
throw new WolfSSLException(
279+
"OCSP support not compiled into wolfSSL");
280+
}
281+
return ret;
282+
}
283+
}
284+
249285
/**
250286
* Frees CertManager object
251287
* @see WolfSSLSession#freeSSL()

src/java/com/wolfssl/provider/jsse/WolfSSLTrustX509.java

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,105 @@ public List<X509Certificate> checkServerTrusted(X509Certificate[] certs,
953953
return certList;
954954
}
955955

956+
/**
957+
* Verifies a specified certificate chain.
958+
* Non standard API, this is called/needed by Android.
959+
*
960+
* Android expects this method signature for OCSP stapling support.
961+
* Native wolfSSL supports OCSP response processing via
962+
* wolfSSL_CertManagerCheckOCSPResponse(). The ocspData parameter
963+
* contains DER-encoded OCSP response data that is processed for
964+
* certificate revocation checking.
965+
*
966+
* @param chain Certificate chain to validate
967+
* @param ocspData OCSP response data (DER-encoded), may be null
968+
* @param tlsSctData TLS SCT data (unused, wolfSSL does not support SCT)
969+
* @param authType Authentication type
970+
* @param host Hostname of the server
971+
*
972+
* @return Certificate chain used for verification, ordered with leaf/peer
973+
* cert first, root CA cert last
974+
*
975+
* @throws CertificateException if chain does not verify properly
976+
*/
977+
public List<X509Certificate> checkServerTrusted(X509Certificate[] chain,
978+
byte[] ocspData, byte[] tlsSctData, String authType, String host)
979+
throws CertificateException {
980+
981+
int ret;
982+
WolfSSLCertManager cm = null;
983+
984+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
985+
() -> "entered checkServerTrusted(chain, ocspData, tlsSctData, " +
986+
"authType, host)");
987+
988+
/* First verify the certificate chain normally, throws exception
989+
* if chain is invalid */
990+
List<X509Certificate> certList =
991+
checkServerTrusted(chain, authType, host);
992+
993+
/* Verify OCSP response data if provided */
994+
if (ocspData != null && ocspData.length > 0) {
995+
996+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
997+
() -> "Verifying OCSP response data (" + ocspData.length +
998+
" bytes)");
999+
1000+
try {
1001+
cm = new WolfSSLCertManager();
1002+
1003+
/* Load the trusted CAs that were used for cert verification */
1004+
ret = cm.CertManagerLoadCAKeyStore(this.store);
1005+
if (ret != WolfSSL.SSL_SUCCESS) {
1006+
throw new CertificateException(
1007+
"Failed to load trusted CAs for OCSP verification, " +
1008+
"ret = " + ret);
1009+
}
1010+
1011+
/* Check OCSP response */
1012+
ret = cm.CertManagerCheckOCSPResponse(ocspData);
1013+
if (ret != WolfSSL.SSL_SUCCESS) {
1014+
throw new CertificateException(
1015+
"OCSP response validation failed: " + ret);
1016+
}
1017+
1018+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1019+
() -> "OCSP response validation successful");
1020+
1021+
} catch (WolfSSLException e) {
1022+
if (e.getMessage().contains("not compiled")) {
1023+
/* OCSP not available, log and continue */
1024+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1025+
() -> "OCSP support not available, skipping " +
1026+
"OCSP validation");
1027+
} else {
1028+
throw new CertificateException("OCSP validation error", e);
1029+
}
1030+
} finally {
1031+
if (cm != null) {
1032+
cm.free();
1033+
}
1034+
}
1035+
1036+
} else {
1037+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1038+
() -> "No OCSP data provided");
1039+
}
1040+
1041+
/* Ignore TLS SCT data as wolfSSL doesn't support it */
1042+
if (tlsSctData != null && tlsSctData.length > 0) {
1043+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1044+
() -> "TLS SCT data provided (" + tlsSctData.length +
1045+
" bytes), currently not processed");
1046+
}
1047+
1048+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1049+
() -> "leaving checkServerTrusted(chain, ocspData, tlsSctData, " +
1050+
"authType, host), success");
1051+
1052+
return certList;
1053+
}
1054+
9561055
/**
9571056
* Returns an array of certificate authorities which are trusted for
9581057
* authenticating peers.

0 commit comments

Comments
 (0)