6

自己署名証明書を使用して認証するための、かなり標準的な NSURLConnection コールバックを次に示します。

- (SecCertificateRef)certRefFromDerNamed:(NSString*)derFileName resultingDataRef:(CFDataRef*)dataRefPtr{
    NSString *thePath = [[NSBundle mainBundle] pathForResource:derFileName ofType:@"der"];
    NSData *certData = [[NSData alloc] initWithContentsOfFile:thePath];
    CFDataRef certDataRef = (__bridge_retained CFDataRef)certData;
    SecCertificateRef cert = SecCertificateCreateWithData(NULL, certDataRef);
    *dataRefPtr = certDataRef;
    return cert;
}

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {

if (connection == self.connection) {

    BOOL trusted = NO;
     if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {

        SecPolicyRef policyRef = SecPolicyCreateBasicX509();

        SecCertificateRef cert1;
        CFDataRef certData1;

        cert1 = [self certRefFromDerNamed:@"some3rdpartycacert" resultingDataRef:&certData1];

        SecCertificateRef certArray[1] = { cert1 };
        CFArrayRef certArrayRef = CFArrayCreate(NULL, (void *)certArray, 1, NULL);

        SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
        SecTrustSetAnchorCertificates(serverTrust, certArrayRef);
        SecTrustResultType trustResult;

        SecTrustEvaluate(serverTrust, &trustResult);

        trusted = (trustResult == kSecTrustResultUnspecified);

        CFRelease(certArrayRef);
        CFRelease(policyRef);
        CFRelease(cert1);
        CFRelease(certData1);
    }
    if (trusted) {
        [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
    } else {
        [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
    }
}
}

そしてtrustResultいつもkSecTrustResultRecoverableTrustFailureです。

証明書自体には少し問題があります。サーバー上のcurl証明書のサブジェクト名によると、接続先のURLと一致しません。そのサードパーティの会社に連絡したところ、コードでこの URL の不一致を受け入れる必要があるとのことでした。問題は、iOS でこれを行う方法がわからないことです。証明書チェックを完全にバイパスするか (単純に を想定しtrusted=YESて呼び出すことによりuseCredential)、完全に失敗するかのいずれかです。最初の解決策は、セキュリティの観点から明らかに間違っており、MITM 攻撃を受けやすくなっています。

これがCURL出力です(ここでは同じ証明書にPEMバージョンを使用しました):

ukaszs-iMac:Preferences lukasz$  curl --verbose --cacert ~/Desktop/some3rdpartycacert.txt  https://dev-service.some3rdparty.com:50101/
* About to connect() to dev-service.some3rdparty.com port 50101 (#0)
*   Trying XXX.XXX.XXX.XXX...
* connected
* Connected to dev-service.some3rdparty.com (XXX.XXX.XXX.XXX) port 50101 (#0)
* successfully set certificate verify locations:
*   CAfile: /Users/lukasz/Desktop/some3rdpartycacert.txt
  CApath: none
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Request CERT (13):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using AES256-SHA
* Server certificate:
*    subject: C=CA; ST=Ontario; O=Some 3rdParty Corporation; CN=otherpage.some3rdparty.com; emailAddress=noc@some3rdparty.com
*    start date: 2013-10-30 16:52:14 GMT
*    expire date: 2013-10-30 16:52:14 GMT
* SSL: certificate subject name 'otherpage.some3rdparty.com' does not match target host name 'dev-service.some3rdparty.com'
* Closing connection #0
* SSLv3, TLS alert, Client hello (1):
curl: (51) SSL: certificate subject name 'otherpage.some3rdparty.com' does not match target host name 'dev-service.some3rdparty.com'

では、iOS でこの特定のエラーを無視するにはどうすればよいでしょうか?

4

2 に答える 2