njh / ruby-mqtt

Pure Ruby gem that implements the MQTT protocol, a lightweight protocol for publish/subscribe messaging.
http://www.rubydoc.info/gems/mqtt
MIT License
542 stars 135 forks source link

Error: can't modify frozen OpenSSL::SSL::SSLContext #144

Open MaffooClock opened 2 years ago

MaffooClock commented 2 years ago

I'm using this library to connect to AWS IoT -- works great! However, from time to time, I guess there's some sort of disruption in the connection (don't really have any good guesses on what those causes might be), and eventually my STDOUT is full of messages like this (because my script is attempting to reconnect):

Error: can't modify frozen OpenSSL::SSL::SSLContext: #<OpenSSL::SSL::SSLContext:0x000000010e4c0f90
    @verify_mode=1,
    @verify_hostname=false,
    @ca_file="services/../lib/ssl/aws-ca1.crt",
    @cert=#<OpenSSL::X509::Certificate:
        subject=#<OpenSSL::X509::Name CN=AWS IoT Certificate>,
        issuer=#<OpenSSL::X509::Name OU=Amazon Web Services O=Amazon.com Inc. L=Seattle ST=Washington C=US>, 
        serial=#<OpenSSL::BN:0x000000010e916cc0>, not_before=2022-05-04 14:24:53 UTC, not_after=2049-12-31 23:59:59 UTC
    >,
    @key=#<OpenSSL::PKey::RSA:0x000000010e4c05e0 oid=rsaEncryption>,
    @max_proto_version=771,
    @min_proto_version=771
>

The fix is simply to terminate the script and restart it, and it works fine again.

Is this gem leaving something dirty on the connection? Or is it my OpenSSL version? Or...?

$ ruby -v      
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-darwin21]

$ gem info mqtt

*** LOCAL GEMS ***

mqtt (0.5.0)
    Author: Nicholas J Humfrey
    Homepage: http://github.com/njh/ruby-mqtt
    License: MIT
    Installed at: /Users/mclark/.rvm/gems/ruby-3.1.2

    Implementation of the MQTT protocol

$ openssl version
LibreSSL 2.8.3
MaffooClock commented 2 years ago

After studying lib/mqtt/client.rb, I wonder if after the connection drops and it is reconnected, if it's re-using the ssl_context instead of instantiating a new one?

As I understand it, an SSLContext cannot be modified after creation of an SSLSocket.

I see where @ssl_context gets instantiated, but nowhere else is it ever cleaned up and re-set. Maybe in disconnect() (and perhaps somewhere else) there should be something like @ssl_context = nil, so that subsequent calls to ssl_context() cause a new one to be instantiated?

I may be waaaaay off in left field here 🙃