Java SSLHandshakeException:没有共同的密码套件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37412374/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java SSLHandshakeException: no cipher suites in common
提问by joao-prg
I am trying to apply security to a simple chat application with Java SSLSockets.
我正在尝试使用 Java SSLSockets 将安全性应用于一个简单的聊天应用程序。
I have created a self-signed CA and with it I signed two certificates (all used RSA keys), one for the server, and one for a client. After that, I imported the certificates to a keystore for the server and to another for the client.
我创建了一个自签名 CA,并用它签署了两个证书(全部使用 RSA 密钥),一个用于服务器,另一个用于客户端。之后,我将证书导入服务器的密钥库和客户端的另一个密钥库。
CA :
openssl genrsa -out ca.key 1024 -rsa
openssl req -new -key ca.key -out ca.csr
openssl x509 -req -days 365 -in ca.csr -out ca.crt -signkey ca.key
SERVER CERTIFICATE:
openssl genrsa -out server.key 1024 -rsa
openssl req -new -key server.key -out server.csr
openssl ca -in server.csr -cert ca.crt -keyfile ca.key -out server.crt
CLIENT CERTIFICATE :
openssl genrsa -out client.key 1024 -rsa
openssl req -new -key client.key -out client.csr
openssl ca -in client.csr -cert ca.crt -keyfile ca.key -out client.crt
KEYSTORES:
keytool -import -keystore serverkeystore -file ca.crt -alias theCARoot
keytool -import -keystore serverkeystore -file server.crt -alias servercrt
keytool -import -keystore serverkeystore -file client.crt -alias clientcrt
keytool -import -keystore clientkeystore -file ca.crt -alias theCARoot
keytool -import -keystore clientkeystore -file server.crt -alias servercrt
keytool -import -keystore clientkeystore -file client.crt -alias clientcrt
I want to use a specific cipher, but apparently none of the supported ciphers works.
我想使用特定的密码,但显然没有一个受支持的密码有效。
My code for the client :
我的客户端代码:
import java.net.*;
import java.io.*;
import java.security.*;
import java.security.cert.CertificateException;
import javax.net.ssl.*;
public class ChatClient implements Runnable
{
private SSLSocket socket = null;
private Thread thread = null;
private DataInputStream console = null;
private DataOutputStream streamOut = null;
private ChatClientThread client = null;
final String[] enabledCipherSuites = {"TLS_RSA_WITH_AES_256_CBC_SHA256"};
final char[] passphrase = "123456".toCharArray();
public ChatClient(String serverName, int serverPort)
{
System.out.println("Establishing connection to server...");
try
{
SSLSocketFactory factory = null;
SSLContext ctx = SSLContext.getInstance("TLS");
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore ks= KeyStore.getInstance("JKS");
ks.load(new FileInputStream("clientkeystore"), passphrase);
kmf.init(ks, passphrase);
KeyStore serverKey = KeyStore.getInstance("JKS");
serverKey.load(new FileInputStream("serverkeystore"),passphrase);
TrustManagerFactory trustManager = TrustManagerFactory.getInstance("SunX509");
trustManager.init(serverKey);
ctx.init(kmf.getKeyManagers(), trustManager.getTrustManagers(), null);
factory = ctx.getSocketFactory();
socket = (SSLSocket)factory.createSocket(serverName, serverPort);
socket.setEnabledCipherSuites(enabledCipherSuites);
start();
}
catch(UnknownHostException uhe)
{
// Host unkwnown
System.out.println("Error establishing connection - host unknown: " + uhe.getMessage());
}
catch(IOException ioexception)
{
// Other error establishing connection
System.out.println("Error establishing connection - unexpected exception: " + ioexception.getMessage());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
public void run()
{
while (thread != null)
{
try
{
// Sends message from console to server
streamOut.writeUTF(console.readLine());
streamOut.flush();
}
catch(IOException ioexception)
{
System.out.println("Error sending string to server: " + ioexception.getMessage());
stop();
}
}
}
public void handle(String msg)
{
// Receives message from server
if (msg.equals(".quit"))
{
// Leaving, quit command
System.out.println("Exiting...Please press RETURN to exit ...");
stop();
}
else
// else, writes message received from server to console
System.out.println(msg);
}
// Inits new client thread
public void start() throws IOException
{
console = new DataInputStream(System.in);
streamOut = new DataOutputStream(socket.getOutputStream());
if (thread == null)
{
client = new ChatClientThread(this, socket);
thread = new Thread(this);
thread.start();
}
}
// Stops client thread
public void stop()
{
if (thread != null)
{
thread.stop();
thread = null;
}
try
{
if (console != null) console.close();
if (streamOut != null) streamOut.close();
if (socket != null) socket.close();
}
catch(IOException ioe)
{
System.out.println("Error closing thread..."); }
client.close();
client.stop();
}
public static void main(String args[])
{
ChatClient client = null;
if (args.length != 2)
// Displays correct usage syntax on stdout
System.out.println("Usage: java ChatClient host port");
else
// Calls new client
client = new ChatClient(args[0], Integer.parseInt(args[1]));
}
}
class ChatClientThread extends Thread
{
private SSLSocket socket = null;
private ChatClient client = null;
private DataInputStream streamIn = null;
public ChatClientThread(ChatClient _client, SSLSocket _socket)
{
client = _client;
socket = _socket;
open();
start();
}
public void open()
{
try
{
streamIn = new DataInputStream(socket.getInputStream());
}
catch(IOException ioe)
{
System.out.println("Error getting input stream: " + ioe);
client.stop();
}
}
public void close()
{
try
{
if (streamIn != null) streamIn.close();
}
catch(IOException ioe)
{
System.out.println("Error closing input stream: " + ioe);
}
}
public void run()
{
while (true)
{ try
{
client.handle(streamIn.readUTF());
}
catch(IOException ioe)
{
System.out.println("Listening error: " + ioe.getMessage());
client.stop();
}
}
}
}
And for the server :
对于服务器:
import java.net.*;
import java.io.*;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.Arrays;
import javax.net.ServerSocketFactory;
import javax.net.ssl.*;
public class ChatServer implements Runnable
{
private ChatServerThread clients[] = new ChatServerThread[20];
private SSLServerSocket server_socket = null;
private Thread thread = null;
private int clientCount = 0;
final String[] enabledCipherSuites = {"TLS_RSA_WITH_AES_256_CBC_SHA256"};
final char[] passphrase = "123456".toCharArray();
public ChatServer(int port)
{
try
{
// Binds to port and starts server
System.out.println("Binding to port " + port);
SSLContext ctx = SSLContext.getInstance("TLS");;
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("serverkeystore"), passphrase);
kmf.init(ks, passphrase);
KeyStore serverKey = KeyStore.getInstance("JKS");
serverKey.load(new FileInputStream("clientkeystore"),passphrase);
TrustManagerFactory trustManager = TrustManagerFactory.getInstance("SunX509");
trustManager.init(serverKey);
ctx.init(kmf.getKeyManagers(), trustManager.getTrustManagers(), null);
SSLServerSocketFactory ssf = ctx.getServerSocketFactory();
server_socket = (SSLServerSocket) ssf.createServerSocket(port);
server_socket.setEnabledCipherSuites(enabledCipherSuites);
server_socket.setNeedClientAuth(true);
System.out.println("Server started: " + server_socket);
start();
}
catch(IOException ioexception)
{
// Error binding to port
System.out.println("Binding error (port=" + port + "): " + ioexception.getMessage());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
public void run()
{
while (thread != null)
{
try
{
// Adds new thread for new client
System.out.println("Waiting for a client ...");
addThread((SSLSocket)server_socket.accept());
}
catch(IOException ioexception)
{
System.out.println("Accept error: " + ioexception); stop();
}
}
}
public void start()
{
if (thread == null)
{
// Starts new thread for client
thread = new Thread(this);
thread.start();
}
}
public void stop()
{
if (thread != null)
{
// Stops running thread for client
thread.stop();
thread = null;
}
}
private int findClient(int ID)
{
// Returns client from id
for (int i = 0; i < clientCount; i++)
if (clients[i].getID() == ID)
return i;
return -1;
}
public synchronized void handle(int ID, String input)
{
if (input.equals(".quit"))
{
int leaving_id = findClient(ID);
// Client exits
clients[leaving_id].send(".quit");
// Notify remaing users
for (int i = 0; i < clientCount; i++)
if (i!=leaving_id)
clients[i].send("Client " +ID + " exits..");
remove(ID);
}
else
// Brodcast message for every other client online
for (int i = 0; i < clientCount; i++)
clients[i].send(ID + ": " + input);
}
public synchronized void remove(int ID)
{
int pos = findClient(ID);
if (pos >= 0)
{
// Removes thread for exiting client
ChatServerThread toTerminate = clients[pos];
System.out.println("Removing client thread " + ID + " at " + pos);
if (pos < clientCount-1)
for (int i = pos+1; i < clientCount; i++)
clients[i-1] = clients[i];
clientCount--;
try
{
toTerminate.close();
}
catch(IOException ioe)
{
System.out.println("Error closing thread: " + ioe);
}
toTerminate.stop();
}
}
private void addThread(SSLSocket socket)
{
if (clientCount < clients.length)
{
// Adds thread for new accepted client
System.out.println("Client accepted: " + socket);
clients[clientCount] = new ChatServerThread(this, socket);
try
{
clients[clientCount].open();
clients[clientCount].start();
clientCount++;
}
catch(IOException ioe)
{
System.out.println("Error opening thread: " + ioe);
}
}
else
System.out.println("Client refused: maximum " + clients.length + " reached.");
}
public static void main(String args[])
{
ChatServer server = null;
if (args.length != 1)
// Displays correct usage for server
System.out.println("Usage: java ChatServer port");
else
// Calls new server
server = new ChatServer(Integer.parseInt(args[0]));
}
}
class ChatServerThread extends Thread
{
private ChatServer server = null;
private SSLSocket socket = null;
private int ID = -1;
private DataInputStream streamIn = null;
private DataOutputStream streamOut = null;
public ChatServerThread(ChatServer _server, SSLSocket _socket)
{
super();
server = _server;
socket = _socket;
ID = socket.getPort();
}
// Sends message to client
public void send(String msg)
{
try
{
streamOut.writeUTF(msg);
streamOut.flush();
}
catch(IOException ioexception)
{
System.out.println(ID + " ERROR sending message: " + ioexception.getMessage());
server.remove(ID);
stop();
}
}
// Gets id for client
public int getID()
{
return ID;
}
// Runs thread
public void run()
{
System.out.println("Server Thread " + ID + " running.");
while (true)
{
try
{
server.handle(ID, streamIn.readUTF());
}
catch(IOException ioe)
{
System.out.println(ID + " ERROR reading: " + ioe.getMessage());
server.remove(ID);
stop();
}
}
}
// Opens thread
public void open() throws IOException
{
streamIn = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
streamOut = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
}
// Closes thread
public void close() throws IOException
{
if (socket != null) socket.close();
if (streamIn != null) streamIn.close();
if (streamOut != null) streamOut.close();
}
}
Sorry if my english is a bit rusty.
对不起,如果我的英语有点生疏。
My OS is OS X El Capitan and Java version is 1.8.
我的操作系统是 OS X El Capitan,Java 版本是 1.8。
Here is the server's stack trace:
/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/bin/java -Djavax.net.debug=all -Didea.launcher.port=7536 "-Didea.launcher.bin.path=/Applications/IntelliJ IDEA 15.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath "/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/tools.jar:/Users/joaogoncalves/Dropbox/STI/out/production/STI Assignment 3:/Applications/IntelliJ IDEA 15.app/Contents/lib/idea_rt.jar" com.intellij.rt.execution.application.AppMain ChatServer 5000
Binding to port 5000
adding as trusted cert:
Subject: CN=Joao Goncalves, OU=DEQ, O=UC, ST=Coimbra, C=PT
Issuer: CN=DEI, OU=DEI, O=UC, L=Coimbra, ST=Coimbra, C=PT
Algorithm: RSA; Serial number: 0xc94895f3863a5c36
Valid from Mon May 23 23:43:42 WEST 2016 until Tue May 23 23:43:42 WEST 2017
adding as trusted cert:
Subject: CN=www.uc.pt, OU=DEM, O=UC, ST=Coimbra, C=PT
Issuer: CN=DEI, OU=DEI, O=UC, L=Coimbra, ST=Coimbra, C=PT
Algorithm: RSA; Serial number: 0xc94895f3863a5c35
Valid from Mon May 23 23:42:54 WEST 2016 until Tue May 23 23:42:54 WEST 2017
adding as trusted cert:
Subject: CN=DEI, OU=DEI, O=UC, L=Coimbra, ST=Coimbra, C=PT
Issuer: CN=DEI, OU=DEI, O=UC, L=Coimbra, ST=Coimbra, C=PT
Algorithm: RSA; Serial number: 0xdb931da4e1abec22
Valid from Mon May 23 23:42:03 WEST 2016 until Tue May 23 23:42:03 WEST 2017
trigger seeding of SecureRandom
done seeding SecureRandom
Server started: [SSL: ServerSocket[addr=0.0.0.0/0.0.0.0,localport=5000]]
Waiting for a client ...
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
Client accepted: 74ce57fc[SSL_NULL_WITH_NULL_NULL: Socket[addr=/127.0.0.1,port=57519,localport=5000]]
Waiting for a client ...
Server Thread 57519 running.
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256 for TLSv1
No available cipher suite for TLSv1
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256 for TLSv1.1
No available cipher suite for TLSv1.1
[Raw read]: length = 5
0000: 16 03 03 00 52 ....R
[Raw read]: length = 82
0000: 01 00 00 4E 03 03 57 44 7B 3B B8 1E 77 88 AF 4E ...N..WD.;..w..N
0010: C7 CA 73 CE AC 38 62 5D 18 BD 9A 16 7E 25 86 25 ..s..8b].....%.%
0020: 36 1C EF F5 B6 FF 00 00 02 00 3D 01 00 00 23 00 6.........=...#.
0030: 0D 00 1A 00 18 06 03 06 01 05 03 05 01 04 03 04 ................
0040: 01 03 03 03 01 02 03 02 01 02 02 01 01 FF 01 00 ................
0050: 01 00 ..
Thread-1, READ: TLSv1.2 Handshake, length = 82
*** ClientHello, TLSv1.2
RandomCookie: GMT: 1464105787 bytes = { 184, 30, 119, 136, 175, 78, 199, 202, 115, 206, 172, 56, 98, 93, 24, 189, 154, 22, 126, 37, 134, 37, 54, 28, 239, 245, 182, 255 }
Session ID: {}
Cipher Suites: [TLS_RSA_WITH_AES_256_CBC_SHA256]
Compression Methods: { 0 }
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA
Extension renegotiation_info, renegotiated_connection: <empty>
***
[read] MD5 and SHA1 hashes: len = 82
0000: 01 00 00 4E 03 03 57 44 7B 3B B8 1E 77 88 AF 4E ...N..WD.;..w..N
0010: C7 CA 73 CE AC 38 62 5D 18 BD 9A 16 7E 25 86 25 ..s..8b].....%.%
0020: 36 1C EF F5 B6 FF 00 00 02 00 3D 01 00 00 23 00 6.........=...#.
0030: 0D 00 1A 00 18 06 03 06 01 05 03 05 01 04 03 04 ................
0040: 01 03 03 03 01 02 03 02 01 02 02 01 01 FF 01 00 ................
0050: 01 00 ..
%% Initialized: [Session-1, SSL_NULL_WITH_NULL_NULL]
%% Invalidated: [Session-1, SSL_NULL_WITH_NULL_NULL]
Thread-1, SEND TLSv1.2 ALERT: fatal, description = handshake_failure
Thread-1, WRITE: TLSv1.2 Alert, length = 2
[Raw write]: length = 7
0000: 15 03 03 00 02 02 28 ......(
Thread-1, called closeSocket()
Thread-1, handling exception: javax.net.ssl.SSLHandshakeException: no cipher suites in common
57519 ERROR reading: no cipher suites in common
Removing client thread 57519 at 0
Thread-1, called close()
Thread-1, called closeInternal(true)
Thread-1, called close()
Thread-1, called closeInternal(true)
Thread-1, called close()
Thread-1, called closeInternal(true)
Process finished with exit code 130
回答by dave_thompson_085
The keystore for each authenticated party, always the server and here the client also because you specified NeedClientAuth
, must have the PRIVATE KEY AND certificate(s), not merely the certificate(s). There are two ways to do this:
每个经过身份验证的方的密钥库,始终是服务器,这里的客户端也是因为您指定的NeedClientAuth
,必须具有私钥和证书,而不仅仅是证书。有两种方法可以做到这一点:
convert the OpenSSL generated privatekey plus the related certs to PKCS#12, and then either convert the PKCS#12 to JKS or just use the PKCS#12 in Java (JCE can handle it, and recent versions of Java8 even if you specify JKS! -- see http://www.oracle.com/technetwork/java/javase/8u60-relnotes-2620227.htmlunder Keystore Compatibility Mode). See:
How to import an existing x509 certificate and private key in Java keystore to use in SSL?
How can i create keystore from an existing certificate (abc.crt) and abc.key files?
Importing the private-key/public-certificate pair in the Java KeyStore
convert certificate from pem into jks(disclosure: mine)
How to create keystore from cer files(disclosure: mine)generate EE privatekey and CSR in Java, then use OpenSSL (with CA key and cert) to issue the EE cert, and import the certs back into the Java keystore:
keytool -keystore server.jks -genkeypair -keyalg RSA # before j7 best to add -keysize 2048 see below keytool -keystore server.jks -certreq >server.csr openssl ca -in server.csr ... -out server.crt # or submit the CSR to a real CA and get its response # then either install the chain all at once: cat server.crt ca.crt >temp keytool -keystore server.jks -importcert -file temp # and confirm (need temp so stdin available for confirm; # if using a public CA, can add -trustcacerts and use pipe instead) # or install the certs separately, top down: keytool -keystore server.jks -importcert -file ca.crt -alias ca # and confirm, THEN keytool -keystore server.jks -importcert -file server.crt # (last) response must be 'Certificate reply was installed' # NOT merely 'Certificate was added' which means you messed up # and similarly for client
将 OpenSSL 生成的私钥和相关证书转换为 PKCS#12,然后将 PKCS#12 转换为 JKS 或仅使用 Java 中的 PKCS#12(JCE 可以处理它,即使您指定 JKS,最新版本的 Java8 也是如此! -- 请参阅密钥库兼容模式下的http://www.oracle.com/technetwork/java/javase/8u60-relnotes-2620227.html)。看:
如何在 Java 密钥库中导入现有的 x509 证书和私钥以在 SSL 中使用?
如何从现有证书 (abc.crt) 和 abc.key 文件创建密钥库?
在 Java KeyStore 中导入私钥/公共证书对
将证书从 pem 转换为 jks(披露:我的)
如何从 cer 文件创建密钥库(披露:我的)在 Java 中生成 EE 私钥和 CSR,然后使用 OpenSSL(带有 CA 密钥和证书)颁发 EE 证书,并将证书导入回 Java 密钥库:
keytool -keystore server.jks -genkeypair -keyalg RSA # before j7 best to add -keysize 2048 see below keytool -keystore server.jks -certreq >server.csr openssl ca -in server.csr ... -out server.crt # or submit the CSR to a real CA and get its response # then either install the chain all at once: cat server.crt ca.crt >temp keytool -keystore server.jks -importcert -file temp # and confirm (need temp so stdin available for confirm; # if using a public CA, can add -trustcacerts and use pipe instead) # or install the certs separately, top down: keytool -keystore server.jks -importcert -file ca.crt -alias ca # and confirm, THEN keytool -keystore server.jks -importcert -file server.crt # (last) response must be 'Certificate reply was installed' # NOT merely 'Certificate was added' which means you messed up # and similarly for client
The latter method (separate entries for ca.crt and privatekey+server.crt) has the advantage this same file can be used as both the keystore and truststore, you don't need to use serverkey as clienttrust and vice versa. If these were real systems, this would be a security benefit.
后一种方法(ca.crt 和 privatekey+server.crt 的单独条目)的优点是同一个文件可以用作密钥库和信任库,您不需要将 serverkey 用作 clienttrust,反之亦然。如果这些是真实系统,这将是一个安全优势。
A final note: you should start using RSA 2048-bit keys. 1024-bit has been prohibited by authorities like NIST and CABforum since 2014, and although Java still accepts them, most browsers and many other tools are already warning for them and likely soon will reject them. For similar reasons you should sign the certificates with at least SHA256 -- this can be set in the config file used by ca
or you can just use the commandline flag -md sha256
.
最后一点:您应该开始使用 RSA 2048 位密钥。自 2014 年以来,1024 位已被 NIST 和 CABforum 等机构禁止,尽管 Java 仍然接受它们,但大多数浏览器和许多其他工具已经对它们发出警告,并且可能很快就会拒绝它们。出于类似的原因,您应该至少使用 SHA256 对证书进行签名——这可以在使用的配置文件中设置,ca
或者您可以只使用命令行标志-md sha256
。
回答by Woot4Moo
I have never seen the KeyManagerFactory declared the way you have, I typically see it like this:
我从未见过 KeyManagerFactory 以您的方式声明,我通常是这样看的:
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
I realize that I missed this second link for you:
我意识到我错过了你的第二个链接:
http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#Debug
http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#Debug
You will need to walk through SSL debug. However, you need to explicitly enable certain ciphers (if I recall correctly) and would recommend that path.
您将需要完成 SSL 调试。但是,您需要明确启用某些密码(如果我没记错的话)并推荐该路径。