Swift/XCode 7: NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)

≯℡__Kan透↙ 提交于 2019-12-12 03:19:44

问题


I have created a self signed certificate with openssl and sha 256 like the following:

openssl req -x509 -nodes -sha256 -days 365 -newkey rsa:2048 -keyout server.key -out server.crt

and I've installed it correctly in my AMPPS server by configuring httpd-ssl.conf file. If I try to perform, on a web browser:

https://localhost

I correctly see that connection uses TLS 1.2. When I run my app under iOS 9 simulator, I guess that error (9813) is raised because my certificate is self signed. Is there a way to enable it anyway, for my test purpouses? I've read here that I should add some function to AppDelegate.swift class but it seems it doesn't work.

This is the complete error message I get:

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Optional(Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this  server is invalid. You might be connecting to a server that is pretending to be  “localhost” which could put your confidential information at risk." UserInfo= {NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x7fc492d54cf0>,  NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?,  _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9813,  NSErrorPeerCertificateChainKey=<CFArray 0x7fc492cc4bc0 [0x103cb67b0]>{type =  immutable, count = 1, values = (
0 : <cert(0x7fc492d520c0) s: Lorenzo Vinci i: Lorenzo Vinci>
)}, NSUnderlyingError=0x7fc492cc1370 {Error Domain=kCFErrorDomainCFNetwork   Code=-1202 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0,   kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x7fc492d54cf0>,  _kCFNetworkCFStreamSSLErrorOriginalValue=-9813, _kCFStreamErrorDomainKey=3,  _kCFStreamErrorCodeKey=-9813, kCFStreamPropertySSLPeerCertificates=<CFArray  0x7fc492cc4bc0 [0x103cb67b0]>{type = immutable, count = 1, values = (
0 : <cert(0x7fc492d520c0) s: Lorenzo Vinci i: Lorenzo Vinci>
)}}}, NSLocalizedDescription=The certificate for this server is invalid. You   might be connecting to a server that is pretending to be “localhost” which could    put your confidential information at risk.,    NSErrorFailingURLKey=https://localhost/protected/excogitoweb/mobile/loginM.php? username=lorenzo&password=lorenzo,  NSErrorFailingURLStringKey=https://localhost/protected/excogitoweb/mobile/loginM.p hp?username=lorenzo&password=lorenzo, NSErrorClientCertificateStateKey=0})

UPDATE: for Mac OS X Yosemite
1) update openssl by brew to version >= 1.0.2d
2) TLS 1.2 work only with apache 2.4 and actually MAMP is still given with apache 2.2. SOLUTION: download and install the latest version of AMPPS which runs a version of apache 2.4.x
3) create a self signed certificate with sha256 (as requested by iOS 9) with

openssl req -x509 -nodes -sha256 -days 365 -newkey rsa:2048 -keyout server.key -out server.crt

and save server.key and server.crt into /Applications/AMPPS/apache/conf
4) Be sure that ssl modules are loaded inside httpd.conf file of AMPPS
5) Edit file /Applications/AMPPS/apache/conf/extra/httpd-ssl.conf adding:

<VirtualHost localhost:443>
   DocumentRoot "/Applications/AMPPS/www"
   ServerName localhost
   SSLEngine on
   SSLProtocol all -SSLv2 -SSLv3
   SSLHonorCipherOrder on
   SSLCertificateFile "/Applications/AMPPS/apache/conf/server.crt"
   SSLCertificateKeyFile "/Applications/AMPPS/apache/conf/server.key"
</VirtualHost>

inside

<IfModule ssl_module> ... </IfModule> 

6) iOS 9 simulator will annoy you each time you use NSURLSession raising an error 9813 saying that the certificate is not valid (because is self signed). So in each class where you are going to use NSURLSession do, for example, the following:

class LoginService: NSObject, NSURLSessionDelegate {

func URLSession(session: NSURLSession,
    task: NSURLSessionTask,
    didReceiveChallenge challenge: NSURLAuthenticationChallenge,
    completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?)
    -> Void) {

    completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
}

...

func requestLoginWithURL (requestURL: NSURL, completionHandler: (success: Bool?) -> Void) {
    let configuration =
    NSURLSessionConfiguration.defaultSessionConfiguration()

    let urlRequest: NSURLRequest = NSURLRequest(URL: requestURL)

    let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue:NSOperationQueue.mainQueue())

    /*
    dataTaskWithRequest: creates an HTTP request for the specified URL request object, and calls a handler upon completion.
    */
    let task = session.dataTaskWithRequest(urlRequest, completionHandler: { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in

...
}

where the function URLSession is a delegate which will prevent the app from crashing because of the self signed certificate and it will accept anyway.

Finally add this to your info.plist:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <!--Include to allow subdomains-->
            <key>NSIncludesSubdomains</key>
            <true/>
            <!--Include to allow HTTP requests-->
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <!--
            <key>NSExceptionMinimumTLSVersion</key>
            <string>TLSv1.1</string>
            <key>NSExceptionRequiresForwardSecrecy</key>
            <false/> -->
        </dict>
    </dict>
</dict>

来源:https://stackoverflow.com/questions/32716766/swift-xcode-7-nsurlsession-nsurlconnection-http-load-failed-kcfstreamerrordoma

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!