Set ssl version with Net::HTTP - ruby

I have an old server that only accepts SSLv3 and SSLv3. I want to set the ssl version when I make the request.
http = Net::HTTP.new(#request.uri.host, #request.uri.port)
http.use_ssl = #request.uri.scheme == 'https'
http.ssl_version = :SSLv3
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
leads to
[2020-09-10T05:37:14.452819 #254200] FATAL -- :
OpenSSL::SSL::SSLError (SSL_CTX_set_min_proto_version):
I tried other combinations but failed.
http.ssl_version = :SSLv3
http.ssl_version = "SSLv3"
How can I set the specific ssl version? I am using Ruby 2.7.1 and Rails 6. Thanks.

In most current versions of OpenSSL, the support for SSLv3 is statically disabled during compile time since the protocol is widely considered as insecure. As such, there is often no way to still use SSLv3 on those OpenSSL versions.
If SSLv3 is a hard requirement, you will likely have to first compile your own OpenSSL version with suitable configuration options, followed by the compilation of your Ruby against your custom OpenSSL.
Preferably, you should either update the server to support newer more secure protocols (such as TLSv1.2 or TLSv1.3) or ask the operator of the server to do so.

Related

Puppet Jruby NetHttp get request seems to have bad ciphers

We wrote a puppet function which needs to do a http get request over tls to a server. The http request is done directly from the puppet master. The remote server needs apparently more recents ciphers than provided by our function (we use the ruby Net/Http library). Consequently, the remote server immedialty close the connection (Client Hello, [ACK], [FIN, ACK] )
def http_client
uri = URI("https://#{#config['server']}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless #config['vmssc_tls_verify']
http
end
We tried to CuRL the same API from the puppet master, with success, it appears the openssl version used by CuRL is different than the one used by puppet.
The difference we found was that in curl we had like 32 ciphers in SHA256 but with the Net/Http library used by puppet we only had 11 ciphers in SHA1.
Puppet server is running with jruby, so we tried to add java cryptography extension in openJDK but without success.
We also observe that the ciphers listed in the /etc/puppetlabs/puppetserver/conf.d/puppetserver.conf file are not honored (hence we got the list of the ciphers used by the client in our tcpdump) :
# settings related to HTTP client requests made by Puppet Server
http-client: {
# A list of acceptable protocols for making HTTP requests
ssl-protocols: [
TLSv1.2,
]
# A list of acceptable cipher suites for making HTTP requests
cipher-suites: [
TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA,
]
We tried to upgrade the version of openJDK to an oracle JDK but without success.
We're running on a puppetserver version 2.7.0 with Jruby and openJDK 8 with a TLS_Version 1.2.
Also when the puppetserver is started in native ruby everything works fine, we've got the goods ciphers. We don't want to stay with that configuration for the performance issue.

API Request - OpenSSL::SSL::SSLError: SSL_connect SYSCALL returned=5 errno=0 state=SSLv3 read server hello A

Another of of these questions, I know this question has been asked (and answered) a lot on StackOverflow, but I can't get any of those to work for me and I also have a few questions I would like to learn.
Here is my error:
OpenSSL::SSL::SSLError: SSL_connect SYSCALL returned=5 errno=0 state=SSLv3 read server hello A
To start, here is my system settings.
I am on OSX El Capitan version 10.11.6
openssl version
OpenSSL 0.9.8zh 14 Jan 2016
which openssl
/usr/bin/openssl
ruby -v
ruby 2.1.6p336 (2015-04-13 revision 50298) [x86_64-darwin14.0]
rbenv -v
rbenv 0.4.0
My questions are these:
1) Does this error mean that a certificate was sent back to me, and then my OpenSSL version was unable to verify it? Did the other server have a chance to read mine, or even see it yet? Is there a way to dig into this request using Net::HTTP and inspect this other than opening up a program like Wireshark? Once I call net::HTTP.new.request(request) I seem to lose control and it just errors.
2) Did I even successfully talk to the other server, and it denied me?
3) At what point in the request am I in when I get this message?
and most of all
4) What are my options to get past this point
4a. So far i'm seeing a possible brew solution, but I haven't been able to get brew to link
4b. I could manually install Mozilla's CA (Or any other CA) into my Mac OSX Keychain
4c. Can I attach the file using the request.ca_file = "file" as I tried in my code? (see below)
4d. Is there any other solutions / best and most politically correct version?
5) Am I going to have this issue when I deploy to Heroku?
From what i'm reading, this is an issue of my OS not containing the correct CA files. the ca_file part is due to my first attempts to add the correct ca_file to my requests. I'm guessing I don't need that. I am using a Proxy with heroku because this API requires a static IP.
Here is my generic code
cert = File.read(File.join(Rails.root, 'ssl', 'test_env', 'their_test_cert.der'))
ca_file = File.read(File.join(Rails.root, 'ssl', 'test_env', 'Class3PublicPrimaryCA.der'))
uri = URI("https://xml.theirtestenv.com/api/receive")
headers = {
'x-IK-Version' => 'IKR/V4.00',
}
proxy_host = "myproxyhose"
proxy_port = "1234"
proxy_user = "myproxyuser"
proxy_pass = "myproxypass"
proxy_request = Net::HTTP.new(uri.hostname, '443', proxy_host, proxy_port, proxy_user, proxy_pass)
# http.key = OpenSSL::PKey::RSA.new(rsa_key)
proxy_request.use_ssl = true
proxy_request.cert = OpenSSL::X509::Certificate.new(cert)
proxy_request.ca_file = ca_file
proxy_request.verify_mode = OpenSSL::SSL::VERIFY_PEER
# proxy_request.ssl_version = :SSLv3
# This doesn't seem to matter whether I put this or not...
# Tried variations of these...
# proxy_request.ssl_version = :TLSv1
# proxy_request.ciphers = ['DES-CBC3-SHA']
post_request = Net::HTTP::Post.new(uri, headers)
post_request.content_type = "multipart/related"
response = proxy_request.request(post_request)
puts response.inspect
Also, i've noticed no matter what proxy_requst.ssl_version I put, my error always specifies SSLv2/v3, does that mean on their end they are requiring that version?
Sorry for all the questions. Thanks in advance
It's been awhile, but I just wanted to post that this was a couple of issues, the certificates I was passing were not the correct ones they were for the wrong environment. Once the correct certificates were passed this started working, though I never got the SSL Version questions quite figured out.

