Ruby Net / imap获取OpenSSL :: SSL :: SSLError-自签名证书?

时间:2019-05-09 18:34:41

标签: ruby ssl imap gmail-imap

在尝试开发一种使用IMAP访问Gmail的工具时,即使使用以下简单的启动代码,我也遇到了麻烦:

require 'net/imap'
imap = Net::IMAP.new('imap.gmail.com', ssl: true)

运行该命令,它会失败,如下所示(注意:为了便于显示,对其进行了轻松编辑)

Traceback (most recent call last):
        5: from test-imap:2:in `<main>'
        4: from test-imap:2:in `new'
        3: from /.../.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/net/imap.rb:1092:in `initialize'
        2: from /.../.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/net/imap.rb:1533:in `start_tls_session'
        1: from /.../.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/net/protocol.rb:44:in `ssl_socket_connect'
/.../.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/net/protocol.rb:44:in
  `connect_nonblock': SSL_connect returned=1 errno=0 state=error:
  certificate verify failed (self signed certificate) (OpenSSL::SSL::SSLError)

四处搜寻,我发现了一些类似的问题,例如imap-backup issue #57ruby/openssl issue #238在下面分享答案后,仍然保持打开状态,在撰写本文时关闭了),还有rbenv/ruby-build issue #380 ...在SO上什么都没有。

从以上资源中整理信息,我想出了以下命令来尝试:

openssl s_client -connect imap.gmail.com:993 \
  -CAfile $(ruby -ropenssl -e 'puts OpenSSL::X509::DEFAULT_CERT_FILE') \
  < /dev/null > /dev/null

哪个报告:

depth=2 /OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign
verify return:1
depth=1 /C=US/O=Google Trust Services/CN=Google Internet Authority G3
verify return:1
depth=0 /C=US/ST=California/L=Mountain View/O=Google LLC/CN=imap.gmail.com
verify return:1
DONE

因此,似乎SSL证书确实以这种方式验证了OK(如人们所期望的那样)。

我确实发现some instructions可以与net/imap一起使用,并且在禁用主机检查的情况下将SSL与SSL结合使用,这确实有效……但我真的不愿意这样做。

我还找到了non-IMAP gmail interface,但是我的目的是可以与其他IMAP提供程序一起使用的工具,因此我在这里的具体目标是坚持使用IMAP。所以:

如何让net/imap使用SSL成功连接,并且仍然验证证书(实际上是有效的)?

2 个答案:

答案 0 :(得分:3)

理想:升级到Ruby 2.6.3或更高版本

升级到Ruby 2.6.3或更高版本应该可以解决问题,因为ruby pull #2077已合并到related issue #15594中,2.6.3 change listcommit that fixed imap-backup issue #57提供了修复程序。对于2.6.3,现在可以使用问题中的原始测试代码片段。

如果您无法升级:

也就是说,如果出于某种原因无法进行升级,则{{3}}提供了一种解决方法。代替以下内容:

imap = Net::IMAP.new('imap.gmail.com', ssl: true)

尝试一下:

imap = Net::IMAP.new('imap.gmail.com', ssl: {ssl_version: :TLSv1_2})

即使在Ruby 2.6.0中,这似乎也可以使工作正常。

答案 1 :(得分:0)

在Ruby 2.4中,我不得不使用此补丁:

require 'net/imap'

class Net::IMAP
  module UseSNI
    def start_tls_session(*)
      @sock.instance_variable_set(:@hostname, @host)
      super
    end
  end

  prepend UseSNI
end

class OpenSSL::SSL::SSLSocket
  module UseSNI
    def connect(*)
      self.hostname = io.instance_variable_get(:@hostname)
      super
    end
  end

  prepend UseSNI
end