のくみあわせで自己署名証明書 (self-signed certificate) を使う場合の話。
allowsAnyHTTPSCertificateForHost:
を override するとかいうマヌケなことはしないこと。
(昔のクソ blog などによく書かれていた完全に間違った方法。このご時世では使えなくなっている気がするが未確認)
1. TN2232 を読む
2. TN2326 にある手順で Certificates を作成
3. server.crt を変換 (CA の certificate のはそのままで OK)
openssl x509 -in server.crt -outform DER -out server.der
4. DER 形式の ceriticate (2 つ) を xcode の project に import
5. -[NSURLSessionTaskDelegate URLSession:task:didReceiveChallenge:completionHandler:]
を実装
エラー処理などを省略して雑に書くとこんな感じになる:
if ([challenge previousFailureCount] == 0 && [challenge proposedCredential] && [[challenge proposedCredential] hasPassword]) {
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
return;
}
NSURLProtectionSpace * protectionSpace = [challenge protectionSpace];
SecTrustRef trust = [protectionSpace serverTrust];
NSURLCredential * credential = [NSURLCredential credentialForTrust: trust];
NSArray *certs = @[
CFBridgingRelease(SecCertificateCreateWithData(NULL, dataForCA)),
CFBridgingRelease(SecCertificateCreateWithData(NULL, dataForServer))
];
SecTrustSetAnchorCertificatesOnly(trust, true);
SecTrustSetAnchorCertificates(trust, (CFArrayRef)certs);
SecTrustEvaluateAsync(
trust,
NULL,
^(SecTrustRef _Nonnull trustRef, SecTrustResultType trustResult) {
BOOL trusted = (trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified);
if (trusted)
completion(NSURLSessionAuthChallengeUseCredential, credential);
else
completion(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
});
stone -z cert=server.crt -z key=server.key HOST:PORT SSL-PORT/ssl
※ 古い情報なので最新の情報を確認の上で使うように
あたりを参照のこと。
なお、 BouncyCastle の version に注意。1.47 以降ではなく 1.46 を使う必要がある。 でないと “java.io.IOException: Wrong version of key store.” で死ぬ。