Forum: Ruby SSLServer crashes when non-essl telnet connection is made

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Erick C. (Guest)
on 2009-03-15 12:10
I have been working with the SSLServer class in Ruby and have run across
a problem that I cannot get my head around:

My basic server application accepts and handles SSL connections as it
should (or as I think it should), but when I use telnet (non-SSL
encrypted) the server crashes.

I immediately assumed that there was a problem in my code so I began
stripping it down to the bare minimum required.  However, when this did
not correct the issue, I ended up with the most basic SSLServer possible
and the symptoms have not gone away.

Current test code(this code is not mine, but was the most basic
SSLServer example that I could find...the result is the same with this
code and my code):

#!/usr/bin/ruby

require 'socket'
require 'openssl'

include OpenSSL

ctx = SSL::SSLContext.new()
ctx.cert = X509::Certificate.new(File.read('/home/riot82/blah.crt'))
ctx.key = PKey::RSA.new(File.read('/home/riot82/blah.key'))
svr = TCPServer.new(2007)
serv = SSL::SSLServer.new(svr, ctx)

loop do
   while soc = serv.accept
        puts soc.read
   end
end



This code works like I would expect when testing a connection with:

openssl s_client -connect localhost:2007

However, a simple telnet test:

telnet localhost 2007

Telnet makes the connection, but upon exit the server crashes with the
following error message:

/usr/lib/ruby/1.8/openssl/ssl.rb:171:in `accept': SSL_accept SYSCALL
returned=5 errno=0 state=SSLv2/v3 read client hello A
(OpenSSL::SSL::SSLError)
        from /usr/lib/ruby/1.8/openssl/ssl.rb:171:in `accept'
        from ./server3.rb:15
        from ./server3.rb:14:in `loop'
        from ./server3.rb:14


I have been able to duplicate this error on both my computer at work
(Ubuntu) and on my workstation at home(Slackware 12.2).  Both are
running ruby 1.8.7.

Since I am making the assumption that my code is still the problem (I
have googled around for anybody having this same problem but have been
unable to find anything) if somebody could possibly help point me in the
right direction it would be most appreciated.

*If somebody is aware of a problem in the actual library itself(I looked
at class but was unable to see anything that I would call
"wrong"...maybe an error could be handled more gracefully though?) or if
this was a known issue and has been fixed in 1.9 I would also love to
know.

Thank you again to anybody that can help.
Michael L. (Guest)
on 2009-03-16 03:44
It's most likely a problem with the certificate that you're using.

- Mac
Erick C. (Guest)
on 2009-03-16 04:53
Mac,

Thank you for replying.  Taking your suggestion under advisement I have
tried using separate SSL certificates and none of them are correcting
the problem.

The certificates that I have been using are all generated from RSA key
files (with both the key file and the certificate file being generated
with openssl from the Linux command line).

I have tried a 512 bit key/cert, a 1024 bit key/cert, and a 2048 bit
key/cert.

Can you please clarify and be more specific in your suggestion as to the
specifics in a certificate that might be causing the problem?

Thank you again for you support.

--Erick C.
Erick C. (Guest)
on 2009-03-16 05:26
I apologize that I did not include this in my last reply.  Here is how I
am generating the certificates:

openssl genrsa 1024 > ./blah.key (as stated I have tried this with 512,
1024, and 2048 bit).

openssl req -new -x509 -key ./blah.key -out ./blah.crt -days 1095

Thank you,

Erick C.
Michael L. (Guest)
on 2009-03-16 05:44
> Can you please clarify and be more specific in your suggestion as to the
> specifics in a certificate that might be causing the problem?

Well, generally speaking, telnet protocol by default doesn't use SSL;
basically not supporting SSL certs. Then later down the road came the
telnet-ssl client. Telnet-SSL uses SSL auth and encryption when the
responding server uses it. However, if the responding server does NOT
use SSL then the client will revert back to the standard (non-ssl)
protocol.

With that said this leads me to believe that telnet is crashing, or
rather..error-ing out, because the certs you are using are not
compatible with basic telnet services.

So how you might go about resolving this conflict is run the cert error
through a begin/rescue block. In rescue you would change the cert to a
standard telnet one.

Hope this helps, feel free to ask otherwise -

Regards,

- Mac
Romek Szczesniak (Guest)
on 2009-03-16 17:55
(Received via mailing list)
Hi,

Before doing this in ruby, it might be better to make sure all is
working ok.

I recommend you looking at stunnel (http://www.stunnel.org) to create
a simple SSL tunnel to test your certificate and network is setup
correctly for SSL.

Then dive into doing it in Ruby OpenSSL.

You might also want to look at my sslplaypen (http://rubyforge.org/
projects/sslplaypen/) for some example code on what Ruby can do (and
can't) with OpenSSL as the manuals are not good here.

Kind regards
Romek
Michal S. (Guest)
on 2009-03-16 20:05
(Received via mailing list)
2009/3/15 Erick C. <removed_email_address@domain.invalid>:
> and the symptoms have not gone away.
> include OpenSSL
>   end
> telnet localhost 2007
>        from ./server3.rb:14
>

You are getting a SSL exception here.

I guess this is perfectly normal and expected. You connect to your SSL
server with telnet which does not support SSL, and then you(or
telnett) write some garbage (or nothing at all) which is not a SSL
handshake.

So the SSL library reports an error which appears as exception in Ruby.

You should catch the exception (and possibly print the error) and
retry the accept in case a valid SSL client connects later.


HTH

Michal
Erick C. (Guest)
on 2009-03-17 04:57
Michal,

You were absolutely correct in that I was getting an SSL exception, but
I refused to believe that this should be "normal" behavior.  In my
opinion an SSLServer in ruby should not crash by default when an
unencrypted connection is made.

I started digging deeper and I ended up fixing it by modifying the
actual openssl/ssl.rb file.  Previously the code in the "accept"  method
looked like this:

def accept
        sock = @svr.accept
        begin
          ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
          ssl.sync_close = true
          ssl.accept if @start_immediately
          ssl
        rescue SSLError => ex
          sock.close
          raise ex
        end
      end

I have modified it by adding an extra rescue clause:

 def accept
        sock = @svr.accept
        begin
          ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
          ssl.sync_close = true
          begin

      ssl.accept if @start_immediately

      rescue SSLError => ex3
      ssl.close
    end
        ssl
        rescue SSLError => ex
          sock.close
          raise ex
        end
      end

This still spews an error server side but my server does not crash
anymore.  I can probably add more code and handle the exception more
gracefully, but for now this will do.

**This fix does not work for the example code that I posted above so
this is not a universal fix.  It does fix the issue in my SSLServer that
uses Threads, though.

Thank you to everyone and their suggestions.
Michal S. (Guest)
on 2009-03-18 12:40
(Received via mailing list)
2009/3/17 Erick C. <removed_email_address@domain.invalid>:
> Michal,
>
> You were absolutely correct in that I was getting an SSL exception, but
> I refused to believe that this should be "normal" behavior.  In my
> opinion an SSLServer in ruby should not crash by default when an
> unencrypted connection is made.

It does not crash. It throws an exception.

In a sample code it is OK to just ignore the exceptional case and let
the server terminate.

In a real server you will want to catch the exception so that the
server continues to run:

begin
  socket = server.accep
  <work with socket>
rescue SSLError => ex
  STDERR. puts ex.inspect
end

HTH

Michal
This topic is locked and can not be replied to.