Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android 8/9 default trust manager: OOM when getting "https://icloud.com" #520

Closed
rfc2822 opened this issue Jul 16, 2018 · 28 comments · Fixed by #1066
Closed

Android 8/9 default trust manager: OOM when getting "https://icloud.com" #520

rfc2822 opened this issue Jul 16, 2018 · 28 comments · Fixed by #1066

Comments

@rfc2822
Copy link

rfc2822 commented Jul 16, 2018

(Copied from square/okhttp#4155)

When using okhttp (which uses the platform default custom manager, which seems to be provided by Conscrypt) to GET (or PROPFIND) https://icloud.com (without www) with code like that:

// compileSdkVersion 27
// buildToolsVersion '28.0.1'
// targetSdkVersion 27
// Kotlin 1.2.51

class ClientTest {
    @Test
    fun testIcloud() {
        val client = OkHttpClient()
        client.newCall(Request.Builder()
                .get()
                .url("https://icloud.com")
                .build())
                .execute()
    }
}

it takes a long time until the process is killed with OOM and the test fails:

Accessing hidden method Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setAlpnProtocols([B)V (light greylist, reflection)
Background concurrent copying GC freed 12119(2MB) AllocSpace objects, 2(40KB) LOS objects, 53% free, 1347KB/2MB, paused 5.288ms total 13.790ms
Background concurrent copying GC freed 255556(7MB) AllocSpace objects, 0(0B) LOS objects, 3% free, 153MB/159MB, paused 160us total 1.134s
Waiting for a blocking GC Alloc
Background concurrent copying GC freed 1659257(48MB) AllocSpace objects, 0(0B) LOS objects, 4% free, 143MB/149MB, paused 166us total 751.739ms
WaitForGcToComplete blocked Alloc on ProfileSaver for 84.800ms
    Starting a blocking GC Alloc
Waiting for a blocking GC Alloc
NativeAlloc concurrent copying GC freed 613455(17MB) AllocSpace objects, 0(0B) LOS objects, 3% free, 171MB/177MB, paused 715us total 800.326ms
WaitForGcToComplete blocked Alloc on HeapTrim for 78.698ms
Starting a blocking GC Alloc
Starting a blocking GC Alloc
Starting a blocking GC Alloc
Alloc concurrent copying GC freed 1471248(40MB) AllocSpace objects, 11(26MB) LOS objects, 4% free, 120MB/126MB, paused 617us total 440.035ms
Waiting for a blocking GC Alloc
Background concurrent copying GC freed 212754(4MB) AllocSpace objects, 1(4MB) LOS objects, 3% free, 179MB/185MB, paused 1.906ms total 414.292ms
WaitForGcToComplete blocked Alloc on HeapTrim for 378.426ms
    Starting a blocking GC Alloc
Waiting for a blocking GC Alloc
Background concurrent copying GC freed 116(286KB) AllocSpace objects, 14(45MB) LOS objects, 3% free, 146MB/152MB, paused 759us total 705.920ms
WaitForGcToComplete blocked Alloc on HeapTrim for 631.676ms
    Starting a blocking GC Alloc
Waiting for a blocking GC Alloc
…
    Starting a blocking GC Alloc
Throwing OutOfMemoryError "Failed to allocate a 32 byte allocation with 16 free bytes and 16B until OOM, max allowed footprint 201326592, growth limit 201326592" (recursive case)
"Instr: android.support.test.runner.AndroidJUnitRunner" prio=5 tid=13 Runnable
      | group="main" sCount=0 dsCount=0 flags=2 obj=0x12c40a80 self=0x7377c9337400
      | sysTid=9630 nice=-8 cgrp=default sched=0/0 handle=0x7377b11934f0
      | state=R schedstat=( 17608058590 1326008400 7326 ) utm=1681 stm=79 core=1 HZ=100
      | stack=0x7377b1090000-0x7377b1092000 stackSize=1041KB
      | held mutexes= "mutator lock"(shared held)
        at libcore.util.NativeAllocationRegistry.registerNativeAllocation(NativeAllocationRegistry.java:129)
        at java.math.BigInt.makeValid(BigInt.java:48)
        at java.math.BigInt.putBigEndianTwosComplement(BigInt.java:179)
        at java.math.BigInteger.<init>(BigInteger.java:304)
        at sun.security.util.DerInputBuffer.getBigInteger(DerInputBuffer.java:170)
        at sun.security.util.DerValue.getBigInteger(DerValue.java:529)
        at sun.security.x509.SerialNumber.construct(SerialNumber.java:44)
        at sun.security.x509.SerialNumber.<init>(SerialNumber.java:86)
        at sun.security.x509.X509CRLEntryImpl.parse(X509CRLEntryImpl.java:460)
        at sun.security.x509.X509CRLEntryImpl.<init>(X509CRLEntryImpl.java:133)
        at sun.security.x509.X509CRLImpl.parse(X509CRLImpl.java:1161)
        at sun.security.x509.X509CRLImpl.<init>(X509CRLImpl.java:146)
        at sun.security.provider.X509Factory.intern(X509Factory.java:206)
        at sun.security.x509.X509CRLImpl.toImpl(X509CRLImpl.java:1235)
        at sun.security.provider.certpath.AlgorithmChecker.check(AlgorithmChecker.java:396)
        at sun.security.provider.certpath.DistributionPointFetcher.verifyCRL(DistributionPointFetcher.java:667)
        at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:209)
        at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:121)
        at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:552)
        at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:465)
        at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:394)
        at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:337)
        at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:125)
        at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:222)
        at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:140)
        at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79)
        at java.security.cert.CertPathValidator.validate(CertPathValidator.java:301)
        at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:703)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:539)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:560)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:605)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:495)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:418)
        at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:339)
        at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
        at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88)
        at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:208)
        at com.android.org.conscrypt.ConscryptFileDescriptorSocket.verifyCertificateChain(ConscryptFileDescriptorSocket.java:404)
        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native method)
        at com.android.org.conscrypt.NativeSsl.doHandshake(NativeSsl.java:375)
        at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:224)
        at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:318)
        at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:282)
        at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:167)
        at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257)
        at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
        at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
        at okhttp3.RealCall.execute(RealCall.java:77)
        at at.bitfire.davdroid.ClientTest.testIcloud(ClientTest.kt:24)
        at java.lang.reflect.Method.invoke(Native method)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.junit.runners.Suite.runChild(Suite.java:128)
        at org.junit.runners.Suite.runChild(Suite.java:27)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
        at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
        at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:384)
        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145)
Waiting for a blocking GC Alloc
Clamp target GC heap from 198MB to 192MB
    Alloc concurrent copying GC freed 0(0B) AllocSpace objects, 0(0B) LOS objects, 0% free, 192MB/192MB, paused 179us total 576.416ms
    Starting a blocking GC Alloc
Waiting for a blocking GC Alloc
Alloc concurrent copying GC freed 4321630(114MB) AllocSpace objects, 7(51MB) LOS objects, 19% free, 25MB/31MB, paused 147us total 245.441ms
WaitForGcToComplete blocked Alloc on HeapTrim for 807.852ms
    Starting a blocking GC Alloc
07-16 14:23:09.335 9513-9630/at.bitfire.cloudsync I/TestRunner: failed: testIcloud(at.bitfire.davdroid.ClientTest)
    ----- begin exception -----
    java.lang.OutOfMemoryError: OutOfMemoryError thrown while trying to throw OutOfMemoryError; no stack trace available
    ----- end exception -----
07-16 14:23:09.336 9513-9630/at.bitfire.cloudsync I/TestRunner: finished: testIcloud(at.bitfire.davdroid.ClientTest)
07-16 14:23:09.339 9513-9513/at.bitfire.cloudsync I/MonitoringInstr: Activities that are still in CREATED to STOPPED: 0
07-16 14:23:09.340 9513-9630/at.bitfire.cloudsync I/TestRunner: run finished: 1 tests, 1 failed, 0 ignored
07-16 14:23:09.494 9513-9630/at.bitfire.cloudsync I/MonitoringInstr: waitForActivitiesToComplete() took: 1ms
07-16 14:23:09.494 9513-9513/at.bitfire.cloudsync I/MonitoringInstr: Activities that are still in CREATED to STOPPED: 0

