我正在尝试构建一个使用基于ECC的证书的服务器。到目前为止,我已采取以下步骤:
1)使用openssl:
创建签名服务器证书openssl ecparam -param_enc explicit -out server\server.key.pem -name secp256k1 -genkey
openssl req -new -nodes -key server\server.key.pem -outform pem -out server\server.csr -sha256
openssl ca -keyfile CA\private\ca.key.pem -cert CA\ca.cert.pem -in server\server.csr -out server\server-cert.pem -md sha256 -outdir .\server
openssl pkcs12 -export -out server\server-cert.p12 -inkey server\server.key.pem -in server\server-cert.pem -certfile CA\ca.cert.pem
ca.sert.pem是一个用于签署服务器证书的自签名CA证书。它同样产生:
openssl ecparam -param_enc explicit -out CA\private\ca.key.pem -name secp256k1 -genkey
openssl req -new -key CA\private\ca.key.pem -x509 -nodes -days 365 -outform pem -sha256 -out CA\ca.cert.pem
2)设置服务器
public void startServer() {
threadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool();
threadPool.setCorePoolSize(20);
try {
SSLContext sslContext = getSSLContext();
SSLServerSocketFactory ssf = sslContext.getServerSocketFactory();
SSLServerSocket serverSocket = (SSLServerSocket) ssf.createServerSocket(8888);
String[] ciphers = {"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"};
serverSocket.setEnabledCipherSuites(ciphers);
serverSocket.setEnabledProtocols(new String[] {"TLSv1.2"});
while (true) {
SSLSocket clientSocket = (SSLSocket) serverSocket.accept();
threadPool.execute(new ClientSession(clientSocket));
}
} catch (Exception e) {
e.printStackTrace();
}
}
protected SSLContext getSSLContextForGWA() throws Exception {
SSLContext sslContext = SSLContext.getInstance("TLS");
try {
KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
File keyFile = new File(System.getProperty("user.dir") + File.separator + "certs" + File.separator + "server" + File.separator + "server-cert.p12");
FileInputStream keyInput = new FileInputStream(keyFile);
ks.load(keyInput, keyStorePassword.toCharArray());
keyInput.close();
// Set up key manager factory to use our key store
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, keyStorePassword.toCharArray());
// Initialize the SSLContext to work with our key managers.
sslContext.init(kmf.getKeyManagers(), null, null);
return sslContext;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
备注:我只使用BouncyCastle成功将服务器证书加载到密钥库中。否则我得到"仅支持命名的ECParameters"错误。
3)设置客户端 除了将服务器证书导入信任库之外,同样设置客户端。
SSLContext sslContext = getSSLContextForSMGW();
SSLSocketFactory sf = sslContext.getSocketFactory();
SSLSocket clientSocket = (SSLSocket) sf.createSocket(host, port);
String[] ciphers = {"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"};
clientSocket.setEnabledCipherSuites(ciphers);
clientSocket.setEnabledProtocols(new String[] {"TLSv1.2"});
printClientSocketInfo(clientSocket);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
String line = null;
while (((line = in.readLine()) != null)) {
System.out.println(line);
break;
}
现在,当客户端连接到服务器时,我得到以下错误堆栈:
Caused by: java.io.IOException: Only named ECParameters supported
at sun.security.ec.ECParameters.engineInit(ECParameters.java:150)
at java.security.AlgorithmParameters.init(AlgorithmParameters.java:293)
at sun.security.x509.AlgorithmId.decodeParams(AlgorithmId.java:132)
at sun.security.x509.AlgorithmId.<init>(AlgorithmId.java:114)
at sun.security.x509.AlgorithmId.parse(AlgorithmId.java:372)
at sun.security.x509.X509Key.parse(X509Key.java:168)
at sun.security.x509.CertificateX509Key.<init>(CertificateX509Key.java:75)
at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:667)
at sun.security.x509.X509CertInfo.<init>(X509CertInfo.java:167)
... 15 more
我猜,客户端无法验证服务器证书(与我不使用BouncyCastle导入证书时相同的错误)。
我用
打印了命名的EC曲线 System.out.println("Named EC-Curves:");
String[] curves = Security.getProvider("SunEC")
.getProperty("AlgorithmParameters.EC SupportedCurves")
.split("\\|");
for (String curve : curves) {
System.out.println(curve.substring(1, curve.indexOf(",")));
}
它显然输出了名称&#39; secp256k1&#39;其中。那我在这里错过了什么?或者如何让SSLContext使用CertificateX509Key的另一个实现?
客户端的调试输出是:
*** ClientHello, TLSv1.2
RandomCookie: GMT: 1427463640 bytes = { 227, 188, 124, 163, 124, 55, 134, 199, 234, 241, 234, 51, 8, 208, 199, 117, 90, 125, 214, 134, 226, 110, 149, 92, 194, 25, 70, 59 }
Session ID: {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256]
Compression Methods: { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA
Extension renegotiation_info, renegotiated_connection: <empty>
***
main, WRITE: TLSv1.2 Handshake, length = 144
main, READ: TLSv1.2 Handshake, length = 1540
*** ServerHello, TLSv1.2
RandomCookie: GMT: 1427463640 bytes = { 155, 184, 16, 18, 186, 249, 50, 70, 182, 75, 129, 217, 165, 78, 228, 255, 138, 98, 193, 58, 229, 70, 45, 1, 244, 84, 187, 235 }
Session ID: {85, 21, 94, 216, 168, 186, 180, 208, 21, 40, 84, 147, 20, 244, 43, 97, 214, 18, 173, 27, 52, 175, 44, 1, 127, 20, 62, 126, 65, 229, 79, 1}
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
***
%% Initialized: [Session-1, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256]
** TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
main, handling exception: javax.net.ssl.SSLProtocolException: java.io.IOException: Only named ECParameters supported
%% Invalidated: [Session-1, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256]
main, SEND TLSv1.2 ALERT: fatal, description = unexpected_message
main, WRITE: TLSv1.2 Alert, length = 2
main, called closeSocket()
main, IOException in getSession(): javax.net.ssl.SSLProtocolException: java.io.IOException: Only named ECParameters supported
Cipher suite = SSL_NULL_WITH_NULL_NULL
Protocol = NONE
曲线也列在曲线名称中。我现在尝试了很多东西,我有点卡住了。任何帮助都非常感谢。