Skip to content

Commit 293e485

Browse files
committed
JSSE: add Android non-standard checkServerTrusted() in X509TrustManager
1 parent 7650f51 commit 293e485

9 files changed

Lines changed: 1180 additions & 3 deletions

File tree

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
Certificate:
2+
Data:
3+
Version: 3 (0x2)
4+
Serial Number: 99 (0x63)
5+
Signature Algorithm: sha256WithRSAEncryption
6+
Issuer: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL root CA, emailAddress=info@wolfssl.com
7+
Validity
8+
Not Before: Nov 13 20:41:34 2025 GMT
9+
Not After : Aug 9 20:41:34 2028 GMT
10+
Subject: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL root CA, emailAddress=info@wolfssl.com
11+
Subject Public Key Info:
12+
Public Key Algorithm: rsaEncryption
13+
Public-Key: (2048 bit)
14+
Modulus:
15+
00:ab:2c:b4:2f:1d:06:09:ef:4e:29:86:84:7e:cc:
16+
bf:a6:79:7c:f0:c0:c1:64:25:8c:75:b7:10:05:ca:
17+
48:27:0c:0e:32:1c:b0:fe:99:85:39:b6:b9:a2:f7:
18+
27:ff:6d:3c:8c:16:73:29:21:7f:8b:a6:54:71:90:
19+
ad:cc:05:b9:9f:15:c7:0a:3f:5f:69:f4:0a:5f:8c:
20+
71:b5:2c:bf:66:e2:03:9a:32:f4:d2:ec:2a:89:4b:
21+
f9:35:88:14:33:47:4e:2e:05:79:01:ed:64:36:76:
22+
b9:f8:85:cd:01:88:ac:c5:b2:b1:59:b8:cd:5a:f4:
23+
09:09:38:9b:da:5a:cf:ce:78:99:1f:49:3d:41:d6:
24+
06:7c:52:99:c8:97:d1:b3:80:3a:a2:4f:36:c4:c5:
25+
96:30:77:31:38:c8:70:cc:e1:67:06:b3:2b:2f:93:
26+
b5:69:cf:83:7e:88:53:9b:0f:46:21:4c:d6:05:36:
27+
44:99:60:68:47:e5:32:01:12:d4:10:73:ae:9a:34:
28+
94:fa:6e:b8:58:4f:7b:5b:8a:92:97:ad:fd:97:b9:
29+
75:ca:c2:d4:45:7d:17:6b:cd:2f:f3:63:7a:0e:30:
30+
b5:0b:a9:d9:a6:7c:74:60:9d:cc:09:03:43:f1:0f:
31+
90:d3:b7:fe:6c:9f:d9:cd:78:4b:15:ae:8c:5b:f9:
32+
99:81
33+
Exponent: 65537 (0x10001)
34+
X509v3 extensions:
35+
X509v3 Basic Constraints:
36+
CA:TRUE
37+
X509v3 Subject Key Identifier:
38+
73:B0:1C:A4:2F:82:CB:CF:47:A5:38:D7:B0:04:82:3A:7E:72:15:21
39+
X509v3 Authority Key Identifier:
40+
keyid:73:B0:1C:A4:2F:82:CB:CF:47:A5:38:D7:B0:04:82:3A:7E:72:15:21
41+
DirName:/C=US/ST=Washington/L=Seattle/O=wolfSSL/OU=Engineering/CN=wolfSSL root CA/emailAddress=info@wolfssl.com
42+
serial:63
43+
X509v3 Key Usage:
44+
Certificate Sign, CRL Sign
45+
Authority Information Access:
46+
OCSP - URI:http://127.0.0.1:22220
47+
Signature Algorithm: sha256WithRSAEncryption
48+
Signature Value:
49+
58:41:01:e5:1b:ce:bc:51:0c:23:b2:66:df:39:d9:1e:b1:bd:
50+
9a:db:fa:da:16:83:26:6e:7e:2e:f9:5d:46:9a:52:a0:09:6f:
51+
f2:c0:96:ba:49:ad:29:54:06:e9:21:d6:36:5e:d5:43:07:2c:
52+
5d:4e:b7:bf:7c:e5:91:75:ea:0d:56:7c:a3:fd:82:d8:2e:70:
53+
fa:fc:ab:36:36:d5:ba:63:d5:42:da:21:b4:50:9a:86:8a:df:
54+
21:26:03:e8:ca:6f:c7:51:50:6c:cc:40:da:4e:8f:06:15:c0:
55+
9a:0d:7a:80:2c:95:aa:5a:ad:e2:66:b0:32:d6:74:87:ea:7a:
56+
b2:46:d5:2c:cf:fa:18:8a:2f:e0:3a:ae:17:6a:f2:ce:75:8d:
57+
e4:4d:74:8f:e7:c6:21:29:65:5d:41:07:fb:29:d9:be:ea:b2:
58+
e3:80:07:8c:14:8d:a3:7d:d1:51:af:26:9d:cd:01:d5:80:af:
59+
68:12:41:2b:eb:94:cc:45:d1:c7:66:f3:f9:15:72:be:94:e3:
60+
21:6d:f1:08:78:b6:5a:ee:73:09:4b:f4:1a:5e:02:2a:25:f0:
61+
3d:d2:03:f2:22:15:4b:3d:aa:35:ea:90:ca:44:4e:61:77:db:
62+
b4:94:46:77:c6:8c:33:09:b6:84:3c:4e:ac:ad:9d:e0:2f:22:
63+
5a:be:25:19
64+
-----BEGIN CERTIFICATE-----
65+
MIIE5jCCA86gAwIBAgIBYzANBgkqhkiG9w0BAQsFADCBlzELMAkGA1UEBhMCVVMx
66+
EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoM
67+
B3dvbGZTU0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQDDA93b2xmU1NM
68+
IHJvb3QgQ0ExHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMjUx
69+
MTEzMjA0MTM0WhcNMjgwODA5MjA0MTM0WjCBlzELMAkGA1UEBhMCVVMxEzARBgNV
70+
BAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoMB3dvbGZT
71+
U0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQDDA93b2xmU1NMIHJvb3Qg
72+
Q0ExHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wggEiMA0GCSqGSIb3
73+
DQEBAQUAA4IBDwAwggEKAoIBAQCrLLQvHQYJ704phoR+zL+meXzwwMFkJYx1txAF
74+
ykgnDA4yHLD+mYU5trmi9yf/bTyMFnMpIX+LplRxkK3MBbmfFccKP19p9ApfjHG1
75+
LL9m4gOaMvTS7CqJS/k1iBQzR04uBXkB7WQ2drn4hc0BiKzFsrFZuM1a9AkJOJva
76+
Ws/OeJkfST1B1gZ8UpnIl9GzgDqiTzbExZYwdzE4yHDM4WcGsysvk7Vpz4N+iFOb
77+
D0YhTNYFNkSZYGhH5TIBEtQQc66aNJT6brhYT3tbipKXrf2XuXXKwtRFfRdrzS/z
78+
Y3oOMLULqdmmfHRgncwJA0PxD5DTt/5sn9nNeEsVroxb+ZmBAgMBAAGjggE5MIIB
79+
NTAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRzsBykL4LLz0elONewBII6fnIVITCB
80+
xAYDVR0jBIG8MIG5gBRzsBykL4LLz0elONewBII6fnIVIaGBnaSBmjCBlzELMAkG
81+
A1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUx
82+
EDAOBgNVBAoMB3dvbGZTU0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQD
83+
DA93b2xmU1NMIHJvb3QgQ0ExHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5j
84+
b22CAWMwCwYDVR0PBAQDAgEGMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYW
85+
aHR0cDovLzEyNy4wLjAuMToyMjIyMDANBgkqhkiG9w0BAQsFAAOCAQEAWEEB5RvO
86+
vFEMI7Jm3znZHrG9mtv62haDJm5+LvldRppSoAlv8sCWukmtKVQG6SHWNl7VQwcs
87+
XU63v3zlkXXqDVZ8o/2C2C5w+vyrNjbVumPVQtohtFCahorfISYD6Mpvx1FQbMxA
88+
2k6PBhXAmg16gCyVqlqt4mawMtZ0h+p6skbVLM/6GIov4DquF2ryznWN5E10j+fG
89+
ISllXUEH+ynZvuqy44AHjBSNo33RUa8mnc0B1YCvaBJBK+uUzEXRx2bz+RVyvpTj
90+
IW3xCHi2Wu5zCUv0Gl4CKiXwPdID8iIVSz2qNeqQykROYXfbtJRGd8aMMwm2hDxO
91+
rK2d4C8iWr4lGQ==
92+
-----END CERTIFICATE-----

