0

我在 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 来生成的。

我真的没有想法,所以任何帮助表示赞赏。您需要的其他任何内容都可以询问。谢谢

4

1 回答 1

0

此异常通常意味着服务器没有私钥。这意味着它只能支持匿名密码套件,如果客户端不允许这些,它不应该允许,则没有共同的密码套件。

您的设置代码很奇怪:

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

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

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

最后:

ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());

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

于 2017-07-13T02:12:41.123 回答