No se puede realizar la comunicación entre el cliente de Java y el servidor de Python con SSL

Estoy tratando de usar las claves y el certificado generado usando java keytool en el servidor de Python y el cliente de Java. He creado key & keystore, exportado certificado, agregado certificado a truststore, convertido keystore a formato pkcs estándar y luego extraje clave y certificado de pkcs para usar en el servidor Python. (Los primeros tres pasos desde aquí y los últimos tres pasos desde aquí ) Estos son los pasos detallados:

  1. Creación de keystore, clave privada y certificado.

     keytool -genkey -alias ssl_key -keyalg RSA -keypass passwd123 -keystore keystore.jks -storepass passwd123 
  2. Exportando certificado desde el almacén de claves a un archivo .cer

     keytool -export -alias ssl_key -file ssl_key.cer -keystore keystore.jks -storepass passwd123 
  3. Exportando el certificado desde el almacén de claves al almacén de confianza

     keytool -import -v -trustcacerts -alias ssl_key -keypass passwd123 -file ssl_key.cer -keystore truststore.jks -storepass passwd123 
  4. Almacén de claves exportado del formato propietario de keytool al formato estándar

     keytool -importkeystore -srckeystore keystore.jks -destkeystore stdkeystore.p12 -deststoretype PKCS12 -srcalias ssl_key -deststorepass passwd123 -destkeypass passwd123 
  5. Certificado exportado desde el almacén de claves de formato estándar mediante openssl

     openssl pkcs12 -in stdkeystore.p12 -nokeys -out cert.pem 
  6. Clave privada sin cifrar exportada desde un almacén de claves de formato estándar usando openssl de la siguiente manera:

     openssl pkcs12 -in stdkeystore.p12 -nodes -nocerts -out key.pem 

Mi pequeño servidor de Python y mi cliente de Java son los siguientes:

server.py

 import socket import ssl def start_server_ssl(): socketObj = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_address = ('127.0.0.1', 6000) socketObj.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) socketObj.bind(server_address) socketObj.listen(10) while True: try: print("Awaiting connection...") data_socket, client_address = socketObj.accept() ssl_socket = ssl.wrap_socket(socketObj, server_side = True, certfile="cert.pem", keyfile="key.pem") reading_status = True data = bytearray() data_decoded = "" while(reading_status): message_chunks = data_socket.recv(90000) data.extend(message_chunks) print(data) data_decoded = str(data.decode("utf-8")) #data_decoded = str(data.decode()) if(data_decoded.startswith("<>")): if(data_decoded.endswith("<>")): reading_status = False print(data_decoded); except socket.error as msg: print (msg) ssl_socket.shutdown(socket.SHUT_RDWR) ssl_socket.close() if __name__ == '__main__': start_server_ssl() 

Client4Py.java

 import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.security.KeyStore; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; public class Client4Py { static KeyStore ks; static KeyManagerFactory kmf; static TrustManagerFactory tmf; static SSLContext sc; static TrustManager[] trustManagers; static { try { ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream("D:\\javasslstores\\truststore.jks"), "passwd123".toCharArray()); kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, "passwd123".toCharArray()); tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks); sc = SSLContext.getInstance("TLS"); sc.init(null, tmf.getTrustManagers(), null); } catch (Exception e) { System.out.println(e.getMessage()); System.out.println(e.getStackTrace()); } } public static void main(String[] args) throws IOException { SSLSocketFactory ssf = sc.getSocketFactory(); SSLSocket socket = (SSLSocket) ssf.createSocket("127.0.0.1", 6000); socket.startHandshake(); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),StandardCharsets.UTF_8))); //PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))); out.println("<>"); out.println("Message from Client4Py"); out.println("<>"); out.flush(); if (out.checkError()) System.out.println( "SSLSocketClient: java.io.PrintWriter error"); out.close(); socket.close(); } } 

