Skip to content

Instantly share code, notes, and snippets.

@cepages
Created June 2, 2020 15:03
Show Gist options
  • Select an option

  • Save cepages/b8abc054be152f45a149208f9857f84d to your computer and use it in GitHub Desktop.

Select an option

Save cepages/b8abc054be152f45a149208f9857f84d to your computer and use it in GitHub Desktop.

Revisions

  1. cepages created this gist Jun 2, 2020.
    86 changes: 86 additions & 0 deletions Using Self signed cert for WKWebview
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,86 @@
    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)
    }
    }
    }