This happens with Android 8.0 and 9.0 (emulator from SDK), but not with Android 4.4 (haven't tested other versions yet).

The problem occurs with okhttp 3.10.0 and 3.11.0 (haven't tested other versions yet).

Everything is working for some other URLs I have tested, including www.icloud.com. It seems to be related to parsing the certificate. When using a custom trust manager (from https://gitlab.com/bitfireAT/cert4android), it works.

I don't know whether this is an okhttp problem (looks like an Android problem?), but I guess it's quite important to understand why a simple GET request causes the whole process to crash.

The questionable certificate seems to be:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            0e:5e:6b:72:54:37:4e:1d:9d:db:ca:97:64:cb:b7:4f
    Signature Algorithm: ecdsa-with-SHA256
        Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Extended Validation CA G3
        Validity
            Not Before: Jan 25 00:00:00 2018 GMT
            Not After : Jan 25 12:00:00 2020 GMT
        Subject: businessCategory = Private Organization, jurisdictionC = US, jurisdictionST = California, serialNumber = C0806592, C = US, ST = California, L = Cupertino, O = Apple Inc., OU = GNS Edge CDN, CN = images.apple.com
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:35:15:6a:1f:88:2c:f2:f6:55:1d:58:00:f3:fc:
                    0f:9f:cc:bc:58:a0:ec:f4:85:e8:c5:4f:83:03:86:
                    12:35:b8:c7:5a:47:9e:5f:24:9a:fa:a0:4c:8e:bf:
                    5f:7f:ce:01:ee:e3:91:29:f6:a3:80:27:54:f2:f0:
                    5b:ef:73:f8:ee
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Authority Key Identifier: 
                keyid:99:39:FF:5F:A4:B3:59:5F:81:C0:57:99:D1:A3:A4:47:AC:60:63:4D

            X509v3 Subject Key Identifier: 
                FB:A4:3B:3E:F5:75:BF:23:3A:C2:FA:D4:86:16:DA:74:22:8A:5B:59
            X509v3 Subject Alternative Name: 
                DNS:images.apple.com
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 CRL Distribution Points: 

                Full Name:
                  URI:http://crl3.digicert.com/evca-g3-group1.crl

                Full Name:
                  URI:http://crl4.digicert.com/evca-g3-group1.crl

            X509v3 Certificate Policies: 
                Policy: 2.16.840.1.114412.2.1
                  CPS: https://www.digicert.com/CPS
                Policy: 2.23.140.1.1

            Authority Information Access: 
                OCSP - URI:http://ocsp.digicert.com
                CA Issuers - URI:http://cacerts.digicert.com/DigiCertExtendedValidationCAG3.crt

            X509v3 Basic Constraints: 
                CA:FALSE
            CT Precertificate SCTs: 
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : A4:B9:09:90:B4:18:58:14:87:BB:13:A2:CC:67:70:0A:
                                3C:35:98:04:F9:1B:DF:B8:E3:77:CD:0E:C8:0D:DC:10
                    Timestamp : Jan 25 05:00:40.359 2018 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:46:02:21:00:F5:5D:0E:80:D0:27:06:98:35:CB:57:
                                A0:82:00:85:2F:56:88:CA:BE:01:25:D7:0C:A3:D9:00:
                                12:4D:70:71:D1:02:21:00:F2:F2:5A:16:70:A5:AB:16:
                                AE:01:D1:BD:C4:C7:6C:32:D6:97:FE:67:2D:EF:D4:22:
                                DD:C1:23:21:41:23:52:CA
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : 56:14:06:9A:2F:D7:C2:EC:D3:F5:E1:BD:44:B2:3E:C7:
                                46:76:B9:BC:99:11:5C:C0:EF:94:98:55:D6:89:D0:DD
                    Timestamp : Jan 25 05:00:40.557 2018 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:45:02:20:44:BF:1C:68:1B:70:24:59:DD:2F:3D:90:
                                8D:DE:76:01:D7:9C:B9:19:4F:E2:72:71:17:61:A0:0D:
                                0B:7C:19:D7:02:21:00:98:7C:8B:9F:9C:5F:01:7B:93:
                                52:24:FC:7C:A9:39:2E:F5:A9:68:C8:3F:45:A8:D1:F2:
                                9F:8A:C9:40:C3:65:1B
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : BB:D9:DF:BC:1F:8A:71:B5:93:94:23:97:AA:92:7B:47:
                                38:57:95:0A:AB:52:E8:1A:90:96:64:36:8E:1E:D1:85
                    Timestamp : Jan 25 05:00:40.567 2018 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:44:02:20:39:8E:86:EA:59:94:A4:CF:08:A4:AA:F4:
                                28:21:DD:FC:A6:64:8C:80:7A:56:24:BF:34:7A:FB:65:
                                EA:31:75:6E:02:20:67:C0:44:59:68:38:1D:D1:AA:84:
                                49:F7:36:86:8C:23:05:68:42:03:34:3A:88:5D:FF:DE:
                                E0:DB:B7:C4:77:89
    Signature Algorithm: ecdsa-with-SHA256
         30:66:02:31:00:cc:95:55:b4:3c:4d:c1:32:25:bd:36:5d:a3:
         40:69:e8:1f:66:5c:e7:ca:b4:d4:b3:00:ad:6d:2d:ca:f6:7a:
         7d:c1:6c:f5:79:a4:c1:87:e9:98:23:fb:35:35:6b:85:57:02:
         31:00:af:75:53:ec:4c:00:99:93:68:87:96:d9:d3:2e:36:c7:
         f0:f9:f8:69:71:93:99:76:83:e9:57:0e:5e:d5:16:ed:89:c9:
         dc:0b:b8:b5:48:31:e9:cb:2c:c7:a9:0b:9d:5e
-----BEGIN CERTIFICATE-----
MIIFzTCCBVKgAwIBAgIQDl5rclQ3Th2d28qXZMu3TzAKBggqhkjOPQQDAjBsMQsw
CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
ZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBFeHRlbmRlZCBWYWxpZGF0
aW9uIENBIEczMB4XDTE4MDEyNTAwMDAwMFoXDTIwMDEyNTEyMDAwMFowgeExHTAb
BgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVT
MRswGQYLKwYBBAGCNzwCAQITCkNhbGlmb3JuaWExETAPBgNVBAUTCEMwODA2NTky
MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTESMBAGA1UEBxMJQ3Vw
ZXJ0aW5vMRMwEQYDVQQKEwpBcHBsZSBJbmMuMRUwEwYDVQQLEwxHTlMgRWRnZSBD
RE4xGTAXBgNVBAMTEGltYWdlcy5hcHBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjO
PQMBBwNCAAQ1FWofiCzy9lUdWADz/A+fzLxYoOz0hejFT4MDhhI1uMdaR55fJJr6
oEyOv19/zgHu45Ep9qOAJ1Ty8Fvvc/juo4IDXjCCA1owHwYDVR0jBBgwFoAUmTn/
X6SzWV+BwFeZ0aOkR6xgY00wHQYDVR0OBBYEFPukOz71db8jOsL61IYW2nQiiltZ
MBsGA1UdEQQUMBKCEGltYWdlcy5hcHBsZS5jb20wDgYDVR0PAQH/BAQDAgeAMB0G
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBvBgNVHR8EaDBmMDGgL6Athito
dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vZXZjYS1nMy1ncm91cDEuY3JsMDGgL6At
hitodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vZXZjYS1nMy1ncm91cDEuY3JsMEsG
A1UdIAREMEIwNwYJYIZIAYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
LmRpZ2ljZXJ0LmNvbS9DUFMwBwYFZ4EMAQEwgYAGCCsGAQUFBwEBBHQwcjAkBggr
BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEoGCCsGAQUFBzAChj5o
dHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRFeHRlbmRlZFZhbGlk
YXRpb25DQUczLmNydDAJBgNVHRMEAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFq
AWgAdwCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWErsHYnAAAE
AwBIMEYCIQD1XQ6A0CcGmDXLV6CCAIUvVojKvgEl1wyj2QASTXBx0QIhAPLyWhZw
pasWrgHRvcTHbDLWl/5nLe/UIt3BIyFBI1LKAHYAVhQGmi/XwuzT9eG9RLI+x0Z2
ubyZEVzA75SYVdaJ0N0AAAFhK7B27QAABAMARzBFAiBEvxxoG3AkWd0vPZCN3nYB
15y5GU/icnEXYaANC3wZ1wIhAJh8i5+cXwF7k1Ik/HypOS71qWjIP0Wo0fKfislA
w2UbAHUAu9nfvB+KcbWTlCOXqpJ7RzhXlQqrUugakJZkNo4e0YUAAAFhK7B29wAA
BAMARjBEAiA5jobqWZSkzwikqvQoId38pmSMgHpWJL80evtl6jF1bgIgZ8BEWWg4
HdGqhEn3NoaMIwVoQgM0Oohd/97g27fEd4kwCgYIKoZIzj0EAwIDaQAwZgIxAMyV
VbQ8TcEyJb02XaNAaegfZlznyrTUswCtbS3K9np9wWz1eaTBh+mYI/s1NWuFVwIx
AK91U+xMAJmTaIeW2dMuNsfw+fhpcZOZdoPpVw5e1RbticncC7i1SDHpyyzHqQud
Xg==
-----END CERTIFICATE-----
@flooey
Copy link
Contributor

flooey commented Aug 3, 2018

That cert is a bit weird, because it doesn't actually match icloud.com (it's for images.apple.com). It looks like icloud.com returns that cert if SNI isn't provided, but OkHttp should always be enabling SNI. So it appears there are at least two problems here:

  • There are some set of circumstances that are causing SNI to not get enabled
  • Conscrypt is using a lot of memory trying to validate that certificate

I'll try to figure out what's going on with the latter and point the OkHttp folks at the former.

@rfc2822
Copy link
Author

rfc2822 commented Aug 3, 2018

I have to apologize. Maybe I got the cert from openssl when debugging and took the wrong one. You would have to see what cert okhttp uses directly.

@flooey
Copy link
Contributor

flooey commented Aug 6, 2018

Cool. Now that I've looked into this more, it looks like the icloud.com cert is pointing to a CRL that revokes around 10k certificates, and we're using a bunch of memory to parse all of those. That's kind of ridiculous on their part, but we should handle this better.

@rfc2822
Copy link
Author

rfc2822 commented Oct 16, 2018

Same test, similar (but not the same) exception again today:

191MB/192MB, paused 156us total 507.017ms
Throwing OutOfMemoryError "Failed to allocate a 32 byte allocation with 8 free bytes and 8B until OOM, max allowed footprint 201326592, growth limit 201326592" (recursive case)
WaitForGcToComplete blocked Alloc on HeapTrim for 4.697s
Starting a blocking GC Alloc
"Instr: android.support.test.runner.AndroidJUnitRunner" prio=5 tid=13 Runnable
  | group="main" sCount=0 dsCount=0 flags=0 obj=0x12c40a80 self=0x7363eaeef400
  | sysTid=12231 nice=-8 cgrp=default sched=0/0 handle=0x7363d31414f0
  | state=R schedstat=( 18991660555 689074809 5242 ) utm=1829 stm=70 core=1 HZ=100
  | stack=0x7363d303e000-0x7363d3040000 stackSize=1041KB
  | held mutexes= "mutator lock"(shared held)
    at sun.security.util.DerValue.init(DerValue.java:406)
    at sun.security.util.DerValue.<init>(DerValue.java:337)
    at sun.security.util.DerInputStream.getDerValue(DerInputStream.java:496)
    at sun.security.x509.X509CRLEntryImpl.parse(X509CRLEntryImpl.java:459)
    at sun.security.x509.X509CRLEntryImpl.<init>(X509CRLEntryImpl.java:133)
    at sun.security.x509.X509CRLImpl.parse(X509CRLImpl.java:1161)
    at sun.security.x509.X509CRLImpl.<init>(X509CRLImpl.java:146)
    at sun.security.provider.X509Factory.intern(X509Factory.java:206)
    at sun.security.x509.X509CRLImpl.toImpl(X509CRLImpl.java:1235)
    at sun.security.provider.certpath.AlgorithmChecker.check(AlgorithmChecker.java:396)
    at sun.security.provider.certpath.DistributionPointFetcher.verifyCRL(DistributionPointFetcher.java:667)
    at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:209)
    at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:121)
    at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:552)
    at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:465)
    at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:394)
    at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:337)
    at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:125)
    at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:222)
    at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:140)
    at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79)
    at java.security.cert.CertPathValidator.validate(CertPathValidator.java:301)
    at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:703)
    at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:539)
    at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:560)
    at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:605)
    at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:495)
    at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:418)
    at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:339)
    at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
    at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88)
    at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:208)
    at com.android.org.conscrypt.ConscryptFileDescriptorSocket.verifyCertificateChain(ConscryptFileDescriptorSocket.java:404)
    at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native method)
    at com.android.org.conscrypt.NativeSsl.doHandshake(NativeSsl.java:375)
    at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:224)
    at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:318)
    at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:282)
    at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:167)
    at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257)
    at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
    at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
    at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
    at okhttp3.RealCall.execute(RealCall.java:77)
    at at.bitfire.davdroid.OkhttpClientTest.testIcloud(OkhttpClientTest.kt:23)
    at java.lang.reflect.Method.invoke(Native method)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:27)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
    at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
    at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:384)
    at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145)
