silkimen / cordova-plugin-advanced-http

Cordova / Phonegap plugin for communicating with HTTP servers. Allows for SSL pinning!
MIT License
391 stars 313 forks source link

Pinned certificate works on Android but not iOS #514

Open halindrome opened 10 months ago

halindrome commented 10 months ago

This is a weird one - sorry! We are using Ionic Capacitor. Because of a complex network topology, one of the things we need to support is accessing a backend (REST) server by IP address (not name) on private local networks. Until recently we have been doing this via HTTP, but a customer has requested we update that connection to use TLS. Unfortunately, getting a real TLS certificate for a server that is not on the Internet is challenging. Fortunately, this plugin exists!

First we set up a tiered private Certificate Authority. So we have a self-signed master (root) CA certificate. That certificate was used to sign a number of intermediate CA certificates. Then we set up a service to generate certificates for the servers that are not on the Internet (and do not have a way to register a name via local DNS) with their IP address in a Subject Alternative Name. Finally, we generated .cer files for each of the intermediate certificates and put them into the www/certificates folder for our app.

On Android this works really well. We set the server trust mode to pinned and we can see it connecting and verifying the connection against the embedded pinned keys. On iOS (16.5.1) it always fails. The specific error we see in the debugging output in XCode is:

⚡️  [debug] - %c2023-07-14T11:14:06.933Z DEBUG [./src/app/services/comms/comms.service.ts:1094:0] color:teal testing TLS with pinned certificate
To Native Cordova ->  CordovaHttpPlugin get CordovaHttpPlugin362646755 ["options": [https://192.168.2.246/scripts/corvex.cgi, {
}, 60, 60, 1, text, 2]]
2023-07-14 06:14:06.999893-0500 App[448:9471] Connection 6: default TLS Trust evaluation failed(-9807)
2023-07-14 06:14:06.999944-0500 App[448:9471] Connection 6: TLS Trust encountered error 3:-9807
2023-07-14 06:14:06.999962-0500 App[448:9471] Connection 6: encountered error(3:-9807)
2023-07-14 06:14:07.000786-0500 App[448:9471] Task <587CDBB3-AE1E-46B7-8F4F-02245E292B4F>.<1> HTTP load failed, 0/0 bytes (error code: -1202 [3:-9807])
2023-07-14 06:14:07.002354-0500 App[448:9124] Task <587CDBB3-AE1E-46B7-8F4F-02245E292B4F>.<1> finished with error [-1202] Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “192.168.2.246” which could put your confidential information at risk." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorPeerCertificateChainKey=(
    "<cert(0x102821a00) s: Self-signed Certificate for gateway i: CCW Delegated Certificate delegate_1>"
), NSErrorClientCertificateStateKey=0, NSErrorFailingURLKey=https://192.168.2.246/scripts/corvex.cgi, NSErrorFailingURLStringKey=https://192.168.2.246/scripts/corvex.cgi, NSUnderlyingError=0x28371e280 {Error Domain=kCFErrorDomainCFNetwork Code=-1202 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x28082cb40>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9807, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9807, kCFStreamPropertySSLPeerCertificates=(
    "<cert(0x102821a00) s: Self-signed Certificate for gateway i: CCW Delegated Certificate delegate_1>"
)}}, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    "LocalDataTask <587CDBB3-AE1E-46B7-8F4F-02245E292B4F>.<1>"
), _kCFStreamErrorCodeKey=-9807, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <587CDBB3-AE1E-46B7-8F4F-02245E292B4F>.<1>, NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x28082cb40>, NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “192.168.2.246” which could put your confidential information at risk.}

We have worked around this already by testing the connection pinned, then falling back to nocheck if the pinned connection fails. This is "working", but is not ideal.

We have 2 questions:

  1. Does this plugin actually support pinning to certificates with a SAN that is an IP address on iOS?
  2. If so, what are we doing wrong?

Thanks!

UlricW commented 9 months ago

We encountered the same issue here