我正在尝试使用自己的SSL客户端连接到我自己的SSL服务器,但是我收到以下错误:
javax.net.ssl.SSLPeerUnverifiedException:peer未经过身份验证
at sun.security.ssl.SSLSessionImpl.getPeerCertificateChain(SSLSessionImpl.java:420)
在server.run(Server.java:70)
在server.main(Server.java:22)
我在*上搜索了同样的问题,但我只能找到在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);
}
}
我非常感谢答案,或者朝着正确的方向努力!
解决方法:
这里有两个问题.
>您正在将密码套件限制为SSL_DH_anon_WITH_RC4_128_MD5,这是一个匿名密码套件,因此没有身份验证.只需删除它,你不需要它.
>您没有在服务器上调用setWantClientAuth(true)或setNeedClientAuth(true),因此永远不会要求客户端发送其证书,因此它不会发送证书.因此让服务器请求对等证书是没有意义的.让客户要求它.
此时,您需要确定是否确实需要客户端身份验证.如果这样做,则必须调用上述方法之一,并且还需要在密钥库中为客户端提供私钥和签名证书,并通过导出/导入或安排服务器的信任库信任此密钥库.通过CA签署客户端证书.目前还不清楚你是否需要这些.