From 1883e41c1b5f2f8d087cb63ba9efe47cdc450972 Mon Sep 17 00:00:00 2001 From: gotoyuzo Date: Mon, 14 Feb 2005 04:14:39 +0000 Subject: [PATCH] * ext/openssl/lib/openssl/ssl.rb (OpenSSL::SSL::SSLSocket#post_connection_check): new method. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@7970 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 ++++ ext/openssl/lib/openssl/ssl.rb | 26 ++++++++++++++++++ test/openssl/test_ssl.rb | 49 ++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2ef4956a10..f9b64912f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Mon Feb 14 13:12:38 2005 GOTOU Yuuzou + + * ext/openssl/lib/openssl/ssl.rb + (OpenSSL::SSL::SSLSocket#post_connection_check): new method. + Mon Feb 14 00:10:17 2005 Masatoshi SEKI * lib/drb/drb.rb (DRbServer): add default_safe_level, safe_level, diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb index 629109a1de..9c31fa73cd 100644 --- a/ext/openssl/lib/openssl/ssl.rb +++ b/ext/openssl/lib/openssl/ssl.rb @@ -52,6 +52,32 @@ module OpenSSL class SSLSocket include Buffering include SocketForwarder + + def post_connection_check(hostname) + check_common_name = true + cert = peer_cert + cert.extensions.each{|ext| + next if ext.oid != "subjectAltName" + ext.value.split(/,\s+/).each{|general_name| + if /\ADNS:(.*)/ =~ general_name + check_common_name = false + reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+") + return true if /\A#{reg}\z/i =~ hostname + elsif /\AIP Address:(.*)/ =~ general_name + check_common_name = false + return true if $1 == hostname + end + } + } + if check_common_name + cert.subject.to_a.each{|oid, value| + if oid == "CN" && value.casecmp(hostname) == 0 + return true + end + } + end + raise SSLError, "hostname not match" + end end class SSLServer diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index c7bf15d82a..8f440076e8 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -198,6 +198,55 @@ class OpenSSL::TestSSL < Test::Unit::TestCase ssls.each{|ssl| ssl.close } } end + + def test_post_connection_check + sslerr = OpenSSL::SSL::SSLError + + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|s, p| + sock = TCPSocket.new("127.0.0.1", p) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.connect + assert_raises(sslerr){ssl.post_connection_check("localhost.localdomain")} + assert_raises(sslerr){ssl.post_connection_check("127.0.0.1")} + assert(ssl.post_connection_check("localhost")) + assert_raises(sslerr){ssl.post_connection_check("foo.example.com")} + } + + now = Time.now + exts = [ + ["keyUsage","keyEncipherment,digitalSignature",true], + ["subjectAltName","DNS:localhost.localdomain",false], + ["subjectAltName","IP:127.0.0.1",false], + ] + @svr_cert = issue_cert(@svr, @svr_key, 4, now, now+1800, exts, + @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|s, p| + sock = TCPSocket.new("127.0.0.1", p) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.connect + assert(ssl.post_connection_check("localhost.localdomain")) + assert(ssl.post_connection_check("127.0.0.1")) + assert_raises(sslerr){ssl.post_connection_check("localhost")} + assert_raises(sslerr){ssl.post_connection_check("foo.example.com")} + } + + now = Time.now + exts = [ + ["keyUsage","keyEncipherment,digitalSignature",true], + ["subjectAltName","DNS:*.localdomain",false], + ] + @svr_cert = issue_cert(@svr, @svr_key, 5, now, now+1800, exts, + @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|s, p| + sock = TCPSocket.new("127.0.0.1", p) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.connect + assert(ssl.post_connection_check("localhost.localdomain")) + assert_raises(sslerr){ssl.post_connection_check("127.0.0.1")} + assert_raises(sslerr){ssl.post_connection_check("localhost")} + assert_raises(sslerr){ssl.post_connection_check("foo.example.com")} + } + end end end