Conexiones secretas SSL Socket en Java
sockets sslhandshakeexception (2)
Has comenzado el apretón de manos. Eso es todo lo que tienes que hacer: de hecho, ni siquiera tienes que hacer eso, ya que sucederá automáticamente. Todo lo que tiene que hacer ahora es la entrada y salida normal, igual que lo haría con un socket de texto sin formato.
Estoy trabajando en el cifrado de una conexión tcp entre un servidor y un cliente. En el curso de la investigación y las pruebas me estoy inclinando hacia el uso de cifrado de clave secreta. Mi problema es que no puedo encontrar ningún tutorial sobre cómo implementar esta característica. Los tutoriales que he encontrado giran en torno a las solicitudes https de un solo uso, todo lo que necesito es un Socket SSL.
El código que he escrito hasta ahora está debajo. Estoy casi seguro de que es necesario extenderlo, simplemente no sé cómo. Cualquier ayuda es apreciada.
private ServerSocketFactory factory;
private SSLServerSocket serverSocket;
factory = SSLServerSocketFactory.getDefault();
serverSocket = (SSLServerSocket) factory.createServerSocket( <portNum> );
Código de servidor para aceptar conexiones de cliente
SSLSocket socket = (SSLSocket) serverSocket.accept();
socket.startHandshake();
Simplemente no sé cómo hacer el apretón de manos.
referencia: http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSefGuide.html
Las conexiones de socket SSL tienen soporte en Java y es una buena opción para usted. Lo que hay que entender de antemano es que SSL proporciona cifrado y autenticación de servidor; no puedes obtener solo el cifrado. A modo de referencia, el cifrado protege contra el espionaje de la red, mientras que la autenticación del servidor protege contra los ataques de "hombre en el medio", donde el atacante actúa como un proxy entre el cliente y el servidor.
Dado que la autenticación es una parte integral de SSL, el servidor deberá proporcionar un certificado SSL y el cliente deberá poder autenticar el certificado. El servidor necesitará un archivo "almacén de claves" donde se almacena su certificado. El cliente necesitará un archivo "trust store" donde almacene los certificados en los que confía, uno de los cuales debe ser el certificado del servidor o un certificado del cual se puede rastrear una "cadena de confianza" al certificado del servidor.
Tenga en cuenta que no necesita saber nada sobre los pormenores de SSL para usar sockets SSL de Java. Creo que es interesante leer la información sobre cómo funciona SSL, por ejemplo, en el artículo de Wikipedia sobre TLS, pero el complicado saludo de multipaso y la configuración del cifrado de conexión real se manejan bajo las coberturas de las clases SSLServerSocket y SSLSocket.
El código
Todo lo anterior es solo información de fondo para explicar algunos de los siguientes códigos. El código asume cierta familiaridad con los sockets regulares no encriptados. En el servidor, necesitarás un código como este:
/**
* Returns an SSLServerSocket that uses the specified key store file
* with the specified password, and listens on the specified port.
*/
ServerSocket getSSLServerSocket(
File keyStoreFile,
char[] keyStoreFilePassword,
int port
) throws GeneralSecurityException, IOException {
SSLContext sslContext
= SSLConnections.getSSLContext(keyStoreFile, keyStoreFilePassword);
SSLServerSocketFactory sslServerSocketFactory
= sslContext.getServerSocketFactory();
SSLServerSocket sslServerSocket
= (SSLServerSocket) sslServerSocketFactory.createServerSocket(port);
return sslServerSocket;
}
El SSLServerSocket se puede usar exactamente como lo haría con cualquier otro ServerSocket; la autenticación, el cifrado y el descifrado serán completamente transparentes para el código de llamada. De hecho, la función afín en mi propio código declara un tipo de devolución de ServerSocket simple, por lo que el código de llamada no puede confundirse.
Nota: si desea utilizar el archivo cacerts predeterminado de JRE como archivo de almacenamiento de claves, puede omitir la línea que crea el SSLContext y usar ServerSocketFactory.getDefault()
para obtener ServerSocketFactory. Aún tendrá que instalar el par de claves pública / privada del servidor en el archivo de almacenamiento de claves, en este caso, el archivo de cacerts
.
En el cliente, necesitarás un código como este:
SSLSocket getSSLSocket(
File trustStoreFile,
char[] trustStoreFilePassword,
InetAddress serverAddress,
port serverPort
) throws GeneralSecurityException, IOException {
SSLContext sslContext
= SSLConnections.getSSLContext(trustStoreFile, trustStoreFilePassword);
SSLSocket sslSocket
= (SSLSocket) sslContext.getSocketFactory().createSocket
(serverAddress, serverPort);
sslSocket.startHandshake();
return sslSocket;
}
Como en el caso de SSLServerSocket en el código del servidor, el SSLSocket devuelto aquí se usa como un Socket normal; Las entradas y salidas de SSLSocket están hechas con datos no encriptados, y todas las cosas criptográficas se hacen dentro.
Al igual que con el código del servidor, si desea utilizar el archivo cacerts JRE predeterminado como su almacén de confianza, puede omitir la creación de SSLContext y usar SSLSocketFactory.getDefault()
lugar de sslContext.getSocketFactory()
. En este caso, solo necesitará instalar el certificado del servidor si el certificado del servidor fue autofirmado o no emitido por una de las principales autoridades certificadoras. Además, para asegurarse de no confiar en un certificado legítimamente emitido dentro de una cadena de certificados en la que confía, sino en un dominio completamente diferente al que está tratando de acceder, debe agregar el siguiente código (no probado) justo después de la línea donde creas el SSLSocket
:
sslSocket.getSSLParameters().setEndpointIdentificationAlgorithm("HTTPS");
Esto también se aplicaría si está utilizando su propio archivo del almacén de confianza, pero confiando en todos los certificados emitidos por una o más autoridades certificadoras en ese archivo, o confiando en una serie de certificados para diferentes servidores en ese archivo.
Certificados, tiendas clave y tiendas de confianza
Ahora, para la parte difícil, o al menos algo más difícil: generar e instalar los certificados. Recomiendo usar la keytool
Java, preferiblemente la versión 1.7 o superior, para hacer este trabajo.
Si está creando un certificado autofirmado, primero genere el par de llaves del servidor desde la línea de comando con un comando como el siguiente: keytool -genkey -alias server -keyalg rsa -dname "cn=server, ou=unit, o=org, l=City, s=ST, c=US" -validity 365242 -keystore server_key_store_file -ext san=ip:192.168.1.129 -v
. Sustituye tus propios nombres y valores. En particular, este comando crea un par de claves que expira en 365242 días, 1000 años, para un servidor que estará en la dirección IP 192.168.1.129. Si los clientes encontrarán el servidor a través del sistema de nombre de dominio, use algo como san=dns:server.example.com
lugar de san=ip:192.168.1.129
. Para obtener más información sobre las opciones de keytool, use la man keytool
.
Se le solicitará la contraseña del almacén de claves, o establecer la contraseña del almacén de claves, si este es un nuevo archivo del almacén de claves, y establecer la contraseña del nuevo par de claves.
Ahora, exporte el certificado del servidor usando keytool -export -alias server -file server.cer -keystore server_key_store_file -rfc -v
. Esto crea un archivo server.cer
que contiene el certificado con la clave pública del servidor.
Finalmente, mueva el archivo server.cer al equipo del cliente e instale el certificado en el almacén de confianza del cliente, utilizando algo así como, keytool -import -alias server -file server.cer -keystore client_trust_store_file -v
. Se le pedirá la contraseña para el archivo del almacén de confianza; el mensaje dirá "Ingrese la contraseña del almacén de claves", ya que la herramienta de claves de Java funciona con los archivos del almacén de claves y los archivos del almacén de confianza. Tenga en cuenta que si está utilizando el archivo cacerts
JRE predeterminado, la contraseña inicial es changeit
, creo.
Si está utilizando un certificado adquirido de una autoridad de certificación generalmente reconocida y está utilizando el archivo cacerts
JRE predeterminado en el cliente, solo tiene que instalar el certificado en el archivo de almacenamiento de claves del servidor; no tiene que meterse con los archivos del cliente. Las instrucciones de instalación del servidor deben ser proporcionadas por la autoridad de certificación, o de nuevo puede consultar la man keytool
de man keytool
para obtener instrucciones.
Existe una enorme cantidad de misticdos que rodean los zócalos y, especialmente, los zócalos SSL, pero en realidad son bastante fáciles de usar. En muchos casos, diez líneas de código evitarán la necesidad de una mensajería compleja o frágil o una infraestructura de puesta en cola de mensajes. Bien por ti por considerar esta opción.