LoginSignup
25
17

More than 5 years have passed since last update.

SNIの仕組みをOpenSSLコマンドで理解する

Last updated at Posted at 2015-12-05

この記事ではOS X Yosemite 10.10と、元々インストールされているOpenSSL 0.9.8を利用しています。

$ openssl version
OpenSSL 0.9.8zg 14 July 2015
  • help.hipchat.comにリクエストを投げたら何故か*.uservoice.comの証明書が返ってくる(2015-12-05現在)
$ openssl s_client -connect help.hipchat.com:443 -showcerts < /dev/null 2>&1 | grep subject
subject=/OU=GT20300774/OU=See www.rapidssl.com/resources/cps (c)15/OU=Domain Control Validated - RapidSSL(R)/CN=*.uservoice.com

SNIという、一つのIPアドレスが複数のSSL証明書を扱える技術があるのですが、サーバ側でSNIを使っている場合、SSLハンドシェイク時にドメイン名を指定しないと正しいSSL証明書が返ってこない事があります。

比較的新しいサービスだとSNIを使っている事が多いです。例えば、HipChatのヘルプページ(help.hipchat.com)ですが、これはSNIを使っています。なので、opensslコマンドを使って証明書を取得しようとすると上記のようなことが起こります。

サイトのURLを表すコモンネーム(CN)の値が*.uservoice.comとなっています。なぜこんなことが起きるのでしょうか?それは、一つのIPアドレスが複数のSSL証明書を持っているからです。ドメイン名は単なるIPアドレスを単に見やすくしたものです。アクセス時は番号に変換されてしまいます。なので、サーバはリクエスト一つ一つが、どのドメイン名を意図して送られたものなのかわからないのです。当然、どの証明書を返してよいか分からないわけです。そこで、SSLハンドシェイク時に明示的に文字列としてドメイン名を指定しなければ、デフォルトとして設定されているSSL証明書が返ってきます。
opensslコマンドで明示的にドメイン名を指定するには下記のオプションを使います。

オプション 内容
-servername 欲しいSSL証明書のドメイン名を明示的に指定する
  • 明示的にサーバ名を指定すると正しい証明書が返ってくる。
$ openssl s_client -connect help.hipchat.com:443 -servername help.hipchat.com -showcerts < /dev/null 2>&1 | grep subject
subject=/C=US/L=San Francisco/ST=California/O=Atlassian, Inc./OU=HipChat/CN=help.hipchat.com

私はとあるAPIを叩いていたのですが、どうしても通信がうまく行きませんでした。それは、APIのエンドポイントでSNIが使われていることと、私が使っているAPIクライアントがJava1.6製だったのが原因でした。Java1.6のHTTPSクライアントは、SSLハンドシェイク時にドメイン名を指定する機能がありません。なので、上記のhelp.hipchat.comのような例では証明書が不正だと判断され通信が失敗します(この場合、何も指定しなくてもhelp.hipchat.comのCNを持った証明書が返ってくるよう、サーバ側で設定されていれば通信はできるのですが……)。

25
17
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
25
17