2015-11-05 70 views
1

我有一個應用程序,我需要執行一種2步驟認證和長話短說我從服務器獲取每用戶base64編碼的pem格式證書並在每個服務器上使用它們請求。iOS:遇到自簽名證書問題。 SSL握手錯誤(-9824)

首先我生成一個密鑰對,做一個CSR,給他們CSR,他們給我證書,這是我必須使用它並失敗的地方。我收到以下錯誤控制檯中的每個單獨的請求:

CFNetwork的SSLHandshake失敗(-4)

CFNetwork的SSLHandshake失敗(-9824)

CFNetwork的SSLHandshake失敗( -9824)

NSURLConnection/CFURLConnection HTTP加載失敗(kCFStreamErrorDomainSSL,-9824)

我的做法是這樣的:

-grab從PEM的DER編碼數據的格式化簽名的證書,他們就送我

-make一個SecCertificateRef我添加到鑰匙扣

-query對於SecIdentityRef中的標籤鑰匙扣

- 然後做一些大多不需要的東西,比如從身份證書中獲取SecCertificateRef和私鑰以確定發生了什麼

- 我還從服務器中插入了一個CA證書,並從鑰匙串中獲取對它的引用(不確定是否需要將它用於證書,但是我嘗試使用或不使用它 - 結果是相同)

- 然後,我使用身份和證書初始化憑證,並在獲得NSURLAuthenticationMethodClientCertificate auth方法時使用它(我沒有執行檢查,但這是我除了服務器信任之外所得到的)。

所以到目前爲止,沒有什麼是NULL,所有的東西都被初始化並且看起來不錯,但是請求並不成功。當我嘗試在所有請求中使用服務器信任憑證時,我會通過並且不會收到錯誤信息,但是我的服務器正在給它發送安全錯誤。只要我使用自定義憑據進行任何挑戰,我都會收到上述錯誤。

注:我知道代碼是凌亂的,我不應該將每個請求證書,但它仍然在進步非常早期的工作,這不是因爲裁判得到正確的初始化

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{ 
    SSLConnectionWrapper *wrapper = [self wrapperForConnection:connection]; 


    NSString *certStringBase64 = [[NSUserDefaults standardUserDefaults] SSLCertificateForUserWithID:wrapper.userID]; 
    NSData *certData = [[NSData alloc] initWithBase64EncodedString:certStringBase64 options:0]; 
    NSString *certString = [[NSString alloc] initWithData:certData encoding:NSUTF8StringEncoding]; 

    certString = [certString stringByReplacingOccurrencesOfString:@"-----BEGIN CERTIFICATE-----" withString:@""]; 
    certString = [certString stringByReplacingOccurrencesOfString:@"-----END CERTIFICATE-----" withString:@""]; 
    certString = [[certString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] componentsJoinedByString:@""]; 
    //at this point certString contains the DER encoded certificate data 

    SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)([[NSData alloc] initWithBase64EncodedString:certString options:kNilOptions])); 

    OSStatus err = SecItemAdd((__bridge CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys: 
                  (__bridge id) kSecClassCertificate, kSecClass, 
                  cert, kSecValueRef, 
                  kCFBooleanTrue, kSecReturnPersistentRef, 
                  [NSString stringWithFormat:@"CertLabel_UserID_%@", wrapper.userID], kSecAttrLabel, 
                  nil], NULL); 

    const void *keys[] = { kSecClass, kSecReturnRef, kSecAttrLabel }; 

    const void *values[] = { kSecClassIdentity, kCFBooleanTrue, (__bridge const void *)([NSString stringWithFormat:@"CertLabel_UserID_%@", wrapper.userID]) }; 

    CFDictionaryRef queryForIdentityDict = CFDictionaryCreate(NULL, keys, values, 
                   3, NULL, NULL); 

    SecIdentityRef identityKeychainRef = NULL; 
    OSStatus s = SecItemCopyMatching(queryForIdentityDict, (CFTypeRef *)&identityKeychainRef); 

    SecCertificateRef certKeychainRef = NULL; 
    OSStatus s2 = SecIdentityCopyCertificate(identityKeychainRef, &certKeychainRef); 

    SecKeyRef privateKey; 
    SecIdentityCopyPrivateKey(identityKeychainRef, &privateKey); 

    NSString *stringForCACert = [self stringForCACert]; 

    SecCertificateRef caCert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)([[NSData alloc] initWithBase64EncodedString:stringForCACert options:kNilOptions])); 
    OSStatus s3 = SecItemAdd((__bridge CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys: 
                  (__bridge id) kSecClassCertificate, kSecClass, 
                  caCert, kSecValueRef, 
                  @"CACert", kSecAttrLabel, 
                  nil], NULL); 

    const void *keys1[] = { kSecClass, kSecReturnRef, kSecAttrLabel }; 

    const void *values1[] = { kSecClassCertificate, kCFBooleanTrue, @"CACert" }; 

    CFDictionaryRef queryForCACert = CFDictionaryCreate(NULL, keys1, values1, 
                   3, NULL, NULL); 

    SecCertificateRef caCertKeychainRef = NULL; 
    OSStatus s4 = SecItemCopyMatching(queryForCACert, (CFTypeRef *)&caCertKeychainRef); 

    NSURLCredential *credential = [[NSURLCredential alloc] initWithIdentity:identityKeychainRef certificates:@[ (__bridge id)certKeychainRef, (__bridge id) caCertKeychainRef] persistence:NSURLCredentialPersistencePermanent]; 

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { 

     [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; 
    }else{ 
     [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; 
    } 

} 

回答

0
問題

這是服務器面臨的認證挑戰。您可以通過下面的代碼繞過(使用NSURLConnection的)

+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host { 
    return YES; 
} 

注意:如果您在應用商店上傳應用程序,不要使用上面。

對於iOS 9個以上是行不通的,請編輯的plist如下

<key>NSAppTransportSecurity</key> 
<dict> 
    <key>NSAllowsArbitraryLoads</key> 
    <true/> 
</dict> 
+0

我已經啓用了AllowsArbitraryLoads。我也嘗試過這個類別,但它並沒有做到這一點。它被調用,但不會阻止發生握手錯誤。它也與iOS 9的TLS 1.2策略無關。 –