Waiting for a blocking GC Alloc
Alloc concurrent copying GC freed 4328837(115MB) AllocSpace objects, 7(51MB) LOS objects, 19% free, 25MB/31MB, paused 260us total 187.842ms
WaitForGcToComplete blocked Background on HeapTrim for 5.553s
WaitForGcToComplete blocked Alloc on HeapTrim for 186.978ms
Starting a blocking GC Alloc
2018-10-16 11:45:09.527 12212-12231/at.bitfire.cloudsync I/TestRunner: failed: testIcloud(at.bitfire.davdroid.OkhttpClientTest)
2018-10-16 11:45:09.527 12212-12231/at.bitfire.cloudsync I/TestRunner: ----- begin exception -----
2018-10-16 11:45:09.528 12212-12231/at.bitfire.cloudsync I/TestRunner: java.lang.OutOfMemoryError: OutOfMemoryError thrown while trying to throw OutOfMemoryError; no stack trace available
2018-10-16 11:45:09.528 12212-12231/at.bitfire.cloudsync I/TestRunner: ----- end exception -----
2018-10-16 11:45:09.528 12212-12231/at.bitfire.cloudsync I/TestRunner: finished: testIcloud(at.bitfire.davdroid.OkhttpClientTest)

@toby78
Copy link

toby78 commented Dec 11, 2018

Is this an issue of Android 8.0.0 which is fixed in 8.0.1 or later?

@orpolaczek
Copy link

Following up 2 years later - we're still seeing instances of this issue.

