2017-11-06 3 views
0

내 서버에서 자체 서명 된 SSL 인증서를 사용합니다. 그리고 iOS는 내가하는 일과 상관없이 그들을 받아들이고 싶지 않습니다. 이건 내 코드입니다 : NSURLSessionAuthChallengeUseCredential이 도움이되지 않습니다. iOS가 내 서버를 신뢰하도록 만드는 방법은 무엇입니까?

- (void)URLSession:(NSURLSession *)session 
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge 
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, 
         NSURLCredential *credential))completionHandler 
{ 
NSString* authenticationMethod = challenge.protectionSpace.authenticationMethod; 

if (![authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) 
{ 
    completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); 
    return; 
} 

SecTrustRef trust = challenge.protectionSpace.serverTrust; 

CFIndex count = SecTrustGetCertificateCount(trust); 
CFMutableArrayRef originalCertificates = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 

for (CFIndex i = 0; i < count; i++) 
{ 
    SecCertificateRef certRef = SecTrustGetCertificateAtIndex(trust, i); 
    CFArrayAppendValue(originalCertificates, certRef); 
    CFStringRef certSummary = SecCertificateCopySubjectSummary(certRef); 
    NSLog(@"CERT %ld %@", i, certSummary); 
} 

//SecPolicyRef policyRef = SecPolicyCreateSSL(true, CFSTR("192.168.50.80")); 
SecPolicyRef policyRef = SecPolicyCreateBasicX509(); 
SecTrustRef newTrust; 

OSStatus status = SecTrustCreateWithCertificates(originalCertificates, policyRef, & newTrust); 

assert(status == noErr); 

NSString* path = [[NSBundle mainBundle] pathForResource:@"no1bcCA" ofType:@"der"]; 
NSData* data = [NSData dataWithContentsOfFile:path]; 
SecCertificateRef cert = SecCertificateCreateWithData(NULL, (CFDataRef) data); 

assert(cert); 

NSString* rootPath = [[NSBundle mainBundle] pathForResource:@"no1bcRootCA" ofType:@"der"]; 
NSData* rootData = [NSData dataWithContentsOfFile:rootPath]; 

SecCertificateRef rootCert = SecCertificateCreateWithData(NULL, (CFDataRef) rootData); 
assert(rootCert); 

SecTrustSetAnchorCertificates(newTrust, (CFArrayRef)@[(__bridge id)rootCert, (__bridge id)cert]); 
SecTrustSetAnchorCertificatesOnly(newTrust, NO); 

SecTrustResultType trustResult; 

SecTrustEvaluate(newTrust, &trustResult); 

if (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed) 
{ 
    NSURLCredential* credential = [NSURLCredential credentialForTrust:newTrust]; 
    completionHandler(NSURLSessionAuthChallengeUseCredential, credential); 

} 
else 
{ 

completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); 
} 
} 

그렇게 trustResultkSecTrustResultUnspecified하지만 내 NSURLSessionDataTask의 완성 처리기에서 나는 여전히 다음과 같은 오류가 나타납니다

Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x6000003040b0>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey=(
"<cert(0x7f81ef80ca00) s: sems.no1bc.local i: no1bcCA>", 
"<cert(0x7f81ef80d400) s: no1bcCA i: no1bcRootCA>", 
"<cert(0x7f81ef82b800) s: no1bcRootCA i: no1bcRootCA>" 
), NSUnderlyingError=0x604000255030 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x6000003040b0>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=(
"<cert(0x7f81ef80ca00) s: sems.no1bc.local i: no1bcCA>", 
"<cert(0x7f81ef80d400) s: no1bcCA i: no1bcRootCA>", 
"<cert(0x7f81ef82b800) s: no1bcRootCA i: no1bcRootCA>" 
)}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://192.168.50.80/pgpuniversaldesktop, NSErrorFailingURLStringKey=https://192.168.50.80/pgpuniversaldesktop, NSErrorClientCertificateStateKey=0} 

내가 복구 제안을 사랑합니다. 그것은 말합니다

Would you like to connect to the server anyway?

네, 어떻게됩니까? 나는 무엇을해야합니까?

<key>NSAppTransportSecurity</key> 
<dict> 
    <key>NSExceptionDomains</key> 
    <dict> 
     <key>192.168.50.80</key> 
     <dict> 
      <key>NSIncludesSubdomains</key> 
      <true/> 
      <key>NSExceptionAllowsInsecureHTTPLoads</key> 
      <true/> 
      <key>NSExceptionMinimumTLSVersion</key> 
      <string>TLSv1.2</string> 
      <key>NSExceptionRequiresForwardSecrecy</key> 
      <false/> 
      <key>NSRequiresCertificateTransparency</key> 
      <false/> 
     </dict> 
    </dict> 
</dict> 

그러나 그것은 결코 도움이되지 : 그렇다 나는 또한 ATS와 재생하려고하는 모든에서

이 내가 PLIST 파일에 넣어 것입니다. 따라서 iOS에게 "이 서버를 신뢰하고 신뢰하십시오."라고 분명히 말하지만 그렇지 않습니다. 이유는 무엇일까요? 시스템에서 서버를 신뢰하도록하려면 어떻게해야합니까? 그리고 어쨌든 서버에 어떻게 연결해야합니까?

Mac 응용 프로그램에서이 코드를 실행하면 문제없이 작동한다는 것은 재미 있습니다. 하지만 iOS에서 작동하지 않습니다

답변

0

서버가 오래된 TLS를 실행 한 것으로 나타났습니다. Mac은 iOS가 아니지만 그것을 처리 할 수 ​​있었으므로 어떤 경우이든 서버에 연결할 수 없었습니다. 해결책은 서버를 수정하는 것이 었습니다.

0

iOS 11에서 분명히 해당 도메인에 대해 NSExceptionRequiresForwardSecrecy에서 false까지 설정해야합니다. 그렇지 않으면 App Transport Security는 맞춤 인증서가 맞춤 인증 코드에 도달하는 것을 허용하지 않습니다. 틀림없이 이것은 버그입니다.

자세한 내용은 Apple 개발자 포럼의 this thread을 참조하십시오.