2015-09-15 14 views
9

के साथ HTTPS अनुरोध करना मैं स्वयं-हस्ताक्षरित प्रमाणपत्र के साथ कस्टम सर्वर के लिए एक HTTPS अनुरोध करना चाहता हूं। मैं NSURLConnection वर्ग और प्रसंस्करण प्रमाणीकरण चुनौतियों उपयोग कर रहा हूँ, लेकिन हमेशा एक कंसोल में त्रुटि संदेश मिलता है:आईओएस 9 में स्वयं हस्ताक्षरित प्रमाणपत्र

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802) 

तो विधि "कनेक्शन: didFailWithError:":

Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x150094100>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey=<CFArray 0x1500ddd90 [0x19f6dab68]>{type = immutable, count = 1, values = (
    0 : <cert(0x14e6fb370) s: (server certificate name) i: (custom CA name)> 
)}, NSUnderlyingError=0x1504ae170 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSErrorFailingURLStringKey=https://217.92.80.156:9090/(method name and parameters), NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, kCFStreamPropertySSLPeerCertificates=<CFArray 0x1500ddd90 [0x19f6dab68]>{type = immutable, count = 1, values = (
    0 : <cert(0x14e6fb370) s: (server certificate name) i: (custom CA name)> 
)}, _kCFStreamPropertySSLClientCertificateState=2, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x150094100>, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., _kCFStreamPropertySSLClientCertificates=<CFArray 0x14e5ee8e0 [0x19f6dab68]>{type = mutable-small, count = 2, values = (
    0 : <SecIdentityRef: 0x15012cd40> 
    1 : <cert(0x15014aa70) s: (client certificate name) i: (custom CA name)> 
)}, _kCFStreamErrorDomainKey=3, NSErrorFailingURLKey=https://217.92.80.156:9090/(method name and parameters), _kCFStreamErrorCodeKey=-9802}}, NSErrorClientCertificateChainKey=<CFArray 0x14e5ee8e0 [0x19f6dab68]>{type = mutable-small, count = 2, values = (
    0 : <SecIdentityRef: 0x15012cd40> 
    1 : <cert(0x15014aa70) s: (client certificate name) i: (custom CA name)> 
)}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://217.92.80.156:9090/(method name and parameters), NSErrorFailingURLStringKey=https://217.92.80.156:9090/(method name and parameters), NSErrorClientCertificateStateKey=2} 

अनुप्रयोग निम्न त्रुटि के साथ बुलाया जाता है दो प्रमाणीकरण चुनौतियों (NSURLAuthenticationMethodClientCertificate और NSURLAuthenticationMethodServerTrust) प्राप्त करता है और उन्हें एक निम्नलिखित तरीके से संसाधित करता है:

