Java — javax.net.ssl.SSLPeerUnverifiedException: одноранговый узел не аутентифицирован

Я пытаюсь подключиться к своему собственному SSL-серверу с помощью собственного SSL-клиента, но получаю следующую ошибку:

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated at sun.security.ssl.SSLSessionImpl.getPeerCertificateChain(SSLSessionImpl.java:420) at server.run(Server.java:70) at server.main(Server.java:22)

Я искал ту же проблему здесь, в stackoverflow, но я могу найти только людей, которые используют это в Apache или других «системах» HTTPS.

Вот мой код сервера:

    /* Server SSL */


import javax.net.ssl.*;
import java.io.*;
import java.net.InetAddress;
import java.security.KeyStore;
//import java.security.cert.X509Certificate;
import java.util.Date;
import javax.security.cert.X509Certificate;

class server {

    ObjectOutputStream out;
    ObjectInputStream in;

    public static void main(String[] args) {    
        new server().run();
    }

    void run() {

    Date date = new Date();


        try {

            // Security test (to avoid starting from the command line)c

            char[] passphrase = "password".toCharArray();

           KeyStore keystore = KeyStore.getInstance("JKS");


           keystore.load(new FileInputStream("/home/ME/CERT/keystore"), passphrase);


           KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
           kmf.init(keystore, passphrase);


           SSLContext context = SSLContext.getInstance("TLS");
           KeyManager[] keyManagers = kmf.getKeyManagers();

           context.init(keyManagers, null, null);


            // -- End of security test

        // 1. Create a server Socket
            SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
            SSLServerSocket sslserversocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(9999);

         // TBH im not sure what the following code does, but I need it?

                    String[] enabledCipherSuites = { "SSL_DH_anon_WITH_RC4_128_MD5" };
                    sslserversocket.setEnabledCipherSuites(enabledCipherSuites);



        // 2. Wait for connection.
        System.out.println("Waiting for connection. ");
            SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();

           SSLSession session = sslsocket.getSession();
           X509Certificate cert = (X509Certificate)session.getPeerCertificateChain()[0];
           String subject = cert.getSubjectDN().getName();
           System.out.println(subject);


        // 2.1 Prints information about client, this could be (very) valuable to save in a file.
        System.out.println("Connection received: ");
        System.out.println("   Hostname: " + sslsocket.getInetAddress().getHostName());
        sslsocket.getInetAddress();
        System.out.println("         IP: " + InetAddress.getLocalHost().getHostAddress());
        System.out.println("          @  " + date.toString());
        System.out.println();

        // 3. Create input and output streams.



        // for some reason i cant make the out/in-variable without using it as global?

        out = new ObjectOutputStream(sslsocket.getOutputStream());
        out.flush();
        in = new ObjectInputStream(sslsocket.getInputStream());

        sendMessage("Connection successful");

        // 4. Client and server talks via the input and output streams

        String message;

        do {
        message = (String)in.readObject();
        System.out.println(" Client says:  " + message);
        if (message.equals("bye")) {
            sendMessage("bye");
        }

        }while(!message.equals("bye"));

        // 5. Closing connection

        in.close();
        out.close();
        sslsocket.close();
System.out.println("Server terminated. ");

        } catch (Exception exception) {
            exception.printStackTrace();

        }
    }
    void sendMessage(String msg) throws Exception
    {
    out.writeObject(msg);
    out.flush();
    System.out.println("  You(server) says: " + msg);
    }


}

И вот мой клиентский код:

/* Java SSL Client */

import javax.net.ssl.*;
import java.io.*;
import java.security.KeyStore;
import java.util.*;

