2011-05-03 70 views
14

我想在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中,证书和文件中的私钥)。文档非常少,网络上也没有太多这方面的内容。

任何想法?

+0

啊,这有助于:http://stackoverflow.com/questions/4730544/ruby-openssl-documentation – Fantius 2011-05-03 18:00:24

回答

15

我想通了,由于链接到一些体面的文件。

首先,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 
+2

你能发布命令来生成cert.pem和priv.pem吗? – adamwong246 2011-08-31 17:44:14

+1

http://www.cryptosys.net/pki/rsakeyformats.html – Fantius 2011-08-31 19:48:35

+0

我无法编辑:'stderrr'应该是'$ stderr' – ribamar 2017-05-02 13:39:31

0

,如果你需要提供中间证书,设置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,因为他明白,这不是问题的补充。如果您同意他的观点,请尝试使用此答案作为问题的解决方案!