A few of our CDNs were using yet another certificate by DigiCert that was pointing to a 15MB CRL (http://crl4.digicert.com/ssca-sha2-g6.crl).

It took us almost 3 days to get a reply from DigiCert (even though we're a 'priority support' customer), and they've successfully pinned our account/did some other magic to point to a much smaller CRL (~300KB). We had to reissue all the certificates and update our endpoints, and once we did that it seems the crashes stopped :)

This happens mostly on low-RAM devices running Android 8.

I hope our experience will help others facing the same issue.

@EditCoder
Copy link

What caused this problem, I also encountered a similar problem

@tejas-ad
Copy link

We are also encountering this problem intermittently on some phones and pretty consistently on the other phones, especially if the date on the phone is advanced, leading to SSL errors. Here is the partial stack trace from one of the phones:
java.lang.OutOfMemoryError: Failed to allocate a 16 byte allocation with 7584 free bytes and 7584B until OOM, target footprint 268435456, growth limit 268435456; failed due to fragmentation (largest possible contiguous allocation 50331648 bytes)
at sun.security.util.DerValue.(DerValue.java:291)
at sun.security.util.DerInputStream.readVector(DerInputStream.java:469)
at sun.security.util.DerInputStream.getSequence(DerInputStream.java:334)
at sun.security.util.DerInputStream.getSequence(DerInputStream.java:348)
at sun.security.x509.X509CRLImpl.parse(X509CRLImpl.java:1156)
at sun.security.x509.X509CRLImpl.(X509CRLImpl.java:146)
at sun.security.provider.X509Factory.intern(X509Factory.java:206)
at sun.security.x509.X509CRLImpl.toImpl(X509CRLImpl.java:1235)
at sun.security.provider.certpath.AlgorithmChecker.check(AlgorithmChecker.java:396)
at sun.security.provider.certpath.DistributionPointFetcher.verifyCRL(DistributionPointFetcher.java:667)
at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:209)
at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:121)
at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:552)
at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:465)
at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:394)
at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:337)
at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:125)
at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:222)
at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:140)
at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79)
at java.security.cert.CertPathValidator.validate(CertPathValidator.java:301)
at android.sec.enterprise.certificate.DelegatingCertPathValidator.engineValidate(DelegatingCertPathValidator.java:63)
at java.security.cert.CertPathValidator.validate(CertPathValidator.java:301)
at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:731)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:557)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:578)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:623)
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:513)
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:432)
at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:360)
at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:89)
at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:224)
at com.android.org.conscrypt.ConscryptFileDescriptorSocket.verifyCertificateChain(ConscryptFileDescriptorSocket.java:430)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(NativeCrypto.java:-2)
at com.android.org.conscrypt.NativeSsl.doHandshake(NativeSsl.java:387)
at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:234)
at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:1471)
at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:1415)
at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:1359)
at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:221)
at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:144)
at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:106)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:400)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:333)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:483)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:135)
at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:90)
at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:30)

Phone and OS details:
Android: 10
Android Build: QP1A.190711.020
Manufacturer: samsung
Model: SM-G975F

Android: 9
Android Build: PPR1.180610.011
Manufacturer: samsung
Model: SM-G950U1

Additional Information:
We initially saw this for one of the Adobe calls and we were working with Adobe engineers on this. They confirmed that they are working with their internal teams to try and point to a CRL that is smaller in size (adobe/xamarin-acpcore#23 (comment)). That being said, we are also seeing this issue on non-Adobe endpoints and it would be great if there is a solution/workaround for this issue.

@prbprbprb
Copy link
Collaborator

It looks like the Android platform (sun.security.provider.X509Factory.intern()) maintains a cache of the last 750 certificates while parsing CRLs which is... suboptimal on low memory devices. Do you have a URL I can access which demonstrates the problem? If so I'll double check that and open an Android issue.

In parallel, I did not expect this code path in the trust manager to be doing online CRL checking - it explicitly disables it in favour of stapled OCSP. I wonder if this is a vendor change... the android.sec.enterprise.certificate.DelegatingCertPathValidator in the stack trace looks like a Samsung KNOX (Enterprise Device Management) hook as it's not an AOSP or Google thing.

Have you seen this on non-Samsung devices? Or on Android 11 or newer?

@tejas-ad
Copy link

@prbprbprb My apologies for the delay in responding. Here is the base part of the URL that we were facing problems with: https://assets.adobedtm.com/ (The CRL size is ~20MB)

Coming to the non-Samsung devices, we don't do a lot of work with non-Samsung devices, so we haven't seen this issue on them. I am pretty sure that this was seen on an Android 11 device too.
I also found a stack trace from an S7 running Android 8 that does not have the Samsung KNOX specific line in the stack trace. Here it is:
sun.security.util.DerInputStream.readVector DerInputStream.java:473
sun.security.util.DerInputStream.getSequence DerInputStream.java:333
sun.security.util.DerInputStream.getSequence DerInputStream.java:347
sun.security.x509.X509CRLImpl.parse X509CRLImpl.java:1160
sun.security.x509.X509CRLImpl. X509CRLImpl.java:146
sun.security.provider.X509Factory.intern X509Factory.java:206
sun.security.x509.X509CRLImpl.toImpl X509CRLImpl.java:1239
sun.security.provider.certpath.AlgorithmChecker.check AlgorithmChecker.java:396
sun.security.provider.certpath.DistributionPointFetcher.verifyCRL DistributionPointFetcher.java:667
sun.security.provider.certpath.DistributionPointFetcher.getCRLs DistributionPointFetcher.java:209
sun.security.provider.certpath.DistributionPointFetcher.getCRLs DistributionPointFetcher.java:121
sun.security.provider.certpath.RevocationChecker.checkCRLs RevocationChecker.java:552
sun.security.provider.certpath.RevocationChecker.checkCRLs RevocationChecker.java:465
sun.security.provider.certpath.RevocationChecker.check RevocationChecker.java:394
sun.security.provider.certpath.RevocationChecker.check RevocationChecker.java:337
sun.security.provider.certpath.PKIXMasterCertPathValidator.validate PKIXMasterCertPathValidator.java:125
sun.security.provider.certpath.PKIXCertPathValidator.validate PKIXCertPathValidator.java:225
sun.security.provider.certpath.PKIXCertPathValidator.validate PKIXCertPathValidator.java:143
sun.security.provider.certpath.PKIXCertPathValidator.engineValidate PKIXCertPathValidator.java:79
com.android.org.conscrypt.DelegatingCertPathValidator.engineValidate DelegatingCertPathValidator.java:44
java.security.cert.CertPathValidator.validate CertPathValidator.java:301
com.android.org.conscrypt.TrustManagerImpl.verifyChain TrustManagerImpl.java:784
com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive TrustManagerImpl.java:612
com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive TrustManagerImpl.java:633
com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive TrustManagerImpl.java:678
com.android.org.conscrypt.TrustManagerImpl.checkTrusted TrustManagerImpl.java:499
com.android.org.conscrypt.TrustManagerImpl.checkTrusted TrustManagerImpl.java:422
com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer TrustManagerImpl.java:343
android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted NetworkSecurityTrustManager.java:94
android.security.net.config.RootTrustManager.checkServerTrusted RootTrustManager.java:88
com.android.org.conscrypt.Platform.checkServerTrusted Platform.java:203
com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain OpenSSLSocketImpl.java:607
com.android.org.conscrypt.NativeCrypto.SSL_do_handshake NativeCrypto.java
com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake OpenSSLSocketImpl.java:357
com.android.okhttp.internal.io.RealConnection.connectTls RealConnection.java:1477
com.android.okhttp.internal.io.RealConnection.connectSocket RealConnection.java:1423
com.android.okhttp.internal.io.RealConnection.connect RealConnection.java:1367
com.android.okhttp.internal.http.StreamAllocation.findConnection StreamAllocation.java:219
com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection StreamAllocation.java:142
com.android.okhttp.internal.http.StreamAllocation.newStream StreamAllocation.java:104
com.android.okhttp.internal.http.HttpEngine.connect HttpEngine.java:410
com.android.okhttp.internal.http.HttpEngine.sendRequest HttpEngine.java:343
com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute HttpURLConnectionImpl.java:489
com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect HttpURLConnectionImpl.java:131
com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect DelegatingHttpsURLConnection.java:89
com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect

Hope this information is sufficient to continue the investigation.

@shashachu
Copy link

At Pinterest we're seeing this occasionally spike. We are also seeing it on Android 11+ devices as well as non-Samsung devices.

Sample stack trace:

java.lang.OutOfMemoryError: Failed to allocate a 50531696 byte allocation with 3200416 free bytes and 3125KB until OOM, target footprint 268435456, growth limit 268435456
at java.util.Arrays.copyOf(Arrays.java:3161)
at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118)
at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153)
at java.io.OutputStream.write(OutputStream.java:75)
at sun.security.util.DerValue.encode(DerValue.java:425)
at sun.security.util.DerValue.toByteArray(DerValue.java:861)
at sun.security.x509.X509CRLImpl.parse(X509CRLImpl.java:1094)
at sun.security.x509.X509CRLImpl.(X509CRLImpl.java:146)
at sun.security.provider.X509Factory.intern(X509Factory.java:206)
at sun.security.x509.X509CRLImpl.toImpl(X509CRLImpl.java:1235)
at sun.security.provider.certpath.DistributionPointFetcher.verifyCRL(DistributionPointFetcher.java:331)
at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:209)
at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:121)
at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:552)
at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:465)
at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:394)
at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:337)
at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:125)
at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:222)
at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:140)
at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79)
at java.security.cert.CertPathValidator.validate(CertPathValidator.java:301)
at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:720)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:554)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:575)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:620)
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:510)
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:428)
at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:356)
at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:90)
at com.android.org.conscrypt.ConscryptEngineSocket$2.checkServerTrusted(ConscryptEngineSocket.java:161)
at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:250)
at com.android.org.conscrypt.ConscryptEngine.verifyCertificateChain(ConscryptEngine.java:1644)
at com.android.org.conscrypt.NativeCrypto.ENGINE_SSL_read_direct(NativeCrypto.java:-2)
at com.android.org.conscrypt.NativeSsl.readDirectByteBuffer(NativeSsl.java:568)
at com.android.org.conscrypt.ConscryptEngine.readPlaintextDataDirect(ConscryptEngine.java:1095)
at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1079)
at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:876)
at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:747)
at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:712)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:849)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.access$100(ConscryptEngineSocket.java:722)
at com.android.org.conscrypt.ConscryptEngineSocket.doHandshake(ConscryptEngineSocket.java:238)
at com.android.org.conscrypt.ConscryptEngineSocket.startHandshake(ConscryptEngineSocket.java:217)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection:379)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection:337)
at okhttp3.internal.connection.RealConnection.connect(RealConnection:209)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder:226)
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder:106)
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder:74)
at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall:255)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor:32)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain:109)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor:95)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain:109)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor:83)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain:109)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor:76)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain:109)
at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall:201)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall:517)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)

