Reputation: 43
I'd like to setup a minimal Ruby TCP server with SSL layer using certificate generated from Letsencrypt.
I install packages (system is Ubuntu 18, 64 bit):
sudo apt install ruby certbot
I generate the cert like this:
certonly -d example.com
Then run the following code:
require "socket"
require "openssl"
require "base64"
port = 443
cert_path = "/etc/letsencrypt/live/example.com/fullchain.pem"
key_path = "/etc/letsencrypt/live/example.com/privkey.pem"
chain_path = "/etc/letsencrypt/live/example.com/chain.pem"
context = OpenSSL::SSL::SSLContext.new
context.cert = OpenSSL::X509::Certificate.new( File.read( cert_path ))
context.key = OpenSSL::PKey::RSA.new( File.read( key_path ))
context.extra_chain_cert = OpenSSL::X509::Certificate.new( File.read( chain_path ))
tcp_server = TCPServer.new( port )
ssl_server = OpenSSL::SSL::SSLServer.new( tcp_server, context )
loop {
client = ssl_server.accept
data = client.gets
response = "I got #{data.dump}"
puts response
client.puts response
client.close
}
Then send a POST request using curl like this:
curl --data "param1=value1¶m2=value2" https://example.com
Then I get the following error message:
Traceback (most recent call last):
5: from api.rb:35:in `<main>'
4: from api.rb:35:in `loop'
3: from api.rb:37:in `block in <main>'
2: from /var/lib/gems/2.5.0/gems/openssl-2.1.2/lib/openssl/ssl.rb:483:in `accept'
1: from /var/lib/gems/2.5.0/gems/openssl-2.1.2/lib/openssl/ssl.rb:483:in `new'
/var/lib/gems/2.5.0/gems/openssl-2.1.2/lib/openssl/ssl.rb:483:in `initialize': undefined method `each' for #<OpenSSL::X509::Certificate:0x0000556df03c22c0> (NoMethodError)
Could you guys kindly help me track down the problem? I've been struggling with this for some time now. The official example does not work either which is here:
https://docs.ruby-lang.org/en/2.1.0/OpenSSL.html#module-OpenSSL-label-SSL+and+TLS+Connections
I've read in a SO thread that for Letsencrpyt certs I should include the .extra_chain_cert property. Still the issue is the same.
Thanks.
Upvotes: 2
Views: 433
Reputation: 87486
The extra_chain_cert
property is supposed to be an array according to its documentation, but you are just setting it to be a single certificate. The openssl
gem is crashing because it expected that property to be an array and called the each
method on it to iterate over the elements of the array.
You can try putting your certificate into a one-element array by enclosing it in square brackets ([
and ]
).
context.extra_chain_cert = [OpenSSL::X509::Certificate.new(File.read(chain_path))]
I just tested it here using my own Lets Encrypt certificate and it worked for me. I used port 444, and when I pointed a browser to https://example.com:444 the Ruby program said:
I got "GET / HTTP/1.1\r\n"
Upvotes: 2