我正在尝试在Python服务器和Java客户端中使用使用Java keytool
生成的密钥和证书。我已经创建了密钥和密钥库,导出了证书,将证书添加到信任库中,将密钥库转换为标准的PKCS格式,然后从PKCS中提取密钥和证书以在Python服务器中使用(前三个步骤来自这里,最后三个步骤来自这里)。以下是详细步骤:
Creating keystore, private key and certificate
keytool -genkey -alias ssl_key -keyalg RSA -keypass passwd123 -keystore keystore.jks -storepass passwd123
Exporting certificate out from keystore to
.cer
filekeytool -export -alias ssl_key -file ssl_key.cer -keystore keystore.jks -storepass passwd123
Exporting certificate from keystore to truststore
keytool -import -v -trustcacerts -alias ssl_key -keypass passwd123 -file ssl_key.cer -keystore truststore.jks -storepass passwd123
Exported keystore from keytool's proprietary format to standard format
keytool -importkeystore -srckeystore keystore.jks -destkeystore stdkeystore.p12 -deststoretype PKCS12 -srcalias ssl_key -deststorepass passwd123 -destkeypass passwd123
Exported certificate from standard format keystore using openssl
openssl pkcs12 -in stdkeystore.p12 -nokeys -out cert.pem
Exported unencrypted private key from standard format keystore using openssl as follows:
openssl pkcs12 -in stdkeystore.p12 -nodes -nocerts -out key.pem
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("<<startMessage>>")):
if(data_decoded.endswith("<<endMessage>>")):
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("<<startMessage>>");
out.println("Message from Client4Py");
out.println("<<endMessage>>");
out.flush();
if (out.checkError())
System.out.println(
"SSLSocketClient: java.io.PrintWriter error");
out.close();
socket.close();
}
}
首次运行服务器和客户端后,服务器控制台的输出如下所示:
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 <module>
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
我取消了客户端和服务器端代码中的utf-8编码解码行,结果在服务器控制台上得到以下输出:
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 <module>
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
我感觉我缺少一些东西,可能是SSL或编码的基础知识。我可以直接使用上面解释过的从Java keystore生成的pem文件来与Python的SSLSocket配合使用吗?还是我需要确保更多的内容,例如用于生成密钥和证书的密码?欢迎提供任何链接/资源以消除我的无知...
while
,一个用于接受不同的连接,另一个用于接收所有数据。(我的原始代码为每个连接派生新进程,这就是为什么问题中的简化代码只包含单个while
)。 (2) 你按照顺序进行了操作:s.bind
、s.listen
、s.setsocketopt
,而我按照s.setsocketopt
、s.bind
、s.listen
进行操作。 (3) 你按照顺序进行了操作:ssl.wrap_socket()
,ssl_socket.accept()
,而我按照socketObj.accept
、ssl.wrap_socket()
进行操作。这些差异可能导致我的代码出现问题吗?为什么?这将有助于更好地理解 SSL 和套接字编程。 - Mahesha999