@himanshumistri
Copy link

I wonder if switch to any older release of okhttp3.
I am facing a Similar issue when the device time is set to a Future date.

in my case URL is https://login.microsoftonline.com

I tried the following version.

implementation 'com.squareup.okhttp3:okhttp:4.2.2'
  implementation 'com.squareup.okhttp3:logging-interceptor:4.0.0-alpha02'

and following version as well.

implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3"))
   // define any required OkHttp artifacts without version
   implementation("com.squareup.okhttp3:okhttp")
   implementation("com.squareup.okhttp3:logging-interceptor")
2022-03-30 21:29:15.964 16911-17001/com.app.app E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
    Process: com.app.app, PID: 16911
    java.lang.OutOfMemoryError: Failed to allocate a 48 byte allocation with 16 free bytes and 16B until OOM, max allowed footprint 268435456, growth limit 268435456
        at sun.security.util.DerInputBuffer.getBigInteger(DerInputBuffer.java:170)
        at sun.security.util.DerValue.getBigInteger(DerValue.java:529)
        at sun.security.x509.SerialNumber.construct(SerialNumber.java:44)
        at sun.security.x509.SerialNumber.<init>(SerialNumber.java:86)
        at sun.security.x509.X509CRLEntryImpl.parse(X509CRLEntryImpl.java:460)
        at sun.security.x509.X509CRLEntryImpl.<init>(X509CRLEntryImpl.java:133)
        at sun.security.x509.X509CRLImpl.parse(X509CRLImpl.java:1161)
        at sun.security.x509.X509CRLImpl.<init>(X509CRLImpl.java:146)
        at sun.security.provider.X509Factory.intern(X509Factory.java:206)
        at sun.security.x509.X509CRLImpl.toImpl(X509CRLImpl.java:1235)
        at sun.security.provider.certpath.DistributionPointFetcher.verifyCRL(DistributionPointFetcher.java:331)
        at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:209)
        at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:121)
        at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:552)
        at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:465)
        at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:394)
        at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:337)
        at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:125)
        at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:222)
        at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:140)
        at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79)
        at java.security.cert.CertPathValidator.validate(CertPathValidator.java:301)
        at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:703)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:539)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:560)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:605)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:495)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:418)
        at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:339)
        at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
        at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88)
        at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:197)
        at com.android.org.conscrypt.ConscryptFileDescriptorSocket.verifyCertificateChain(ConscryptFileDescriptorSocket.java:399)
        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
        at com.android.org.conscrypt.SslWrapper.doHandshake(SslWrapper.java:374)
        at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:217)
        at okhttp3.internal.connection.RealConnection.connectTls(Unknown Source:72)
        at okhttp3.internal.connection.RealConnection.establishProtocol(Unknown Source:52)
        at okhttp3.internal.connection.RealConnection.connect(Unknown Source:196)
        at okhttp3.internal.connection.ExchangeFinder.findConnection(Unknown Source:257)
        at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(Unknown Source:0)
        at okhttp3.internal.connection.ExchangeFinder.find(Unknown Source:47)
        at okhttp3.internal.connection.RealCall.initExchange$okhttp(Unknown Source:31)
2022-03-30 21:29:15.964 16911-17001/com.app.app E/AndroidRuntime:     at okhttp3.internal.connection.ConnectInterceptor.intercept(Unknown Source:11)
        at okhttp3.internal.http.RealInterceptorChain.proceed(Unknown Source:166)
        at okhttp3.internal.cache.CacheInterceptor.intercept(Unknown Source:191)
        at okhttp3.internal.http.RealInterceptorChain.proceed(Unknown Source:166)
        at okhttp3.internal.http.BridgeInterceptor.intercept(Unknown Source:167)
        at okhttp3.internal.http.RealInterceptorChain.proceed(Unknown Source:166)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(Unknown Source:34)
        at okhttp3.internal.http.RealInterceptorChain.proceed(Unknown Source:166)
        at okhttp3.logging.HttpLoggingInterceptor.intercept(Unknown Source:492)
        at okhttp3.internal.http.RealInterceptorChain.proceed(Unknown Source:166)
        at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(Unknown Source:113)
        at okhttp3.internal.connection.RealCall$AsyncCall.run(Unknown Source:51)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)

More detail is here

SO Link

I think, If i sync device time and then call API, it's seem to be working and not creating issue. any one else also have such experience?

@prbprbprb
Copy link
Collaborator

I think the issue here is all Conscrypt and Android, so switching okhttp versions probably won't help.

There seem to be two things going on:

  1. The Sun X509 classes are pulling a CRL when I don't think they should be (see above) which will cause massive latency and
  2. They are also caching a large number of certificates in RAM which is going to be an issue on low memory devices.

If you could flesh out your SO code into a working repro for me, that would help a lot with figuring out (1) and maybe preventing it. That change can probably go into an Android Mainline update of Conscrypt which will help devices running Android 11+.

The RAM-eating cache is in Android platform code outside of Conscrypt. It's also fixable (which I'll try and do), but needs some more analysis to tune the cache sizes - I'm not sure we'd want to remove it altogether. Unfortunately there's no feasible way to get such a fix to older devices where it would do the most good. The Android runtime is a Mainline module in Android 12+ so we can get it there at least.

