Hi guys,
I'm trying to implement mutual TLS connection. Here is the flow:
- I generate the csr request (using elliptic curve key, secp512r1)
- Send the signing rquest to the server and receive the public key certificate as a response
- I make p12 certificate using public key certificate received in step2 with my ECC secp512r1 private key. I save it as "ca.p12" file in Documents
- when I get NSURLAuthenticationMethodClientCertificate challenge I resolve it using the credentials from this certificate.
- Get Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made."
While checking the traffic between server and client it appears that it's a client side issue.
Questions:
1. Does iOS 9/10 support elliptic curve keys, secp512r1 in TLS handshake?
2. Is there anything that is wrong or I missed some critical item in my flow?
Any thoughts, suggestions are really appreciated. Thanks.
public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) {
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate) {
let identityAndTrust: IdentityAndTrust = self.extractIdentity()
let urlCredential: URLCredential = URLCredential(
identity: identityAndTrust.identityRef,
certificates: identityAndTrust.certArray as? [AnyObject],
persistence: URLCredential.Persistence.forSession)
completionHandler(.useCredential, urlCredential)
}
// server trust verification works fine
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
if (self.shouldTrustProtectionSpace(space: challenge.protectionSpace)) {
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
}
}
struct IdentityAndTrust {
var identityRef: SecIdentity
var trust: SecTrust
var certArray: AnyObject
}
func extractIdentity() -> IdentityAndTrust {
var identityAndTrust: IdentityAndTrust!
var securityError: OSStatus = errSecSuccess
var path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
path = path + "/ca.p12"
let PKCS12Data = NSData(contentsOfFile:path)!
let key: NSString = kSecImportExportPassphrase as NSString
let options: NSDictionary = [key : "123"]
var items: CFArray?
securityError = SecPKCS12Import(PKCS12Data, options, &items)
if securityError == errSecSuccess {
let certItems: CFArray = items as CFArray!
let certItemsArray: Array = certItems as Array
let dict: AnyObject? = certItemsArray.first
if let certEntry: Dictionary = dict as? Dictionary<String, AnyObject> {
/
let identityPointer: AnyObject? = certEntry["identity"]
let secIdentityRef: SecIdentity = identityPointer as! SecIdentity!
print("\(identityPointer) :::: \(secIdentityRef)")
/
let trustPointer: AnyObject? = certEntry["trust"]
let trustRef: SecTrust = trustPointer as! SecTrust
print("\(trustPointer) :::: \(trustRef)")
//get certificates from identity
var certRef: SecCertificate?
SecIdentityCopyCertificate(secIdentityRef, &certRef)
let certArray: NSMutableArray = NSMutableArray()
certArray.add(certRef as SecCertificate!)
//add also ca root certificate
let caRootCert = CertRepository.caRootCertificate()
certArray.add(caRootCert)
identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certArray: certArray)
}
}
return identityAndTrust
}