package ar.com.javacuriosities.networking.tcp.ssl;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import javax.net.ServerSocketFactory;
import javax.net.ssl.SSLServerSocketFactory;
/*
* Para realizar comunicaciones seguras en una red lo mas habitual es usar
* Secure Sockets Layer (SSL)
* - Esto es un protocolo sobre TCP
* - Proporciona cifrado y autenticación
*
* Este protocolo es usado en Hipertext Transfer Protocol Secure (HTTPS)
* - Es una version de HTTP que se base en SSL
* - Proporciona aspectos de seguridad en HTTP
* - Es usado para identificación y confidencialidad de la información que envían los usuarios
*
* Podremos encontrar que existe SSL 3.0 y luego el Internet Engineering Task Force (IETF) lo actualizo ligeramente y lo llamo TLS 1.0
*
* Java soporta SSL 3.0 y TLS 1.0
*
* SSL permite usar distintos algoritmos de cifrados pero lo mas habitual es usar RSA
*
* Explicación:
* En el mundo SSL los servidores deben autenticarse usando certificados (Para confirmar ser quien dicen ser), habitualmente los clientes no tienen que autenticarse
* - Certificados:
* Un servidor debe enviar su certificado al cliente
* El cliente debe verificar el certificado del servidor con una CA
* Opcionalmente el cliente tambien se autenticara con un certificado al servidor
*
* En el contexto de SSL, se utilizan de varios ficheros de keystore
* - Truststore
* Es un keystore que tiene el cliente y contiene los certificado de aquellas personas u organizaciones en las que confía el usuario
*
* - Keystore
* Es un keystore que tiene el servidor (Y también el cliente si tiene que autenticarse y contiene tanto su certificado como su clave privada)
*
* Validación de los certificados de los servidores:
* Por defecto se usa el truststore
* $JREHOME/lib/security/cacerts
* Podemos configurar uno con la propiedad
* javax.net.ssl.trustStore
*
* Validación de los certificados del cliente
* Debemos establecer la ruta del fichero de certificados con la propiedad
* javax.net.ssl.keyStore
* Además debemos establecer la contraseña de acceso con la propiedad
* javax.net.ssl.keyStorePassword
*
* Generación del certificado (Otra opción es comprar un certificado en una CA)
*
* keytool -keystore MyServerKeyStore -genkey -keypass GenericPassword -keyalg RSA -alias MyServerCert
*
* Luego si pensamos usar este keyStore podemos copiarlo a la raíz del proyecto y ejecutar nuestro server con los siguientes parámetros
* -Djavax.net.ssl.keyStore=MyServerKeyStore
* -Djavax.net.ssl.keyStorePassword=GenericPassword
*
* Ahora debemos exportar el certificado para el cliente
*
* keytool -export -alias MyServerCert -keystore MyServerKeyStore -storepass GenericPassword -file Server.cer
*
* Luego importamos el certificado en el trustStore
*
* keytool -import -keystore MyClientTrustStore -storepass 123456 -file Server.cer
*
* Luego debemos indicarle al cliente que trustStore usar
*
* -Djavax.net.ssl.trustStore=MyClientTrustStore
* -Djavax.net.ssl.trustStorePassword=123456
*
* Para definir los socket servidor y cliente debemos usar factories ya definidas
* Servidor
* javax.net.ssl.SSLServerSocketFactory
*
* Cliente
* javax.net.ssl.SSLSocketFactory
*
*/
public class Step1SSLServer {
public static void main(String[] args) {
try {
// Aquí agregamos la properties desde el código lo ideal es pasarla como parámetros o leerlas de una locación externa
System.setProperty("javax.net.ssl.keyStore", "MyServerKeyStore");
/*
* Si definimos esta property la "keypass" tiene que coincidir con la "keyStorePassword"
* El archivo debe estar dentro del proyecto
*/
System.setProperty("javax.net.ssl.keyStorePassword", "GenericPassword");
// Podemos activar esta property en caso de solicitar información para el debugging
// System.setProperty("javax.net.debug", "ssl");
// KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
// InputStream keyStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("MyServerKeyStore");
// keyStore.load(keyStoreStream, "123456".toCharArray());
// Utilizamos un SocketFactory de SSL el cual maneja la creacion por nosotros
ServerSocketFactory serverSocketFactory = SSLServerSocketFactory.getDefault();
try (ServerSocket serverSocket = serverSocketFactory.createServerSocket(4000, 50, InetAddress.getLocalHost())) {
/*
* El método accept() es bloqueante por lo cual genera un
* bloqueo hasta que llega una conexión
*/
while (true) {
Socket clientSocket = serverSocket.accept();
// Pedimos el output stream para enviar mensajes al cliente
OutputStream os = clientSocket.getOutputStream();
// Usamos un wrapper el cual nos permite escribir valores
// primitivos de forma simple
DataOutputStream dos = new DataOutputStream(os);
// Write message
dos.writeUTF("Hi!!!");
// Close output stream and client
dos.close();
os.close();
clientSocket.close();
}
}
} catch (Exception e) {
// Log and Handle exception
e.printStackTrace();
}
}
}