Java SSL:没有共同的密码套件

时间:2016-12-30 13:45:06

标签: java ssl

我们目前正在研究用Java编写的使用TLS的服务器程序。为此,我们使用了Java SSLServerSocket。但是,每次客户端尝试连接到服务器时,当服务器尝试启动握手时,都会导致javax.net.ssl.SSLHandshakeException。为了解决这个问题,我们提取了相关的代码部分并编写了一个调试服务器和客户端程序,但仍然发生了相同的错误。

我们安装了最新版本的Java(8u111),它是常规的Oracle版本。我们选择的密码套件肯定应该受到支持,因为它位于SSLSocket.getSupportedCipherSuites()的列表中。

我们在这个论坛上阅读了其他主题,建议使用Diffie-Hellman禁用密码或使用带有RSA签名的密码代替ECDSA,但没有修复它。

服务器程序

package ch.debugging.server

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.util.encoders.Base64;

import javax.net.ssl.*;
import java.io.*;
import java.math.BigInteger;
import java.net.BindException;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Date;


public class Main {

    public static void main(String[] args) {

        KeyStore keystore = null;
        try {
            BouncyCastleProvider bc = new BouncyCastleProvider();
            File keystoreFile = new File("D:\\keystore.asdf");
            keystore = KeyStore.getInstance("JKS");

        //Create new keystore if there is none
            if (!keystoreFile.exists()) {
                SecureRandom r = SecureRandom.getInstanceStrong();

                KeyPairGenerator keygen = KeyPairGenerator.getInstance("EC", bc);
                keygen.initialize(384, r);
                KeyPair keys = keygen.generateKeyPair();
                System.out.println("Keys successfully generated");

                //Parameters for the certificate
                X500Name issuer = new X500Name("C=, ST=, L=, O=, OU=, CN=");
                X500Name subject = issuer; //self-signed certificate: issuer and subject are the same
                BigInteger serial = BigInteger.valueOf(r.nextLong());
                Date notBefore = new Date(System.currentTimeMillis());
                Date notAfter = new Date(System.currentTimeMillis() + (1000 * 3600 * 24 * 365 * 10)); //valid for one year from now

                //Build the certificate
                X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, keys.getPublic());
                ContentSigner signer = new JcaContentSignerBuilder("SHA512WithECDSA").build(keys.getPrivate());
                X509CertificateHolder certHolder = certGen.build(signer);
                X509Certificate[] certChain = {new JcaX509CertificateConverter().setProvider(bc).getCertificate(certHolder)};
                System.out.println(Base64.toBase64String(certChain[0].getEncoded()));
                System.out.println("Certificate built");

                //Save keys and the certificate to keystore
                keystore.load(null, "123456".toCharArray());
                keystore.setCertificateEntry("Certificate", certChain[0]);
                keystore.store(new FileOutputStream(keystoreFile), "123456".toCharArray());
                System.out.println("Certificate saved in keystore");
            }
        //load keystore if it exists
            else {
                keystore.load(new FileInputStream(keystoreFile), "123456".toCharArray());
                System.out.println("Keystore loaded");
            }
        } catch(Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
        try {
            SecureRandom r = SecureRandom.getInstanceStrong();
            //Prepare SSLServerSocket
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            kmf.init(keystore,"123456".toCharArray());
            tmf.init(keystore);
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(kmf.getKeyManagers(),tmf.getTrustManagers(),r);

            //Create and set up server socket
            SSLServerSocketFactory factory = sslContext.getServerSocketFactory();
            SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(6060);

            serverSocket.setEnabledProtocols(new String[]{"TLSv1.2"});
            serverSocket.setEnabledCipherSuites(new String[]{"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
            serverSocket.setEnableSessionCreation(true);
            serverSocket.setNeedClientAuth(false);
            System.out.println("Waiting for incoming connections...");
            SSLSocket s = (SSLSocket) serverSocket.accept();
            s.startHandshake();
            System.out.println("------Connection established------");
            BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
            while (true) {
                System.out.println(in.readLine());
            }
        } catch(BindException bind) {
            System.out.println("Failed to bind port 6060. Is it already in use?");
            bind.printStackTrace();
        } catch(IOException io) {
            io.printStackTrace();
        } catch(Exception kse) {
            kse.printStackTrace();
        }
    }
}

客户端程序

import javax.net.ssl.*;
import javax.swing.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.security.KeyStore;
import java.security.SecureRandom;


public class main {
    public static void main(String[] args) {
        try {

            //Load keystore
            KeyStore keystore = KeyStore.getInstance("JKS");
            keystore.load(new FileInputStream(new File("D:\\keystore.asdf")), "123456".toCharArray());

            //Prepare SSLServerSocket
            SecureRandom r = SecureRandom.getInstanceStrong();
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            kmf.init(keystore,"123456".toCharArray());
            tmf.init(keystore);

            //initialize SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(kmf.getKeyManagers(),tmf.getTrustManagers(),r);
            SSLSocketFactory factory = sslContext.getSocketFactory();
            SSLSocket socket = (SSLSocket) factory.createSocket();

            socket.setEnabledProtocols(new String[]{"TLSv1.2"});
            socket.setEnabledCipherSuites(new String[]{"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
            socket.setEnableSessionCreation(true);
            socket.connect(new InetSocketAddress("localhost",6060));
            socket.startHandshake();
            PrintWriter out = new PrintWriter(socket.getOutputStream(),true);

            while (true) {
                String msg = JOptionPane.showInputDialog(null,"Message");
                if (!msg.equalsIgnoreCase("")) {
                    out.println(msg);
                } else {
                    socket.close();
                    break;
                }
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

服务器程序的输出(使用-Djavax.net.debug = ssl,握手)

加载密钥库

添加为受信任的证书:

主题:CN =,OU =,O =,L =,ST =,C =

发行人:CN =,OU =,O =,L =,ST =,C =

算法:EC;序列号:0x-dde391bb99f8ce8

有效期从2016年12月30日星期五13:55:36到2016年1月20日星期五17:32:03 CET 2017

触发SecureRandom的播种

完成播种SecureRandom

等待传入连接...

允许不安全的重新谈判:false

允许遗留问候消息:true

初始握手:是真的

安全重新谈判:错误

main,READ:TLSv1.2握手,长度= 140

*** ClientHello,TLSv1.2

RandomCookie:GMT:1483105145 bytes = {70,211,55,52,24,196,174,198,164,57,157,130,143,21,91,86,53,112,138,55 ,208,249,218,82,245,224,32,184}

会话ID:{}

密码套件:[TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384]

压缩方法:{0}

扩展elliptic_curves,曲线名称:{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}

扩展ec_point_formats,格式:[未压缩]

扩展signature_algorithms,signature_algorithms:SHA512withECDSA,SHA512withRSA,SHA384withECDSA,SHA384withRSA,SHA256withECDSA,SHA256withRSA,SHA256withDSA,SHA1withECDSA,SHA1withRSA,SHA1withDSA

扩展renegotiation_info,renegotiated_connection:

%%已初始化:[会话-1,SSL_NULL_WITH_NULL_NULL]

%%无效:[会话-1,SSL_NULL_WITH_NULL_NULL]

main,SEND TLSv1.2 ALERT:致命,描述= handshake_failure

main,WRITE:TLSv1.2警报,长度= 2

main,名为closeSocket()

main,处理异常:javax.net.ssl.SSLHandshakeException:没有共同的密码套件

javax.net.ssl.SSLHandshakeException: no cipher suites in common
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:292)
    at sun.security.ssl.ServerHandshaker.chooseCipherSuite(ServerHandshaker.java:1035)
    at sun.security.ssl.ServerHandshaker.clientHello(ServerHandshaker.java:738)
    at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:221)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at ch.debugging.server.Main.main(Main.java:93)

客户端程序的输出

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2023)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1125)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at main.main(main.java:38)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

感谢您的帮助。

0 个答案:

没有答案