Skip to content

Instantly share code, notes, and snippets.

@cepages
Created June 2, 2020 15:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cepages/b8abc054be152f45a149208f9857f84d to your computer and use it in GitHub Desktop.
Save cepages/b8abc054be152f45a149208f9857f84d to your computer and use it in GitHub Desktop.
import Foundation
import WebKit
class SelfSignedCert: NSObject, WKNavigationDelegate {
private let CERT_NAME = "ca"
private let CERT_TYPE = "der"
public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.protectionSpace.authenticationMethod != NSURLAuthenticationMethodServerTrust {
NSLog("SelfSignedCert: Unexpected authentication method \(challenge.protectionSpace.authenticationMethod)");
completionHandler(.rejectProtectionSpace, .none)
}
guard let trust = challenge.protectionSpace.serverTrust else {
completionHandler(.rejectProtectionSpace, .none)
return
}
// First load our extra root-CAs to be trusted from the app bundle.
let rootCa = CERT_NAME
guard let rootCaPath = Bundle(for: SelfSignedCert.self).path(forResource: rootCa, ofType: CERT_TYPE), let rootCaData = NSData(contentsOfFile: rootCaPath) else {
completionHandler(.rejectProtectionSpace, .none)
return
}
let rootCert = SecCertificateCreateWithData(nil, rootCaData)
SecTrustSetAnchorCertificates(trust, [rootCert] as CFArray)
SecTrustSetAnchorCertificatesOnly(trust, false)
evaluateTrust(trust: trust) { (trustResult) in
self.evaluateTrustResult(trust:trust, trustResult: trustResult, tryToFixTrust: true, completionHandler: completionHandler)
}
}
private func evaluateTrust(trust:SecTrust, completionHandler: @escaping (_ trustResult:SecTrustResultType) -> Void) {
var trustResult: SecTrustResultType = SecTrustResultType.invalid
if #available(iOS 13.0, *) {
if (SecTrustEvaluateWithError(trust, nil)) {
trustResult = SecTrustResultType.proceed;
} else {
SecTrustGetTrustResult(trust, &trustResult)
}
} else {
SecTrustEvaluate(trust, &trustResult)
}
completionHandler(trustResult);
}
private func evaluateTrustResult(trust:SecTrust, trustResult:SecTrustResultType, tryToFixTrust:Bool, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
switch trustResult {
case SecTrustResultType.unspecified,
SecTrustResultType.proceed:
// Trust certificate.
let credential = URLCredential(trust: trust)
completionHandler(.useCredential, credential);
case SecTrustResultType.recoverableTrustFailure:
if (!tryToFixTrust) {
completionHandler(.rejectProtectionSpace, .none)
return
}
// Fix the result if it's a recoverable trust failure
let errDataRef = SecTrustCopyExceptions(trust)
SecTrustSetExceptions(trust, errDataRef)
evaluateTrust(trust: trust) { (trustResult) in
self.evaluateTrustResult(trust:trust, trustResult: trustResult, tryToFixTrust: false, completionHandler: completionHandler)
}
default:
// We reject the challenge
completionHandler(.rejectProtectionSpace, .none)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment