13
15

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.

Ruby の SSLSocket で SNI する

Posted at

Ruby でバーチャルホスト対応の HTTPS サーバーを書こうとしていたのですが、Ruby から TLS 拡張の SNI を利用する方法が分からなかったので簡単に調べました。

SNI とは?

SNI (Server Name Indication) とは、RFC 6066 で定義されている TLS の拡張で、Client hello の中にサーバーのホスト名を埋めこむことができる拡張です。
これを利用することにより、例えばサーバーは要求されたホスト名によって使用するサーバー証明書を変えることができます。

例えば nginx の設定ファイルでは

nginx.conf
http {
  server {
    listen server_a:443 ssl;
    ssl_certificate server_a.crt;
  }
  server {
    listen server_b:443 ssl;
    ssl_certificate server_b.crt;
  }
}

と書くと、ブラウザから https://server_a/ でアクセスした場合には server_a.crt が使用され、https://server_b/ でアクセスした場合には server_b.crt が使用されますね。

Ruby では?

Ruby の openssl 標準添付ライブラリでは、サーバー側は OpenSSL::SSL::SSLContext#servername_cb=、クライアント側では OpenSSL::SSL::SSLSocket#hostname= を使用することで実現できます。

サーバー

server.rb
require "openssl"
require "socket"

ctx = OpenSSL::SSL::SSLContext.new
ctx.servername_cb = proc {|sslsock, hostname|
  puts hostname

  new_ctx = OpenSSL::SSL::SSLContext.new
  case hostname
  when "0.example.com"
    new_ctx.cert = OpenSSL::X509::Certificate.new(File.read("0.example.com.crt"))
    new_ctx.key = OpenSSL::PKey::RSA.new(File.read("0.example.com.key"))
  else
    new_ctx.cert = OpenSSL::X509::Certificate.new(File.read("1.example.com.crt"))
    new_ctx.key = OpenSSL::PKey::RSA.new(File.read("1.example.com.key"))
  end
  new_ctx
}
tcp_server = TCPServer.new("127.0.0.1", 40443)
ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server, ctx)

loop do
  sock = ssl_server.accept
  sock.close
end

クライアント

client.rb
require "openssl"
require "socket"

tcp_socket = TCPSocket.new("127.0.0.1", 40443)
ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket)
ssl_socket.hostname = ARGV[0]

ssl_socket.connect

puts ssl_socket.peer_cert.subject

実行結果

サーバー
% ruby server.rb
0.example.com
example.org
クライアント
% ruby client.rb 0.example.com
/C=JP/CN=0.example.com/emailAddress=postmaster@0.example.com
% ruby client.rb example.org
/C=JP/CN=1.example.com/emailAddress=postmaster@1.example.com
13
15
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
13
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?