Jump to content

Problemas com certificados de uma socket SSL


Sergiosaturn
 Share

Recommended Posts

Saudações programadores. 🙂

Devido a motivos academicos , eu tenho de desnvolver um programa em java que use sockets SSL. Como so conhecia essa materia na pratica eu invetiguei na internet como usar as sockets SSL em java. De inicio eu copiei alguns codigos de net para testar o funcionamento dessas sockets, no entanto para pelo o que eu li nos sites que investiguei , para que as sockets SSL funcionem é necessario usar certificados.

Mais uma vez voltei a investigar na internet como é que poderia criar um certificado , nessa pesquisa eu encontrei varios sites , no entanto para gerar um certificado eu usei o seguinte site.

http://pedro-costa.wikidot.com/keytool

Seguindo as intrucoes deste site eu usei o programa keytool para gerar um certificado.Em seguida usando os sites que encontrei nas minhas investigações eu criei o seguinte codigo.

O objectivo destes programas é ter uma aplicacao cliente - servidor que use as sockets SSL. De um lado o cliente vai enviar uma mensagem "ola Mundo" e do outro lado o servidor vai ler essa mensagem , e vai imprimi-la no ecra. A aplicacao Cliente e a aplicacao Servidor usam certificados diferentes.

Aqui esta o codigo do cliente.

package socket_seguro_cliente;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;


public class Main {

      public static SSLSocket createSSLContext() throws Exception
    {

          KeyStore ks =  Utils.getKeyStore("JKS");
          ks.load(new FileInputStream("c:\\cliente.jks"), "servidor".toCharArray());

          KeyManagerFactory kmf = Utils.getKMFactory("SunX509");
          kmf.init(ks, "servidor".toCharArray());

          SSLContext sslcontext = Utils.criaSSLContext("SSLv3");
          sslcontext.init(kmf.getKeyManagers(), null, null);

          SSLSocketFactory ssf = sslcontext.getSocketFactory();
          SSLSocket socket = (SSLSocket) ssf.createSocket("localhost",9999);

          socket.setEnabledCipherSuites(socket.getEnabledCipherSuites());

          return socket;

    }


    public static void main(String[] args) throws IOException, Exception {

//            System.setProperty("javax.net.ssl.keyStore", "c:\\servidor.jks");
//            System.setProperty("javax.net.ssl.keyStorePassword", "servidor");

           SSLSocket socket;
           ObjectInputStream dataInput;
           ObjectOutputStream dataOutput;

            System.out.println("Bem vindo ao Cliente\n");

            System.out.println("A estabelecer conexoes\n\n");

            socket = createSSLContext();
            

//          socket.startHandshake();

            dataInput = new ObjectInputStream(socket.getInputStream());
            dataOutput = new ObjectOutputStream(socket.getOutputStream());

            System.out.println("A enviar mensagens\n\n");

            dataOutput.writeUTF("ola mundo");
            dataOutput.flush();

            System.out.println("Mensagem enviada\n\n");

    }

}

Aqui esta o codigo do servidor

package socket_seguro_servidor;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;

import java.net.Socket;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.cert.CertificateException;
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.SSLSessionContext;




public class Main {
    
    public static void showPropSSLContext(SSLContext contextoSSL){

      System.out.println("-------Informaçoes de contexto SSL-------");

      String protocol = contextoSSL.getProtocol();
      System.out.println("Protocolo : "+protocol);

      Provider provider = contextoSSL.getProvider();
      System.out.println("Nome do provedor : "+provider.getName());
      System.out.println("Versao do provedor : "+provider.getVersion());
      SSLSessionContext sslsessioncontext = contextoSSL.getServerSessionContext();
   
}

   public static ServerSocket criaSSLServerSocket() throws Exception{

      KeyStore ks = Utils.getKeyStore("JKS");
       ks.load(new FileInputStream("c:\\servidor.jks"), "servidor".toCharArray());

      KeyManagerFactory kmf = Utils.getKMFactory("SunX509");
       kmf.init(ks, "servidor".toCharArray());

      SSLContext contextoSSL = Utils.criaSSLContext("SSLv3");
      contextoSSL.init(kmf.getKeyManagers(), null, null);

      showPropSSLContext(contextoSSL);

      ServerSocketFactory ssf = contextoSSL.getServerSocketFactory();
      SSLServerSocket servidorSSL = (SSLServerSocket) ssf.createServerSocket(9999);
      //Se necessário, autentica o cliente

      servidorSSL.setEnabledCipherSuites(servidorSSL.getSupportedCipherSuites());

      servidorSSL.setNeedClientAuth(false);

  return servidorSSL;
}


    public static void main(String[] args) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, Exception {

//        System.setProperty("javax.net.ssl.keyStore", "c:\\servidor.jks");
//        System.setProperty("javax.net.ssl.keyStorePassword", "servidor");

        ObjectInputStream dataInput;
        ObjectOutputStream dataOutput;

        System.out.println("Bem vindo ao servidor\n\n");

        System.out.println("A estabelecer conexoes\n\n");

        ServerSocket servidorSSL = criaSSLServerSocket();

//        sSock.

        Socket socket = servidorSSL.accept();

        dataOutput = new ObjectOutputStream(socket.getOutputStream());
        dataInput = new ObjectInputStream(socket.getInputStream());

        System.out.println("A receber mensagens\n\n");

        String pedido = dataInput.readUTF();

        System.out.println("Recebi isto -> " + pedido + "\n\n");

        System.out.println("Mensagem recebida\n\n");
    }

    }


