Olá. Estou desenvolvendo um servidor socket que trabalha com SSL porém estou me deparando com a seguinte exception: signature check failed. O erro acontece no servidor ServidorSSL na Thread RecebeCliente no momento em que ele executa a instrução System.out.println(in.readLine()); Vou postar os códigos e o script de criação dos certificados, talvez o problema pode ser nos certificados. Por favor se puderem me ajudar! Qual detalhe está faltando nessa comunicação?
Exception:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: signature check failed
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1649)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:893)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:632)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)
at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:276)
at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122)
at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212)
at java.io.BufferedWriter.flush(BufferedWriter.java:236)
at gatewaynutrik.ClienteSimplesSSL.run(ClienteSimplesSSL.java:81)
at gatewaynutrik.ClienteSimplesSSL.main(ClienteSimplesSSL.java:104)
Caused by: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: signature check failed
at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:289)
at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:263)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:184)
at sun.security.validator.Validator.validate(Validator.java:218)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1185)
... 15 more
Caused by: java.security.cert.CertPathValidatorException: signature check failed
at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:139)
at sun.security.provider.certpath.PKIXCertPathValidator.doValidate(PKIXCertPathValidator.java:328)
at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:178)
at java.security.cert.CertPathValidator.validate(CertPathValidator.java:250)
at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:275)
... 22 more
Caused by: java.security.SignatureException: Signature does not match.
at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:446)
at sun.security.provider.certpath.BasicChecker.verifySignature(BasicChecker.java:133)
at sun.security.provider.certpath.BasicChecker.check(BasicChecker.java:112)
at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:117)
... 26 more
SCRIPT DOS JKS
CERTIFICADO DO SERVIDOR
1º CRIA UM KEYSTORE VAZIOga
keytool -genkey -alias tmp -keystore truststore.jks
keytool -delete -alias tmp -keystore truststore.jks
2º Gerar uma chave privada e um certificado inicial como um keystore JKS
keytool -genkey -keyalg RSA -keysize 1024 -alias “servidor” -keystore kservidor.jks -storepass “123456” -validity 365
3º Gerar um Certificate Signing Request para uma chave em um keystore JKS.O CSR é enviado para a CA e esta devolve o certificado assinado. Ai basta importar para o keystore (kservidor.jks) com o mesmo alias (servidor) com que foi criada a chabe privada
keytool -certreq -v -alias “servidor” -keystore kservidor.jks -storepass “123456” -file servidor.csr
4º Exporta o certificado para um arquivo
keytool -export -alias “servidor” -keystore kservidor.jks -file servidor.x509
5º Importa um certificado (assinado) para o keystore
keytool -import -keystore kservidor.jks -storepass “123456” -file servidor.x509
6º Adicionar um certificado público para um keystore JKS, por exemplo, o truststore JVM
keytool -import -trustcacerts -alias “servidor” -file servidor.x509 -keystore truststore.jks
CERTIFICADO DO CLIENTE
1º CRIA UM KEYSTORE VAZIO
keytool -genkey -alias tmp -keystore truststoreCliente.jks
keytool -delete -alias tmp -keystore truststoreCliente.jks
2º Gerar uma chave privada e um certificado inicial como um keystore JKS
keytool -genkey -keyalg RSA -keysize 1024 -alias “cliente” -keystore kcliente.jks -storepass “123456” -validity 365
3º Gerar um Certificate Signing Request para uma chave em um keystore JKS.O CSR é enviado para a CA e esta devolve o certificado assinado. Ai basta importar para o keystore (kcliente.jks) com o mesmo alias (cliente) com que foi criada a chabe privada
keytool -certreq -v -alias “cliente” -keystore kcliente.jks -storepass “123456” -file cliente.csr
4º Exporta o certificado para um arquivo
keytool -export -alias “cliente” -keystore kcliente.jks -file cliente.x509
5º Importa um certificado (assinado) para o keystore
keytool -import -keystore kcliente.jks -storepass “123456” -file cliente.x509
6º Adicionar um certificado público para um keystore JKS, por exemplo, o truststore JVM
keytool -import -trustcacerts -alias “cliente” -file cliente.x509 -keystore truststoreCliente.jks
ESSE É CÓDIGO DO SERVIDOR
import com.sun.corba.se.impl.logging.UtilSystemException;
import java.net.*;
import java.io.*;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
public class ServerSSL implements Runnable {
private SSLServerSocket ssocket;
private SSLServerSocketFactory factory;
private int SERVER_PORT;
public SSLServerSocket criaSSLServerSocket() throws Exception {
System.setProperty("java.naming.security.protocol", "ssl");
System.setProperty("javax.net.ssl.trustStore", "C:\\Program Files\\Java\\jdk1.6.0_22\\bin\\kservidor.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "123456");
KeyStore ks = Utils.getKeyStore("JKS");
ks.load(new FileInputStream("C:\\Program Files\\Java\\jdk1.6.0_22\\bin\\kservidor.jks"), "nrqi85".toCharArray());
KeyManagerFactory kmf = Utils.getKMFactory("SunX509");
kmf.init(ks, "123456".toCharArray());
SSLContext contextoSSL = Utils.criaSSLContext("SSLv3");
//CustomTrustManager[] cus = new CustomTrustManager[2979];
contextoSSL.init(kmf.getKeyManagers(), null, null);
ServerSocketFactory ssf = contextoSSL.getServerSocketFactory();
SSLServerSocket servidorSSL = (SSLServerSocket) ssf.createServerSocket(SERVER_PORT);
servidorSSL.setEnabledCipherSuites(servidorSSL.getSupportedCipherSuites());
servidorSSL.setNeedClientAuth(false);
return servidorSSL;
}
public ServerSSL(int port) {
}
public void start() throws UnknownHostException {
SSLSocket _socket = null;
//this.AddLista("Servidor iniciou com sucesso em " + InetAddress.getLocalHost().toString() + " porta " + SERVER_PORT);
System.out.println("Servidor iniciou com sucesso em " + InetAddress.getLocalHost().toString() + " porta " + SERVER_PORT);
while (true) {
try {
new RecebeCliente((SSLSocket) ssocket.accept()).start();
System.out.println("Novo cliente na lista");
} catch (Exception e) {
System.out.println("Thread exception" + e.getMessage());
try {
_socket.close();
} catch (Exception ex) {
System.out.println("Erro ao fechar o SOCKET");
}
}
}
}
public void run() {
try {
factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
try {
this.SERVER_PORT = 2979;
ssocket = criaSSLServerSocket();
} catch (Exception ex) {
Logger.getLogger(frmSever.class.getName()).log(Level.SEVERE, null, ex);
}
this.start();
} catch (UnknownHostException ex) {
Logger.getLogger(ServerSSL.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) throws Exception {
ServerSSL server = new ServerSSL(2979);
server.run();
}
}
class RecebeCliente extends Thread implements Constants {
private SSLSocket cliente;
private DataInputStream dis;
private SSLSocket socket;
private boolean done = false;
private Thread thread;
private String hostname;
private User user;
BufferedReader in;
DataOutputStream out;
//frmSever Server = new frmSever();
public RecebeCliente(SSLSocket s) throws IOException, Exception {
cliente = s;
this.socket = cliente;
//dis = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(cliente.getOutputStream());
in = new BufferedReader(new InputStreamReader(cliente.getInputStream()));
System.out.println("Novo cliente acessando.");
System.out.println(in.readLine());
}
public void run() {
try {
out.writeUTF("Olá Cliente!");
out.flush();
} catch (Exception err) {
err.printStackTrace();
done = true;
try {
socket.close();
} catch (Exception se) {
se.printStackTrace();
}
}
}
}
ESSE É O CÓDIGO DO CLIENTE
import java.io.*;
import java.net.*;
import java.security.*;
import javax.net.SocketFactory;
import javax.net.ssl.*;
public class ClienteSimplesSSL {
private static final int HTTPS_PORT = 2979;
private static SSLSocket socket;
private String keystore = "C:\\Program Files\\Java\\jdk1.6.0_22\\bin\\kcliente.jks";
private char[] password;
private String nome;
private String host;
public ClienteSimplesSSL(String nome, String password, String host) {
this.nome = nome;
this.password = password.toCharArray();
this.host = host;
System.setProperty("java.naming.security.protocol", "ssl");
System.setProperty("javax.net.ssl.trustStore", keystore);
System.setProperty("javax.net.ssl.trustStoreType", "JKS");
System.setProperty("javax.net.ssl.trustStorePassword", password);
/*System.setProperty("javax.net.ssl.trustStoreType", "JKS");
System.setProperty("javax.net.ssl.trustStore", "C:\\Program Files\\Java\\jdk1.6.0_22\\bin\\truststoreCliente.jks");
System.setProperty("javax.net.ssl.trustStorePassword", password);*/
}
private SSLSocket criaSSLSocket(String host) throws Exception {
System.setProperty("javax.net.ssl.trustStore", keystore);
System.setProperty("javax.net.ssl.trustStorePassword", "123456");
KeyStore ks = Utils.getKeyStore("JKS");
ks.load(new FileInputStream(keystore), password);
KeyManagerFactory kmf = Utils.getKMFactory("SunX509");
kmf.init(ks, password);
SSLContext sslcontext = Utils.criaSSLContext("SSLv3");
sslcontext.init(kmf.getKeyManagers(), null, null);
SSLSocketFactory ssf = sslcontext.getSocketFactory();
SSLSocket socket = (SSLSocket) ssf.createSocket(host, HTTPS_PORT);
return (SSLSocket) socket;
}
public void run() {
try {
socket = criaSSLSocket(host); //cria o socket SSL que o cliente utilizará
socket.setSoTimeout(0);
socket.setKeepAlive(true);
((SSLSocket) socket).setEnableSessionCreation(true);
} catch (Exception e) {
System.out.println("Excecao 1 lancada : " + e.getMessage());
}
try {
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.write("Olá servidor");
out.flush();
String linha;
StringBuffer sb = new StringBuffer();
while ((linha = in.readLine()) != null) {
sb.append(linha);
sb.append("\n");
}
out.close();
in.close();
System.out.println(sb.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String argv[]) throws IOException {
System.out.print("Informe o password para o keystore do cliente:");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String password = in.readLine();
ClienteSimplesSSL cliente = new ClienteSimplesSSL("Cliente 1", password, "192.168.0.225");
cliente.run();
}
}