SSLSocket握手异常没有共同的密码服务器

时间:2017-07-13 01:41:52

标签: java sockets ssl encryption sslsocketfactory

我在StackOverflow上到处搜索,但这些问题似乎与我的不同,我在修复它时遇到了很多麻烦。

现在,我的程序应该只使用SSL套接字建立客户端 - 服务器连接,客户端只发送一条消息并关闭(我稍后会向其中添加更多内容)

我遇到了消息部分和No Cipher Suites in Common错误的问题。下面我将发布我的服务器和客户端代码以及输出。我使用的是Ubuntu 16.04和Netbeans 8.2

服务器代码:

public static void main(String[] args) 
        throws IOException, KeyStoreException, NoSuchAlgorithmException, 
        CertificateException, UnrecoverableKeyException, KeyManagementException {

    FileInputStream keyFile = new FileInputStream(archivoKey);//Server.jks with Client.crt and .key as well as Server.crt and .key
    char[] archivopwd = mypassword.toCharArray();
    String password = mypassword;

    System.setProperty("javax.net.ssl.trustStore", archivoKey);
    System.setProperty("javax.net.ssl.trustStorePassword", password); 

    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(keyFile, archivopwd);

    KeyManagerFactory keyManagerFactory = 
            KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    keyManagerFactory.init(keyStore, archivopwd);
    KeyManager keyManagers[] = keyManagerFactory.getKeyManagers();

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(keyManagers, null, null);


    SSLServerSocketFactory factory=(SSLServerSocketFactory) 
            SSLServerSocketFactory.getDefault();
    SSLServerSocket ss = (SSLServerSocket) factory.createServerSocket(6000);
    System.out.println("Esperando conexion...");
    ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());
    SSLSocket so =(SSLSocket) ss.accept();
    so.startHandshake();
    System.out.println("Conexion realizada");

    BufferedReader in = new BufferedReader
        (new InputStreamReader(so.getInputStream()));
    String msg = in.readLine();
    System.out.println(msg);

}

服务器输出:

Exception in thread "main" 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:1045)
at sun.security.ssl.ServerHandshaker.clientHello(ServerHandshaker.java:741)
at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:224)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
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 servidorseguridad.ServidorSeguridad.main(ServidorSeguridad.java:73)

客户端代码

public static void main(String[] args) {
    int port = 6000;
    String host = "localhost";
    String password = mypassword;
    System.setProperty("javax.net.ssl.trustStore", archivoKey);
    System.setProperty("javax.net.ssl.trustStorePassword", password); 
    try {
        SSLContext sc = SSLContext.getInstance("TLS");
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        InputStream keyFile = new FileInputStream(archivoKey); //Client.jks, exactly the same as the Server.jks
        try {
            keyStore.load(keyFile, archivopwd);
        } finally {
            if (keyFile != null) {
                keyFile.close();
            }
        }
        KeyManagerFactory keyManagerFactory = 
                KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(keyStore, archivopwd);

        sc.init(null,  null, null);

        SocketFactory factory = sc.getSocketFactory();

        System.out.println("Buscando conexion...");

        try (SSLSocket so = (SSLSocket) factory.createSocket(host, port)) {
            so.getEnabledCipherSuites();
            so.startHandshake();

            System.out.println("Conexion exitosa!");

            DataOutputStream os = new DataOutputStream(so.getOutputStream());

            os.writeUTF("Prueba!");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

客户端输出

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 clienteseguridad.ClienteSeguridad.main(ClienteSeguridad.java:65)

大多数东西(比如System.setProperty的东西)让我测试了我在这里读过的几个选项。 .jks是通过将crt和密钥文件获取到p12并将其添加到.jks来生成的。

我真的没有想法,所以任何帮助都表示赞赏。你需要的任何其他东西你都可以问。谢谢

1 个答案:

答案 0 :(得分:0)

此异常通常表示服务器没有私钥。这意味着它只能支持匿名密码套件,如果客户端不允许这样,那么就没有共同的密码套件。

您的设置代码很奇怪:

  • 两者加载信任库设置系统属性:您不需要同时执行这两项操作。
  • 您正在为密钥库和信任库使用相同的文件,这在技术上是有效的,但绝不可取。

您需要创建服务器端密钥库,密钥对,然后

  1. 自签名证书,您需要导出到客户的信任库,或者更好
  2. CSR,由CA签名,然后使用您用于创建密钥对的相同别名将签名证书导入服务器密钥库。
  3. 最后:

    ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());
    

    删除此行。这是不安全的。永远不要这样做。