2017-02-06 14 views
0

Я использую NSURLSessionDelegate-х (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler для сложной проверки подлинности сервера, как это:IOS не принимает действующий самостоятельно подписанный сертификат и не принимает недопустимые

BOOL trusted = NO; 
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { 

    if (!cert) { 

     NSURL* certURL = [[NSBundle mainBundle] URLForResource: @"cert_new" withExtension: @"der"]; 
     NSData* certData = [NSData dataWithContentsOfURL: certURL]; 
     cert = SecCertificateCreateWithData(kCFAllocatorDefault, CFBridgingRetain(certData)); 

    } 

    SecPolicyRef policyRef = SecPolicyCreateBasicX509(); 
    SecCertificateRef certArray[1] = { cert }; 
    CFArrayRef certArrayRef = CFArrayCreate(NULL, (void *)certArray, 1, NULL); 
    SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; 

    // Create a policy that ignores the host name… 

    OSStatus err = SecTrustCreateWithCertificates(CFBridgingRetain((__bridge id _Nullable)(certArrayRef)), policyRef, &serverTrust); 
    CFRelease(policyRef); 
    if (err != noErr) 
    { 
     XLog(@"Error creating trust: %d", (int)err); 
     [challenge.sender cancelAuthenticationChallenge: challenge]; 
     return; 
    } 

    err = SecTrustSetAnchorCertificates(serverTrust, certArrayRef); 
    if (err == noErr) 
    { 
     SecTrustResultType trustResult; 
     err = SecTrustEvaluate(serverTrust, &trustResult); 

     trusted = (err == noErr && (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified)); 
    } 
    CFRelease(certArrayRef); 
    CFRelease(policyRef); 
    CFRelease(cert); 

} 
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; 
if (trusted) { 

    [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; 
    return; 


} else { 
    [challenge.sender cancelAuthenticationChallenge: challenge]; 
} 

Свидетельство я должен использовать это в формате PEM. Таким образом, я преобразовал его через OpenSSL в формате DER, как это:

openssl x509 -in pem_file.pem -out cert_new.der -outform DER 

Теперь кажется, что каждый сертификат будет (ли действительным или нет) быть принятым определенной битовой длины: trusted будет вычисляться YES. И действительный сертификат с более низкой длиной бита будет оценен до trusted = NO из-за kSecTrustResultRecoverableTrustFailure. Странное поведение ... Может кто-нибудь объяснить мне, как это сделать правильно?

Спасибо!

ответ

0

Теперь у меня есть рабочая версия:

// Build a new trust based on the supplied trust, so that we can set the policy… 
NSURLProtectionSpace* protectionSpace = challenge.protectionSpace; 
SecTrustRef trust = protectionSpace.serverTrust; 

CFIndex numCerts = SecTrustGetCertificateCount(trust); 
NSMutableArray* certs = [NSMutableArray arrayWithCapacity: numCerts]; 
for (CFIndex idx = 0; idx < numCerts; ++idx) 
{ 
    SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, idx); 
    [certs addObject: CFBridgingRelease(cert)]; 

} 

// Create a policy that ignores the host name… 
SecPolicyRef policy = SecPolicyCreateSSL(true, NULL); // SecPolicyCreateBasicX509(); 
OSStatus err = SecTrustCreateWithCertificates(CFBridgingRetain(certs), policy, &trust); 
CFRelease(policy); 
if (err != noErr) 
{ 
    //NSLogDebug(@"Error creating trust: %d", err); 
    [challenge.sender cancelAuthenticationChallenge: challenge]; 
    return; 
} 

// Set the root cert and evaluate the trust… 
NSURL* certURL = [[NSBundle mainBundle] URLForResource: @"doorbird_certificate" withExtension: @"der"]; 
NSData* certData = [NSData dataWithContentsOfURL: certURL]; 
SecCertificateRef rootCert = SecCertificateCreateWithData(kCFAllocatorDefault, CFBridgingRetain(certData)); 

NSArray* rootCerts = @[ CFBridgingRelease(rootCert) ]; 
err = SecTrustSetAnchorCertificates(trust, CFBridgingRetain(rootCerts)); 
if (err == noErr) 
{ 
    SecTrustResultType trustResult; 
    err = SecTrustEvaluate(trust, &trustResult); 
    SecTrustSetAnchorCertificatesOnly(trust, YES); 
    NSURLCredential* credential = [NSURLCredential credentialForTrust: trust]; 

    CFRelease(trust); 

    bool trusted = err == noErr; 
    trusted = trusted && (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified); 
    if (trusted) 
    { 

     [challenge.sender useCredential: credential forAuthenticationChallenge: challenge]; 
     return; 
    } 
} 

// An error occurred, or we don't trust the cert, so disallow it… 

[challenge.sender cancelAuthenticationChallenge: challenge]; 

Но только сертификаты с минимумом 1024 бит работают. Сертификатов с 512 бит нет. Может ли кто-нибудь подтвердить это?

Благодаря

Edit:

Я создал сертификаты, как описано здесь:

http://www.akadia.com/services/ssh_test_certificate.html

 Смежные вопросы

  • Нет связанных вопросов^_^