问题
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