Created
January 13, 2017 16:33
-
-
Save celian-m/8da09ad293507940a0081507f057def5 to your computer and use it in GitHub Desktop.
Perform client side certificate check
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
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 SessionDelegate : NSObject, URLSessionDelegate { | |
public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { | |
if let localCertPath = Bundle.main.url(forResource: "{YOUR_CERT_NAME}", withExtension: "{YOUR_CERT_EXTENSION}"), | |
let localCertData = try? Data(contentsOf: localCertPath) | |
{ | |
let identityAndTrust:IdentityAndTrust = extractIdentity(certData: localCertData as NSData, certPassword: "{YOUR_CERT_PWD}") | |
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { | |
let urlCredential:URLCredential = URLCredential( | |
identity: identityAndTrust.identityRef, | |
certificates: identityAndTrust.certArray as [AnyObject], | |
persistence: URLCredential.Persistence.forSession); | |
completionHandler(URLSession.AuthChallengeDisposition.useCredential, urlCredential); | |
return | |
} | |
} | |
challenge.sender?.cancel(challenge) | |
completionHandler(URLSession.AuthChallengeDisposition.rejectProtectionSpace, nil) | |
} | |
} | |
How to call this file in view VC or Button click
where is trustRef used in didReceiveChallenge?
If you have more than one certificate (SecCertificate) use this:
I used it for MBWAY authentication.
struct IdentityAndTrust {
var identityRef: SecIdentity
var trust: SecTrust
var certificates: [SecCertificate]
}
func extractIdentity(certData: NSData, certPassword: String) -> IdentityAndTrust? {
var identityAndTrust: IdentityAndTrust?
var securityStatus: OSStatus = errSecSuccess
var items: CFArray?
let certOptions: Dictionary = [kSecImportExportPassphrase as String : certPassword]
securityStatus = SecPKCS12Import(certData, certOptions as CFDictionary, &items)
if securityStatus == errSecSuccess {
let certificateItems: CFArray = items! as CFArray
let certItemsArray: Array = certificateItems as Array
let dict: AnyObject? = certItemsArray.first
if let certificateDict: Dictionary = dict as? Dictionary<String, AnyObject> {
// get the identity
let identityPointer: AnyObject? = certificateDict["identity"]
let secIdentityRef: SecIdentity = identityPointer as! SecIdentity
// get the trust
let trustPointer: AnyObject? = certificateDict["trust"]
let trustRef: SecTrust = trustPointer as! SecTrust
// get the certificate chain
var certRef: SecCertificate? // <- write on
SecIdentityCopyCertificate(secIdentityRef, &certRef)
var certificateArray = [SecCertificate]()
certificateArray.append(certRef! as SecCertificate)
let count = SecTrustGetCertificateCount(trustRef)
if count > 1 {
for i in 1..<count {
if let cert = SecTrustGetCertificateAtIndex(trustRef, i) {
certificateArray.append(cert)
}
}
}
identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certificates: certificateArray)
}
}
return identityAndTrust
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Please attach sample ViewController File