Skip to content

Instantly share code, notes, and snippets.

@0xPr0xy
Last active October 3, 2018 10:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 0xPr0xy/49f30d61737f8d4840463e350781ff6e to your computer and use it in GitHub Desktop.
Save 0xPr0xy/49f30d61737f8d4840463e350781ff6e to your computer and use it in GitHub Desktop.
//
// CertificatePinner.swift
// BenuApp
//
// Created by Peter IJlst | The Mobile Company on 02/10/2018.
// Copyright © 2018 The Mobile Company. All rights reserved.
//
import WebKit
import Alamofire
/// Class that provides certificate pinning logic for Alamofire and WKWebView requests
class CerPinsky: SessionDelegate {
/// Return a session manager configured for certificate pinning
lazy var sessionManager: SessionManager = {
sessionDidReceiveChallengeWithCompletion = { session, challenge, completionHandler in
self.handleChallenge(challenge: challenge, completionHandler: completionHandler)
}
return SessionManager(configuration: .default, delegate: self, serverTrustPolicyManager: nil)
}()
/// Execute certificate pinning
///
/// - Parameters:
/// - challenge: the authentication challenge
/// - completionHandler: the completion handler
private func handleChallenge(challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
let serverTrust = challenge.protectionSpace.serverTrust else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
var secResult: SecTrustResultType = .invalid
let status = SecTrustEvaluate(serverTrust, &secResult)
guard status == errSecSuccess,
let serverCert = SecTrustGetCertificateAtIndex(serverTrust, 1) else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let certData = SecCertificateCopyData(serverCert)
let data = CFDataGetBytePtr(certData);
let size = CFDataGetLength(certData);
let domainCertificate = NSData(bytes: data, length: size)
let includedCertificatePaths = Bundle.main.paths(forResourcesOfType: "crt", inDirectory: "")
for includedCertificatePath in includedCertificatePaths {
if let includedCertificate = NSData(contentsOfFile: includedCertificatePath) {
if domainCertificate.isEqual(to: includedCertificate as Data) {
completionHandler(.useCredential, URLCredential(trust: serverTrust))
return
}
}
}
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
}
// MARK: - WKNavigationDelegate Conformance
extension CerPinsky: WKNavigationDelegate {
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
handleChallenge(challenge: challenge, completionHandler: completionHandler)
}
}
// MARK: - UIWebViewDelegate Conformance
extension CerPinsky: UIWebViewDelegate {
override func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
handleChallenge(challenge: challenge, completionHandler: completionHandler)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment