ssl-certificatealamofirepinning

Failed to apply certificate pinning with Alamofire 5.0.2


I am migrating my app to use Alamofire 5.0.2, in the past version it uses Alamofire 4.x and the certificate pinning is working fine.

Then I migrated Alamofire and its certificate pinning configuration with these changes:


//Usage example of the function `defaultSessionManager`
class ViewController: UIViewController {

    let sessionManager = defaultSessionManager(defaultRequestInterceptor())
    //...
}

private func defaultSessionManager(_ requestInterceptor: RequestInterceptor?) -> Alamofire.Session {

  let evaluators: [String: ServerTrustEvaluating] = [
    "https://myapp.com": PinnedCertificatesTrustEvaluator(certificates: pinnedCertificates()),
  ]

  let configuration: URLSessionConfiguration = URLSessionConfiguration.af.default
  configuration.timeoutIntervalForRequest = 10 // seconds
  configuration.timeoutIntervalForResource = 10 // seconds

  return Alamofire.Session(
    configuration: configuration,
    interceptor: requestInterceptor,
    serverTrustManager: ServerTrustManager(evaluators: evaluators))
}

func pinnedCertificates() -> [SecCertificate] {

  var certificates: [SecCertificate] = []
  let directoryContents: [URL] = //...

  let certificateName: String = "app.cer" // Replaced for the demo

  let pinnedCertificateURL: URL? = directoryContents.first { (url: URL) in url.lastPathComponent == certificateName }

  if let pinnedCertificateURL: URL = pinnedCertificateURL {
    do {
      let pinnedCertificateData: CFData = try Data(contentsOf: pinnedCertificateURL) as CFData
      if let pinnedCertificate: SecCertificate = SecCertificateCreateWithData(nil, pinnedCertificateData) {
        certificates.append(pinnedCertificate)
      }
    } catch {
        //...
    }
  }
  return certificates
}

With the solution above, I am getting the error:

MyApp[374:21470] Task <DDC8F9FD-81A3-EBA4-8AA2-D7C99DD3E63B>.<1> HTTP load failed, 0/0 bytes (error code: -999 [1:89])

If I remove the line serverTrustManager: ServerTrustManager(evaluators: evaluators)), Alamofire works but without certificate pinning.

Any idea how to solve this and what I am doing wrong?

Thank you.


Solution

  • The String in your evaluator mapping should only be the host, not a full url:

    let evaluators: [String: ServerTrustEvaluating] = [
        "myapp.com": PinnedCertificatesTrustEvaluator(certificates: pinnedCertificates()),
      ]
    

    Also, you need to make sure the host exactly matches the domains you're making requests against.

    Additionally, Alamofire will automatically find certificates in your bundle so you may not need to find it yourself.