E aqui esta a classe util que ambos os programas usam.

package socket_seguro_servidor;

import javax.net.ssl.*;
import java.security.*;

public class Utils{

protected static KeyStore getKeyStore(String tipo) throws KeyStoreException{

   //utiliza a implementação do keystore provido pela Sun
   return KeyStore.getInstance(tipo);

}

protected static KeyManagerFactory getKMFactory(String algoritmo) throws NoSuchAlgorithmException{

  //cria um caminho de certificação baseado em X509
  return KeyManagerFactory.getInstance(algoritmo);

}

protected static SSLContext criaSSLContext(String protocolo) throws NoSuchAlgorithmException{

//cria um SSLContext segundo o protocolo informado
  return SSLContext.getInstance(protocolo);

}

}

No entanto ao executar estes codigos eu obtives as seguintes execpcoes.

No servidor eu obtive isto.

Bem vindo ao servidor


A estabelecer conexoes


-------Informaçoes de contexto SSL-------
Protocolo : SSLv3
Nome do provedor : SunJSSE
Versao do provedor : 1.6
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1682)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:932)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1112)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:623)
        at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59)
        at java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1838)
        at java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1747)
        at java.io.ObjectOutputStream.<init>(ObjectOutputStream.java:226)
        at socket_seguro_servidor.Main.main(Main.java:85)

E no cliente eu obtive isto

Bem vindo ao Cliente

A estabelecer conexoes


Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1611)
        at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:187)
        at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:181)
        at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1035)
        at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:124)
        at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:516)
        at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:454)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:884)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1112)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:744)
        at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:75)
        at java.io.ObjectInputStream$PeekInputStream.read(ObjectInputStream.java:2266)
        at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2279)
        at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:2750)
        at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:780)
        at java.io.ObjectInputStream.<init>(ObjectInputStream.java:280)
        at socket_seguro_cliente.Main.main(Main.java:56)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:285)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:191)
        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:1014)
        ... 13 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:280)
        ... 19 more

Eu tentei investigar na internet porque é que estes erros ocorrem no entanto nao consegui encontrar resposta. Ja tentei gerar varias vezes os certificados mas o mesmo erro continua. Por favor se alguem encontrou algum erro parecido , por favor , diga.me como devo proceder. ja investiguei na net , ja testei todas as solucoes que me vieram a cabeça e mesmo assim nada.

Muito obrigado e boa sorte.

Link to comment
Share on other sites

Até agora só trabalhei com HTTPS, ao nível de socktes acho nunca trabalhei.

Encontrei este exemplo que me pareceu bastante completo

http://stilius.net/java/java_ssl.php

Pessoalmente não gostei foi muito da passagem de parâmetros pela linha de comandos, mas se não me engano é possivél carregar o keystore do ficheiro e depois passar a password in code.

I haven’t lost my mind; it’s backed up on DVD somewhere!

Link to comment
Share on other sites

Saudações magician.

Obrigado pela tua resposta.

A linha de codigo que estavas a falar não era a seguinte :

System.setProperty("javax.net.ssl.trustStore", "c:\\servidor.jks");
    System.setProperty("javax.net.ssl.trustStorePassword", "123456");

Eu pesquisei na net e encontrei isso , e ate ja meti no codigo , no entanto continua a rebentar. Da a mesma execpcao.

Obrigado e adeus.

Link to comment
Share on other sites

Saudações.

Eu segui todos os passos do link que me deste e mesmo assim nao funcionou. No entanto investiguei mais um bocado e encontrei o seguinte codigo.

package teste;

public class Main {
public static void main(String[] args) {
  String trustStore = System.getProperty("javax.net.ssl.trustStore");
  if(trustStore == null)
   System.out.println("javax.net.ssl.trustStore is not defined");
  else System.out.println("javax.net.ssl.trustStore = " + trustStore);
}
}

Pelo o que eu li no site de onde retirei isto , este codigo diz se o truststore esta ok ou nao. No entanto ao executar o programa ele devolve isto. ?

run:
javax.net.ssl.trustStore is not defined
BUILD SUCCESSFUL (total time: 0 seconds)

Foi a partir dai que andei na net a procura de uma maneira para adicionar o certificado ao trustore e foi ai que encontrei as linha de codigo que te apresentei anteriormente. 🙂

Depois desta experiencia estou convencido que falta alguma operacao no truststore. ?

Obrigado e adeus.

Link to comment
Share on other sites

Realmente isso é estranho porque pela exception dá a entender que não encontra o certificado ou então ele não é valido.

Talvez estejas a gerar o certificado de forma errada, ou então é algum parâmetro de validação, no caso do https para que ele processe todos os tipos de ligação https tem que se desactivar alguns parâmetros porque se não ele apenas aceita certificados dentro da validade e assinados :|

Talvez seja algum problema do género, mas infelizmente não sei bem o que é 🙂

I haven’t lost my mind; it’s backed up on DVD somewhere!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.