@yschimke
Copy link
Contributor

Question on stackoverflow if you can workaround this.

I suspect something like

    val clientCertificates = HandshakeCertificates.Builder()
        .addPlatformTrustedCertificates()
        .addInsecureHost("badhost.com")
        .build()

Might work.

https://github.com/square/okhttp/blob/3ad1912f783e108b3d0ad2c4a5b1b89b827e4db9/okhttp/src/jvmTest/java/okhttp3/InsecureForHostTest.kt#L41-L48

@yschimke
Copy link
Contributor

yschimke commented Mar 28, 2022

I had a play around with this to confirm the issue. Seeing 30MB certificates for login.microsoftonline.com cashapp/certifikit#104

Looking at OneSignal/OneSignal-Android-SDK#1517, it appears that HttpUrlConnection is used by URICertStore.

        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:248)
        at sun.security.provider.certpath.URICertStore.engineGetCRLs(URICertStore.java:396)

So a potential workaround is to intercept these requests by overriding it.

    URL.setURLStreamHandlerFactory(new ObsoleteUrlFactory(okHttpClient));

https://gist.github.com/swankjesse/dd91c0a8854e1559b00f5fc9c7bfae70

We can't ship this in OkHttp even if it fixes things, because we aren't the right place to do Security policy changes, but maybe the play provider could workaround it? I suspect it might have a measurable impact on a bunch of android apps that are hitting this without realising it. It seems like a really common problem.

@prbprbprb three questions

  1. Do we know on which versions of Android this is a problem? The Conscrypt code seems to disable it
    params.setRevocationEnabled(false);
  2. Is it safe to ignore CRLs in 2022, my understanding is yes, this is not how they get decomissioned anymore.
  3. Is the play store provider (ProviderInstaller) susceptible to this? I assume yes, if setRevocationEnabled is called and it happens anyway.

@yschimke
Copy link
Contributor

I can't reproduce the problem on Android 9 emulator. I think that's a good thing. My test is using URL.setURLStreamHandlerFactory and hitting the hostnames listed above.

So I suspect either fixed in those new emulator images, or it's actually constrained to only the samsung devices that @prbprbprb mentioned.

Any ideas how to reproduce with an emulator? or some particular device?

@himanshumistri
Copy link

HI @yschimke @prbprbprb

Git Repo link

Here is Repo, i pushed to test the API and I observe the memory usage gets increases when i start app after killing it from the recent list in android and then only lunch app after disabling of Automatic date & time and timezone and set date as 10-15 day ahead of the current date.

Steps:-

  1. Kill the app.
  2. Disable Automatic date & time and timezone on android Emulator of API 27, OS 8.1.0,x86_64, Set date of the device ahead of the current date, 10-15 days ahead.
  3. Start the app

For now, I have resolved the issue by forcing the auto time sync as we are using the app as Kiosk mode with custom android 8.1.

@yschimke
Copy link
Contributor

yschimke commented Mar 30, 2022

@himanshumistri Thanks, that was it. Failing on Android 9 emulator.

So it confirms it is not solely a Samsung issue.

HTTP Connections may not work anyway because of time but I can at least reproduce the CRL request.

[0 ms] callStart: Request{method=GET, url=https://icloud.com/robots.txt}
[3 ms] proxySelectStart: https://icloud.com/
[4 ms] proxySelectEnd: [DIRECT]
[4 ms] dnsStart: icloud.com
[70 ms] dnsEnd: [icloud.com/17.253.144.10]
[71 ms] connectStart: icloud.com/17.253.144.10:443 DIRECT
[99 ms] secureConnectStart
[0 ms] callStart: Request{method=GET, url=http://crl.apple.com/apsecc12g1.crl, headers=[User-Agent:Dalvik/2.1.0 (Linux; U; Android 9; Android SDK built for arm64 Build/PSR1.210301.009.B1)]}
[0 ms] proxySelectStart: http://crl.apple.com/
[0 ms] proxySelectEnd: [DIRECT]
[0 ms] dnsStart: crl.apple.com
[56 ms] dnsEnd: [crl.apple.com/17.253.37.201]
[56 ms] connectStart: crl.apple.com/17.253.37.201:80 DIRECT
[81 ms] connectEnd: http/1.1
[81 ms] connectionAcquired: Connection{crl.apple.com:80, proxy=DIRECT hostAddress=crl.apple.com/17.253.37.201:80 cipherSuite=none protocol=http/1.1}
[82 ms] requestHeadersStart
[82 ms] requestHeadersEnd
[127 ms] responseHeadersStart
[127 ms] responseHeadersEnd: Response{protocol=http/1.1, code=200, message=OK, url=http://crl.apple.com/apsecc12g1.crl}
[128 ms] responseBodyStart
[128 ms] responseBodyEnd: byteCount=1485
[128 ms] connectionReleased
[128 ms] callEnd
[284 ms] connectFailed: null javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
[285 ms] callFailed: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

This does give another option for OkHttp users.

@yschimke
Copy link
Contributor

 java.lang.Exception: trace
     at okhttp.android.test.ObsoleteUrlFactory.open(ObsoleteUrlFactory.java:153)
     at okhttp.android.test.ObsoleteUrlFactory.open(ObsoleteUrlFactory.java:149)
     at okhttp.android.test.ObsoleteUrlFactory$1.openConnection(ObsoleteUrlFactory.java:180)
     at java.net.URL.openConnection(URL.java:1006)
     at sun.security.provider.certpath.URICertStore.engineGetCRLs(URICertStore.java:390)
     at java.security.cert.CertStore.getCRLs(CertStore.java:190)
     at sun.security.provider.certpath.DistributionPointFetcher.getCRL(DistributionPointFetcher.java:245)
     at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:189)
     at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:121)
     at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:552)
     at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:465)
     at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:394)
     at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:337)
     at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:125)
     at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:222)
     at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:140)
     at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79)
     at java.security.cert.CertPathValidator.validate(CertPathValidator.java:301)
     at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:703)
     at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:539)
     at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:560)
     at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:605)
     at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:495)
     at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:418)
     at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:339)
     at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
     at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88)
     at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:208)
     at com.android.org.conscrypt.ConscryptFileDescriptorSocket.verifyCertificateChain(ConscryptFileDescriptorSocket.java:404)
     at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
     at com.android.org.conscrypt.NativeSsl.doHandshake(NativeSsl.java:375)
     at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:224)
     at okhttp3.internal.connection.ConnectPlan.connectTls(ConnectPlan.kt:315)
     at okhttp3.internal.connection.ConnectPlan.connectTlsEtc(ConnectPlan.kt:180)
     at okhttp3.internal.connection.FastFallbackExchangeFinder.find(FastFallbackExchangeFinder.kt:87)
     at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:267)
     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:96)
     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:84)
     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:64)
     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
     at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:205)
     at okhttp3.internal.connection.RealCall.execute(RealCall.kt:158)
     at okhttp.android.test.CrlTest.testRequest(CrlTest.kt:48)
     at java.lang.reflect.Method.invoke(Native Method)
     at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
     at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
     at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
     at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
     at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
     at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
     at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor$$ExternalSyntheticLambda3.apply(Unknown Source:0)
     at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall$-CC.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
     at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall$$ExternalSyntheticLambda0.apply(Unknown Source:2)
     at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
     at org.junit.jupiter.engine.execution.ExecutableInvoker$$ExternalSyntheticLambda3.apply(Unknown Source:6)
     at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
     at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
     at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
     at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
     at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
     at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
     at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7$org-junit-jupiter-engine-descriptor-TestMethodTestDescriptor(TestMethodTestDescriptor.java:214)
     at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor$$ExternalSyntheticLambda6.execute(Unknown Source:6)
     at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
     at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
     at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
     at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6$org-junit-platform-engine-support-hierarchical-NodeTestTask(NodeTestTask.java:151)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask$$ExternalSyntheticLambda2.execute(Unknown Source:2)
     at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8$org-junit-platform-engine-support-hierarchical-NodeTestTask(NodeTestTask.java:141)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask$$ExternalSyntheticLambda11.invoke(Unknown Source:2)
     at org.junit.platform.engine.support.hierarchical.Node$-CC.$default$around(Node.java:137)
     at org.junit.jupiter.engine.descriptor.JupiterTestDescriptor.around(Unknown Source:0)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9$org-junit-platform-engine-support-hierarchical-NodeTestTask(NodeTestTask.java:139)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask$$ExternalSyntheticLambda4.execute(Unknown Source:2)
     at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
     at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService$$ExternalSyntheticLambda0.accept(Unknown Source:2)
     at java.util.ArrayList.forEach(ArrayList.java:1262)
     at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6$org-junit-platform-engine-support-hierarchical-NodeTestTask(NodeTestTask.java:155)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask$$ExternalSyntheticLambda2.execute(Unknown Source:2)
     at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8$org-junit-platform-engine-support-hierarchical-NodeTestTask(NodeTestTask.java:141)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask$$ExternalSyntheticLambda11.invoke(Unknown Source:2)
     at org.junit.platform.engine.support.hierarchical.Node$-CC.$default$around(Node.java:137)
     at org.junit.jupiter.engine.descriptor.JupiterTestDescriptor.around(Unknown Source:0)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9$org-junit-platform-engine-support-hierarchical-NodeTestTask(NodeTestTask.java:139)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask$$ExternalSyntheticLambda4.execute(Unknown Source:2)
     at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
     at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService$$ExternalSyntheticLambda0.accept(Unknown Source:2)
     at java.util.ArrayList.forEach(ArrayList.java:1262)
     at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6$org-junit-platform-engine-support-hierarchical-NodeTestTask(NodeTestTask.java:155)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask$$ExternalSyntheticLambda2.execute(Unknown Source:2)
     at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8$org-junit-platform-engine-support-hierarchical-NodeTestTask(NodeTestTask.java:141)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask$$ExternalSyntheticLambda11.invoke(Unknown Source:2)
     at org.junit.platform.engine.support.hierarchical.Node$-CC.$default$around(Node.java:137)
     at org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor.around(Unknown Source:0)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9$org-junit-platform-engine-support-hierarchical-NodeTestTask(NodeTestTask.java:139)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask$$ExternalSyntheticLambda4.execute(Unknown Source:2)
     at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
     at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
     at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
     at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
     at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
     at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
     at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
     at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0$org-junit-platform-launcher-core-EngineExecutionOrchestrator(EngineExecutionOrchestrator.java:54)
     at org.junit.platform.launcher.core.EngineExecutionOrchestrator$$ExternalSyntheticLambda1.accept(Unknown Source:8)
     at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
     at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
     at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
     at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:95)
     at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:91)
     at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:60)
     at de.mannodermaus.junit5.internal.runners.AndroidJUnit5.run(AndroidJUnit5.kt:44)
     at org.junit.runners.Suite.runChild(Suite.java:128)
     at org.junit.runners.Suite.runChild(Suite.java:27)
     at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
     at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
     at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
     at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
     at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
     at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
     at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
     at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:444)