class client {

String message;
ObjectOutputStream out;
ObjectInputStream in;


public static void main(String[] args) {
    new client().run();
}

void run() {

System.out.println();

int port = 9999;

String host = "127.0.0.1";

try {

    // Security test (to avoid starting with the command line)
    char[] passphrase = "trustword".toCharArray();

    KeyStore keystore = KeyStore.getInstance("JKS");
    keystore.load(new FileInputStream("/home/ME/CERT/truststore"), passphrase);

   TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
   tmf.init(keystore);


   SSLContext context = SSLContext.getInstance("TLS");
   TrustManager[] trustManagers = tmf.getTrustManagers();

   context.init(null, trustManagers, null);



    // --- End of security test



    System.out.println("Connecting to " + host + " on port " + port);

    // 1. Create a client socket. 
    SSLSocketFactory sslFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
    SSLSocket sslSocket = (SSLSocket)sslFactory.createSocket(host, port);

    // TBH im not sure what the following code does, but I need it?
    String[] enabledCipherSuites = { "SSL_DH_anon_WITH_RC4_128_MD5" };
    sslSocket.setEnabledCipherSuites(enabledCipherSuites);


    System.out.println("Connected.");

    // 2. Create input and output streams
    out = new ObjectOutputStream(sslSocket.getOutputStream());
    out.flush();
    in = new ObjectInputStream(sslSocket.getInputStream());

    // 3. Client and server talks via the input and output streams

    Scanner input = new Scanner(System.in);

    message = (String)in.readObject();
    System.out.println(" Server says: " + message);

    sendMessage("Hello Server! ");

    do {
    // Sends input text
    System.out.print("Enter text to send: ");
    message = input.nextLine();
    sendMessage(message);

    if (message.equals("bye")) {
        message = (String)in.readObject();
        System.out.println(" Server says: " + message);
    }

    } while(!message.equals("bye"));

    // 4. Closing connection

    in.close();
    out.close();
    sslSocket.close();
    System.out.println("Client terminated. ");
}

catch (Exception exception) {
    exception.printStackTrace();

}

}

void sendMessage(String msg) throws Exception
{
out.writeObject(msg);
out.flush();
System.out.println("  You(client) says: " + msg);
}

}

Я глубоко признателен за ответ или толчок в правильном направлении!


person phiip    schedule 27.02.2012    source источник


Ответы (2)


Здесь есть две проблемы.

  1. Вы ограничиваете наборы шифров SSL_DH_anon_WITH_RC4_128_MD5, который является анонимным набором шифров, поэтому аутентификация отсутствует. Просто удалите это, оно вам не нужно.

  2. Вы не вызываете setWantClientAuth(true) или setNeedClientAuth(true) на сервере, поэтому клиенту никогда не предлагается отправить свой сертификат, поэтому он его не отправляет. Таким образом, запрос сервером сертификата однорангового узла бессмысленен. Пусть клиент попросит об этом.

На этом этапе вам нужно решить, действительно ли вам нужна аутентификация клиента или нет. Если вы это сделаете, вы должны вызвать один из вышеперечисленных методов, а также предоставить клиенту закрытый ключ и подписанный сертификат в хранилище ключей, а также сделать так, чтобы хранилище доверенных сертификатов сервера доверяло этому хранилищу ключей либо путем экспорта/импорта, либо при наличии сертификата клиента, подписанного ЦС. Не сразу понятно, нужно ли вам что-то из этого.

person user207421    schedule 28.02.2012
comment
1. У меня было подозрение, что этот анон DeffieHelman может иметь какое-то отношение к этому, но если я удалю эти строки, я получу следующую ошибку: Нет доступного сертификата или ключа, соответствующего включенным наборам шифров SSL. at sun.security.ssl.SSLServerSocketImpl.checkEnabledSuites(SSLServerSocketImpl.java:327) at sun.security.ssl.SSLServerSocketImpl.accept(SSLServerSocketImpl.java:272) 2. Таким образом, нет способа сделать это без клиента аутентифицировать себя? Я знаю, что хочу аутентификацию сервера, но я не уверен насчет клиента... - person phiip; 28.02.2012
comment
@phiip 1. если вам нужен сертификат однорангового узла, одноранговый узел должен его отправить, и если одноранговый узел является клиентом, вам нужно хотеть или нуждаться в аутентификации клиента, чтобы это произошло. 2. Исключение, связанное с набором шифров, означает, что в вашем сертификате сервера есть что-то очень странное. Сгенерируйте новый закрытый ключ с помощью RSA и начните процесс подписи заново. - person user207421; 28.02.2012
comment
@phiip Конечно, вам нужно удалить этот набор шифров на обоих концах, как на сервере, так и на клиенте. - person user207421; 28.02.2012

Сертификат с истекшим сроком действия был причиной нашего «javax.net.ssl.SSLPeerUnverifiedException: узел не аутентифицирован».

keytool -list -v -keystore filetruststore.ts

    Enter keystore password:
    Keystore type: JKS
    Keystore provider: SUN
    Your keystore contains 1 entry
    Alias name: somealias
    Creation date: Jul 26, 2012
    Entry type: PrivateKeyEntry
    Certificate chain length: 1
    Certificate[1]:
    Owner: CN=Unknown, OU=SomeOU, O="Some Company, Inc.", L=SomeCity, ST=GA, C=US
    Issuer: CN=Unknown, OU=SomeOU, O=Some Company, Inc.", L=SomeCity, ST=GA, C=US
    Serial number: 5011a47b
    Valid from: Thu Jul 26 16:11:39 EDT 2012 until: Wed Oct 24 16:11:39 EDT 2012
person buzz3791    schedule 30.10.2012