Working with TCP Sockets 読書メモ 目次
SSLソケット
- SSLを利用すると、公開鍵暗号によって、ソケット上でデータを安全にやりとりできる
- SSLはTCPの上に安全なレイヤーを追加する
- ひとつのソケットがSSLと非SSLの両方の通信を行うことはできない
- たとえば、HTTPは80番、HTTPSは443番ポートを使用する
- TCPソケットをSSLソケットに変更するには
openssl
ライブラリを使用する
require 'socket'
require 'openssl'
def main
ssl_server = OpenSSL::SSL::SSLServer.new(
TCPServer.new(4481),
build_ssl_context
)
connection = ssl_server.accept
connection.write('bra')
connection.close
end
# SSLContextを作成する
def build_ssl_context
ctx = OpenSSL::SSL::SSLContext.new
ctx.cert, ctx.key = create_self_signed_cert(
1024,
[['CN', 'localhost']],
'Generated by Ruby/OpenSSL'
)
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
ctx
end
# 自己証明書を作成するメソッド
# webrick/ssl からコピーしたもの
# @see https://github.com/ruby/ruby/blob/v2_3_1/lib/webrick/ssl.rb#L92
def create_self_signed_cert(bits, cn, comment)
rsa = OpenSSL::PKey::RSA.new(bits){|p, n|
case p
when 0; $stderr.putc "." # BN_generate_prime
when 1; $stderr.putc "+" # BN_generate_prime
when 2; $stderr.putc "*" # searching good prime,
# n = #of try,
# but also data from BN_generate_prime
when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
# but also data from BN_generate_prime
else; $stderr.putc "*" # BN_generate_prime
end
}
cert = OpenSSL::X509::Certificate.new
cert.version = 2
cert.serial = 1
name = OpenSSL::X509::Name.new(cn)
cert.subject = name
cert.issuer = name
cert.not_before = Time.now
cert.not_after = Time.now + (365*24*60*60)
cert.public_key = rsa.public_key
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
ef.issuer_certificate = cert
cert.extensions = [
ef.create_extension("basicConstraints","CA:FALSE"),
ef.create_extension("keyUsage", "keyEncipherment"),
ef.create_extension("subjectKeyIdentifier", "hash"),
ef.create_extension("extendedKeyUsage", "serverAuth"),
ef.create_extension("nsComment", comment),
]
aki = ef.create_extension("authorityKeyIdentifier",
"keyid:always,issuer:always")
cert.add_extension(aki)
cert.sign(rsa, OpenSSL::Digest::SHA1.new)
return [ cert, rsa ]
end
- 自己署名のSSL証明書を作成して使用している
verify_mode = OpenSSL::SSL::VERIFY_PEER
によって未検証のSSL証明書を使えないようにしている- SSLのサーバにアクセスする際はクライアントもSSLを使用する必要がある
require 'socket'
require 'openssl'
socket = TCPSocket.new('0.0.0.0', 4481)
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket)
ssl_socket.connect
ssl_socket.read