ruby / openssl

Provides SSL, TLS and general purpose cryptography.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Can no longer pass file contents as ca_file property with OpenSSL 3

thoiberg opened this issue · comments

Hi, I have some code that was retrieving the string contents of a certificate from a database (so "-----BEGIN CERTIFICATE...") and setting it to the ca_file property with OpenSSL. This works for OpenSSL 1.1.1, but on OpenSSL 3.0.9 raises SSL_CTX_load_verify_file: system lib (OpenSSL::SSL::SSLError). From what I've read I'm guessing this might have always been unsupported behaviour with OpenSSL 1.1.1, but I was wondering if this was an intentional breaking change, or if there is an alternative way to pass the contents of a certificate to OpenSSL.

I have a set of minimal reproduction steps based of the wget sample below:

OpenSSL 1.1.1

docker run -it ruby:3.1-bullseye
require 'net/https'

pem_contents = File.read(OpenSSL::X509::DEFAULT_CERT_FILE)
uri = URI.parse("https://github.com/ruby/openssl")
h = Net::HTTP.new(uri.host, uri.port)
h.use_ssl = true
h.ca_file = pem_contents
path = uri.path.empty? ? "/" : uri.path
h.get2(path)
# returns <Net::HTTPOK 200 OK readbody=true>

OpenSSL 3.0.9

docker run -it ruby:3.1-bookworm
require 'net/https'

pem_contents = File.read(OpenSSL::X509::DEFAULT_CERT_FILE)
uri = URI.parse("https://github.com/ruby/openssl")
h = Net::HTTP.new(uri.host, uri.port)
h.use_ssl = true
h.ca_file = pem_contents
path = uri.path.empty? ? "/" : uri.path
h.get2(path)
# raises SSL_CTX_load_verify_file: system lib (OpenSSL::SSL::SSLError)

full stacktrace

/usr/local/lib/ruby/3.1.0/net/http.rb:1081:in `initialize': SSL_CTX_load_verify_file: system lib (OpenSSL::SSL::SSLError)
	from /usr/local/lib/ruby/3.1.0/net/http.rb:1081:in `new'
	from /usr/local/lib/ruby/3.1.0/net/http.rb:1081:in `connect'
	from /usr/local/lib/ruby/3.1.0/net/http.rb:995:in `do_start'
	from /usr/local/lib/ruby/3.1.0/net/http.rb:984:in `start'
	from /usr/local/lib/ruby/3.1.0/net/http.rb:1564:in `request'
	from /usr/local/lib/ruby/3.1.0/net/http.rb:1474:in `request_get'
	from (irb):10:in `<main>'
	from /usr/local/lib/ruby/gems/3.1.0/gems/irb-1.4.1/exe/irb:11:in `<top (required)>'
	from /usr/local/bin/irb:25:in `load'
	from /usr/local/bin/irb:25:in `<main>'

Yes, Net::HTTP#ca_file (OpenSSL::SSL::SSLContext#ca_file) wants the path to the file.

I don't think setting the file contents to the attribute ever worked. With OpenSSL 1.1.1, it is simply ignored with a verbose-mode warning:

#ifdef HAVE_SSL_CTX_LOAD_VERIFY_FILE
if (ca_file && !SSL_CTX_load_verify_file(ctx, ca_file))
ossl_raise(eSSLError, "SSL_CTX_load_verify_file");
if (ca_path && !SSL_CTX_load_verify_dir(ctx, ca_path))
ossl_raise(eSSLError, "SSL_CTX_load_verify_dir");
#else
if(ca_file || ca_path){
if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
rb_warning("can't set verify locations");
}
#endif

$ ruby -w -ropenssl -e'ctx=OpenSSL::SSL::SSLContext.new; ctx.ca_file=File.read("/etc/ssl/certs/Go_Daddy_Class_2_CA.pem"); ctx.setup'
-e:1: warning: can't set verify locations

The behavior difference was not intentional, but I think the OpenSSL <= 1.1.1 code should've also raised an exception since this is clearly an error case.

ahhhhhh, ok that makes a lot more sense 😄 . Thanks for investigating 🙇

Reopening because the OpenSSL <= 1.1.1 code should be fixed.