Net:HTTP SSL negotiation timeout on Ubuntu 14.04

After a long day I managed to get to the bottom of what I believe is a SSL/TLS cipher negotiation issue with a server that doesn't support the latest and greatest versions.
Stack:
Ubuntu 14.04 fully patched
OpenSSL 1.0.1f 6 Jan 2014
irb 0.9.6(09/06/30)
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux] (using rbenv)
After 60 seconds the snippet below gives me an error:
require 'net/http'
require 'openssl'
uri = URI.parse('https://some_old_server/my/path')
http = Net::HTTP.new('some_old_server', 443)
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.use_ssl = true
response = http.request(Net::HTTP::Get.new(uri.request_uri))
Errno::ECONNRESET: Connection reset by peer - SSL_connect
If I add this to the code, it works:
(...)
http.ciphers = ['AES128-SHA']
(...)
=> #<Net::HTTPOK 200 OK readbody=true>
This isn't a ruby-specific issue but ideally there's a ruby solution. I can't lock the ciphers to 'AES128-SHA' because the same code handles a number of sites that may or may not support this cipher.
Has anyone ever come across this and found a generic solution?
EDIT: this seems to be caused by the "TLS hang bug" and was fixed in openssl 1.0.1g.
New question: is there a work-around that can be implemented on the ruby side?
More information.
A Gentoo server running OpenSSL 1.0.1j 15 Oct 2014 doesn't have this issue. I tried installing 1.0.1j on the Ubuntu 14.04 server, recompiling ruby (rbenv install 2.2.2) and the error was still present.
I've tried to monkey patch ext/openssl but that didn't work.
Using the whole cipher list from the link above doesn't work. However, using a small subset does work:
require 'net/http'
require 'openssl'
uri = URI.parse('https://some_old_server/my/path')
http = Net::HTTP.new('some_old_server', 443)
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.use_ssl = true
http.ciphers = %w{
AES128-GCM-SHA256
AES256-GCM-SHA384
AES128-SHA256
AES256-SHA256
AES128-SHA
AES256-SHA
ECDHE-ECDSA-RC4-SHA
ECDHE-RSA-RC4-SHA
RC4-SHA
}.join(":")
response = http.request(Net::HTTP::Get.new(uri.request_uri))
Openssl agrees with ruby (as it should). Running these, on the same system, replicates the issue as I see them in ruby:
openssl s_client -connect some_old_server:443
CONNECTED(00000003)
(...)
write:errno=104
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 295 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---
Passing the cipher:
openssl s_client -cipher AES128-SHA -connect some_old_server:443
CONNECTED(00000003)
(...)
---
No client certificate CA names sent
---
SSL handshake has read 2721 bytes and written 425 bytes
---
New, TLSv1/SSLv3, Cipher is AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : AES128-SHA
Session-ID: removed
Session-ID-ctx:
Master-Key: removed
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1454394952
Timeout : 300 (sec)
Verify return code: 20 (unable to get local issuer certificate)
---
I read somewhere to use
http.ssl_options = OpenSSL::SSL::OP_ALL
but ssl_options isn't available in Net::HTTP on ruby 2.2.2.
After spending more time on this than I'd care to admit, my solution was to upgrade from Ubuntu 14.04 to 15.10 which comes with OpenSSL 1.0.2d 9 Jul 2015.
While the TLS negotiation still hangs using the openssl CLI, in Ruby it does not:
require 'net/http'
require 'openssl'
require 'pp'
uri = URI.parse('https://broken_server/my/path')
http = Net::HTTP.new('broken_server', 443)
http.instance_eval {
#ssl_context = OpenSSL::SSL::SSLContext.new
#ssl_context.set_params({:options=>OpenSSL::SSL::OP_ALL})
}
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.use_ssl = true
pp response = http.request(Net::HTTP::Get.new(uri.request_uri))
SSL context code above courtesy of #vinhboy.
The CLI equivalent of the above is turned-on with the -bugs option:
openssl s_client -bugs -connect broken_server:443