2022-04-07 07:00:18.809 4859-4883/okhttp.android.test.test W/System.err:     at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145)

@prbprbprb
Copy link
Collaborator

Apologies, I missed the @himanshumistri 's repro link above, I'll have a look at that. The fact that it's reproducible on the emulator pretty much rules out any OEM changes being involved.

I also did some archeology and the code which supposedly disables CRL checking was submitted in 2016, and shipped in Android 8.0, and it's been largely unchanged since.

@yschimke
Copy link
Contributor

If you want to repro with a URLHandler you can tweak, this commit to a branch will be useful yschimke/okhttp@e73c446

@prbprbprb
Copy link
Collaborator

Understanding this a bit better now. Doesn't reproduce on 8.0, but on 8.1 it does download the CRL.

I believe the trigger is whether the OCSP response stapled to the cert is valid which is a window of about 5 days into the future). On 8.0 setting the date a few days in the future has no effect, but setting it further causes a handshake failure with Response is unreliable: its validity interval is out-of-date. On 8.1, I get the same exception (no OOM) but see lots of large allocs as it downloads the CRL and I can catch it in URICertStore.engineGetCRLs() with a breakpoint.

I suspect the bug is that the "mode" for the revocation status checker is set to PREFER_OCSP and not ONLY_OCSP. Further work to do to figure out which Android versions are affected.

Mitigation is going to be tricky if not impossible as 8.1 is outside its support window.

@himanshumistri
Copy link

Hi @prbprbprb @yschimke
Since we have control over our custom android 8.1 OS, Do you have a quick snippet that i can apply to the AOSP tree to avoid this into android 8.1? If it's safe to apply.

@yschimke
Copy link
Contributor

@prbprbprb
Copy link
Collaborator

I need to double check my working - I just reproduced it on on 8.0, so maybe I wasn't careful enough about killing the process between runs... And FWIW it reproduces with a simple URL connection, as you'd expect.

Worse, it sort of reproduces on Android 10, but doesn't cause memory issues because the CRL fetch gets suppressed for other reasons:

Caused by: java.security.cert.CertPathValidatorException: Response is unreliable: its validity interval is out-of-date
 	at sun.security.provider.certpath.OCSPResponse.verify(OCSPResponse.java:619)
 	at sun.security.provider.certpath.RevocationChecker.checkOCSP(RevocationChecker.java:709)
 	at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:363)
	at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:337)
 	at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:125)
 	... 46 more
 	Suppressed: java.security.cert.CertPathValidatorException: Unable to determine revocation status due to network error
 		at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:562)
		at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:465)
 		at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:394)
 		... 48 more
 	Caused by: sun.security.provider.certpath.PKIX$CertStoreTypeException: java.io.IOException: Cleartext HTTP traffic to crl3.digicert.com not permitted
		at sun.security.provider.certpath.URICertStore.engineGetCRLs(URICertStore.java:430)
		at java.security.cert.CertStore.getCRLs(CertStore.java:190)
 		at sun.security.provider.certpath.DistributionPointFetcher.getCRL(DistributionPointFetcher.java:245)
 		at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:189)
 		at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:121)
 		at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:552)
 		... 50 more

So I suspect (but have yet to confirm) that the logic is "wrong" on all current Android versions it just doesn't affect more recent versions because the CRL fetch fails for other reasons.

Since we have control over our custom android 8.1 OS, Do you have a quick snippet that i can apply

This is where the CRL download gets triggered. eSoftFail is always false in this case when the OCSP check fails, so I'm pretty sure you can safely change lines 381-383 to simply throw e. I.e. never failover from OCSP revocation checking to CRL revocation checking if the OCSP was a hard fail.

Obviously that's a bit of a hack, the correct fix is to ensure the RevocationChecker gets created with mode ONLY_OCSP and I'll work on that - next week though as I can't build Android 8 from source right now due to an office move this weekend

If you're working with memory constrained devices, you might also want to tune these values. E.g. maybe 10 for the cert cache and less for the CRL cache and 1M for the max size. That's totally untested though!

It sounds like you're an Android OEM? If you're registered on partner.android.com then please also raise a bug there, as it makes it easier for me to justify spending time on this.

@prbprbprb
Copy link
Collaborator

prbprbprb commented Apr 17, 2022

Soooooo..... It's actually a Conscrypt bug, I believe.

The PKIXRevocationChecker which is doing the CRL download is the one explicitly created by Conscrypt's TrustManagerImpl for checking the OCSP status of the leaf certificate. Because it is created with the option ONLY_END_ENTITY it will only be used for the leaf cert (correct) but without the NO_FALLBACK option as well, it will initialise into mode PREFER_OCSP rather than OCSP_ONLY and will try to download a CRL if the OCSP checking fails (incorrect). This code is unchanged between Android 8.0 and HEAD.

