2012-06-09 12 views
8

Ésta es la forma en que genero mi certificado SSL, llave, etc:certificado SSL, no se autentica mediante el ahorro, pero bien a través del navegador

openssl genrsa -out server.key 1024 
openssl rsa -in server.key -out new_key.pem 
openssl req -new -key server.key -out server.csr 
openssl x509 -req -days 10000 -in server.csr -signkey new_key.pem -out server.crt 

Esto funciona, puedo ver la salida en cromo, aunque consigo una advirtiendo que voy a tener virus primero.

openssl s_server -cert server.crt -www -key new_key.pem 

esto es un fragmento del servidor. Voy a ser honesto, no estoy seguro exactamente lo que está haciendo cada línea, aunque no tengo una buena idea:

socketFactory->server(true); // this is the server 
socketFactory->authenticate(false); // no auth? 
socketFactory->loadCertificate("server.crt"); 
socketFactory->loadPrivateKey("new_key.pem"); 

cliente:

socketFactory->loadTrustedCertificates("server.crt"); 
socketFactory->authenticate(true); //auth? wierd, right? This guy does this:[1] 

[1] http://permalink.gmane.org/gmane.comp.lib.thrift.user/1651

Si Comente loadTrustedCertificates en el cliente, luego recibo una excepción de certificado SSL no verificado. Con esa línea, recibo una excepción de error de autenticación.

Aquí hay 2 fragmentos de código mucho más largos, que ponen los fragmentos anteriores en una mejor perspectiva.
servidor:

shared_ptr<SkullduggeryHandler> handler(new SkullduggeryHandler()); 
shared_ptr<TBufferedTransportFactory> transportFactory = 
     shared_ptr<TBufferedTransportFactory>(new TBufferedTransportFactory()); 
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); 
shared_ptr<TProcessor> processor(new SkullduggeryProcessor(handler)); 
shared_ptr<TSSLSocketFactory> socketFactory = 
     shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory()); 
socketFactory->server(true); 
socketFactory->authenticate(false); 
socketFactory->loadCertificate("server.crt"); 
socketFactory->loadPrivateKey("new_key.pem"); 
shared_ptr<TSSLServerSocket> socket(new TSSLServerSocket(port, socketFactory)); 
TThreadedServer server(processor, 
           socket, 
           transportFactory, 
           protocolFactory); 
server.serve(); 

cliente:

shared_ptr <TSSLSocketFactory> socketFactory = shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory()); 
socketFactory->loadTrustedCertificates("server.crt"); 
socketFactory->authenticate(false); 
shared_ptr <TSSLSocket>socket = socketFactory->createSocket(configuration.ip, configuration.port); 
shared_ptr<TBufferedTransport> transport(new TBufferedTransport(socket)); 
shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport)); 
SkullduggeryClient client(protocol); 
transport->open(); 

Gracias por tomarse el tiempo para leer esto. Si hay errores evidentes, estaré encantado de saber de eso. Esta ha sido la ruina de mi existencia por mucho tiempo ahora. Demasiado largo.

Respuesta

10

Parece que está generando certificados autofirmados (lo cual está bien), pero las operaciones que está realizando con la utilidad openssl son confusas.

La línea 1 está bien, genera una clave privada.
La línea 2 es inútil: la tecla de salida es la misma que la tecla de entrada. (Intente llamar al diff las dos teclas para ver).
La línea 3 genera una CSR y la línea 4 en realidad la firma por sí misma, por lo que se pueden fusionar en una línea como veremos.

Ahora, vamos a dar un paso atrás y vamos a tratar de entender lo que estamos haciendo :-)

Está utilizando SSL para autenticar y cifrar la comunicación entre un servidor y un cliente de Ahorro de Ahorro. Asumo que desea tanto:

  1. proteger al cliente de un servidor pirata (lo que el código está tratando de hacer)
  2. proteger el servidor desde un cliente rogue (que parece aún más importante para mí).

Para hacer una analogía HTTPS, (1) es el certificado de servidor clásico, (2) es normalmente un nombre de usuario/contraseña para el usuario. Pero con Thrift SSL, obtendremos autenticación mutua al emitir un certificado también al cliente.

Los ejemplos que haré utilizarán certificados autofirmados. Se pueden adaptar fácilmente a una mini CA administrada por openssl, y dejo esto como un ejercicio para el lector.

generar la clave privada del servidor:
openssl genrsa -out server-key.pem 2048

generar la clave pública asociada y la auto-firmarlo:
openssl req -new -x509 -key server-key.pem -out server-cert.pem -days 10000

generar la clave privada del cliente:
openssl genrsa -out client-key.pem 2048

Generar la clave pública asociada y auto-firmarlo:
openssl req -new -x509 -key client-key.pem -out client-cert.pem -days 10000

Nota: cuando openssl req pregunta por "Common Name (e.g. server FQDN or YOUR name)", ingrese el FQDN del host en el que se ejecutará el programa Thrift. Esto permitirá no personalizar la clase AccessManager de Thrift. Si, por otro lado, el FQDN no se puede conocer de antemano, se debe heredar AccessManager y anular los métodos verify() en consecuencia. Ver TSSLSocket.cpp.

Bien, ahora al código.

En el lado del servidor:

socketFactory->server(true); es redundante, eliminarlo.

socketFactory->authenticate(false) es un poco engañoso. Un mejor nombre habría sido authenticatePeer. Si dices false, no autenticará al cliente, pero decidimos antes de querer la autenticación mutua.

Así, un preámbulo SSL para un servidor es:

try { 
    signal(SIGPIPE, SIG_IGN); // See README.SSL 
    shared_ptr<TSSLSocketFactory> sslSocketFactory(new TSSLSocketFactory()); 
    sslSocketFactory->loadPrivateKey(myKey); 
    sslSocketFactory->loadCertificate(myCert); 
    sslSocketFactory->authenticate(true); 
    sslSocketFactory->loadTrustedCertificates(trustedCerts); 
    sslSocketFactory->ciphers("HIGH:!DSS:[email protected]"); 
    ... 
    } catch (TException& tx) { 
     .... 
    } 

Dónde myKey es server-key.pem, myCert es server-cert.pem y trustedCerts se ... o bien el certificado de una CA de confianza, o, en caso de un auto -cert firmado, el certificado del cliente. Puede cat certs múltiples uno después del otro en el mismo archivo. En nuestro ejemplo, pondremos client-cert.pem que creamos antes.

Un preámbulo SSL para un cliente es exactamente el mismo, con la clave privada del cliente correcta, el certificado del cliente y, para trustedCerts, el certificado del par: server-cert.pem que creamos anteriormente.

Eso es todo :-) Trate de entender antes de saltar a codificarlo, si no tiene una idea clara de cómo funciona la autenticación SSL (mutua), es difícil entender los mensajes de error. El código que mostré está probado para funcionar.

En cuanto a la documentación, por desgracia, Thrift está cerca de nada. Para SSL, puede ver: lib/cpp/README.SSL, test/cpp/src/TestServer.cpp y test/cpp/src/TestClient.cpp. Tenga en cuenta que TestServer.cpp no hace autenticación mutua, que es un error en mi humilde opinión.

Cuestiones relacionadas