public struct IdentityAndTrust {
public var identityRef:SecIdentity
public var trust:SecTrust
public var certArray:NSArray
}
public func extractIdentity(certData:NSData, certPassword:String) -> IdentityAndTrust {
var identityAndTrust:IdentityAndTrust!
var securityError:OSStatus = errSecSuccess
var items: CFArray?
let certOptions: Dictionary = [ kSecImportExportPassphrase as String : certPassword ];
// import certificate to read its entries
securityError = SecPKCS12Import(certData, certOptions as CFDictionary, &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> {
// grab the identity
let identityPointer:AnyObject? = certEntry["identity"];
let secIdentityRef:SecIdentity = identityPointer as! SecIdentity!;
// grab the trust
let trustPointer:AnyObject? = certEntry["trust"];
let trustRef:SecTrust = trustPointer as! SecTrust;
// grab the certificate chain
var certRef: SecCertificate?
SecIdentityCopyCertificate(secIdentityRef, &certRef);
let certArray:NSMutableArray = NSMutableArray();
certArray.add(certRef as SecCertificate!);
identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certArray: certArray);
}
}
return identityAndTrust;
}
public class MyURLSessionDelegate: NSObject, URLSessionDelegate {
public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
// `NSURLAuthenticationMethodClientCertificate`
// indicates the server requested a client certificate.
if challenge.protectionSpace.authenticationMethod
!= NSURLAuthenticationMethodClientCertificate {
completionHandler(.performDefaultHandling, nil)
return
}
guard let file = Bundle(for: HTTPAccessURLSessionDelegate.self).url(forResource: p12Filename, withExtension: "p12"),
let p12Data = try? Data(contentsOf: file) else {
// Loading of the p12 file's data failed.
completionHandler(.performDefaultHandling, nil)
return
}
// Interpret the data in the P12 data blob with
// a little helper class called `PKCS12`.
let password = "MyP12Password" // Obviously this should be stored or entered more securely.
let p12Contents = PKCS12(pkcs12Data: p12Data, password: password)
guard let identity = p12Contents.identity else {
// Creating a PKCS12 never fails, but interpretting th contained data can. So again, no identity? We fall back to default.
completionHandler(.performDefaultHandling, nil)
return
}
// In my case, and as Apple recommends,
// we do not pass the certificate chain into
// the URLCredential used to respond to the challenge.
let credential = URLCredential(identity: identity,
certificates: nil,
persistence: .none)
challenge.sender?.use(credential, for: challenge)
completionHandler(.useCredential, credential)
}
}