Skip to content

Instantly share code, notes, and snippets.

@celian-m
Created January 13, 2017 16:33
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save celian-m/8da09ad293507940a0081507f057def5 to your computer and use it in GitHub Desktop.
Save celian-m/8da09ad293507940a0081507f057def5 to your computer and use it in GitHub Desktop.
Perform client side certificate check
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)
}
}
@Alkeshm29
Copy link

Alkeshm29 commented Feb 3, 2018

Please attach sample ViewController File

@Alkeshm29
Copy link

How to call this file in view VC or Button click

@akshay1188
Copy link

where is trustRef used in didReceiveChallenge?

@SerggioC
Copy link

SerggioC commented Jun 26, 2020

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