Hi guys Im trying to apply this authentication strategy . Basically I create RSA Key pair, then I create CSR(Certificate Signing Request), then I send it to server which will return (X.509)Self-signed client certificate in response. Then I remove ----BEGIN CERTIFICATE---- and ----END CERTIFICATE----, transform it to base64 encoded data with line length 64 characters, and save it to keychain this way
- create reference with
let certRef: CFTypeRef? = SecCertificateCreateWithData(nil , cert)
- save it to keychain with
let params: NSDictionary = [kSecClass as String: kSecClassCertificate, kSecValueRef as String: certRef!] let status = SecItemAdd(params, nil)
certificate is saved, now If I understand it correctly, if I have private key with which CSR was created saved in keychain, I should be able to get SecIdentity
which I will use in NSURLSession to make request. So I created method to get this identity this is how it looks like :
func getIdentityReference() -> SecIdentityRef? {
let parameters = [
kSecClass as String: kSecClassIdentity,
kSecAttrApplicationTag as String: kAsymmetricCryptoManagerApplicationTag,
kSecReturnRef as String: true
]
var ref: AnyObject?
let status = SecItemCopyMatching(parameters, &ref)
if status == errSecSuccess { return ref as! SecIdentityRef? } else { return nil }
}
everything works fine, Im getting identity so the only thing to do is actual request. For that I need to implement NSURLSessionDelegate's did receive challenge method and here it is
func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
let method = challenge.protectionSpace.authenticationMethod
print(method)
if method == NSURLAuthenticationMethodServerTrust {
let host = challenge.protectionSpace.host
print(host)
let credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential)
}
let identity = AsymmetricCryptoManager.sharedInstance.getIdentityReference()!
var certificate: SecCertificateRef? = nil
SecIdentityCopyCertificate(identity, &certificate)
var certArray = [certificate!]
let credential = NSURLCredential(identity: identity, certificates: certArray, persistence: .Permanent)
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential)
}
(I'm just prototyping, that's the reason for implicit unwrapping)
but when I fire this request I'm getting error
Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={_kCFStreamErrorCodeKey=-9824, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, NSUnderlyingError=0x13cfe7850 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9824, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9824}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://blabla.blabla, NSErrorFailingURLStringKey=https://blabla.blabla, _kCFStreamErrorDomainKey=3}
now I really don't know where is the problem, note that on Android everything works well, so server is set up correctly. Any help will be appreciated and it might help few people in the future. Thank you