10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

OpenSSLを利用して接続したServerの証明書検証について

Posted at

はじめに

間違いがある場合はご指摘いただけると嬉しい
あと、素直にSwiftかObj-Cで実装したほうが絶対にいい

どのような方向けのTipsか?

  1. Verisign、Let's Encryptなどから発行されたサーバ証明書および中間証明書を持つSSLサーバに、 iOS端末からNSURLConnectionなどではなく、OpenSSLのAPIを用いてSSL接続を行いたい
  2. ただし、接続後にサーバからクライアント側に渡されたサーバ証明書および中間証明書が正しいかどうかを、iOSのシステムに組み込まれたルートCA証明書まで辿って検証したい
  3. ここで、iOSに於いてはルートCA証明書リストへのアクセスは不可能(と思われる)
  4. つまり、OpenSSLで提供されている、SSL_CTX_load_verify_locationsやSSL_CTX_set_default_verify_pathsといったAPIが利用できず、BundleにルートCA証明書リストなどを追加しておかなくてはならない(オレオレ証明書を通すのと同様に)
  5. これは嫌だ!

という方向け

解決方法

OpenSSL(C/C++)での実装

  1. SSL_set_verifyを用いて、SSL_VERIFY_NONEにしておく
    (なお、verifycallbackを利用する、という手段は未検証)
  2. SSL_Connectする
  3. SSL_get_peer_certificate_chainする
    これにより、サーバ証明書(と中間証明書)が得られる
    得られた証明書は、X509形式のポインタで表されているため、OpenSSLで提供されるAPIを利用して、iOSで取り扱うことのできる、DER形式のバイナリ列に直す
  unsigned char* buf = NULL; // NULL  
  int len = i2d_X509(cert, &buf); // NULLを与えると、新たにmallocしてDERを返してくれる。勿論、後ほどfree必須

Objective-C側の実装

CFMutableArrayRef certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); // 最大配列個数 => 指定なし
for (サーバから返答された証明書チェーンに含まれる証明書の個数) {
  CFDataRef data = CFDataCreate(kCFAllocatorDefault, buf, len); // 前節3.で得られたDERへのポインタと長さ
  SecCertificateRef cert = SecCertificateCreateWithData(NULL, data);
  CFArrayAppendValue(certs, cert);
}
SecTrustRef trust;
OSStatus status = SecTrustCreateWithCertificates(certs, SecPolicyreateBasicX509(), &trust);
SecTrustResultType r = kSecTrustResultInvalid;
status = SecTrustEvaluate(trust, &r);

これで、rの返り値がkSecTrustResultProceed==1もしくはkSecTrustResultUnspecified==4であれば、サーバ証明書検証成功1
なお、サーバから渡された証明書に中間CAが含まれていないなどのミスでルートCAまで辿れなかったり、オレオレ証明書+オレオレCA証明書(システムにインストールされていない証明書)がサーバから渡された場合は、kSecTrustResultRecoverableTrustFailure == 5となる

最後に

この辺りを実装したコードは、
https://github.com/linear-rpc/linear-objc/blob/master/src/LinearSSLClient.mm#L89
にあるので、興味があればご参照を

  1. https://developer.apple.com/library/mac/qa/qa1360/_index.html
    The semantics behind receiving a kSecTrustResultUnspecified (4) error from Security APIs is that the certificate is indeed valid. However, the user has not explicitly set the trust settings for the certificate via Keychain Access.

10
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?