Farhad Farhad - 5 months ago 43
Ruby Question

Ruby SSL_read: tlsv1 alert protocol version

I'm writing a simple ssl web client which worked fine without adding ssl support. Now that I have added ssl functionality to get request I get this error message:

SSL_read: tlsv1 alert protocol version

After googling about it, I came to conclusion to check openssl version, which I can see that it supports TLSv1.2. I even created a context to explicitly forcing tlsv1.2 but still same error message. My openssl version:

ruby -ropenssl -e 'puts OpenSSL::OPENSSL_VERSION' ===> OpenSSL 1.0.1f 6 Jan 2014

My code:

require 'socket'
require 'openssl'

puts "Please select:"
puts "get ==> to use GET method"
puts "post ==> to use POST method"
method = gets.chomp.downcase

case method
when "get"
print "Please enter the domain name to get the http: "
domain = "www." << gets.chomp
print "Now enter the page you want to get: "
page = gets.chomp

# opening socket
soc = TCPSocket.new domain, 443
ctx = OpenSSL::SSL::SSLContext.new
ctx.ssl_version = :TLSv1_2
ssl = OpenSSL::SSL::SSLSocket.new(soc, ctx)
ssl.sync_close = true
soc.puts "GET #{page} HTTP/1.1\nHost: #{domain}\n\n\n"
while line = ssl.gets
puts line
when "post"
print "Please enter the domain name to post the http:"
domain = gets.chomp.downcase
print "Now enter the post form page:"
form_page = gets.chomp.downcase
puts "Please enter the parameters of POST and related values one at a time:"
puts "(\"done\" to end input)"
post_variable = []
while true
print "Parameter:"
parameter = gets.chomp.downcase
break if parameter == "done"
print "Value:"
value = gets.chomp.downcase
break if value == "done"
post_sentense = post_variable.join("&")
# opening socket
soc = TCPSocket.new domain, 80
soc.puts "POST #{form_page} HTTP/1.1\nHost: #{domain}\nContent-Length: #{post_sentense.length}\n\n\n#{post_variable}"
while line = soc.gets
puts line
puts "wrong input!!!"

I should mention that the domain name should be entered without www and page normally is
Can someone help me through this???


I found the problem. This line:

soc.puts "GET #{page} HTTP/1.1\nHost: #{domain}\n\n\n"

should be this:

ssl.puts "GET #{page} HTTP/1.1\nHost: #{domain}\n\n\n"

I don't exactly know why but I think by sending the message to socket instead of ssl, it participated in ssl negotiation and didn't let negotiation to complete the process.