尝试通过 SSL 创建一个简单的 Ruby 服务器
我正在尝试用 Ruby 创建一个简单的 SSL 客户端和服务器。但我收到一条神秘的错误消息,并且文档没有任何帮助。
这是我的服务器代码:
#!/usr/bin/ruby
require "gserver"
require "openssl"
listeningPort = Integer(ARGV[0])
class Server < GServer
def initialize(listeningPort)
@sslContext = OpenSSL::SSL::SSLContext.new
@sslContext.cert = OpenSSL::X509::Certificate.new(File.open("MyCert.pem"))
super(listeningPort, "0.0.0.0")
end
def serve(io)
begin
ssl = OpenSSL::SSL::SSLSocket.new(io, @sslContext)
ssl.sync_close = true
ssl.connect
while (lineIn = ssl.gets)
lineIn = lineIn.chomp
$stdout.puts "=> " + lineIn
lineOut = "You said: " + lineIn
$stdout.puts "<= " + lineOut
ssl.puts lineOut
end
rescue
$stderr.puts $!
end
end
end
server = Server.new(listeningPort)
server.start
server.join
客户端代码类似:
#!/usr/bin/ruby
require "socket"
require "thread"
require "openssl"
host = ARGV[0]
port = Integer(ARGV[1])
socket = TCPSocket.new(host, port)
sslContext = OpenSSL::SSL::SSLContext.new
sslContext.cert = OpenSSL::X509::Certificate.new(File.open("MyCert.pem"))
ssl = OpenSSL::SSL::SSLSocket.new(socket, sslContext)
ssl.sync_close = true
ssl.connect
puts ssl.peer_cert # this is nil
Thread.new {
begin
while lineIn = ssl.gets
lineIn = lineIn.chomp
$stdout.puts lineIn
end
rescue
$stderr.puts "Error in input loop: " + $!
end
}
while (lineOut = $stdin.gets)
lineOut = lineOut.chomp
ssl.puts lineOut
end
当我连接时,我在服务器和客户端上都收到此错误:
in `connect': SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: unknown protocol (OpenSSL::SSL::SSLError)
问题可能是它不信任证书(自签名)。我不知道如何告诉客户端信任该证书。上面,我已将服务器的证书放在上下文中,但这只是盲目的尝试。我什至不确定我的证书是否采用可接受的格式(它采用 base64 格式,证书和私钥位于文件中)。文档非常少,网上似乎也没有太多这方面的内容。
有什么想法吗?
I am trying to create a simple SSL client and server in Ruby. But I'm getting a cryptic error message and the documentation is of no help.
Here is my server code:
#!/usr/bin/ruby
require "gserver"
require "openssl"
listeningPort = Integer(ARGV[0])
class Server < GServer
def initialize(listeningPort)
@sslContext = OpenSSL::SSL::SSLContext.new
@sslContext.cert = OpenSSL::X509::Certificate.new(File.open("MyCert.pem"))
super(listeningPort, "0.0.0.0")
end
def serve(io)
begin
ssl = OpenSSL::SSL::SSLSocket.new(io, @sslContext)
ssl.sync_close = true
ssl.connect
while (lineIn = ssl.gets)
lineIn = lineIn.chomp
$stdout.puts "=> " + lineIn
lineOut = "You said: " + lineIn
$stdout.puts "<= " + lineOut
ssl.puts lineOut
end
rescue
$stderr.puts $!
end
end
end
server = Server.new(listeningPort)
server.start
server.join
The client code is similar:
#!/usr/bin/ruby
require "socket"
require "thread"
require "openssl"
host = ARGV[0]
port = Integer(ARGV[1])
socket = TCPSocket.new(host, port)
sslContext = OpenSSL::SSL::SSLContext.new
sslContext.cert = OpenSSL::X509::Certificate.new(File.open("MyCert.pem"))
ssl = OpenSSL::SSL::SSLSocket.new(socket, sslContext)
ssl.sync_close = true
ssl.connect
puts ssl.peer_cert # this is nil
Thread.new {
begin
while lineIn = ssl.gets
lineIn = lineIn.chomp
$stdout.puts lineIn
end
rescue
$stderr.puts "Error in input loop: " + $!
end
}
while (lineOut = $stdin.gets)
lineOut = lineOut.chomp
ssl.puts lineOut
end
When I connect, I get this error on both the server and the client:
in `connect': SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: unknown protocol (OpenSSL::SSL::SSLError)
The problem could be that it doesn't trust the certificate (self-signed). I'm not sure how to tell the client to trust that certificate. Above, I have put the server's cert in the context, but that was just a shot in the dark. I'm not even sure my certificate is in an acceptable format (it is in base64 with the cert and the private key in the file). The documentation is very scant and there doesn't seem to be much on the web in this area either.
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我想通了,多亏了一些不错的文档的链接。
一方面,SSLSocket.connect() 只能在客户端上调用。
但主要问题是我正在尝试使用 GServer 套接字并将其升级到 SSL。相反,我应该使用 OpenSSL::SSL::SSLServer。
另外,我将证书和私钥分成两个文件。
这是工作服务器:
和客户端:
I figured it out, thanks to that link to some decent documentation.
For one thing, SSLSocket.connect() is only meant to be called on the client.
But the main problem is that I'm trying to take a GServer socket and upgrade it to SSL. Instead, I should use OpenSSL::SSL::SSLServer.
Also, I separated my certificate and private key into two files.
Here is the working server:
And client:
如果您需要提供中间证书,请使用它们设置 sslContext.extra_chain_cert 。
如果使用 LetsEncrypt 证书,请使用 fullchain.pem 作为 sslContext.cert,使用 privkey.pem 作为 sslContext.key,使用 [“chain.pem”] 作为 sslContext.extra_chain_cert。这样做,您还可以通过全链验证来测试从浏览器到服务器的连接。
注意:这补充了作者的答案 https://stackoverflow.com/a/5873796/533510 ,但被拒绝了用户@joe,因为他知道这不是问题的补充。如果您同意他的观点,请尝试使用此答案作为问题的解决方案!
if you need to provide intermediate certificates, set sslContext.extra_chain_cert with them.
If use have letsencrypt certificates, use your fullchain.pem for sslContext.cert, privkey.pem for sslContext.key and ["chain.pem"] for sslContext.extra_chain_cert. Doing so, you can also test the connection to the server from your browser, with full chain verification.
Note: this complements the author's answer https://stackoverflow.com/a/5873796/533510 , but it was rejected by user @joe , because he understands that this is not a complement for the question. If you agree to him, try using this answer as solution to the question!