/* * Demoiselle Framework * Copyright (C) 2010 SERPRO * ---------------------------------------------------------------------------- * This file is part of Demoiselle Framework. * * Demoiselle Framework is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License version 3 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License version 3 * along with this program; if not, see <http://www.gnu.org/licenses/> * or write to the Free Software Foundation, Inc., 51 Franklin Street, * Fifth Floor, Boston, MA 02110-1301, USA. * ---------------------------------------------------------------------------- * Este arquivo é parte do Framework Demoiselle. * * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação * do Software Livre (FSF). * * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português * para maiores detalhes. * * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título * "LICENCA.txt", junto com esse programa. Se não, acesse <http://www.gnu.org/licenses/> * ou escreva para a Fundação do Software Livre (FSF) Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. */ package br.gov.frameworkdemoiselle.certificate.ca.manager; import java.security.InvalidKeyException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SignatureException; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.logging.Level; import java.util.logging.Logger; import br.gov.frameworkdemoiselle.certificate.ca.provider.ProviderCA; import br.gov.frameworkdemoiselle.certificate.ca.provider.ProviderCAFactory; import br.gov.frameworkdemoiselle.certificate.ca.provider.ProviderSignaturePolicyRootCA; import br.gov.frameworkdemoiselle.certificate.ca.provider.ProviderSignaturePolicyRootCAFactory; public class CAManager { private static final CAManager instance = new CAManager(); private static final Logger LOGGER = Logger.getLogger(CAManager.class.getName()); private CAManager() { } public static CAManager getInstance() { return CAManager.instance; } public Collection<X509Certificate> getSignaturePolicyRootCAs(String policyOID) { Collection<ProviderSignaturePolicyRootCA> providers = ProviderSignaturePolicyRootCAFactory.getInstance() .factory(policyOID); Collection<X509Certificate> result = new HashSet<X509Certificate>(); for (ProviderSignaturePolicyRootCA provider : providers) { try { result.addAll(provider.getCAs()); } catch (Throwable error) { // TODO: Nao foi possivel resgatar as raizes confiaveis // de uma determinada politica } } return result; } public boolean validateRootCAs(Collection<X509Certificate> cas, X509Certificate certificate) { boolean valid = false; for (X509Certificate ca : cas) { try { this.validateRootCA(ca, certificate); valid = true; break; } catch (CAManagerException error) { continue; } } if (!valid) { throw new CAManagerException( "Nenhuma autoridade informada faz parte da cadeia de certificados do certificado informado"); } return true; } public boolean validateRootCA(X509Certificate ca, X509Certificate certificate) { if (ca == null) { throw new CAManagerException("Certificado da autoridade raiz não informado"); } if (!this.isRootCA(ca)) { throw new CAManagerException("Certificado da autoridade não é raiz"); } Collection<X509Certificate> acs = this.getCertificateChain(certificate); if (acs == null || acs.size() <= 0) { throw new CAManagerException("Não foi possível resgatar a cadeia de autoridades do certificado informado"); } X509Certificate rootCA = null; for (X509Certificate x509 : acs) { if (this.isRootCA(x509)) { rootCA = x509; break; } } if (rootCA == null) { throw new CAManagerException( "Não foi possível achar um certificado raiz na cadeia do certificado informado"); } if (!this.isCAofCertificate(rootCA, ca)) { throw new CAManagerException( "A autoridade raiz não faz parte da cadeia de certificados do certificado informado"); } return true; } public boolean isRootCA(X509Certificate ca) { if (ca == null) { return false; } return this.isCAofCertificate(ca, ca); } public boolean isCAofCertificate(X509Certificate ca, X509Certificate certificate) { try { certificate.verify(ca.getPublicKey()); return true; } catch (SignatureException error) { return false; } catch (InvalidKeyException error) { return false; } catch (CertificateException error) { throw new CAManagerException("Algum erro ocorreu com o certificado informado", error); } catch (NoSuchAlgorithmException error) { throw new CAManagerException("Não há o algoritmo necessário", error); } catch (NoSuchProviderException error) { throw new CAManagerException("Provider inválido", error); } } public Certificate[] getCertificateChainArray(X509Certificate certificate) { Certificate[] result = null; LinkedList<X509Certificate> chain = (LinkedList<X509Certificate>) this.getCertificateChain(certificate); if (chain == null || chain.size() <= 0) { return result; } result = new Certificate[chain.size()]; for (int i = 0; i < chain.size(); i++) { result[i] = chain.get(i); } return result; } /** * Get ALL certificate chains previously added in * * @param certificate * @return list of certificates */ public Collection<X509Certificate> getCertificateChain(X509Certificate certificate) { Collection<X509Certificate> result = new LinkedList<X509Certificate>(); result.add(certificate); if (this.isRootCA(certificate)) { return result; } Collection<ProviderCA> providers = ProviderCAFactory.getInstance().factory(); for (ProviderCA provider : providers) { try { LOGGER.info(">>> Procurando certificado no Provider: " + provider.getName()); // Get ALL CAs of ONE provider Collection<X509Certificate> acs = provider.getCAs(); // Variable to control if go to next Provider is necessery boolean ok = false; // Iterate this provider to create a Cert Chain for (X509Certificate ac : acs) { if (this.isCAofCertificate(ac, certificate)) { result.add(ac); X509Certificate acFromAc = this.getCAFromCertificate(acs, ac); while (acFromAc != null) { // If the chain was created SET OK result.add(acFromAc); // If Certificate is ROOT end while if (this.isRootCA(acFromAc)) { ok = true; break; } else { acFromAc = this.getCAFromCertificate(acs, acFromAc); } } } if (ok == true) { break; } } LOGGER.log(Level.INFO, ">>> Foram encontrados [" + result.size() + "] níveis na cadeia do provider [" + provider.getName() + "]."); // If chain is created BREAK! Doesn't go to next Provider if (ok) { break; } else { LOGGER.info("Não foi possivel montar a cadeia com o provider: " + provider.getName()); } } catch (Throwable error) { // TODO: Nao foi possivel resgatar as CAs de um determinado // provedor } } return result; } private X509Certificate getCAFromCertificate(Collection<X509Certificate> certificates, X509Certificate certificate) { if (this.isRootCA(certificate)) { return null; } if (certificates == null || certificates.isEmpty()) { return null; } for (X509Certificate ca : certificates) { if (this.isCAofCertificate(ca, certificate)) { return ca; } } return null; } public Certificate[] getCertificateChainArray(KeyStore keyStore, String privateKeyPass, String certificateAlias) { Certificate[] certificateChain = null; try { keyStore.getKey(certificateAlias, privateKeyPass.toCharArray()); certificateChain = keyStore.getCertificateChain(certificateAlias); if (certificateChain == null) { throw new CAManagerException("Não há caminho de certificação para o alias informado"); } } catch (KeyStoreException error) { throw new CAManagerException("O provedor não suporta este tipo de keystore", error); } catch (UnrecoverableKeyException error) { throw new CAManagerException("Impossível recuperar a chave privada do keystore", error); } catch (NoSuchAlgorithmException error) { throw new CAManagerException("Não há o algoritmo necessário", error); } return certificateChain; } public Collection<X509Certificate> getCertificateChain(KeyStore keyStore, String privateKeyPass, String certificateAlias) { Collection<X509Certificate> result = null; Certificate[] certificateChain = this.getCertificateChainArray(keyStore, privateKeyPass, certificateAlias); if (certificateChain != null) { result = new LinkedList<X509Certificate>(); for (Certificate certificate : certificateChain) { result.add((X509Certificate) certificate); } } else { throw new CAManagerException("Não há caminho de certificação para o alias informado"); } return result; } }