La salida en la consola del servidor después de la primera ejecución del servidor y el cliente es la siguiente:

 Awaiting connection... bytearray(b'\x16\x03\x03\x00\xc1\x01\x00\x00\xbd\x03\x03["}o\x12\x01\xb2\xd4E\xa1\x1fy\xa8/d\x11\xd2\x00)\\t\x9a:\xb6\n\xcd\x03\x05\xbe\xe58\xd6\x00\x00:\xc0#\xc0\'\x00<\xc0%\xc0)\x00g\x00@\xc0\t\xc0\x13\x00/\xc0\x04\xc0\x0e\x003\x002\xc0+\xc0/\x00\x9c\xc0-\xc01\x00\x9e\x00\xa2\xc0\x08\xc0\x12\x00\n\xc0\x03\xc0\r\x00\x16\x00\x13\x00\xff\x01\x00\x00Z\x00\n\x004\x002\x00\x17\x00\x01\x00\x03\x00\x13\x00\x15\x00\x06\x00\x07\x00\t\x00\n\x00\x18\x00\x0b\x00\x0c\x00\x19\x00\r\x00\x0e\x00\x0f\x00\x10\x00\x11\x00\x02\x00\x12\x00\x04\x00\x05\x00\x14\x00\x08\x00\x16\x00\x0b\x00\x02\x01\x00\x00\r\x00\x18\x00\x16\x06\x03\x06\x01\x05\x03\x05\x01\x04\x03\x04\x01\x03\x03\x03\x01\x02\x03\x02\x01\x02\x02') Traceback (most recent call last): File "D:\Mahesh\workspaces\workspace6\PythonServer\server.py", line 44, in  start_server_ssl() File "D:\Mahesh\workspaces\workspace6\PythonServer\server.py", line 29, in start_server_ssl data_decoded = str(data.decode("utf-8")) UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc1 in position 4: invalid start byte 

Sin comentar las líneas de encoding-deencoding de utf-8 en el código del cliente y del servidor y terminé obteniendo el siguiente resultado en la consola del servidor:

 Awaiting connection... bytearray(b'\x16\x03\x03\x00\xc1\x01\x00\x00\xbd\x03\x03["\x7f>s\x04\x15S\x14\xb0\xa2\xa0\x7f\x90}@\xe8\xa3:\x15\x04z\xeb\x986\\b\xe9\xe0v=\x1f\x00\x00:\xc0#\xc0\'\x00<\xc0%\xc0)\x00g\x00@\xc0\t\xc0\x13\x00/\xc0\x04\xc0\x0e\x003\x002\xc0+\xc0/\x00\x9c\xc0-\xc01\x00\x9e\x00\xa2\xc0\x08\xc0\x12\x00\n\xc0\x03\xc0\r\x00\x16\x00\x13\x00\xff\x01\x00\x00Z\x00\n\x004\x002\x00\x17\x00\x01\x00\x03\x00\x13\x00\x15\x00\x06\x00\x07\x00\t\x00\n\x00\x18\x00\x0b\x00\x0c\x00\x19\x00\r\x00\x0e\x00\x0f\x00\x10\x00\x11\x00\x02\x00\x12\x00\x04\x00\x05\x00\x14\x00\x08\x00\x16\x00\x0b\x00\x02\x01\x00\x00\r\x00\x18\x00\x16\x06\x03\x06\x01\x05\x03\x05\x01\x04\x03\x04\x01\x03\x03\x03\x01\x02\x03\x02\x01\x02\x02') Traceback (most recent call last): File "D:\Mahesh\workspaces\workspace6\PythonServer\server.py", line 44, in  start_server_ssl() File "D:\Mahesh\workspaces\workspace6\PythonServer\server.py", line 30, in start_server_ssl data_decoded = str(data.decode()) UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc1 in position 4: invalid start byte 

Siento que me estoy perdiendo algo. Ya sea algunos conceptos básicos de SSL o encoding. ¿Puedo usar el archivo pem generado desde el almacén de claves de Java como se explicó anteriormente directamente con python SSLSocket ? ¿O tengo que asegurarme de algo más como los cifrados utilizados para generar claves y certificados?

Cualquier enlace / recursos para disipar mi ignorancia son bienvenidos …

server.py tu server.py con este ejemplo. No hay nada malo con su servidor acerca de las claves y certificados.

server.py

 import socket from socket import AF_INET, SOCK_STREAM, SO_REUSEADDR, SOL_SOCKET, SHUT_RDWR import ssl KEYFILE = 'key.pem' CERTFILE = 'cert.pem' def print_data(s): while True: data = s.recv(8192) print(data.decode("utf-8")) if data == b'': break s.send(b'This is a response.') print('Connection closed') s.close() def start_server_ssl(address): s = socket.socket(AF_INET, SOCK_STREAM) s.bind(address) s.listen(1) s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) ssl_socket = ssl.wrap_socket(s, keyfile=KEYFILE, certfile=CERTFILE, server_side=True) print("Awaiting connection...") while True: try: (c,a) = ssl_socket.accept() print('Got connection', c, a) print_data(c) except socket.error as e: print('Error: {0}'.format(e)) start_server_ssl((socket.gethostbyname('localhost'), 6000))