examples/certs/update-certs.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ do
7070
fi
7171
done
7272

73+
# Copy OCSP root CA cert (stored flat, not in subdirectory)
74+
printf "Updating: ocsp-root-ca-cert.pem\n"
75+
cp $CERT_LOCATION/ocsp/root-ca-cert.pem ./ocsp-root-ca-cert.pem
76+
if [ $? -ne 0 ]; then
77+
printf "Failed to copy cert: ocsp/root-ca-cert.pem\n"
78+
exit 1
79+
fi
80+
7381
# Generate ca-keyPkcs8.der, used by examples/X509CertificateGeneration.java
7482
openssl pkcs8 -topk8 -inform DER -outform DER -in ca-key.der -out ca-keyPkcs8.der -nocrypt
7583
if [ $? -ne 0 ]; then

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
@@ -1018,6 +1018,105 @@ public List<X509Certificate> checkServerTrusted(X509Certificate[] certs,
10181018
return certList;
10191019
}
10201020

1021+
/**
1022+
* Verifies a specified certificate chain.
1023+
* Non standard API, this is called/needed by Android.
1024+
*
1025+
* Android expects this method signature for OCSP stapling support.
1026+
* Native wolfSSL supports OCSP response processing via
1027+
* wolfSSL_CertManagerCheckOCSPResponse(). The ocspData parameter
1028+
* contains DER-encoded OCSP response data that is processed for
1029+
* certificate revocation checking.
1030+
*
1031+
* @param chain Certificate chain to validate
1032+
* @param ocspData OCSP response data (DER-encoded), may be null
1033+
* @param tlsSctData TLS SCT data (unused, wolfSSL does not support SCT)
1034+
* @param authType Authentication type
1035+
* @param host Hostname of the server
1036+
*
1037+
* @return Certificate chain used for verification, ordered with leaf/peer
1038+
* cert first, root CA cert last
1039+
*
1040+
* @throws CertificateException if chain does not verify properly
1041+
*/
1042+
public List<X509Certificate> checkServerTrusted(X509Certificate[] chain,
1043+
byte[] ocspData, byte[] tlsSctData, String authType, String host)
1044+
throws CertificateException {
1045+
1046+
int ret;
1047+
WolfSSLCertManager cm = null;
1048+
1049+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1050+
() -> "entered checkServerTrusted(chain, ocspData, tlsSctData, " +
1051+
"authType, host)");
1052+
1053+
/* First verify the certificate chain normally, throws exception
1054+
* if chain is invalid */
1055+
List<X509Certificate> certList =
1056+
checkServerTrusted(chain, authType, host);
1057+
1058+
/* Verify OCSP response data if provided */
1059+
if (ocspData != null && ocspData.length > 0) {
1060+
1061+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1062+
() -> "Verifying OCSP response data (" + ocspData.length +
1063+
" bytes)");
1064+
1065+
try {
1066+
cm = new WolfSSLCertManager();
1067+
1068+
/* Load the trusted CAs that were used for cert verification */
1069+
ret = cm.CertManagerLoadCAKeyStore(this.store);
1070+
if (ret != WolfSSL.SSL_SUCCESS) {
1071+
throw new CertificateException(
1072+
"Failed to load trusted CAs for OCSP verification, " +
1073+
"ret = " + ret);
1074+
}
1075+
1076+
/* Check OCSP response */
1077+
ret = cm.CertManagerCheckOCSPResponse(ocspData);
1078+
if (ret != WolfSSL.SSL_SUCCESS) {
1079+
throw new CertificateException(
1080+
"OCSP response validation failed: " + ret);
1081+
}
1082+
1083+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1084+
() -> "OCSP response validation successful");
1085+
1086+
} catch (WolfSSLException e) {
1087+
if (e.getMessage().contains("not compiled")) {
1088+
/* OCSP not available, log and continue */
1089+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1090+
() -> "OCSP support not available, skipping " +
1091+
"OCSP validation");
1092+
} else {
1093+
throw new CertificateException("OCSP validation error", e);
1094+
}
1095+
} finally {
1096+
if (cm != null) {
1097+
cm.free();
1098+
}
1099+
}
1100+
1101+
} else {
1102+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1103+
() -> "No OCSP data provided");
1104+
}
1105+
1106+
/* Ignore TLS SCT data as wolfSSL doesn't support it */
1107+
if (tlsSctData != null && tlsSctData.length > 0) {
1108+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1109+
() -> "TLS SCT data provided (" + tlsSctData.length +
1110+
" bytes), currently not processed");
1111+
}
1112+
1113+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1114+
() -> "leaving checkServerTrusted(chain, ocspData, tlsSctData, " +
1115+
"authType, host), success");
1116+
1117+
return certList;
1118+
}
1119+
10211120
/**
10221121
* Returns an array of certificate authorities which are trusted for
10231122
* authenticating peers.

0 commit comments

Comments
 (0)