Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS 12: validate local certificate with URLSession

I have a service in the local network with uses custom signed certificate for HTTPS connection. I have the certificate (cer, p12, der, whatever, they are all convertible to each other). Question is what should I write in didReceiveChallenge when receiveing a chellenge of NSURLAuthenticationMethodClientCertificate?

And NO, I don't want to use NSAllowsArbitraryLoads, that would be a security breach. I'm about to use NSAllowsLocalNetworking so far.

- (void)URLSession:(NSURLSession*)session
    didReceiveChallenge:(NSURLAuthenticationChallenge*)challenge
      completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential* _Nullable))completionHandler {
    bool handled = false;

    // Always trust any server name (which is an IP address actually)
    NSLog(@"method: %@", challenge.protectionSpace.authenticationMethod);
    if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
        SecTrustRef trust = challenge.protectionSpace.serverTrust;
        if (trust != nullptr) {
            completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:trust]);
            handled = true;
        }
    }
    else if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate) {
        NSString* cerFile = [NSBundle.mainBundle pathForResource:@"dev" ofType:@"der"];
        NSData* data = [NSData dataWithContentsOfFile:cerFile];
        SecCertificateRef cert = SecCertificateCreateWithData(nil, (CFDataRef)data);


        // here I have to somehow validate using existing certificate...

    }

    if (!handled) {
        completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
    }

}
like image 876
Vladimir Avatar asked Nov 07 '22 14:11

Vladimir


1 Answers

Have a look in TrustKit https://github.com/datatheorem/TrustKit. It is the defacto standard for certificate validation and pinning.

For example code will be something like this:

func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        let validator = configureTrustKit().pinningValidator
        if(!validator.handle(challenge, completionHandler: completionHandler)){
            completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
        }
    }

func configureTrustKit()->TrustKit{
        let config = [kTSKPinnedDomains:
            [URLRepository.baseURL.host: [kTSKIncludeSubdomains: true,
                                          kTSKEnforcePinning: true,
                                          kTSKPublicKeyHashes: 

    URLRepository.pinForCurrentStage
                    ]
                ]
            ]
            return TrustKit(configuration: config)
        }

URLSession or frameworks like Alamofire have similar callbacks.

like image 113
netshark1000 Avatar answered Nov 14 '22 22:11

netshark1000