The emulator doesn't include Conscrypt source for 8.0/8.1 (dunno why), but with breakpoints in the Sun code I verified that (1) the previous paragraph is correct and (2) forcing the PKIXRevocationChecker options to include NO_FALLBACK forces the revocation checker into the correct mode and no CRL download occurs.

PR forthcoming which will fix the platform Conscrypt for R, S and T (and some Q) devices and I'll get it into the next release of the Maven libraries (due Real Soon Now!).

However note that whilst this stops the latency and memory pressure of a CRL download, the TLS handshake will still fail as the OCSP data being outside of its trusted time window is considered a hard failure.

prbprbprb added a commit to prbprbprb/conscrypt that referenced this issue Apr 17, 2022
Fixes google#520.

If stapled OCSP is present, TrustmanagerImpl.setOcspResponses()
adds a PKIXRevocationChecker to the list in the current
PKIXParameters to check it, with option END_ENTITY_ONLY set to
ensure only the root CA is checked.

However unless the NO_FALLBACK option is also set then if the
OCSP check fails (e.g. because the date on the device is wrong)
then the Sun PKIXRevocationChecker will fall back to downloading
a CRL and checking that.  On Android 8.0/8.1 this causes large
latency and possible OOM.  On later Androids, the CRL download
fails if the CRL distribution URL is plain HTTP, avoiding the
issue but potentially causing confusing errors.

I don't *yet* have a regression test for this as it turns
out we don't have _any_ tests for the OCSP path
prbprbprb added a commit to prbprbprb/conscrypt that referenced this issue Apr 17, 2022
Fixes google#520.

If stapled OCSP is present, TrustmanagerImpl.setOcspResponses()
adds a PKIXRevocationChecker to the list in the current
PKIXParameters to check it, with option END_ENTITY_ONLY set to
ensure only the root CA is checked.

However unless the NO_FALLBACK option is also set then if the
OCSP check fails (e.g. because the date on the device is wrong)
then the Sun PKIXRevocationChecker will fall back to downloading
a CRL and checking that.  On Android 8.0/8.1 this causes large
latency and possible OOM.  On later Androids, the CRL download
fails if the CRL distribution URL is plain HTTP, avoiding the
issue but potentially causing confusing errors.

I don't *yet* have a regression test for this as it turns
out we don't have _any_ tests for the OCSP path
prbprbprb added a commit to prbprbprb/conscrypt that referenced this issue Apr 17, 2022
Fixes google#520.

If stapled OCSP is present, TrustmanagerImpl.setOcspResponses()
adds a PKIXRevocationChecker to the list in the current
PKIXParameters to check it, with option END_ENTITY_ONLY set to
ensure only the root CA is checked.

However unless the NO_FALLBACK option is also set then if the
OCSP check fails (e.g. because the date on the device is wrong)
then the Sun PKIXRevocationChecker will fall back to downloading
a CRL and checking that.  On Android 8.0/8.1 this causes large
latency and possible OOM.  On later Androids, the CRL download
fails if the CRL distribution URL is plain HTTP, avoiding the
issue but potentially causing confusing errors.

I don't *yet* have a regression test for this as it turns
out we don't have _any_ tests for the OCSP path, but confirmed
by single stepping that adding NO_FALLBACK prevents CRL download
when the OCSP data is rejected.
prbprbprb added a commit to prbprbprb/conscrypt that referenced this issue Apr 17, 2022
Fixes google#520.

If stapled OCSP is present, TrustmanagerImpl.setOcspResponses()
adds a PKIXRevocationChecker to the list in the current
PKIXParameters to check it, with option END_ENTITY_ONLY set to
ensure only the root CA is checked.

However unless the NO_FALLBACK option is also set then if the
OCSP check fails (e.g. because the date on the device is wrong)
then the Sun PKIXRevocationChecker will fall back to downloading
a CRL and checking that.  On Android 8.0/8.1 this causes large
latency and possible OOM.  On later Androids, the CRL download
fails if the CRL distribution URL is plain HTTP, avoiding the
issue but potentially causing confusing errors.

I don't *yet* have a regression test for this as it turns
out we don't have _any_ tests for the OCSP path, but confirmed
by single stepping that adding NO_FALLBACK prevents CRL download
when the OCSP data is rejected.
prbprbprb added a commit to prbprbprb/conscrypt that referenced this issue Apr 18, 2022
Fixes google#520.

If stapled OCSP is present, TrustmanagerImpl.setOcspResponses()
adds a PKIXRevocationChecker to the list in the current
PKIXParameters to check it, with option END_ENTITY_ONLY set to
ensure only the leaf certificate is checked.

However unless the NO_FALLBACK option is also set then if the
OCSP check fails (e.g. because the date on the device is wrong)
then the Sun PKIXRevocationChecker will fall back to downloading
a CRL and checking that.  On Android 8.0/8.1 this causes large
latency and possible OOM.  On later Androids, the CRL download
fails if the CRL distribution URL is plain HTTP, avoiding the
issue but potentially causing confusing errors.

I don't *yet* have a regression test for this as it turns
out we don't have _any_ tests for the OCSP path, but confirmed
by single stepping that adding NO_FALLBACK prevents CRL download
when the OCSP data is rejected.
@shashachu
Copy link

@prbprbprb - just to confirm - will your fixes also fix the OOM in #520 (comment)? And would this fix would have to come via an OS update or can OkHttp take a fix?

@yschimke
Copy link
Contributor

@prbprbprb please correct me if I'm wrong.

My understanding is that it's unlikely to get out to Android 8 and 9 via system updates, even if it lands in the source for them. And it hasn't landed yet #1066

Do mainline updates mean this gets deployed to Android 10 and onwards? https://source.android.com/devices/architecture/modular-system https://www.xda-developers.com/android-project-mainline-modules-explanation/

There is no fix possible in OkHttp.

I assume you could still do one of the following:

a) Use Play provider for Conscrypt?
b) Ship unbundled conscrypt in your app.
c) Work around with URL.setURLStreamHandlerFactory

prbprbprb added a commit that referenced this issue Oct 18, 2022
…ad. (#1066)

Fixes #520.

If stapled OCSP is present, TrustmanagerImpl.setOcspResponses()
adds a PKIXRevocationChecker to the list in the current
PKIXParameters to check it, with option END_ENTITY_ONLY set to
ensure only the leaf certificate is checked.

However unless the NO_FALLBACK option is also set then if the
OCSP check fails (e.g. because the date on the device is wrong)
then the Sun PKIXRevocationChecker will fall back to downloading
a CRL and checking that.  On Android 8.0/8.1 this causes large
latency and possible OOM.  On later Androids, the CRL download
fails if the CRL distribution URL is plain HTTP, avoiding the
issue but potentially causing confusing errors.

I don't *yet* have a regression test for this as it turns
out we don't have _any_ tests for the OCSP path, but confirmed
by single stepping that adding NO_FALLBACK prevents CRL download
when the OCSP data is rejected.
prbprbprb added a commit to prbprbprb/conscrypt that referenced this issue Jan 2, 2023
…ad. (google#1066)

Fixes google#520.

If stapled OCSP is present, TrustmanagerImpl.setOcspResponses()
adds a PKIXRevocationChecker to the list in the current
PKIXParameters to check it, with option END_ENTITY_ONLY set to
ensure only the leaf certificate is checked.

However unless the NO_FALLBACK option is also set then if the
OCSP check fails (e.g. because the date on the device is wrong)
then the Sun PKIXRevocationChecker will fall back to downloading
a CRL and checking that.  On Android 8.0/8.1 this causes large
latency and possible OOM.  On later Androids, the CRL download
fails if the CRL distribution URL is plain HTTP, avoiding the
issue but potentially causing confusing errors.

I don't *yet* have a regression test for this as it turns
out we don't have _any_ tests for the OCSP path, but confirmed
by single stepping that adding NO_FALLBACK prevents CRL download
when the OCSP data is rejected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants