SecPolicy for mismatching hostname

Hello,


for development purposes, I would like to make my app accept the TLS connection to our development server, even though there is a mismatching hostname.


TN-2232 (1) states:

"If server trust evaluation fails because the server's DNS name does not match the DNS name in the certificate, you can work around the failure by overriding the DNS name in the trust object. To do this, call

SecPolicyCreateSSL
to create a new policy object with the correct server name and then call
SecTrustSetPolicies
to apply it to the trust object."


This does not appear to work for me:

#warning REMOVE BEFORE FLIGHT
    if ([challenge.protectionSpace.host isEqualToString:@"development.example"]) {
    
        SecTrustRef trust = challenge.protectionSpace.serverTrust;
        SecTrustResultType result;
        OSStatus status = SecTrustEvaluate(trust, &result);
        if (status == noErr && result == kSecTrustResultRecoverableTrustFailure) {
            SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("development.example"));
            SecTrustSetPolicies(trust, policy);
            status = SecTrustEvaluate(trust, &result);


At this point, the trust still evalutates to kSecTrustResultRecoverableTrustFailure. If I put in the name of the production server, the result is kSecTrustResultUnspecified.


Am I doing it wrong? Am I missing something?


If I simply use copy exceptions and set exceptions, the connection is accepted (of course).


Any other hints are appreciated!


1) https://developer.apple.com/library/content/technotes/tn2232/_index.html#//apple_ref/doc/uid/DTS40012884-CH1-SECTRUSTEXCEPTIONS

Accepted Answer

This is working for me. Pasted in below is some code that I used to verify it. You should be able to paste the code into a new command line tool project and call it from

main
.

Note If you put the code in an app, you’ll need to also disable ATS.

Note that

anarchistturtle.com
is my personal web server that just happens to be on my home network, and thus I can access it via its local name,
fluffy.local
. You’ll need to change the names to match your own setup.

IMPORTANT

anarchistturtle.com
has a TLS certificate issued by my own personal CA and thus, to run my test as is, you’d have to install that CA’s certificate.

My best guess as to what’s going on here is that your server has other trust issues, above and beyond that name. The Investigating Hard-To-Debug Trust Evaluation Failures section of TN2232 has other hints as to how to debug this.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
@import Foundation;

@interface Main : NSObject <NSURLSessionDelegate>

@property (nonatomic, strong, readwrite) NSURLSession * session;

@end

@implementation Main 

- (void)test {
    NSURL *                     url;
    NSURLRequest *              request;
    NSURLSessionConfiguration * config;

    config = [NSURLSessionConfiguration defaultSessionConfiguration];
    self.session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];

    url = [NSURL URLWithString:@"https://fluffy.local"];
    request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60.0];
    [[self.session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        #pragma unused(data)
        #pragma unused(response)
        if (error != nil) {
            NSLog(@"transport error %@ / %d", error.domain, (int) error.code);
        } else {
            NSLog(@"success");
        }
        exit(0);
    }] resume];

    dispatch_main();
}

static BOOL evaluateTrust(SecTrustRef trust) {
    OSStatus            err;
    SecTrustResultType  result;

    err = SecTrustEvaluate(trust, &result);
    return (err == errSecSuccess) && ( (result == kSecTrustResultProceed) || (result == kSecTrustResultUnspecified) );
}

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {
    #pragma unused(session)

    NSLog(@"challenge %@", challenge.protectionSpace.authenticationMethod);

    if ([challenge.protectionSpace.authenticationMethod isEqual:NSURLAuthenticationMethodServerTrust]) {
        BOOL            allow;
        SecTrustRef     trust;

        trust = challenge.protectionSpace.serverTrust;

        allow = evaluateTrust(trust);
        if ( ! allow ) {
            OSStatus        err;
            SecPolicyRef    policy;

            policy = SecPolicyCreateSSL(true, CFSTR("anarchistturtle.com"));
            err = SecTrustSetPolicies(trust, policy);
            if (err == errSecSuccess) {
                allow = evaluateTrust(trust);
            }

            CFRelease(policy);
        }
        if (allow) {
            completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:trust]);
        } else {
            completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
        }
    } else {
        completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
    }
}

@end

Thank you! The thing that got me was that kSecTrustResultUnspecified apparently is a "good" result

kSecTrustResultUnspecified
apparently is a "good" result

Yes, that’s super weird. There is, however, some logic to it:

  • kSecTrustResultProceed
    indicates that the user has taken specific action to trust this certificate.
  • kSecTrustResultUnspecified
    indicates that this certificate should be trusted, although the user hasn’t taken any specific action to allow it.

You can get

kSecTrustResultProceed
on macOS, where the system supports user-configurable trust settings. AFAIK you can’t get it on iOS, although iOS’s trust environment is evolving rapidly so it’s important that you accept both results.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
SecPolicy for mismatching hostname
 
 
Q