eduvpn / android

Android eduVPN application
https://play.google.com/store/apps/details?id=nl.eduvpn.app&hl=en
GNU General Public License v3.0
129 stars 44 forks source link

enable OCSP stapling in HTTP (API) client #339

Closed ghost closed 3 years ago

ghost commented 3 years ago

would it be possible to enable (=force) OCSP stapling for (Android?) HTTP client as used by the eduVPN/Let's Connect! apps?

This is important to be able to detect revoked certificates as there currently is no other means to make sure clients do not continue to connect to MITM servers after the TLS key has been stolen from the "real" server and this has been detected.

dzolnai commented 3 years ago

It doesn't seem to be supported out-of-the-box: https://github.com/square/okhttp/issues/2348

ghost commented 3 years ago

Won't be doing this anymore.

fantostisch commented 2 years ago

I had a look at this when the issue was still open, documenting here so the information is not lost.

OkHTTP (HTTP(S) library that we use) does not have the functionality to verify OCSP responses. Conscrypt does have the functionality to check the OCSP stapling response, but it only checks it if the server sends the OCSP stapling response. With a simple patch to the Conscrypt library we can enforce OCSP stapling:

diff --git a/common/src/main/java/org/conscrypt/TrustManagerImpl.java b/common/src/main/java/org/conscrypt/TrustManagerImpl.java
index ccec8e98..e5f96b87 100644
--- a/common/src/main/java/org/conscrypt/TrustManagerImpl.java
+++ b/common/src/main/java/org/conscrypt/TrustManagerImpl.java
@@ -695,6 +695,9 @@ public final class TrustManagerImpl extends X509ExtendedTrustManager {
                 PKIXParameters params = new PKIXParameters(anchorSet);
                 params.setRevocationEnabled(false);
                 X509Certificate endPointCert = untrustedChain.get(0);
+                if (ocspData == null) {
+                    throw new CertificateException("No ocsp response provided by server");
+                }
                 setOcspResponses(params, endPointCert, ocspData);
                 params.addCertPathChecker(
                         new ExtendedKeyUsagePKIXCertPathChecker(clientAuth, endPointCert));
@@ -739,10 +742,6 @@ public final class TrustManagerImpl extends X509ExtendedTrustManager {
      * Sets the OCSP response data that was possibly stapled to the TLS response.
      */
     private void setOcspResponses(PKIXParameters params, X509Certificate cert, byte[] ocspData) {
-        if (ocspData == null) {
-            return;
-        }
-
         PKIXRevocationChecker revChecker = null;
         List<PKIXCertPathChecker> checkers =
                 new ArrayList<PKIXCertPathChecker>(params.getCertPathCheckers());
@@ -759,7 +758,7 @@ public final class TrustManagerImpl extends X509ExtendedTrustManager {
             try {
                 revChecker = (PKIXRevocationChecker) validator.getRevocationChecker();
             } catch (UnsupportedOperationException e) {
-                return;
+                return; //todo: do not just return
             }

             checkers.add(revChecker);

By default, Conscrypt is not used to verify the TLS certificates. To use Conscrypt we have to tell the OkHttp library to use the Conscrypt factory and trust manager.

This was tested and it works. There is however one problem: the first time the client connects the server, the server might not have an OCSP stapling response ready and will not return one. The next time the client connects, the server will have the OCSP stapling response. This problem was encountered by trying to connect to different servers and checking the OCSP response. The servers will thus have to be modified to always serve the OCSP response or the client should be modified to retry when the server does not return the OCSP response the first time.