How do I get the peer_cert for a https request using Ruby?

How can I get access to the peer_cert when making a SSL request?
I've updated my ruby ssl certs with rvm osx-ssl-certs update all
What I'm trying is
require 'httpclient'
c = HTTPClient.new
r = c.get( "https://gmail.com" )
puts r.peer_cert
But I keep getting either
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server hello A: sslv3 alert handshake failure
or
OpenSSL::SSL::SSLError: hostname "gmail.com" does not match the server certificate
What does the first error mean? Is there a way to get it to set the property version automatically?
I'm able to load up the data on the URL using HTTParty and Farday, but in that case I don't know here to access the actual SSL cert that was used.
You can't get the peer cert until you succesfully make the connection, and you're getting an error in succesfully making the connection. Have you upgraded to the latest httpclient? Many servers changed their SSL handshake configurations in response to recent vulnerabilties, and a new httpclient was released in response to same, which perhaps is neccesary to be compatible with new server configurations.

Connecting using https to a server with a certificate signed by a CA I created

I have a test environment that uses Ruby to drive a server over an https connection. Since the latest versions of Ruby refuse to connect to an https server with an invalid certificate (see this earlier question of mine) and I would like to start using a newer version of Ruby, I am trying to set up a valid certificate.
I have created a CA certificate to use (there are multiple servers being tested so this seems the easier way), and have successfully used it to sign a new certificate which has been installed on a server and is being used. I have added the CA certificate to the browser store and it (the browser) will now connect to the server without complaint. So I am confident my certificates are valid and set up correctly.
I know that Ruby does not use the same store as the browser. I have used the CA file available here to test connecting to other (public) servers (set using the Net::HTTP#ca_file= method) and this also works.
What I cannot get to work is Ruby connecting to my server using my certificate. I have tried various ways of pointing it at my certificate (including adding my certificate to the file linked above) and it always gives the same error:
SSL_connect SYSCALL returned=5 errno=0 state=SSLv2/v3 read server hello A (OpenSSL::SSL::SSLError)
What do I have to do to convince Ruby to accept my certificate and connect to my server?
The code I am using is:
require 'net/https'
uri = URI.parse("https://hostname/index.html")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.ca_file = "My CA cert file"
request = Net::HTTP::Get.new(uri.path)
response = http.request(request)
I'm assuming this is wrong somehow. What I want to know is, what should I do to use my CA certificate?
I assume that your Tomcat doesn't like the protocol version that Ruby tries to negotiate. Ruby uses SSLv23 by default, but I've heard other cases where this was a problem for Java-based web servers. The error message you are getting indicates that the handshake fails while setting up the connection and trying to read the server's response. Try adding either
http.ssl_version = :TLSv1
or
http.ssl_version = :SSLv3
and see if that already helps.
If this does not fix the problem yet, it would be very interesting to see why your server rejects the connection attempt. Try running your Tomcat with -Djavax.net.debug=ssl and please post the relevant parts (connection information, exception stacktrace) as to why the attempt fails.
I am using ruby 1.9.3 and faced the same error while using nokogiri to parse some secure urls.
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: (null)
The above answer provided by emboss is correct but make sure the ssl error generated is this one that is mentioned above. I have followed the same and found a solution like this mentioned below.
uri = URI(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.ssl_version = :SSLv3
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
response = http.get(url)
now the response is having the correct html parsed for the secured url that is passed to the codes in the url .
Make sure that the your certificate file is in PEM format, not CRT (so the documentation for Net::HTTP in Ruby 1.9.3 says).
Update it looks like the documentation is not up to date, Ruby 1.9.3 will accept any kind of certificate.

Resources