I have a problem with my evaluate function with Alamofire. It works fine for most cases, but it does not go through the security check. They use a MITM solution, they also pre-installed a cert to the phone, then they sniffed on the web, and my solution did not alert them about the men in the middle. So I'd change this to alert for user installed CAs. Can anybody help me how to do that?
public final class CertificatePinnerTrustEvaluator: ServerTrustEvaluating {
public init() {}
func setupCertificatePinner(host: String) -> CertificatePinner {
return CertificatePinner(host: host)
}
public func evaluate(_ trust: SecTrust, forHost host: String) throws {
let pinner = setupCertificatePinner(host: host)
if !pinner.validateCertificateTrustChain(trust) {
print("failed: invalid certificate chain!")
throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
}
let certificates = pinner.makeCertChain(from: trust)
guard !certificates.isEmpty else {
throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
}
try trust.af.performDefaultValidation(forHost: host)
try trust.af.performValidation(forHost: host)
let serverCertificatesData = Set(trust.af.certificateData)
let pinnedCertificatesData = Set(certificates.af.data)
let pinnedCertificatesInServerData = !serverCertificatesData.isDisjoint(with: pinnedCertificatesData)
if !pinnedCertificatesInServerData {
throw AFError.serverTrustEvaluationFailed(reason: .certificatePinningFailed(host: host,
trust: trust,
pinnedCertificates: certificates,
serverCertificates: trust.af.certificates))
}
}
}
I have a problem with my evaluate function with Alamofire. It works fine for most cases, but it does not go through the security check. They use a MITM solution, they also pre-installed a cert to the phone, then they sniffed on the web, and my solution did not alert them about the men in the middle. So I'd change this to alert for user installed CAs. Can anybody help me how to do that?
public final class CertificatePinnerTrustEvaluator: ServerTrustEvaluating {
public init() {}
func setupCertificatePinner(host: String) -> CertificatePinner {
return CertificatePinner(host: host)
}
public func evaluate(_ trust: SecTrust, forHost host: String) throws {
let pinner = setupCertificatePinner(host: host)
if !pinner.validateCertificateTrustChain(trust) {
print("failed: invalid certificate chain!")
throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
}
let certificates = pinner.makeCertChain(from: trust)
guard !certificates.isEmpty else {
throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
}
try trust.af.performDefaultValidation(forHost: host)
try trust.af.performValidation(forHost: host)
let serverCertificatesData = Set(trust.af.certificateData)
let pinnedCertificatesData = Set(certificates.af.data)
let pinnedCertificatesInServerData = !serverCertificatesData.isDisjoint(with: pinnedCertificatesData)
if !pinnedCertificatesInServerData {
throw AFError.serverTrustEvaluationFailed(reason: .certificatePinningFailed(host: host,
trust: trust,
pinnedCertificates: certificates,
serverCertificates: trust.af.certificates))
}
}
}
Share
Improve this question
asked Feb 17 at 13:47
kisstajmikisstajmi
2652 silver badges12 bronze badges
1 Answer
Reset to default 0If your pinning is working correctly it doesn't matter if the user has installed their own root trusts, the pin won't match.
For iOS 15 and later I suggest following Apple's directions and using the native pinning provided by the OS. It allows you to pin any certificate in the chain.
For older OSes that need to use Alamofire's pinning, I suggest using Alamofire's built in trust evaluators, as they're tested to work. Adding the cert you want to pin to your app bundle and adding a ServerTrustManager
to your Alamofire Session
. You can review Alamofire's security documentation here.