Closed r3ckd closed 5 years ago
Interesting comments here: https://stackoverflow.com/questions/5625642/crl-and-ocsp-behavior-of-ios-security-framework
"To sum it up, there are several things to keep in mind for OCSP implementation on iOS:
OCSP policy cannot be configured at this moment
it works for the EV certificates only
high-level stuff, such as NSURLConnection or UIWebView use TLS security policy, which uses OCSP
SecTrustEvaluate is a blocking network operation
it works the "best attempt" - if OCSP server cannot be contacted, the trust evaluation will not fail
"
Seems like this only happens with "EV" certificates
interestingly enough, there's a block here that i believe is used for determining trust/validity and EV status https://github.com/OnionBrowser/OnionBrowser/blob/f211932ad6ec534096e1c71efe4f339ab784a908/Endless/SSLCertificate.m#L34-L54
but all of those functions (SecTrustGetCertificateAtIndex, SecTrustCopyResult, etc) seem to be after iOS has evaluated trust? (i don't see anything in here where our code/endless code explicitly sends something up for trust evaluation.)
but this might be a good place to start experimenting with changes.
I have documented everything I know about this bug (basically summarized my research that I spewed out in chat a couple weeks ago) on the GitHub wiki for the app:
I'll be linking to it from the homepage, default app homepage, and other places I think.
Upon seeing this issue we realized that our project (https://github.com/Psiphon-Inc/endless), which relies on proxying UIWebView with an NSURLProtocol subclass, has the same issue with OCSP requests leaking in plaintext.
This is just a quick overview, but we can provide more details or provide instructions on how to integrate OCSPCache.
https://github.com/Psiphon-Labs/OCSPCache
We created a CocoaPod for making OCSP requests and caching OCSP responses on iOS. This includes handling authentication challenges with a default series of revocation checks.
Our solution roughly takes the following steps.
// Use this policy for checking all OCSP responses to ensure
// that no plaintext OCSP requests are made by the system.
SecPolicyRef = SecPolicyCreateRevocation(kSecRevocationOCSPMethod |
kSecRevocationRequirePositiveResponse |
kSecRevocationNetworkAccessDisabled);
SecTrustSetPolicies(trust, policy);
If SecTrustEvaluate succeeds, then there was a pinned OCSP response.
If there is no pinned OCSP response, or the pinned response was invalid, make proxied OCSP requests manually. This is done by either modifying all OCSP request URLs to point through our local reverse proxy or by providing an NSURLSession with the connection proxy dictionary set to use our local HTTP or SOCKS proxy.
If the previous OCSP checks fail, fallback to system revocation checking with CRLs.
Some comments on getting OCSP URLs from a SecTrust object and constructing OCSP requests can be found in: https://github.com/Psiphon-Labs/OCSPCache/blob/b945a5784cd88ed5693a62a931617bd371f3c9a8/OCSPCache/Classes/OCSPCert.h.
@mirokuratczyk This is great, thanks a lot!
Can you point me to the place where you use this, so I can get an idea? Or is that part of Psiphon closed source?
Unfortunately, we can't add the package just like that, as we're using Swift, also, which makes OpenSSL-Universal unusable due to the statically linked libraries. (See an explanation about this here: https://github.com/googlemaps/google-maps-ios-utils/blob/master/Swift.md) So we first need to figure out a way to include this in the most elegant way possible.
@tladesignz No problem!
We use this in our NSURLProtocol subclass here.
Also, we have sample apps which we updated to use OCSPCache as well: TunneledWebRequest and TunneledWebView. TunneledWebView has a more straight forward integration.
I think CocoaPods added support for statically linked libraries in 1.5.0: http://blog.cocoapods.org/CocoaPods-1.5.0/.
pod install
with the following change seems to work (using CocoaPods 1.7.3):
-use_frameworks!
+use_modular_headers!
Although, I did not look into the implications of use_modular_headers!
.
@mirokuratczyk Awesome! Thanks a ton!
We have found a few bugs in the OCSPCache code while reviewing it with Apple through a support ticket.
Quick summary below:
SecTrustSetPolicies
These bugs are confined to AuthURLSessionDelegate, which provides some default certificate validation code. We are working on fixes for these, but the AuthURLSessionDelegate should not be used in its current state.
I'll provide an update when the fixes are released!
@mirokuratczyk I dived deep into all the interceptor code. I replaced ours with yours (basically your JAHPAuthenticatingHTTPProtocol
stuff) so I get the OCSPCache support and also because that seems way better than our CFNetwork usage. (Thanks a ton for that!)
AuthURLSessionDelegate should not be used in its current state.
Well, why not? The issues you describe still seem to be better than leaking IPs via OCSP calls. How big is the chance that an exit node gets ahold of an intermedia certificate which was revoked or of a sibling server's cert and tries MitM traffic with these compared to the problem of actually always leaking IP addresses with OCSP requests to a state censor?
Or do I have a thought error there?
I'm almost finished adapting your code to OnionBrowser, however I ran into some issues. Check out this site: https://badssl.com
Most of the links are completely breaking. Meaning no timeout just endless loading. That's not good.
I'll provide an update when the fixes are released!
Not trying to get annoying, but can you provide a horizon of when to expect these?
BTW.: I got really annoyed with the CSP header mangling from Endless, so I did it "right". Check this out:
https://cocoapods.org/pods/CSPHeader https://github.com/OnionBrowser/OnionBrowser/blob/cce6300cfb20bfde33fa7a1627b04e3c7ae4a1bc/Psiphon/JAHPAuthenticatingHTTPProtocol.m#L1275-L1320
I guess, that's usable for you, too!
@tladesignz that's great to hear!
Well, why not? The issues you describe still seem to be better than leaking IPs via OCSP calls. How big is the chance that an exit node gets ahold of an intermedia certificate which was revoked or of a sibling server's cert and tries MitM traffic with these compared to the problem of actually always leaking IP addresses with OCSP requests to a state censor?
That's a valid point. I agree that the risk of leaking OCSP requests is worse.
I'm almost finished adapting your code to OnionBrowser, however I ran into some issues. Check out this site: https://badssl.com Most of the links are completely breaking. Meaning no timeout just endless loading. That's not good.
I checked it out and you are right. I think the issue is that, currently, the default timeout for network requests on iOS is used for OCSP requests. An NSURLSession with ephemeralSessionConfiguration is used unless an NSURLSession is explicitly provided to OCSPAuthURLSessionDelegate. This default timeout is quite long and I believe some of the OCSP servers corresponding to some certs on https://badssl.com are not responding to the requests; hence the endless loading caused by certificate validation being stuck on the OCSP step.
Allowing timeout configuration seems to fix this (included in the PR mentioned below). I set the timeout for OCSP requests to 1s and the tests load quickly. If you get a chance, it would be great to know if the same works for you.
Not trying to get annoying, but can you provide a horizon of when to expect these?
The fixes for the issues mentioned in my previous comment and above are completed, but not yet merged: https://github.com/Psiphon-Labs/OCSPCache/pull/6. I'll be AFK for the next week, but i'll do some further tests, merge and make an official release next week -- assuming everything goes smoothly.
You can work off of my fork if you'd like to test the changes before they are merged.
This looks great, thanks! We can definitely use this.
Allowing timeout configuration seems to fix this (included in the PR mentioned below). I set the timeout for OCSP requests to 1s and the tests load quickly. If you get a chance, it would be great to know if the same works for you.
Yay! That works, thanks!
Please give me a heads up, when you do a release, so I don't need to point to your fork anymore!
Yay! That works, thanks!
Good to hear!
I've merged the changes in my fork so you can switch over.
Hello @mirokuratczyk,
I have found this issue from rdar://716337334.
I'm investigating OCSP revocation check from Alamofire's ServerTrustEvaluation, RevocationTrustEvaluator
class.
I'm wondering, you mention here and in radar "pinned OCSP response" term. Did you mean, that when one specifies (kSecRevocationOCSPMethod | kSecRevocationNetworkAccessDisabled)
flag it will effectively check for OCSP Stapling? Or you meant some other OCSP pin?
Any feedback would be greatly appreciated.
Hi @OlexandrStepanov,
Did you mean, that when one specifies (kSecRevocationOCSPMethod | kSecRevocationNetworkAccessDisabled) flag it will effectively check for OCSP Stapling? Or you meant some other OCSP pin?
Yes, I meant that it will effectively check for OCSP stapling. This was confirmed by Apple and through our testing. Thanks for pointing this ambiguity out! I updated my comment on the rdar to specifically mention OCSP stapling.
UPDATE, JUNE 15 2019: See advisory note & summary about this leak:
2019-178: sites with EV HTTPS certificates leak information via OCSP
Original GitHub issue:
Onion Browser on iOS is leaking data about some visited sites (both onion services and clearnet hosted servers). This happens because the browser checks for certificate revocations with OCSPv1 over non tor transport.
OCSP requests and responses made by Onion Browser goes via regular network, and since these are HTTP requests, any party with enough access to network can sniff it and identify the domains user is visiting.
Steps to reproduce
Consider a scenario where user is connected to an evil access point running tcpdump, and tries visiting “www.nytimes3xbfgragh.onion” in Onion Browser.
As you can see, the OCSP request is going via non TOR transport in HTTP and we can dump and Identify the domain.
We were also able to reproduce it for other OCSPv1 services - we tested
We can also provide the packet dumps if you need.
Since the request payload is small OCSP spec allows it to be encoded in request URI. We got the http requests from browser on regular transport from tcpdump.
for e.g, this is the one from nytimes onion service. [Full request URI: http://ocsp.digicert.com/MFYwVKADAgEAME0wSzBJMAkGBSsOAwIaBQAEFEn0vYoYv3YGmMXeQC1oO3Fq5OaGBBQ901Cl1qCt7vNKYApl0yHU%2BPjWDwIQATXM5lnIy5Cdngkc9hmitg%3D%3D]
Reversing the encodings and parsing with ocsptool from gnuTLS.
echo MFYwVKADAgEAME0wSzBJMAkGBSsOAwIaBQAEFEn0vYoYv3YGmMXeQC1oO3Fq5OaGBBQ901Cl1qCt7vNKYApl0yHU%2BPjWDwIQATXM5lnIy5Cdngkc9hmitg%3D%3D | python -c "import sys, urllib.parse as ul; print(ul.unquote(sys.stdin.read()));" | base64 -d | ocsptool -i OCSP Request Information: Version: 1 Request List: Certificate ID: Hash Algorithm: SHA1 Issuer Name Hash: 49f4bd8a18bf760698c5de402d683b716ae4e686 Issuer Key Hash: 3dd350a5d6a0adeef34a600a65d321d4f8f8d60f Serial Number: 0135cce659c8cb909d9e091cf619a2b6
Looking this serial up in cert logs, you can see this is an OCSP request for nytimes onion services.
https://crt.sh/?serial=0135cce659c8cb909d9e091cf619a2b6
X509v3 Subject Alternative Name: DNS:nytimes3xbfgragh.onion DNS:graylady3jvrrxbe.onion DNS:.graylady3jvrrxbe.onion DNS:.dev.graylady3jvrrxbe.onionDNS:.stg.graylady3jvrrxbe.onion DNS:.nytimes3xbfgragh.onionDNS:.api.nytimes3xbfgragh.onion DNS:.api.dev.nytimes3xbfgragh.onionDNS:.api.stg.nytimes3xbfgragh.onion DNS:.blogs.nytimes3xbfgragh.onionDNS:.blogs.stg.nytimes3xbfgragh.onion DNS:.blogs5.stg.nytimes3xbfgragh.onionDNS:.dev.nytimes3xbfgragh.onion DNS:.dev.blogs.nytimes3xbfgragh.onionDNS:.newsdev.nytimes3xbfgragh.onion DNS:.prd.nytimes3xbfgragh.onionDNS:.sbx.nytimes3xbfgragh.onion DNS:.stg.nytimes3xbfgragh.onionDNS:.stg.blogs.nytimes3xbfgragh.onion DNS:.stg.newsdev.nytimes3xbfgragh.onionDNS:www.bestsellers.nytimes3xbfgragh.onion DNS:www.homedelivery.nytimes3xbfgragh.onion