package gov.pr.celepar.tabeliao.core; /* Este programa � licenciado de acordo com a LPG-AP (LICEN�A P�BLICA GERAL PARA PROGRAMAS DE COMPUTADOR DA ADMINISTRA��O P�BLICA), vers�o 1.1 ou qualquer vers�o posterior. A LPG-AP deve acompanhar todas PUBLICA��ES, DISTRIBUI��ES e REPRODU��ES deste Programa. Caso uma c�pia da LPG-AP n�o esteja dispon�vel junto com este Programa, voc� pode contatar o LICENCIANTE ou ent�o acessar diretamente: http://www.celepar.pr.gov.br/licenca/LPG-AP.pdf Para poder USAR, PUBLICAR, DISTRIBUIR, REPRODUZIR ou ALTERAR este Programa � preciso estar de acordo com os termos da LPG-AP */ import gov.pr.celepar.tabeliao.core.validacao.TabeliaoResultadoValidacao; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.xml.crypto.MarshalException; import javax.xml.crypto.XMLStructure; import javax.xml.crypto.dsig.Reference; import javax.xml.crypto.dsig.XMLSignature; import javax.xml.crypto.dsig.XMLSignatureException; import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.dom.DOMValidateContext; import javax.xml.crypto.dsig.keyinfo.X509Data; import org.apache.log4j.Logger; import org.jcp.xml.dsig.internal.dom.DOMReference; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import sun.security.x509.X509CertImpl; /** * * Classe para tratamento e validacao de assinatura em formato XML * * @author Emerson Sachio Saito - GIC/CELEPAR * */ public class TabeliaoAssinaturaXML { private static Logger logger = Logger.getLogger(TabeliaoAssinaturaXML.class); private Document xmlAssinado = null; private List<XMLSignature> assinaturas = new ArrayList<XMLSignature>(); private List<TabeliaoResultadoValidacao> resultadosValidacao = new ArrayList<TabeliaoResultadoValidacao>(); private List<TabeliaoCertificate> certificadosDasAssinaturas = new ArrayList<TabeliaoCertificate>(); public void setXmlAssinado(Document pXmlAssinado){ xmlAssinado = pXmlAssinado; } public Document getXmlAssinado(){ return xmlAssinado; } public List<XMLSignature> getAssinaturas(){ return assinaturas; } public List<TabeliaoResultadoValidacao> getResultadosValidacao(){ return resultadosValidacao; } public List<TabeliaoCertificate> getCertificadosDasAssinaturas(){ return certificadosDasAssinaturas; } /** * Executa a validacao da(s) assinatura(s) para o arquivo, fazendo com que as listas: * assinaturas, resultadosValidacao e certificadosDasAssinaturas sejam populadas. * NAO Executa validacao de Data de Validade, Cadeia de Certificacao ou LCR (Lista de Certificados Revogados) * MAS eh pre-requisito para uso das demais validacoes. * @throws Exception */ public void valida() throws Exception{ XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); NodeList nl = xmlAssinado.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); if (nl.getLength() == 0) { throw new Exception("N�o foi poss�vel encontrar nenhuma assinatura no arquivo!"); } for (int ix=0; ix <nl.getLength(); ix++){ boolean sv=false; DOMValidateContext valContext = new DOMValidateContext (new X509KeySelector(), nl.item(ix)); valContext.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE); // Unmarshal the XMLSignature. XMLSignature assinatura; try { assinatura = fac.unmarshalXMLSignature(valContext); } catch (MarshalException e1) { throw new Exception("Problemas com o conte�do/arquivo XML!"+e1.getMessage()); } // valida a assinatura. boolean coreValidity; try { coreValidity = assinatura.validate(valContext); } catch (XMLSignatureException e1) { throw new Exception("Problemas com o conte�do/arquivo XML!"+e1.getMessage()); } // Checa core validation status. Em Co-Assinatura em formato Enveloping if (coreValidity == false) { try { sv = assinatura.getSignatureValue().validate(valContext); } catch (XMLSignatureException e) { throw new Exception("Problemas com o conte�do/arquivo XML!"+e.getMessage()); } if (sv) { // Checa o validation status para cada Reference. Iterator<?> i = assinatura.getSignedInfo().getReferences().iterator(); for (int j=0; i.hasNext(); j++) { boolean refValid; try { refValid = ((Reference) i.next()).validate(valContext); } catch (XMLSignatureException e) { throw new Exception("Problemas com as refer�ncias do XML!"+e.getMessage()); } if (!refValid){ logger.info("Assinatura:"+ix+"ref["+j+"] status de valida��o: " + refValid); System.err.println("Assinatura:"+ix+"ref["+j+"] status de valida��o: " + refValid); } } } } assinaturas.add(assinatura); // recupera o certificado do assinante X509Certificate cert = null; X509CertImpl certImpl = null; Iterator<?> ki = assinatura.getKeyInfo().getContent().iterator(); while (ki.hasNext()) { XMLStructure info = (XMLStructure) ki.next(); if (!(info instanceof X509Data)) continue; X509Data x509Data = (X509Data) info; Iterator<?> xi = x509Data.getContent().iterator(); while (xi.hasNext()) { Object o = xi.next(); if (!(o instanceof X509CertImpl)) continue; certImpl = (X509CertImpl)o; cert=certImpl; } } // Verifica se o certificado existe. if (cert == null) { throw new Exception( "N�o foi poss�vel encontrar o certificado da assinatura."); } try { TabeliaoResultadoValidacao resultVal = new TabeliaoResultadoValidacao(); resultadosValidacao.add(resultVal); TabeliaoCertificate certificado = new TabeliaoCertificate(cert); certificadosDasAssinaturas.add(certificado); if (coreValidity){ resultadosValidacao.get(ix).addOk(TabeliaoResultadoValidacao.VAL_CONTEUDO); }else { if (sv){ //N�o deve entrar neste ELSE. resultadosValidacao.get(ix).addErro(TabeliaoResultadoValidacao.VAL_CONTEUDO, "O conte�do do arquivo foi corrompido, para o certificado de:\n"+cert.getSubjectDN().getName()+ "\n URI: "+getUriTagAssinada(ix)); }else{ resultadosValidacao.get(ix).addErro(TabeliaoResultadoValidacao.VAL_CONTEUDO, "A Assinatura no arquivo foi corrompida, para o certificado de:\n"+cert.getSubjectDN().getName()+ "\n URI: "+getUriTagAssinada(ix)); } } } catch (Exception e) { resultadosValidacao.get(ix).addExcecao(TabeliaoResultadoValidacao.VAL_CONTEUDO, e.getMessage()); } } } /** * Executa a validacao da(s) Data(s) de Validade(s), para o(s) certificado(s) da(s) * assinatura(s) no arquivo. * Tem como base para validade o atributo ValidadeAte, e toma como base a data atual do sistema. * Eh preciso que o metodo valida() tenha sido executado. * @return boolean -> false se nao efetuou a validacao * @throws Exception */ public boolean validarVigencias() throws Exception{ if (certificadosDasAssinaturas.isEmpty()){ return false; }else{ for (int i=0; i < certificadosDasAssinaturas.size(); i++){ TabeliaoResultadoValidacao resultVal = certificadosDasAssinaturas.get(i).getResultadoDataVigencia(); String res = resultVal.getMensagem(TabeliaoResultadoValidacao.VAL_VALIDADE); if(TabeliaoResultadoValidacao.MSG_ERRO.equals(res)) { resultadosValidacao.get(i).addErro(TabeliaoResultadoValidacao.VAL_VALIDADE,resultVal.getDescricao(TabeliaoResultadoValidacao.VAL_VALIDADE)); }else{ resultadosValidacao.get(i).addOk(TabeliaoResultadoValidacao.VAL_VALIDADE); } } return true; } } /** * Executa a validacao da(s) cadeia(s) de certificacao, para o(s) certificado(s) da(s) * assinatura(s) no arquivo * Eh preciso que o metodo valida() tenha sido executado. * Este metodo fara acesso a base de dados de cadeias do Tabeliao. * @return boolean -> false se nao efetuou a validacao * @throws Exception */ public boolean validarCadeias() throws Exception{ if (certificadosDasAssinaturas.isEmpty()){ return false; }else{ for (int i=0; i < certificadosDasAssinaturas.size(); i++){ TabeliaoResultadoValidacao resultVal = certificadosDasAssinaturas.get(i).getResultadoCadeia(); String res = resultVal.getMensagem(TabeliaoResultadoValidacao.VAL_CADEIA); if(TabeliaoResultadoValidacao.MSG_ERRO.equals(res)) { resultadosValidacao.get(i).addErro(TabeliaoResultadoValidacao.VAL_CADEIA,resultVal.getDescricao(TabeliaoResultadoValidacao.VAL_CADEIA)); }else{ resultadosValidacao.get(i).addOk(TabeliaoResultadoValidacao.VAL_CADEIA); } } return true; } } /** * Executa a validacao da LRC (Lista de Certificados Revogados), para o(s) certificado(s) da(s) * assinatura(s) no arquivo * Eh preciso que o metodo valida() tenha sido executado. * Este metodo fara acesso a base de dados LCR do Tabeliao. * @return boolean -> false se nao efetuou a validacao * @throws Exception */ public boolean validarLCR() throws Exception{ if (certificadosDasAssinaturas.isEmpty()){ return false; }else{ for (int i=0; i < certificadosDasAssinaturas.size(); i++){ TabeliaoResultadoValidacao resultVal = certificadosDasAssinaturas.get(i).getResultadoLCR(); String res = resultVal.getMensagem(TabeliaoResultadoValidacao.VAL_LCR); if(TabeliaoResultadoValidacao.MSG_ERRO.equals(res)) { resultadosValidacao.get(i).addErro(TabeliaoResultadoValidacao.VAL_LCR,resultVal.getDescricao(TabeliaoResultadoValidacao.VAL_LCR)); }else{ resultadosValidacao.get(i).addOk(TabeliaoResultadoValidacao.VAL_LCR); } } return true; } } /** * Retorna o resultado da validacao para indice ix referente a assinatura correspondente. * Se nao houver validacao para o indice retornara nulo. * * @param ix indica qual a assinatura validar. * @return TabeliaoResultadoValidacao * @see TabeliaoResultadoValidacao * @throws Exception */ public TabeliaoResultadoValidacao getResultadoValidacao(int ix) throws Exception { if (resultadosValidacao.isEmpty()) { return null; } return resultadosValidacao.get(ix); } /** * Retorna todos os resultados das validacoes. Se nao houver validacoes retornara nulo. * * @return Lista de TabeliaoResultadoValidacao * @see TabeliaoResultadoValidacao * @throws Exception */ public List<TabeliaoResultadoValidacao> getResultadosValidacoes() throws Exception { if (resultadosValidacao.isEmpty()) { return null; } return resultadosValidacao; } /** * Retorna valor URI/ID da TAG assinada, na assinatura de indice ix, * se vazio ou null significa que o arquivo todo foi assinado. * * @param ix indica de qual a assinatura. * @return String com o ID ou a situacao da TAG. * * @throws Exception */ public String getUriTagAssinada(int ix) throws Exception { String uriTagAssinada = ""; if (assinaturas.isEmpty()){ return uriTagAssinada; } if (assinaturas.get(ix).getSignedInfo() == null) { return uriTagAssinada; } if (assinaturas.get(ix).getSignedInfo().getReferences().isEmpty()){ return uriTagAssinada; }else{ DOMReference objDR = null; Iterator<?> it = getAssinaturas().get(ix).getSignedInfo().getReferences().iterator(); while (it.hasNext()) { Object ob1 = it.next(); if (ob1 instanceof DOMReference){ objDR = (DOMReference) ob1; uriTagAssinada = objDR.getURI(); } } } return uriTagAssinada; } /** * Retorna a quantidade de assinaturas no arquivo XML, se igual a 0(zero) nao ha assinatura. * * @return int com a quantidade de assinaturas no arquivo * * @throws Exception */ public int getQuantidadeAssinaturas() throws Exception{ int quantidade=0; // pode n�o existir a tag de assinatura. NodeList nl = xmlAssinado.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); quantidade = nl.getLength(); return quantidade; } /** * Retorna a assinatura XML do arquivo conforme o indice (ix) * * @param ix indica de qual a assinatura. * @return XMLSignature * * @throws Exception */ public XMLSignature getAssinatura(int ix) throws Exception { // Se vazio n�o h� assinaturas no arquivo. if (assinaturas.isEmpty()){ return null; } if (assinaturas.get(ix).getSignedInfo() == null) { return null; } return assinaturas.get(ix); } /** * Retorna a lista da assinaturas contidas no arquivo XML * * @return Lista de XMLSignature * * @throws Exception */ public List<XMLSignature> getAssinaturasAssinantes() throws Exception { if (assinaturas.isEmpty()) { return null; } else{ return assinaturas; } } /** * Retorna o certificado do assinante conforme o indice (ix) * * @param ix indica de qual a assinatura. * @return certificado na classe TabeliaoCertificate * @see TabeliaoCertificate * @throws Exception */ public TabeliaoCertificate getCertificadoAssinante(int ix) throws Exception { if (certificadosDasAssinaturas.isEmpty()){ return null; } if (certificadosDasAssinaturas.get(ix) == null) { return null; } return certificadosDasAssinaturas.get(ix); } /** * Retorna a lista de Certificados contidos no arquivos XML * * @return Lista de certificados na classe TabeliaoCertificate * @see TabeliaoCertificate * @throws Exception */ public List<TabeliaoCertificate> getCertificadosAssinantes () throws Exception{ if (certificadosDasAssinaturas.isEmpty()) { return null; } return certificadosDasAssinaturas; } }