Certificate Authentication using Alamofire

Hey everyone,

I am trying to successfully authenticate in a a system using a certificate stored in the phone (Xcode simulator in this case). I am using Alamofire to do this. Actually, following their documentation, I set the trust certificates of the server url to the session

Code Block
let manager = ServerTrustManager(evaluators: [location: PinnedCertificatesTrustEvaluator()])
let session = Session(serverTrustManager: manager)


I have seen that probably the best way is to authenticate using the URLCredentials, but I am not able to obtain this from the certificates of the system.

Trying to use my own certificate, I've done something like this:
Code Block
let filePath = Bundle.main.path(forResource: "alvaro", ofType: "p12")!
let data = try! Data(contentsOf: URL(fileURLWithPath: filePath))
let certificate = SecCertificateCreateWithData(nil, data as CFData)!

As you can see I find .p12 extension certificate directly from the resources (although I am getting Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value), but my final objetive it's to get my app showing that a client certificate is required, allowing this to use the certificate installed on his device when connecting to the website.

Thanks in advance.

There’s two parts to this:
  • Catching and responding to the client certificate authentication challenge.

  • Getting access to the digital identity with which to respond to that challenge.

Which part do you need help with?

I can help you with the latter but the former is doing to be specific to the third-party library you’re using.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
I would like to know how to access to the digital identity to response that challenge, cause I already have the server evaluators, the Trust Manager and the session


Code Block
let evaluators: [String: ServerTrustEvaluating] = [
"my.domain.es": PinnedCertificatesTrustEvaluator(certificates: [certificate!], acceptSelfSignedCertificates : false,
                                                                 performDefaultValidation: false, validateHost : true)
]
let serverTrustManager = ServerTrustManager(evaluators: evaluators)
let session = Session(serverTrustManager: serverTrustManager)




I would like to know how to access to the digital identity to response that challenge

How was that digital identity installed? If you’re hoping to access digital identities that are installed system wide, that won’t work. See QA1745 Making Certificates and Keys Available To Your App.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Thanks for your answer, once again.

I have already successfully installed the PKCS12 certificate into the configuration profile of the device. Safari prompts a dialog which asks for a client certificate, and offers me to use the certificate installed of the phone, being the authentication successfully done after continuing.

I need to do something similar in code (or at least, that is my objetive). Actually I am doing it building the URLCredential with the certificate in the bundle

Code Block
var pathToCert = Bundle.main.path(forResource: "certname", ofType: "certtype")
var localCertificate : NSData = NSData(contentsOfFile: pathToCert! )!


Now, what I need to do is to use it when passing the URLCredential to the request.
Code Block
let credentials = URLCredential(identity: identity, certificates: [certificate!], persistence: .forSession)


Reading the docs attached, I can see there is not posible to access directly from code to the profile where the PKCS12 is stored, and load it after using SecPKCS12Import (it's possible I am wrong).

If I can't do this, then, will I have to ask for the certificate inside my app? Or there's other way to do this?

Thank you very much in advance. Really appreciate Apple support

You will not be able to access credentials installed via a configuration profile. Those are added to an Apple keychain access group that you can’t access.

Or there's other way to do this?

It very much depends on your deployment arrangements. Do you plan to deploy this in a managed environment? Or is this app distributed to a wide range of users via the App Store?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
My plan is to distribute this app via the App Store, giving access to several users using their certificates.

Maybe the best option if it's not possible to access the certificate given in the configuration profile, is to ask them for the certificate inside the app, before doing the authentication

A parenthesis: Is it possible to give the certificate access to other applications via Settings?

Is it possible to give the certificate access to other applications via Settings?

No, but that’d be a cool enhancement request.

Maybe the best option if it's not possible to access the certificate given in the configuration profile, is to ask them for the certificate inside the app

Probably. In a managed environment you have various other options but outside of that you typically have to get the user involved.

What does your digital identity workflow look like? Who is issuing these? And how does the user get one from them?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Thank you for your answer.

Certificates are emited by a trust certification authority. I have actually the .p12 certificate obtained plus its private key, which I use to authenticate successfully against a certificate entity (just doing a GET request)

Code Block
let pathToCert = Bundle.main.path(forResource: "aLosada_7", ofType: "p12")
let localCertificate = NSData(contentsOfFile: pathToCert! )!
let options = [String(kSecImportExportPassphrase):"yourpassword"]
var items: CFArray? = nil
let result = SecPKCS12Import(localCertificate, options as CFDictionary, &items)
if (result != errSecSuccess) {
print(result)
}
let info = (items! as NSArray).firstObject! as! NSDictionary
let identity = info[String(kSecImportItemIdentity)] as! SecIdentity
let credentials = URLCredential(identity: identity, certificates: nil, persistence: .forSession)


This way I am doing it right but using the certificate stored in the Bundle of my app. Now I want to do this globally to any user trying to access to my application.

This is why I thought the best way to do it was obtaining the certificate from the profile (until I got that certificate will be only accesible by the Apple keychain group).

So I am trying to access this .p12 from somewhere else, but I am confused on how to do this.

Certificates are emited by a trust certification authority.

OK, but how does that work for your users? Do they contact the CA to get their digital identity? Or do you contact the CA on their behalf? Or is there one digital identity shared between all your users?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Yes, I need help with the latter one, accusing the digital identity which will allow me to response to that challenge. I am doing something like this, but I am not getting any result.


Code Block
func retrieveData(accessGroup: String) {
let query = [kSecClass: kSecClassIdentity,
kSecReturnAttributes: true,
    kSecReturnData: true] as [String: Any]
    var item: CFTypeRef?
    let status = SecItemCopyMatching(query as CFDictionary, &item)
if status == errSecItemNotFound {
print("none")
}
if let resultDictionary = item as? [String: Any],
let data = resultDictionary[kSecValueData as String] as? Data {
}
    }



OK, this code suggests you want to access the digital identity from the keychain. How are you expecting it to get into the keychain?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Hey, sorry for the late reply.

I would need help to access the digital identity to respond that challenge. As I told you before, I installed the certificate on the mobile, but this way probably I won't be able to access it and use it to respond that challenge.

I was wondering if there is a chance of making the challenge using the browser (Safari), and after it has been done, get a cookie value and return it to the program (which is all I need in the end)
Certificate Authentication using Alamofire
 
 
Q