- (void) connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 
{ 
    if(challenge.proposedCredential && !challenge.error) 
    { 
     [challenge.sender useCredential:challenge.proposedCredential forAuthenticationChallenge:challenge]; 

     return; 
    } 

    NSString *strAuthenticationMethod = challenge.protectionSpace.authenticationMethod; 
    NSLog(@"authentication method: %@", strAuthenticationMethod); 

    NSURLCredential *credential = nil; 
    if([strAuthenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) 
    { 
     // get identity and certificate from p.12 
     NSData *PKCS12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"]]; 

     NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:@"password" forKey:(__bridge id)kSecImportExportPassphrase]; 
     CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); 
     OSStatus securityError = SecPKCS12Import((__bridge CFDataRef)PKCS12Data,(__bridge CFDictionaryRef)optionsDictionary, &items); 

     SecIdentityRef identity = NULL; 
     SecCertificateRef certificate = NULL; 
     if(securityError == errSecSuccess) 
     { 
      CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0); 
      identity = (SecIdentityRef)CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity); 

      CFArrayRef array = (CFArrayRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemCertChain); 
      certificate = (SecCertificateRef)CFArrayGetValueAtIndex(array, 0); 
     } 

     credential = [NSURLCredential credentialWithIdentity:identity certificates:[NSArray arrayWithObject:(__bridge id)(certificate)] persistence:NSURLCredentialPersistenceNone]; 

     CFRelease(items); 
    } 
    else if([strAuthenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) 
    {  
     int trustCertificateCount = (int)SecTrustGetCertificateCount(challenge.protectionSpace.serverTrust); 
     NSMutableArray *trustCertificates = [[NSMutableArray alloc] initWithCapacity:trustCertificateCount]; 
     for(int i = 0; i < trustCertificateCount; i ++) 
     { 
      SecCertificateRef trustCertificate = SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, i); 
      [trustCertificates addObject:(__bridge id) trustCertificate]; 
     }    

     SecPolicyRef policyRef = NULL; 
     policyRef = SecPolicyCreateSSL(YES, (__bridge CFStringRef) challenge.protectionSpace.host); 

     SecTrustRef trustRef = NULL; 
     if(policyRef) 
     { 
      SecTrustCreateWithCertificates((__bridge CFArrayRef) trustCertificates, policyRef, &trustRef); 
      CFRelease(policyRef); 
     } 

     if(trustRef) 
     { 
//   SecTrustSetAnchorCertificates(trustRef, (__bridge CFArrayRef) [NSArray array]); 
//   SecTrustSetAnchorCertificatesOnly(trustRef, NO); 

      SecTrustResultType result; 
      OSStatus trustEvalStatus = SecTrustEvaluate(trustRef, &result); 
      if(trustEvalStatus == errSecSuccess) 
      { 
       // just temporary attempt to make it working. 
       // i hope, there is no such problem, when we have final working version of certificates. 
       if(result == kSecTrustResultRecoverableTrustFailure) 
       { 
        CFDataRef errDataRef = SecTrustCopyExceptions(trustRef); 
        SecTrustSetExceptions(trustRef, errDataRef); 

        SecTrustEvaluate(trustRef, &result); 
       } 

       if(result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) 
        credential = [NSURLCredential credentialForTrust:trustRef]; 
      } 

      CFRelease(trustRef); 
     } 
    } 
    else 
    { 
     DDLogWarn(@"Unexpected authentication method. Cancelling authentication ..."); 
     [challenge.sender cancelAuthenticationChallenge:challenge]; 
    } 

    if(credential) 
     [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; 
    else 
     [challenge.sender cancelAuthenticationChallenge:challenge]; 
} 

सीएफनेटवर्क डायग्नोस्टिक लॉग में मैं देख सकता हूं कि हैंडशेक प्रक्रिया शुरू होने वाली है। कम से कम ऐप "क्लाइंटहेल्लो" संदेश भेजता है, तो सर्वर अपना "सर्वरहेल्लो" संदेश भेजता है और प्रमाणीकरण की आवश्यकता होती है। और यहां ऐप प्रमाणीकरण प्रतिक्रिया भेजने की कोशिश करता है, लेकिन तुरंत त्रुटि प्राप्त करता है। (उसी समय, सर्वर लॉग में मुझे हैंडशेक के बारे में कोई संदेश नहीं दिखता है)। यहाँ नैदानिक ​​लॉग का हिस्सा है:

