2


    SSLチャネルを使用してWebサービスを使用するのは初めてです。かなり良い検索を行った後、NSURLConnection デリゲート API を使用して SSL/HTTPS 認証を実行する方法を見つけました。以下は、実際の認証を行うコード スニペットです。

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
[self printLogToConsole:@"Authenticating...."];
[self printLogToConsole:[NSString stringWithFormat:@"\n%@\n", [challenge description]]];
NSLog(@"\n\nserverTrust: %@\n", [[challenge protectionSpace] serverTrust]);

/* Extract the server certificate for trust validation
 */
NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
assert(protectionSpace);
SecTrustRef trust = [protectionSpace serverTrust];    
assert(trust);
CFRetain(trust); // Make sure this thing stays around until we're done with it
NSURLCredential *credential = [NSURLCredential credentialForTrust:trust];


/* On iOS 
 * we need to convert it to 'der' certificate. It can be done easily through Terminal as follows:
 * $ openssl x509 -in certificate.pem -outform der -out rootcert.der
 */
NSString *path = [[NSBundle mainBundle] pathForResource:@"rootcert" ofType:@"der"];
assert(path);
NSData *data = [NSData dataWithContentsOfFile:path];
assert(data);

/* Set up the array of certificates, we will authenticate against and create credentials */
SecCertificateRef rtCertificate = SecCertificateCreateWithData(NULL, CFBridgingRetain(data));
const void *array[1] = { rtCertificate };
trustedCerts = CFArrayCreate(NULL, array, 1, &kCFTypeArrayCallBacks);
CFRelease(rtCertificate); // for completeness, really does not matter

/* Build up the trust anchor using our root cert */
int err;
SecTrustResultType trustResult = 0;
err = SecTrustSetAnchorCertificates(trust, trustedCerts);
if (err == noErr) {
    err = SecTrustEvaluate(trust, &trustResult);
}
CFRelease(trust); // OK, now we're done with it

[self printLogToConsole:[NSString stringWithFormat:@"trustResult: %d\n", trustResult]];

/* http://developer.apple.com/library/mac/#qa/qa1360/_index.html
 */
BOOL trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultConfirm) || (trustResult == kSecTrustResultUnspecified));

// Return based on whether we decided to trust or not
if (trusted) {
    [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
    [self printLogToConsole:@"Success! Trust validation successful."];
} else {
    [self printLogToConsole:@"Failed! Trust evaluation failed for service root certificate.\n"];
    [[challenge sender] cancelAuthenticationChallenge:challenge];
}

}

しかし、次のエラーが発生します。

2012-06-11 17:10:12.541 SecureLogin[3424:f803] Error during connection: Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x682c790 {NSErrorFailingURLKey=https://staging.esecure.url/authentication/signin/merchants, NSErrorFailingURLStringKey=https://staging.esecure.url/authentication/signin/merchants}


サーバーから取得して「der」形式に変換したものと同じ証明書を使用しています。iOS 5.x 用のアプリを作成しています。何かを見逃しているかどうかはわかりません。あなたの提案を教えてください。

ありがとう。

編集 ここで証明書を調べた後、出力は次のようになります。 Portecle アプリの検査


何か問題がある場合はお知らせください。

ありがとう。

4

2 に答える 2

2

REST インターフェイスを使用するために RestKit を使用しているため、コードが有効かどうかはわかりませんが、発生する最も一般的な問題は、アドレスの場合、自己署名証明書に Web サービスを指す拡張子NSURLErrorDomain Code=-1012がないことです。subject alternative name

証明書を調べるには、Portecle アプリをダウンロードします。これは、ssl 証明書の内部を確認する必要がある場合に非常に便利です。それを実行し、メニューから Examine->Examine Certificate を選択し、証明書に移動します。証明書に関する基本情報が表示されるので、[調査] ボタンを押してから [サブジェクトの別名] をクリックし、Web サービスの適切な IP アドレスがそこにあることを確認します。そうでない場合は、この情報を使用して証明書を再度作成する必要があります。

于 2012-06-11T13:24:06.933 に答える
1

この問題を解決する方法を見つけました。

最終的に、クライアントとサーバーの信頼証明書をバイト単位で比較しました。このような自己署名証明書の問題を解決する別の方法があるかもしれませんが、この解決策はうまくいきました。CFData オブジェクトを使用して、クライアント証明書とサーバー証明書をバイト単位で比較する方法を次に示します (Apple が提供する「AdvancedURLConnections」のサンプル コードを参照することもできます)。

success = NO;
        pServerCert = SecTrustGetLeafCertificate(trust);
        if (clientCert != NULL) {
            CFDataRef       clientCertData;
            CFDataRef       serverCertData;

            clientCertData = SecCertificateCopyData(clientCert);
            serverCertData   = SecCertificateCopyData(pServerCert);

            assert(clientCertData != NULL);
            assert(serverCertData   != NULL);

            success = CFEqual(clientCertData, serverCertData);

            CFRelease(clientCertData);
            CFRelease(serverCertData);
        }
        if (success) {
            [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
            [self printLogToConsole:@"Success! Trust validation successful."];
        } else {
            [self printLogToConsole:@"Failed! Trust evaluation failed for service root certificate.\n"];
            [[challenge sender] cancelAuthenticationChallenge:challenge];
        }

これが、同様の問題の解決策を探している誰かに役立つことを願っています,

ありがとう。

于 2012-07-23T08:15:14.927 に答える