Utilitário para geração de TrustStore (JKS) – Java
Desenvolvi um utilitário que transforma um arquivo zip, contendo “n” certificados de Autoridades Certificadoras para um arquivo JKS.
Para referência segue um link que contém todas as CA’s brasileiras:
Como seria o processo normal ?
1 – Java Keytool – http://download.oracle.com/javase/6/docs/technotes/tools/windows/keytool.html
É um software que acompanha a máquina virtual Java (jdk), utilizado para diversas finalidades com relação à segurança de aplicações e pode ser usado para gerar o pacote JKS.
Seguem dois comandos exemplo para se trabalhar com arquivos JKS de truststore:
1. Listando todos os certificados contidos em um arquivo JKS:
[sourcecode language=”java”]keytool –list –v –keystore C:\meukeystore.jks[/sourcecode]
2. Importando um certificado de uma AC para dentro de um JKS pré-existente
[sourcecode language=”java”]keytool –import –trustcacerts –file C:\certificadoAC.cer –alias apelidoentrada –keystore C:\meutruststore.jks[/sourcecode]
Observação: Caso não exista um jks no diretório especificado em -keystore, será criado um automaticamente.
O arquivo ACcompactado.zip especificado na URL anteriormente, possui atualmente 84 certificados, portanto, deve-se executar o comando (2), 84 vezes, alterando o -alias e o –file. Por ser esta uma forma muito trabalhosa de se gerar um arquivo Trusted JKS, foi criado um utilitário que auxiliará nesta etapa, apresentado no próximo capítulo.
2 – Usando o utilitário – utilitarioTrustJKS.jar
O utilitário desenvolvido basicamente recebe como entrada um arquivo zip com todos os certificados desejados e gera um arquivo trust.jks.
Parâmetros de Entrada:
1 – caminhoZip – Diretório do arquivo zip que contém todos os certificados das AC’s
2 – caminhoSaida – Diretório de saída, onde será gerado o truststore.jks
3 – senhaKestore – Senha do arquivo TrustStore JKS
4 – incluirExpirados (opcional) – valor default => false) – Possui os valores true ou false. Informa se certificados expirados ou não válidos ainda deverão ser incluídos no arquivo JKS gerado.
Exemplo de utilização:
java -jar utilitarioTrustJKS.jar C:\ACcompactado.zip C:\truststore.jks 123456789 true
Link para Download do arquivo Jar:
http://arquivos.victorjabur.com/java/seguranca/utilitarioTrustJKS.jar
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.security.KeyStore; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateFactory; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.LinkedList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import com.sun.xml.internal.messaging.saaj.util.ByteInputStream; public class Main { private String caminhoZIP = "C:\\ACcompactado.zip"; private String caminhoSaida = "C:\\truststore.jks"; private String senhaKeystore = "123456789"; private Boolean incluirExpirados = false; public static void main(String[] args) throws Exception { Main main = new Main(); main.validarParametrosEntrada(args); List<X509Certificate> listaCertificadosValidos = main.getListaCertificadosValidos(); main.gerarJKS(listaCertificadosValidos); System.out.println("Arquivo JKS gerado com sucesso - " + listaCertificadosValidos.size() + " certificados incluidos"); } public void validarParametrosEntrada(String[] args){ if(args.length < 3){ throw new RuntimeException("O numero minimo de parametros = 3. caminhoZip caminhoSaida senhaKeystore e incluirExpirados (Opcional) "); }else{ String caminhoZip = args[0]; validacaoLeituraArquivo(new File(caminhoZip)); this.caminhoZIP = caminhoZip; String caminhoSaida = args[1]; this.caminhoSaida = caminhoSaida; String senhaKeystore = args[2]; this.senhaKeystore = senhaKeystore; if(args.length >= 4){ String incluirExpirados = args[3]; if(incluirExpirados.equals("true") || incluirExpirados.equals("false")){ this.incluirExpirados = Boolean.valueOf(incluirExpirados); }else{ throw new RuntimeException("O parametro incluirExpirados (4) deve ser true ou false"); } } } } public List<X509Certificate> getListaCertificadosValidos() { File arquivoZipEntrada = new File(this.caminhoZIP); validacaoLeituraArquivo(arquivoZipEntrada); List<X509Certificate> x509CertificateList = new LinkedList<X509Certificate>(); try { InputStream in = new FileInputStream(arquivoZipEntrada); ZipInputStream zipInputStream = new ZipInputStream(in); ZipEntry zipentry = zipInputStream.getNextEntry(); while (zipentry != null) { byte[] buffer = new byte[(int) zipentry.getSize()]; int offset = 0; int numRead = 0; while (offset < buffer.length && (numRead = zipInputStream.read(buffer, offset, buffer.length - offset)) >= 0) { offset += numRead; } InputStream bis = new ByteInputStream(buffer, 0, buffer.length); CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate) cf.generateCertificate(bis); try { cert.checkValidity(); x509CertificateList.add(cert); } catch (CertificateExpiredException e) { if(this.incluirExpirados){ x509CertificateList.add(cert); System.out.println("Certificado Expirado - " + zipentry.getName()); }else{ System.out.println("Certificado Expirado - " + zipentry.getName() + " - nao sera adicionado no JKS"); } } catch (CertificateNotYetValidException e) { if(this.incluirExpirados){ x509CertificateList.add(cert); System.out.println("Certificado não válido ainda - " + zipentry.getName()); }else{ System.out.println("Certificado não válido ainda - " + zipentry.getName() + " - nao sera adicionado no JKS"); } } zipInputStream.closeEntry(); zipentry = zipInputStream.getNextEntry(); } zipInputStream.close(); in.close(); } catch (Exception e) { e.printStackTrace(); } return x509CertificateList; } public OutputStream gerarJKS(List<X509Certificate> listaCertificados){ OutputStream out = null; try { KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); keystore.load(null, null); int indice = 0; for (X509Certificate cert : listaCertificados) { keystore.setCertificateEntry("ac_" + indice, cert); indice++; } File jks = new File(this.caminhoSaida); String diretorioDestino = jks.getParent(); new File(diretorioDestino).mkdirs(); out = new FileOutputStream(this.caminhoSaida); keystore.store(out, this.senhaKeystore.toCharArray()); out.close(); out.flush(); } catch (Exception e) { throw new RuntimeException("Erro ao gerar o arquivo de Keystore - " + e.getCause() + " - " + e.getMessage()); } return out; } public void validacaoLeituraArquivo(File arquivo) { if (!arquivo.exists()) { throw new RuntimeException("Arquivo Inexistente - " + arquivo.getAbsolutePath()); } if (!arquivo.canRead()) { throw new RuntimeException("Sem permissão de Leitura do Arquivo - " + arquivo.getAbsolutePath()); } } }
Abraços,
Victor Jabur