2012-04-21 26 views
6

¿Cómo se puede asegurar un socket con SSL en Ruby cuando necesita comunicarse primero sobre texto plano?Agregar SSL a una conexión

no puedo usar OpenSSL::SSL::SSLServer porque es responsabilidad del cliente para solicitar una conexión SSL primera

coloques una larga historia corta, que estoy tratando de poner en práctica RFC3207, donde el cliente envía la palabra clave "STARTTLS", y luego se crea una conexión SSL.

Mi pregunta es "¿Cómo creo la conexión SSL después de que el servidor ha enviado '220 OK'?"

sé que puedo usar OpenSSL::SSL::SSLSocket en el lado del cliente, pero no tengo ni idea de qué hacer en el lado del servidor

Si sabe cómo hacer esto en un idioma que no sea Ruby, simplemente colocar el código y voy a traducirlo, he estado trabajando en esto durante aproximadamente 8 horas y necesito todo lo que puedo obtener

He pedido en # ruby-lang, pero sin éxito, y he intentado envolver Socket objetos en SSLSockets en el servidor y el cliente al mismo tiempo, pero eso no funciona

En resumen, estoy muy atascado, necesito toda la ayuda Puedo conseguir

Respuesta

3

Creé este gist para ilustrar cómo configurar un servidor TLS mínimo. Es posible que desee dejar fuera las líneas 62-67, que era para ilustrar una nueva función en el maletero.

Pero aparte de eso, es un servidor TLS que funciona completamente, puede construir sobre él para agregar funcionalidad adicional.

También es posible que desee cambiar CN del certificado de servidor de "localhost" a un dominio real si desea utilizar en serio :)

Usted puede notar que la mayor parte del trabajo es en realidad la creación de la Aspectos PKI correctamente. La parte del servidor central es la siguiente:

ctx = OpenSSL::SSL::SSLContext.new 
ctx.cert = ... # the server certificate 
ctx.key = ... # the key associated with this certificate 
ctx.ssl_version = :SSLv23 
tcps = TCPServer.new('127.0.0.1', 8443) 
ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) 
ssls.start_immediately = true 
begin 
    loop do 
    ssl = ssls.accept 
    puts "Connected" 
    begin 
     while line = ssl.gets 
     puts "Client says: #{line}" 
     ssl.write(line) # simple echo, do something more useful here 
     end 
    ensure 
     ssl.close 
    end 
    end 
ensure 
    tcps.close if tcps 
end 
+0

¿Cuánto de la generación de certificados puedo eliminar? Estoy considerando poner eso en una secuencia de comandos para generar un certificado por un año y mantener los certificados en control de fuente. Su ejemplo de barebones arriba es (más o menos, salvo reutilización del contexto) lo que estoy usando ahora, y ocasionalmente está causando errores extraños, y creo que ya los ha visto :) – lcarpenter

0

he hecho algunos avances en este, salvo para uso futuro:

  • Sí, usted debe usar OpenSSL SSL :: :: SSLSocket en ambos extremos
  • En el lado servidor, debe crear un objeto OpenSSL :: SSL :: SSLContext , pasando un símbolo con el protocolo que desea utilizar y "_server" agregado al final, vea OpenSSL :: SSL :: SSLContext :: METHODS para lo que quiero decir, en uso corto ": TLSv1_server" para RFC3207 ni siquiera necesita hacer eso, en el lado del servidor crear el contexto con certs y luego llamar a #accept en el socket para esperar la transferencia del cliente
  • pase en los certificados SSL al objeto CTX

Editar a su gusto

3

Usted tiene que fijar campo start_immediately del SSLServer a falsa con el fin de iniciar el servidor SSL en modo de texto sin formato. En cualquier punto (es decir, cuando recibe el comando STARTTLS del cliente), puede llamar al método de aceptación SSLSocket para iniciar el protocolo de enlace SSL/TLS. El cliente, por supuesto, tienen que estar de acuerdo con el protocolo :)

Aquí es un servidor de ejemplo que escribí para probar esto:

#!/usr/bin/ruby 

require 'socket'; 
require 'openssl'; 

certfile = 'mycert.pem'; 
port = 9002; 

server = TCPServer.new(port); 

# Establish an SSL context 
sslContext = OpenSSL::SSL::SSLContext.new 
sslContext.cert = OpenSSL::X509::Certificate.new(File.open(certfile)); 
sslContext.key = OpenSSL::PKey::RSA.new(File.open(certfile)); 

# Create SSL server 
sslServer = OpenSSL::SSL::SSLServer.new(server, sslContext); 

# Don't expect an immidate SSL handshake upon connection. 
sslServer.start_immediately = false; 

sslSocket = sslServer.accept; 

sslSocket.puts("Toast.."); 

# Server loop 
while line = sslSocket.gets 

     line.chomp!; 

     if "STARTTLS" == line 
       # Starting TLS 
       sslSocket.accept; 
     end 

     sslSocket.puts("Got '#{line}'"); 

end 

sslSocket.close; 

Estoy seguro de que el cartel original sabe cómo poner a prueba STARTTLS, pero el el resto de nosotros podría necesitar este recordatorio. Actaually estoy normalmente utilizando las utilidades del paquete GNUTLS (gnutls-bin en Debian/Ubuntu) para poner a prueba STARTTLS, ya que me permite iniciar el apretón de manos cada vez que quiero:

$ gnutls-cli --starttls --port 9002 --insecure localhost 

Esto conecta en texto plano Modo de socket TCP Escriba algunas líneas y haga que se hagan eco. Este tráfico no está encriptado. Si envía STARTTLS, se llama al sslSocket.accept y el servidor espera el protocolo de enlace SSL. Presione ctrl-d (EOF) para iniciar el protocolo de enlace desde el cliente gnutls y ver cómo establece una conexión SSL cifrada. Las líneas subsiguientes se repetirán también, pero el tráfico ahora está encriptado.

+0

monté aparte de la aplicación OpenSSL SSLServer como referencia para escribir el código que estoy usando hoy en día, y que está buscando casi idénticas, aparte de #sync_close, y todavía está lanzando los errores:/ – lcarpenter

Cuestiones relacionadas