Sep 15 10:51:49 AppName[331] <Notice>: CFNetwork Diagnostics [3:49] 10:51:49.185 { 
    Authentication Challenge 
     Loader: <CFURLRequest 0x1501931c0 [0x19f6dab68]> {url = https://217.92.80.156:9090/(method name and parameters), cs = 0x0} 
    Challenge: challenge space https://217.92.80.156:9090/, ServerTrustEvaluationRequested (Hash f9810ad8165b3620) 
    } [3:49] 
Sep 15 10:51:49 AppName[331] <Notice>: CFNetwork Diagnostics [3:50] 10:51:49.189 { 
    Use Credential 
     Loader: <CFURLRequest 0x1501931c0 [0x19f6dab68]> {url = https://217.92.80.156:9090/(method name and parameters), cs = 0x0} 
    Credential: Name: server, Persistence: session 
    } [3:50] 
Sep 15 10:51:49 AppName[331] <Notice>: CFNetwork Diagnostics [3:51] 10:51:49.190 { 
    touchConnection 
       Loader: <CFURLRequest 0x1501931c0 [0x19f6dab68]> {url = https://217.92.80.156:9090/(method name and parameters), cs = 0x0} 
    Timeout Interval: 60.000 seconds 
    } [3:51] 
Sep 15 10:51:49 AppName[331] <Notice>: CFNetwork Diagnostics [3:52] 10:51:49.192 { 
    Response Error 
    Request: <CFURLRequest 0x14e5d02a0 [0x19f6dab68]> {url = https://217.92.80.156:9090/(method name and parameters), cs = 0x0} 
     Error: Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFNetworkCFStreamSSLErrorOriginalValue=-9802, kCFStreamPropertySSLPeerCertificates=<CFArray 0x1500ddd90 [0x19f6dab68]>{type = immutable, count = 1, values = (
       0 : <cert(0x14e6fb370) s: (server certificate name) i: (custom CA name)> 
      )}, _kCFStreamPropertySSLClientCertificateState=2, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x150094100>, _kCFStreamPropertySSLClientCertificates=<CFArray 0x14e5ee8e0 [0x19f6dab68]>{type = mutable-small, count = 2, values = (
       0 : <SecIdentityRef: 0x15012cd40> 
       1 : <cert(0x15014aa70) s: (client certificate name) i: (custom CA name)> 
      )}, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802} 
    } [3:52] 

हमारी पीठ के अंत उदाहरण ग्राहक पक्ष पर स्थापित किया जा सकता, तो मैं Info.plist फ़ाइल में किसी भी डोमेन अपवाद निर्धारित नहीं कर सकते। ऐप भी IPv4 फॉर्म में आईपी पते द्वारा सर्वर का अनुरोध कर सकता है, लेकिन डोमेन नाम से नहीं (जैसा कि यह मेरे उदाहरण में है)। किसी भी सफलता के बिना

  • इस्तेमाल किया NSURLConnection के बजाय NSURLSession, लेकिन;:

    क्या मैं करने की कोशिश की है

  • सर्वर कार्यान्वयन के लिए ऐप्पल की एटीएस आवश्यकताओं की जांच here (बैक-एंड डेवलपर सुनिश्चित है कि उनका कार्यान्वयन उन सभी को पूरा करता है);
  • स्टैक ओवरफ्लो और ऐप्पल के डेवलपर मंचों से विभिन्न हल किए गए मुद्दों के अनुसार ट्रस्ट सत्यापन के लिए एंकर प्रमाणपत्र सेट करने के साथ खेला गया;
  • डेवलपर मंचों पर विशेष रूप से similar पोस्ट और इसके संबंधित solution पर ध्यान दिया;

मैं आईओएस 9 जीएम बीज (13 ए 340 बिल्ड) और एक्सकोड 7 जीएम बीज (बिल्ड 7 ए 218) के साथ आईपैड एयर 2 पर https अनुरोध का परीक्षण कर रहा हूं। महत्वपूर्ण नोट: यह कार्यक्षमता आईओएस 8 के साथ ठीक काम करती है। इसे ध्यान में रखते हुए मैं मान सकता हूं कि यह समस्या हमारे सर्वर में है, लेकिन हमारे बैक एंड डेवलपर ने मुझे आश्वासन दिया कि सबकुछ ठीक है।

अब मैं विचारों से बाहर हूं। मैं सराहना करता हूं कि कोई मुझे संकेत दे सकता है, या कम से कम कुछ अन्य नैदानिक ​​सुझाव दे सकता है, जो विशेष त्रुटि प्रकट करेगा, "घातक चेतावनी" से अधिक विशिष्ट।

धन्यवाद।

संपादित करें 1: SecTrustEvaluate हमेशा kSecTrustResultRecoverableTrustFailure देता है, यही वजह है कि मैं वैकल्पिक हल के कुछ प्रकार की तलाश करनी है।

+0

क्या आपको कोई समाधान मिला है? मुझे यह समस्या भी हो रही है और मैं परीक्षण के लिए अपने स्थानीय सर्वर का उपयोग करना चाहता हूं लेकिन स्वयं हस्ताक्षरित प्रमाण पत्र के साथ काम करना असंभव है और मुझे आपकी ही त्रुटियां मिलती हैं ... –

+0

अभी तक, मुझे अन्य उच्च प्राथमिकता कार्यों पर काम करना है कई कारणों से। अगर मेरे पास समाधान है तो मैं आपसे संपर्क करूंगा। – alfared

+0

यह एक आईओएस पिटा प्रोटोकॉल त्रुटि है। (पीआईटीए दर्द में खड़ा है ....) – Josh

उत्तर

0

इस समस्या को कुछ समय पहले हल किया गया था। यह अमान्य स्व-हस्ताक्षरित प्रमाणपत्र साबित हुआ। यह ऐप्पल से सभी आवश्यकताओं को पूरा नहीं किया। दुर्भाग्य से मुझे नहीं पता, यह वास्तव में क्या था।

3

क्या आपने कनेक्शन समस्या का निदान करने के लिए nscurl का उपयोग किया है? वैकल्पिक रूप से

/usr/bin/nscurl --ats-diagnostics https://www.yourdomain.com 

, यदि आप 10 की जरूरत नहीं है: यदि आप Mac चल ओएस एक्स v10.11 है, तो आप कुछ इस तरह चला सकते हैं।11, आप नमूना कोड यहाँ डाउनलोड कर सकते हैं: https://developer.apple.com/library/mac/samplecode/SC1236/ और XCode के साथ इसे बनाने और इस तरह इसे चलाने के (अपने मशीन के अनुसार पथ को बदलने):

/Users/somebody/Library/Developer/Xcode/DerivedData/TLSTool-hjuytnjaqebcfradighsrffxxyzq/Build/Products/Debug/TLSTool s_client -connect www.yourdomain.com:443 

(ऊपर के लिए पूरा पथ ढूंढने के लिए, के बाद आपने अपने प्रोजेक्ट नेविगेटर में उत्पाद समूह खोल दिया है, टीएलएसटीूल पर राइट क्लिक करें, और "फाइंडर में दिखाएं" पर क्लिक करें।)

आप इस विषय पर पहले से ही ऐप्पल के टेक्नोट से जुड़े हैं, https://developer.apple.com/library/prerelease/ios/technotes/App-Transport-Security-Technote/ लेकिन आपने यह नहीं कहा कि क्या आप nscurl भाग गया या नहीं।

+0

मेरा वीएम का एंडपॉइंट/usr/bin/nscurl --ats-diagnostics में सभी परीक्षणों को पास करता है [https: //mydomain.local: 8888] (https: // mydomain। स्थानीय: 8888) लेकिन मुझे अभी भी सिम्युलेटर में त्रुटि मिलती है। –

3

इस के अनुसार: https://forums.developer.apple.com/message/36842#36842

HTTP लोड ठीक करने के लिए सबसे अच्छा तरीका में विफल रहा है (kCFStreamErrorDomainSSL, -9802) के रूप में Info.plist फ़ाइल में एक अपवाद सेट है:

<key>NSAppTransportSecurity</key> 
<dict> 
    <key>NSExceptionDomains</key> 
    <dict> 
    <key>test.testdomain.com</key> 
    <dict> 
     <key>NSIncludesSubdomains</key> 
     <true/> 
     <key>NSExceptionAllowsInsecureHTTPLoads</key> 
     <true/> 
    </dict> 
    </dict> 
</dict> 

महत्वपूर्ण मुद्दा यह है कि यह आईओएस 8 की तुलना में कम सुरक्षित नहीं है, आईओएस 9 द्वारा समर्थित पूर्ण एटीएस के रूप में सुरक्षित नहीं है।

+1

धन्यवाद - dict टैग बंद करने के बाद बहुत अच्छा काम किया। – dlw

+1

बहुत बहुत धन्यवाद, लेकिन: 1. यह सामान्य HTTP डाउनलोड की अनुमति देता है, और मुझे HTTPS (सुरक्षा कारणों से) की आवश्यकता है। 2. जैसा कि मैंने लिखा है, मैं अपवाद सूची में कोई भी डोमेन सेट नहीं कर सकता, क्योंकि हमारे ग्राहक अक्सर अपने सर्वर पर बैक-एंड इंस्टॉल करते हैं। उदाहरण के लिए, यह "server.company1.com" और "server.company2.com" हो सकता है। आपका जवाब मानता है कि ऐप को तीसरे कंपनी को बेचने के बाद मुझे ऐप को फिर से बनाना होगा और एक नया अपवाद डोमेन "server.company3.com" जोड़ना होगा। – alfared

+0

आप एटीएस के साथ-साथ इस ब्लॉग पोस्ट पर ऐप्पल के दस्तावेज़ से जानकारी के संयोजन का उपयोग करने में सक्षम हो सकते हैं विशेष रूप से स्वयं हस्ताक्षरित प्रमाणपत्र # 5 पर <5blog.httpwatch.com/2013/12/12/five-tips-for-using-self-signed-ssl-certificates-with-ios/> अपनी समस्या का समाधान करने के लिए (आपको शायद इसे तब तक दोबारा करने की आवश्यकता होगी जब तक आप इसे सही न करें)। – spirographer

0

मैं सिर्फ ur's.Now साथ एक ही समस्या से मुलाकात की मैं ठीक करता है it.It है क्योंकि TLS संस्करण और प्रमाण पत्र sign.As सेब के दस्तावेज़ नीचे apple's document

कहना तो मैं इस काम करते हैं info.plist setting

और यह

संबंधित मुद्दे