4

Has anyone seen a way to do pinning with Alamofire with the fingerprint instead of the public key?

Sorry if this has been answered, I haven't seen it anywhere.

Thanks

Bob
  • 91
  • 1
  • 5

3 Answers3

3

This ended up being pretty straight forward. The code below might not be perfect, my real code is doing some addtional checks, but this is most of it.

The .SHA1Fingerprint is an extension method on SecCertificate that copies it into NSData and then converts it to a SHA1. I use RNCryptor to do that, but you can do it however.

The isValidFingerprint just compares the result to each of my known fingerprint(s).

This all hangs off my static Alamofire.Manager.

manager.delegate.sessionDidReceiveChallenge = { session, challenge in
        var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
        var credential: NSURLCredential?

        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            let host = challenge.protectionSpace.host

            if let serverTrust = challenge.protectionSpace.serverTrust {

                let serverTrustPolicy = ServerTrustPolicy.PerformDefaultEvaluation(validateHost: true)

                if serverTrustPolicy.evaluateServerTrust(serverTrust, isValidForHost: host) {
                    disposition = .UseCredential
                    credential = NSURLCredential(forTrust: serverTrust)
                } else {
                    disposition = .CancelAuthenticationChallenge
                    return (disposition, credential)
                }

                for index in 0..<SecTrustGetCertificateCount(serverTrust) {
                    if let certificate = SecTrustGetCertificateAtIndex(serverTrust, index) {
                        if let fingerPrint = certificate.SHA1Fingerprint {
                            if isValidFingerprint(fingerPrint)  {
                                return (disposition, credential)
                            }
                        }
                    }
                }
            }
        }
        disposition = .CancelAuthenticationChallenge
        return (disposition, credential)
    }
Bob
  • 91
  • 1
  • 5
2

Swift 4

I changed Bob answer and it's worked for me, you can change your validation algorithm according to your requirement, this code just check one of pinned certificates is valid or not. this link helped me for understanding my problem

private static var Manager : Alamofire.SessionManager = {
    let man = Alamofire.SessionManager()
    man.delegate.sessionDidReceiveChallenge = { session, challenge in
        var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
        var credential: URLCredential?
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            let host = challenge.protectionSpace.host

            if let serverTrust = challenge.protectionSpace.serverTrust {

                let serverTrustPolicy = ServerTrustPolicy.performDefaultEvaluation(validateHost: true)
                if serverTrustPolicy.evaluate(serverTrust, forHost: host) {
                    disposition = .useCredential
                    credential = URLCredential(trust: serverTrust)
                } else {
                    disposition = .cancelAuthenticationChallenge
                    return (disposition, credential)
                }
                let fingerPrints = [
                    "AJKSFGSGFR64563RFGY874FG43G784F48FG4F4GF74GF4F7G4FGF4F74F7GFF58Y".lowercased(),
                    "BJKSFGSGFR64563RFGY874FG43G784F48FG4F4GF74GF4F7G4FGF4F74F7GFF58Y".lowercased(),
                    "CJKSFGSGFR64563RFGY874FG43G784F48FG4F4GF74GF4F7G4FGF4F74F7GFF58Y".lowercased()
                ]

                for index in 0..<SecTrustGetCertificateCount(serverTrust) {
                    let cer = SecTrustGetCertificateAtIndex(serverTrust, index)

                    if let certificate = SecTrustGetCertificateAtIndex(serverTrust, index) {
                        let certData = certificate.data
                        let certHashByteArray = certData.sha256()
                        let certificateHexString = certHashByteArray.toHexString().lowercased()

                        if fingerPrints.contains(certificateHexString) {
                            return (disposition, credential)
                        }
                    }
                }
            }
        }
        disposition = .cancelAuthenticationChallenge
        return (disposition, credential)
    }
    return man
}()

For converting SecTrustGetCertificateAtIndex(serverTrust, index) (this line let certData = certificate.data) use this extension

import Foundation
public extension SecCertificate {
    public var data: Data {
        return SecCertificateCopyData(self) as Data
    }
}

for these two line I used CryptoSwift library, you can use sha1 instead of sha256, I pinned certificate with sha256 finger print.

let certHashByteArray = certData.sha256()
let certificateHexString = certHashByteArray.toHexString().lowercased()
Hamed
  • 1,678
  • 18
  • 30
  • Thanks Hamed for such a beautiful piece of code. Can you share your code for swift 5? because in swift 5 sessionDidReceiveChallenge has been removed. – IHSAN KHAN Jun 15 '20 at 06:40
  • `sessionDidReceiveChallenge` is for Alamofire 4, If you want to use this code you should use Alamofire 4 instead of 5, I never implemented ssl pinning for Alamofire 5, I'll try it as soon as possible. – Hamed Jun 15 '20 at 11:43
  • Thanks for quick reply. Actually we migrated every things to swift 5 so it is now necessary. Let's try soon and I will wait to see your findings. – IHSAN KHAN Jun 15 '20 at 12:45
  • Excuse me,I can not work on it in the immediate future. – Hamed Jun 15 '20 at 13:10
0

Can I ask the reason why you try to pin the fingerprint instead of the public key or the certificate?

In my experience, the key point of pinning is to hardcode something into your program.

FYI: https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning

NINJAJA
  • 51
  • 1
  • 3
  • Edit: I had other words, but just finished reading the link you sent. Under the hashing section, that article actually talks about the advantages of pinning with the fingerprint instead of the public key. I do appreciate the help and the link, it was a good article I hadn't run across yet. – Bob May 10 '16 at 06:35
  • @Bob Oh, I see. Thanks for sharing :) – NINJAJA May 11 '16 at 03:06