Прочитав многочисленные ответы на эти темы, я обнаружил, что совершенно не могу связать воедино кусочки головоломки, надеюсь, вы меня извините за это.
Я пытаюсь изменить свое простое соединение с сокетом в Java для использования SSL. Я бы хотел, чтобы и сервер, и клиент аутентифицировали себя, если это возможно, но только аутентификация сервера будет хорошим началом.
В настоящее время это чрезвычайно простой код на стороне сервера:
ServerSocket serverSocket = new ServerSocket(port);
Socket socket = serverSocket.accept();
И это код на стороне клиента:
Socket socket = null;
while (true) {
try {
socket = new Socket(ipAddress, port);
break;
} catch (Exception e) {}
}
Это нормально работает, но без SSL.
Я сгенерировал SSL-сертификаты для сервера и клиента с помощью OpenSSL, получив в итоге:
- Сертификат для сервера (формат PEM)
- Сертификат для клиента (формат PEM)
- Приватный ключ для сервера (формат PEM)
- Приватный ключ для клиента (формат PEM)
- Файл CA (формат PEM, CER и CRT)
Исходя из этого, я использовал OpenSSL для создания хранилищ ключей PKCS12 (.p12) как для клиента, так и для сервера, как показано ниже.
- server.p12, созданный с помощью openssl pkcs12 -export -in server-cert.pem -inkey server-private-key.pem -out server.p12
- client.p12, созданный с помощью openssl pkcs12 -export -in client-cert.pem -inkey client-private-key.pem -out client.p12
Затем я превратил их в хранилища ключей JKS с помощью keytool (например, для сервера команда была keytool -importkeystore -srckeystore server.p12 -srcstoretype PKCS12 -destkeystore server.jks -deststoretype JKS), в результате появятся два файла с именами server.jks и client.jks.
Затем я использую следующий код в качестве замены предыдущего фрагмента сервера:
char[] keyStorePassword = "JKSPassword".toCharArray();
FileInputStream keyStoreFile = new FileInputStream("somepath/server.jks");
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(keyStoreFile, keyStorePassword);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "PKCS12Password".toCharArray());
SSLContext sslContext = SSLContext.getDefault();
ServerSocket serverSocket = sslContext.getServerSocketFactory().createServerSocket(port);
Socket socket = serverSocket.accept();
И следующий код в качестве замены клиентского фрагмента:
Socket socket = null;
while (true) {
try {
char[] keyStorePassword = "JKSPassword".toCharArray();
FileInputStream keyStoreFile = new FileInputStream("somepath/client.jks");
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(keyStoreFile, keyStorePassword);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "PKCS12Password".toCharArray());
SSLContext sslContext = SSLContext.getDefault();
socket = sslContext.getSocketFactory().createSocket(ipAddress, port);
break;
} catch (Exception e) {}
}
Теперь я все еще получаю javax.net.ssl.SSLHandshakeException: нет общих наборов шифров на сервере (и javax.net.ssl.SSLHandshakeException: получено фатальное предупреждение: handshake_failure on клиент).
Что могло быть не так?