【问题标题】:Using a self-signed certificate使用自签名证书
【发布时间】:2023-05-26 22:58:01
【问题描述】:

我只是想了解 SSL。

我已经在我的本地主机上设置了一个 Jetty 服务器,并使用Keytool 生成了我自己的证书。

现在当我转到 https://localhost:8443/ 时,我得到了无法信任此证书的错误。

我用

keytool -export -alias pongus -keystore keystore -file certfile.cer

创建我认为客户端需要向服务器进行身份验证的证书。 (这可能是我大错特错的地方!)

我有以下红宝石代码:

require 'net/https'
require 'openssl'

require 'open-uri'

puts 'yay' if File.exists?('certfile.cer')

uri = URI.parse("https://localhost:8443/")
http_session = Net::HTTP.new(uri.host, uri.port)
http_session.use_ssl = true
http_session.verify_mode = OpenSSL::SSL::VERIFY_PEER
http_session.ca_file = 'certfile.cer'
res = http_session.start do |http|
  # do some requests here
  http.get('/')
end

这确实会打印 'yay',因此 certfile.cer 文件确实存在。

但我得到了错误

/Applications/NetBeans/NetBeans 6.8.app/Contents/Resources/NetBeans/ruby2/jruby-1.4.0/lib/ruby/1.8/net/http.rb:586 warning: can't set verify locations
/Applications/NetBeans/NetBeans 6.8.app/Contents/Resources/NetBeans/ruby2/jruby-1.4.0/lib/ruby/1.8/net/http.rb:586:in `connect': certificate verify failed (OpenSSL::SSL::SSLError)

任何想法我做错了什么?

编辑

我想得到它,所以我保证我正在连接到正确的服务器,并且服务器可以保证是我连接到它,中间没有任何篡改。我正在开发服务器和客户端。

【问题讨论】:

    标签: ruby ssl jruby keytool


    【解决方案1】:

    您的客户需要访问其 私钥。

    服务器证书验证不需要私钥。您所需要的只是包含公钥的证书本身。只有服务器拥有私钥。在这里http://www.helpbytes.co.uk/https.php 和这里http://www.verisign.com/ssl/ssl-information-center/how-ssl-security-works/ 描述得很好

    我的建议很简单。检查您的证书是否正确。

    openssl x509 -text -in mycert.crt
    

    此外,如果您有权访问服务器,则可以明确验证证书和密钥(用于 httpd 配置)是否正确(匹配):http://kb.wisc.edu/middleware/page.php?id=4064 请注意这是在服务器上运行的显式检查。永远不要泄露私钥。此检查只能由管理员进行,以验证 httpd 是否配置错误。

    (openssl x509 -noout -modulus -in server.pem | openssl md5 ;\
       openssl rsa -noout -modulus -in server.key | openssl md5) | uniq
    

    您还可以使用标准 openssl 命令调试 SSL 证书通信。发出此命令,然后等待几秒钟,然后键入 QUIT 并按 Enter。您将看到服务器发出的证书。

    openssl s_client -connect your.server.com:443
    

    还可以尝试将证书导入浏览器并访问 URL 资源。浏览器可以通过单击 https(Firefox 和 Chrome)来验证它。然后你会看到证书本身和有效性信息。

    以上所有内容都是关于服务器证书。这只是问题的一部分。 “我正在连接到正确的服务器,服务器可以保证是我连接到它”实际上在您上面的代码中,您只检查服务器证书。现在。如果你想要一个客户端证书(你声明的第二部分)而不是你在 Ruby 中需要这个:

    File.open( "client_certificate.pem", 'rb' ) { |f| cert = f.read }
    File.open( "client_key.pem", 'rb' ) { |f| key = f.read }
    http_session.cert = OpenSSL::X509::Certificate.new(cert)
    http_session.key = OpenSSL::PKey::RSA.new(key, nil)
    

    这就是 client cert 在 Ruby 中的使用方式。如果您的私钥是用密码加密的,只需在 RSA 构造函数的第二个参数中传递它而不是 nil。

    我强烈建议让服务器证书(您的代码)工作,然后从客户端证书开始。请注意,您保留当前代码(ca_cert,验证常量)并将上述四行添加到其中。

    希望这会有所帮助。

    【讨论】:

    • 在任何情况下,您都不需要客户端上的私钥。永远不能。期间。
    • 还有一件事。您还可以使用 Firefox 或 IE 导出证书!它非常简单。访问该页面并将其导出到 PEM 文件。您可以将其与 Ruby 一起使用。我这样做了好几次。有效!
    • 错了。您只是不了解 SSL 客户端身份验证,这是提问者明确表示他需要的。 “...我认为这是客户端需要向服务器进行身份验证的内容...”以及编辑中的评论表明这一点。
    • 不,格雷格,你是对的。他询问 SSL 客户端身份验证,但他面临 SSL 服务器证书验证的问题。这是不同的。属性 http_session.ca_file 和 http_session.verify_mode 用于 SSL 客户端证书。
    • @Izap:你需要阅读他写的内容:“......所以我保证我正在连接到正确的服务器,并且服务器可以保证是我连接到它,.. ."。这称为客户端身份验证。
    【解决方案2】:

    您的客户需要访问其私钥。私钥不在证书中,证书只包含公钥。抱歉,我不了解 ruby​​,但一种常用技术是将私钥和证书捆绑在单个 PKCS#12(又名 p12)文件中,并将其提供给加密库。

    【讨论】:

    • 很好,这是很好的信息,可以让我继续前进!生病回到 keytool 文档。谢谢
    • Ruby 接受 PEM。根本不需要 p12 和私钥。发出 PK 是一个安全漏洞 :-)
    • @Izap:没有私钥,有两个:一个给客户端,一个给服务器。这就是为什么我说客户端需要访问 ITS 私钥,而不是服务器的。
    • 格雷格你试图混合两件事。上面的那个人要求针对 CA 证书进行 SSL 服务器证书验证。您正在描述 SSL 用户认证授权。这是两个不同的东西。他们可以住在一起。
    • 抱歉,他确实需要私钥,但仅用于客户端证书。对于服务器证书,私钥存储在服务器上。请参阅我上面的帖子。
    【解决方案3】:

    改变

    http_session.verify_mode = OpenSSL::SSL::VERIFY_PEER
    

    http_session.verify_mode = OpenSSL::SSL::VERIFY_NONE
    

    一旦你这样做了,SSL 就会正常工作。我在我的开发环境中多次使用它,总是完美无缺。

    【讨论】:

    • 谢谢,但我不希望它回避验证。 . ;-)
    • 很抱歉花了这么长时间才回复这个问题。由于 VERIFY_PEER 尝试针对已知的 SSL 颁发者验证证书,因此您必须使用 VERIFY_NONE 绕过此检查。它不是验证证书本身,而是验证证书的颁发者。由于自签名证书没有已知的颁发者,因此无法通过检查。
    • 这真的很危险。如果您不知道自己在做什么,请不要这样做。