6

チーム、

双方向 SSL で構成された .net ベースの REST サービスがあります。iPhone 側では、サーバー証明書をデバイス プロファイルにインストールし、クライアント証明書はアプリケーション リソースとしてバンドルされています。サーバー証明書の検証は正常に機能していますが、クライアント証明書の認証は失敗します。以下は私のコードスニペットです

- (void)connection:(NSURLConnection *) connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    NSLog(@"Authentication challenge with host: %@", challenge.protectionSpace.host);

    if([challenge previousFailureCount] == 0) {
        NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
        NSString *authMethod = [protectionSpace authenticationMethod];
        if(authMethod == NSURLAuthenticationMethodServerTrust ) {
            NSLog(@"Verifying The Trust");
            [[challenge sender] useCredential:[NSURLCredential credentialForTrust:[protectionSpace serverTrust]] forAuthenticationChallenge:challenge];
        } 
        else if(authMethod == NSURLAuthenticationMethodClientCertificate ) {
            NSLog(@"Trying Certificate");
            // load cert

            NSString *thePath = [[NSBundle mainBundle]
                                 pathForResource:@"Myclientcertificate" ofType:@"pfx"];
            NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
            CFDataRef inPKCS12Data = (CFDataRef)PKCS12Data;             

            OSStatus status = noErr;
            SecIdentityRef myIdentity;
            SecTrustRef myTrust;

            status = extractIdentityAndTrust(
                                             inPKCS12Data,
                                             &myIdentity,
                                             &myTrust); 

            SecTrustResultType trustResult;

            if (status == noErr) {                                      
                status = SecTrustEvaluate(myTrust, &trustResult);
            }

            SecCertificateRef myCertificate;
            SecIdentityCopyCertificate(myIdentity, &myCertificate);
            const void *certs[] = { myCertificate };
            CFArrayRef certsArray = CFArrayCreate(NULL, certs, 1, NULL);


            NSURLCredential *credential = [NSURLCredential credentialWithIdentity:myIdentity certificates:(NSArray*)certsArray persistence:NSURLCredentialPersistencePermanent];

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


        }
    } 

}

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    BOOL result;
    NSLog(@"canAuthenticateAgainstProtectionSpace: %@", protectionSpace.authenticationMethod);
    if ([protectionSpace authenticationMethod] == NSURLAuthenticationMethodServerTrust) {
        result= YES;
    } else if([protectionSpace authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
        result = YES;
    }   
    return result;
}

OSStatus extractIdentityAndTrust(CFDataRef inPKCS12Data, SecIdentityRef *identity, SecTrustRef *trust){
    OSStatus securityError = errSecSuccess;


    CFStringRef password = CFSTR("1234");
    const void *keys[] =   { kSecImportExportPassphrase };
    const void *values[] = { password };
    CFDictionaryRef optionsDictionary = CFDictionaryCreate(
                                                           NULL, keys,
                                                           values, 1,
                                                           NULL, NULL); 
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    securityError = SecPKCS12Import(inPKCS12Data,
                                    optionsDictionary,
                                    &items);  

      if (securityError == 0) {                                  
        CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
        const void *tempIdentity = NULL;
        tempIdentity = CFDictionaryGetValue (myIdentityAndTrust,
                                             kSecImportItemIdentity);
        *identity = (SecIdentityRef)tempIdentity;
        const void *tempTrust = NULL;
        tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);
        *trust = (SecTrustRef)tempTrust;
    }

    if (optionsDictionary) {
        CFRelease(optionsDictionary);
    }

    return securityError;
}

下記のエラーで接続に失敗しています。

{
    NSErrorFailingURLKey = "https://myIpdaddress/Service1.svc/test/random";
    NSErrorFailingURLStringKey = "https://myIpdaddress/Service1.svc/test/random";
    NSLocalizedDescription = "The server \U201cmyIpdaddress\U201d requires a client certificate.";
    NSUnderlyingError = "Error Domain=kCFErrorDomainCFNetwork Code=-1206 \"The server \U201cmyIpdaddress\U201d requires a client certificate.\" UserInfo=0x4b240b0 {NSErrorFailingURLKey=https://myIpdaddress/Service1.svc/test/random, NSErrorFailingURLStringKey=https://myIpdaddress/Service1.svc/test/random, NSLocalizedDescription=The server \U201cmyIpdaddress\U201d requires a client certificate.}";
}

これを再愛用する方法を教えてください。

4

1 に答える 1

1

私はこれとまったく同じ問題に遭遇していました。

私にとっての修正は、「ホスト」HTTPヘッダーを修正することでした。

私が使用していたものには、ポートとパスの一部が含まれていました。このヘッダーを修正して、URL のホスト部分のみを含めるようにすると、動作が開始されました。

ホスト ヘッダーが間違っていたときに、サーバーが私の ID を拒否していたと思います。また、「クライアント証明書が必要です」というメッセージは、提示された証明書をサーバーが受け入れなかったことを意味する一般的な応答であると思います。

于 2012-02-09T16:10:00.640 に答える