Working with TCP Sockets 読書メモ 第13章 SSLソケット

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

コメントをどうぞ

コメントを残す