试图通过SSL创建一个简单的Ruby服务器
我想在Ruby中创建一个简单的SSL客户端和服务器。但是我收到了一条神秘的错误消息,文档没有任何帮助。试图通过SSL创建一个简单的Ruby服务器
这里是我的服务器代码:
#!/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中,证书和文件中的私钥)。文档非常少,网络上也没有太多这方面的内容。
任何想法?
我想通了,由于链接到一些体面的文件。
首先,SSLSocket.connect()仅用于在客户端上调用。
但主要的问题是,我试图采取GServer套接字并将其升级到SSL。相反,我应该使用OpenSSL :: SSL :: SSLServer。
此外,我将我的证书和私钥分隔为两个文件。
这里是工作服务器:
#!/usr/bin/ruby
require "socket"
require "openssl"
require "thread"
listeningPort = Integer(ARGV[0])
server = TCPServer.new(listeningPort)
sslContext = OpenSSL::SSL::SSLContext.new
sslContext.cert = OpenSSL::X509::Certificate.new(File.open("cert.pem"))
sslContext.key = OpenSSL::PKey::RSA.new(File.open("priv.pem"))
sslServer = OpenSSL::SSL::SSLServer.new(server, sslContext)
puts "Listening on port #{listeningPort}"
loop do
connection = sslServer.accept
Thread.new {
begin
while (lineIn = connection.gets)
lineIn = lineIn.chomp
$stdout.puts "=> " + lineIn
lineOut = "You said: " + lineIn
$stdout.puts "<= " + lineOut
connection.puts lineOut
end
rescue
$stderr.puts $!
end
}
end
和客户端:
#!/usr/bin/ruby
require "socket"
require "thread"
require "openssl"
host = ARGV[0]
port = Integer(ARGV[1])
socket = TCPSocket.new(host, port)
expectedCert = OpenSSL::X509::Certificate.new(File.open("cert.pem"))
ssl = OpenSSL::SSL::SSLSocket.new(socket)
ssl.sync_close = true
ssl.connect
if ssl.peer_cert.to_s != expectedCert.to_s
stderrr.puts "Unexpected certificate"
exit(1)
end
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
你能发布命令来生成cert.pem和priv.pem吗? – adamwong246 2011-08-31 17:44:14
http://www.cryptosys.net/pki/rsakeyformats.html – Fantius 2011-08-31 19:48:35
我无法编辑:'stderrr'应该是'$ stderr' – ribamar 2017-05-02 13:39:31
,如果你需要提供中间证书,设置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,因为他明白,这不是问题的补充。如果您同意他的观点,请尝试使用此答案作为问题的解决方案!
啊,这有助于:http://stackoverflow.com/questions/4730544/ruby-openssl-documentation – Fantius 2011-05-03 18:00:24