Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly verify abbreviated IPv6 SANs #185

Merged
merged 1 commit into from
Feb 19, 2018
Merged

Correctly verify abbreviated IPv6 SANs #185

merged 1 commit into from
Feb 19, 2018

Conversation

cunnie
Copy link
Contributor

@cunnie cunnie commented Jan 30, 2018

IPv6 SAN-verification accommodates "zero-compression". 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.

@cunnie
Copy link
Contributor Author

cunnie commented Jan 30, 2018

Hello Maintainers,

We are a heavy user of the Ruby OpenSSL, and we generate some of our certs using IPv6 SANs, and we would find it convenient if the openssl library accepted all RFC-compliant addresses, hence this PR.

And, as always, thank you for your excellent work.

@cunnie
Copy link
Contributor Author

cunnie commented Jan 30, 2018

@rhenium Could you please review this PR when you have time? Thank you very much.

@cunnie
Copy link
Contributor Author

cunnie commented Feb 2, 2018

To reassure you that other OpenSSL packages convert the certificate's SAN's IP bytes to IP address-type (not string or byte array) and convert the hostname to an IP address-type, too:

Golang's library https://golang.org/src/crypto/x509/verify.go line 78 converts the hostname to an IP address-type before verification, and the Certificate stores the SANs IPs as IP address-types: https://golang.org/pkg/crypto/x509/#Certificate:

// Subject Alternate Name values
DNSNames       []string
EmailAddresses []string
IPAddresses    []net.IP

begin
return true if IPAddr.new(san.value.unpack('n*').map {|e| sprintf("%X", e)}.join(':')) == IPAddr.new(hostname)
rescue IPAddr::InvalidAddressError
end
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this can be simplified to return true if san.value == IPAddr.new(hostname).hton.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much nicer, and shorter. I have updated my PR.

Note: I could not remove the begin ... rescue guard: I tried, and I got the the following failure:

Error: test_verify_certificate_identity(OpenSSL::TestSSL): IPAddr::InvalidAddressError: invalid address
...
408 tests, 3850 assertions, 0 failures, 1 errors, 5 pendings, 0 omissions, 0 notifications
98.5294% passed

@rhenium
Copy link
Member

rhenium commented Feb 5, 2018

The ipaddr library is a default gem in Ruby 2.5, so it needs to be added to openssl.gemspec as a runtime dependency.

@cunnie
Copy link
Contributor Author

cunnie commented Feb 5, 2018

Hi Kazuki,

Thank you for taking the time to review my PR and suggest improvements. I have implemented the changes you suggested. Let me know if there's anything else I should do or change.

—Brian

begin
return true if san.value == IPAddr.new(hostname).hton
rescue IPAddr::InvalidAddressError
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works for both IPv4 and v6 addresses. And can you remove the misleading comment "follows GENERAL_NAME_print() [...]" while you are at it?

Copy link
Contributor Author

@cunnie cunnie Feb 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code is applied to both IPv4 and IPv6 SANs.

Misleading comment is removed.

openssl.gemspec Outdated
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|

spec.required_ruby_version = ">= 2.3.0"

spec.add_runtime_dependency 'ipaddr'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use double quotes. The style is not consistent throughout the code base sadly, but the file is using double quotes for all other string literals.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Sorry about that — I should have paid more attention before I cut-and-pasted.

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.
@cunnie
Copy link
Contributor Author

cunnie commented Feb 9, 2018

Hi Kazuki,

Let me know if there's anything else you'd like me to change. For example, let me know if you'd like me to remove the surrounding if block (it's unnecessary).

Thanks,

—Brian

cppforlife added a commit to cloudfoundry/bosh that referenced this pull request Feb 10, 2018
…tificate verification

This is a temporary patch until this [PR](ruby/openssl#185) is
merged. Ruby OpenSSL's verification for IPv6 is flawed in that in only accepts
a very specific format (e.g. "0:0:0:0:0:0:0:1", but not "::1"). This causes SSL verification
to mistakenly fail.

Signed-off-by: Brian Cunnie <bcunnie@pivotal.io>
@rhenium rhenium merged commit 5c5bf71 into ruby:master Feb 19, 2018
@rhenium
Copy link
Member

rhenium commented Feb 19, 2018

It looks good and is merged now. Thank you!

@cunnie
Copy link
Contributor Author

cunnie commented Feb 19, 2018

Thank you, @rhenium . I appreciate the time & effort you spent coaching me through the pull request process, and I realize you could have made the changes yourself in the fraction of the time you spent with me. I am grateful.

@cunnie cunnie deleted the IPv6_SAN_verification branch February 19, 2018 21:02
cppforlife added a commit to cloudfoundry/bosh that referenced this pull request May 5, 2018
…tificate verification

This is a temporary patch until this [PR](ruby/openssl#185) is
merged. Ruby OpenSSL's verification for IPv6 is flawed in that in only accepts
a very specific format (e.g. "0:0:0:0:0:0:0:1", but not "::1"). This causes SSL verification
to mistakenly fail.

Signed-off-by: Brian Cunnie <bcunnie@pivotal.io>
cppforlife added a commit to cloudfoundry/bosh that referenced this pull request Jun 5, 2018
…tificate verification

This is a temporary patch until this [PR](ruby/openssl#185) is
merged. Ruby OpenSSL's verification for IPv6 is flawed in that in only accepts
a very specific format (e.g. "0:0:0:0:0:0:0:1", but not "::1"). This causes SSL verification
to mistakenly fail.

Signed-off-by: Brian Cunnie <bcunnie@pivotal.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants