问题
I'm trying to connect to my own SSL Server with my own SSL Client, but i get the following error:
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)
I've searched for the same problem here on stackoverflow but I can only find people who are using this in Apache or other HTTPS "systems".
Here is my server code:
/* 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);
}
}
And here is my Client code:
/* 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);
}
}
I deeply appreciate an answer, or a push in the right direction!
回答1:
There are two problems here.
You are restricting the cipher suites to SSL_DH_anon_WITH_RC4_128_MD5, which is an anonymous cipher suite, so there is no authentication. Just remove this, you don't need it.
You aren't calling
setWantClientAuth(true)
orsetNeedClientAuth(true)
at the server, so the client is never being asked to send its certificate, so it isn't sending one. So having the server ask for the peer certificate is pointless. Have the client ask for it.
At this point you need to decide whether you really need client authentication or not. If you do, you have to call one of the above methods, and you also need to provide the client with a private key and a signed certificate in a keystore, and arrange that the server's truststore trusts this keystore, either by export/import or by having the client certificate signed by a CA. It's not immediately clear that you need any of this.
回答2:
Expired certificate was the cause of our "javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated".
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
来源:https://stackoverflow.com/questions/9474313/java-javax-net-ssl-sslpeerunverifiedexception-peer-not-authenticated