Permalink
Browse files

Correctly verify abbreviated IPv6 SANs

IPv6 SAN-verification accommodates
["zero-compression"](https://tools.ietf.org/html/rfc5952#section-2.2).
It also accommodates non-compressed addresses.

Previously the verification of IPv6 addresses would fail unless the
address syntax matched a specific format (no zero-compression, no
leading zeroes).

As an example, the IPv6 loopback address, if represented as `::1`, would
not verify.  Nor would it verify if represented as
`0000:0000:0000:0000:0000:0000:0000:0001`; however, both representations
are valid, RFC-compliant representations.  The library would only accept
a very specific representation (i.e.  `0:0:0:0:0:0:0:1`).

This commit addresses that shortcoming, and ensures that any valid IPv6
representation will correctly verify.
  • Loading branch information...
cunnie committed Jan 30, 2018
1 parent f707996 commit 9322a104d16b02c7a79f9ab589859c9d63fabf52
Showing with 12 additions and 6 deletions.
  1. +6 −5 lib/openssl/ssl.rb
  2. +1 −0 openssl.gemspec
  3. +5 −1 test/test_ssl.rb
@@ -12,6 +12,7 @@
require "openssl/buffering"
require "io/nonblock"
require "ipaddr"
module OpenSSL
module SSL
@@ -272,11 +273,11 @@ def verify_certificate_identity(cert, hostname)
return true if verify_hostname(hostname, san.value)
when 7 # iPAddress in GeneralName (RFC5280)
should_verify_common_name = false
# follows GENERAL_NAME_print() in x509v3/v3_alt.c
if san.value.size == 4
return true if san.value.unpack('C*').join('.') == hostname
elsif san.value.size == 16
return true if san.value.unpack('n*').map { |e| sprintf("%X", e) }.join(':') == hostname
if san.value.size == 4 || san.value.size == 16
begin
return true if san.value == IPAddr.new(hostname).hton
rescue IPAddr::InvalidAddressError
end
end
end
}
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
spec.required_ruby_version = ">= 2.3.0"
spec.add_runtime_dependency "ipaddr"
spec.add_development_dependency "rake"
spec.add_development_dependency "rake-compiler"
spec.add_development_dependency "test-unit", "~> 3.0"
@@ -516,8 +516,12 @@ def test_verify_certificate_identity
assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, "www.example.com\0.evil.com"))
assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '192.168.7.255'))
assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, '192.168.7.1'))
assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '13::17'))
assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, '13::17'))
assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '13::18'))
assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, '13:0:0:0:0:0:0:17'))
assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '44:0:0:0:0:0:0:17'))
assert_equal(true, OpenSSL::SSL.verify_certificate_identity(cert, '0013:0000:0000:0000:0000:0000:0000:0017'))
assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '1313:0000:0000:0000:0000:0000:0000:0017'))
end
end

0 comments on commit 9322a10

Please sign in to comment.