Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use an AVPlayer with HTTPS and self-signed server certificates?

I have a server that uses self-signed SSL certificates for HTTPS. I have the self-signed root cert bundled into my app. I'm able to get NSURLSession to use and validate the self-signed root cert by using SecTrustSetAnchorCertificates() in the -URLSession:didReceiveChallenge:completionHandler: delegate method.

When I try this with AVPlayer, however, I get an SSL error and playback fails. This is my AVAssetResourceLoader delegate implementation:

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForResponseToAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if ([challenge.protectionSpace.authenticationMethod isEqual:NSURLAuthenticationMethodServerTrust]) {
        SecTrustRef trust = challenge.protectionSpace.serverTrust;
        SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)self.secTrustCertificates);

        SecTrustResultType trustResult = kSecTrustResultInvalid;
        OSStatus status = SecTrustEvaluate(trust, &trustResult);

        if (status == errSecSuccess && (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed)) {
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:trust] forAuthenticationChallenge:challenge];
            return YES;
        } else {
            [challenge.sender cancelAuthenticationChallenge:challenge];
            return YES;
        }
    }
    return NO;
}

The delegate gets called, and the trustResult equates to kSecTrustResultUnspecified (which means "trusted, without explicit user override"), as expected. However, playback fails shortly after, with the following AVPlayerItem.error:

Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, NSUnderlyingError=0x16c35720 {Error Domain=NSOSStatusErrorDomain Code=-1200 "(null)"}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made.}

How can I get AVPlayer to accept the SSL handshake?

like image 497
Nick Forge Avatar asked Jul 06 '16 06:07

Nick Forge


1 Answers

This implementation has worked for me:

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader
shouldWaitForResponseToAuthenticationChallenge:(NSURLAuthenticationChallenge *)authenticationChallenge
{
    //server trust
    NSURLProtectionSpace *protectionSpace = authenticationChallenge.protectionSpace;
    if ([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        [authenticationChallenge.sender useCredential:[NSURLCredential credentialForTrust:authenticationChallenge.protectionSpace.serverTrust] forAuthenticationChallenge:authenticationChallenge];
        [authenticationChallenge.sender continueWithoutCredentialForAuthenticationChallenge:authenticationChallenge];
    }
    else { // other type: username password, client trust...
    }
    return YES;
}

However, it stopped working as of iOS 10.0.1 for a reason I have yet to discern. So this may or may not be helpful to you. Good luck!

like image 171
T'Pol Avatar answered Sep 28 '22 08:09

T'Pol