Ruby openssl SSLContext密码

问题描述

我用OpenSSL库在Ruby中编写了以下代码,该库从cloudflare.com获取证书链。但是Cloudflare有一个混合系统,其中旧的浏览器接收RSA证书,而新的客户端接收ECDSA证书(请参阅https://www.ssllabs.com/ssltest/analyze.html?d=cloudflare.com&s=104.17.176.85)。 就我而言,我想获得较旧的RSA证书,这就是为什么我设置ctx.ciphers = 'aRSA'的原因。但是我总会收到ECDSA证书。 通过openssl s_client -cipher aRSA -connect cloudflare.com:443 -showcerts可以执行以下命令。

require 'openssl'

ctx = OpenSSL::SSL::SSLContext.new
ctx.ciphers = 'aRSA'
sock = Socket.tcp("https://www.cloudflare.com",443,connect_timeout: 10)
connection = connect(sock,ctx,hostname)
connection.peer_cert_chain

def connect(sock,url)
   ssl = OpenSSL::SSL::SSLSocket.new(sock,ctx)
   ssl.hostname = url
   begin
      ssl.connect_nonblock
   rescue IO::WaitReadable
      return nil unless IO.select([ssl],nil,10)

      retry
   rescue IO::WaitWritable
      return nil unless IO.select(nil,[ssl],10)

      retry
   end
   ssl
end

谢谢

Ruby版本:2.6.3 Ruby OpenSSL版本:2.2.0 OpenSSL版本:LibreSSL 2.8.3

解决方法

TLS 1.3更改了对密码套件的定义方式。来自OpenSSL Wiki

新密码套件的定义不同,没有指定证书类型(例如RSA,DSA,ECDSA)或密钥交换机制(例如DHE或ECHDE)。这对密码套件的配置有影响。

就您而言,即使您指定了aRSA,OpenSSL仍包含1.3密码,该密码可与EC证书一起使用。

我不知道是否可以指定密码列表以排除这些密码(我无法使其工作),但是您可以将最高版本设置为1.2:

ctx.max_version = :TLS1_2
ctx.ciphers = 'aRSA'

这将使Cloudflare使用RSA证书。

我认为在TLS 1.3中指定您不希望ECDSA证书的正确方法是使用请求中的signature_algorithms扩展名字段,但是Ruby的OpenSSL绑定不支持该扩展名。