2011-05-03 63 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,因爲他明白,這不是問題的補充。如果您同意他的觀點,請嘗試使用此答案作爲問題的解決方案!