Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the reason of kSecTrustResultRecoverableTrustFailure?

I'd like to validate my ssl server certificates with some extra checks. And sometimes I get a

kSecTrustResultRecoverableTrustFailure 

instead of

kSecTrustResultProceed or kSecTrustResultUnspecified

It seems to happen if

  • the certificate is md5 hashed (IOS5)
  • the server does not present the root and intermediate certificates
  • the SecTrustSetAnchorCertificatesOnly(trust,YES) is set and the anchor certificate is only in the built in anchor certificates
  • the certificate is expired
  • ?

It depends on the AppleX509TP policy used to evaluate the trust.

My problem is I do not want to trust if the chain fails, but I want to trust if MD5 is used.

Is there a way to find out why the evaluation failed?

As an alternative is there a way to extract the CSSM_ALGID_MD5 from a SecCertificateRef?

like image 662
n3utrino Avatar asked Oct 10 '11 15:10

n3utrino


2 Answers

It may be a server certificate problem....

Check here, I solved my kSecTrustResultRecoverableTrustFailure problem, adding subjectAltName = DNS:example.com into openssl config file, specifically in server key generation...

If you are not using openssl to generate it, I'm sorry but I can help you.. Anyway if you want to use openssl, here is a good tutorial to generate those keys and sign then with your own root certificate authority.

From this tutorial, I just changed my openssl server config file to:

    [ server ]
    basicConstraints = critical,CA:FALSE
    keyUsage = digitalSignature, keyEncipherment, dataEncipherment
    extendedKeyUsage = serverAuth
    nsCertType = server
    subjectAltName = IP:10.0.1.5,DNS:office.totendev.com
    

Hope it helps !

EDITED:

My Server evaluation code:

#pragma mark - SERVER Auth Helper
//Validate server certificate with challenge
+ (BOOL)validateServerWithChallenge:(NSURLAuthenticationChallenge *)challenge {
//Get server trust management object a set anchor objects to validate it
SecTrustSetAnchorCertificates([challenge.protectionSpace serverTrust], (__bridge CFArrayRef)[self allowedCAcertificates]);
//Set to server trust management object to JUST ALLOW those anchor objects assigned to it (ABOVE), and disable apple CA trusts 
SecTrustSetAnchorCertificatesOnly([challenge.protectionSpace serverTrust], YES);
//Try to evalute it
SecTrustResultType evaluateResult = kSecTrustResultInvalid; //evaluate result
OSStatus sanityCheck = SecTrustEvaluate([challenge.protectionSpace serverTrust], &evaluateResult);
//Check for no evaluate error
if (sanityCheck == noErr) {
    //Check for result
    if ([[self class] validateTrustResult:evaluateResult]) { return YES ; }
}
//deny!
return NO ;
}
//Validate SecTrustResulType
+ (BOOL)validateTrustResult:(SecTrustResultType)result {
switch (result) {
    case kSecTrustResultProceed: { TDLog(kLogLevelHandshake,nil,@"kSecTrustResultProceed"); return YES ; }
        break;
    case kSecTrustResultConfirm: { TDLog(kLogLevelHandshake,nil,@"kSecTrustResultConfirm"); return YES ; }
        break;
    case kSecTrustResultUnspecified: { TDLog(kLogLevelHandshake,nil,@"kSecTrustResultUnspecified"); return YES ; }
        break;
    case kSecTrustResultDeny: { TDLog(kLogLevelHandshake,nil,@"kSecTrustResultDeny"); return YES ; }
        break;
    case kSecTrustResultFatalTrustFailure: { TDLog(kLogLevelHandshake,nil,@"kSecTrustResultFatalTrustFailure"); return NO ; }
        break;
    case kSecTrustResultInvalid: { TDLog(kLogLevelHandshake,nil,@"kSecTrustResultInvalid"); return NO ; }
        break;
    case kSecTrustResultOtherError: { TDLog(kLogLevelHandshake,nil,@"kSecTrustResultOtherError"); return NO ; }
        break;
    case kSecTrustResultRecoverableTrustFailure: { TDLog(kLogLevelHandshake,nil,@"kSecTrustResultRecoverableTrustFailure"); return NO ; }
        break;
    default: { TDLog(kLogLevelHandshake,nil,@"unkown certificate evaluate result type! denying..."); return NO ; }
        break;
}

}

Hope now it helps :) !

like image 114
gwdp Avatar answered Oct 09 '22 12:10

gwdp


Is there a way to find out why the evaluation failed?

Call SecTrustCopyProperties() after calling SecTrustEvaluate():

SecTrustRef trust = ...;
SecTrustResultType trustResult = kSecTrustResultOtherError;
OSStatus status = SecTrustEvaluate(trust, &trustResult);
if (trustResult == kSecTrustResultRecoverableTrustFailure) {
    NSArray * trustProperties = (__bridge_transfer id)
        SecTrustCopyProperties(certTrust);
}

trustProperties is an array of dictionaries, one dictionary per cert in the cert chain evaluated. Every dictionary has an entry title, containing the name of the cert and if the cert didn't evaluate, it also contains an entry error containing the error. E.g. if the problem was that the cert has expired, the value of error will be CSSMERR_TP_CERT_EXPIRED.

like image 32
Mecki Avatar answered Oct 09 '22 11:10

Mecki