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.util.Base64Utils;
import gov.pr.celepar.tabeliao.util.CertificationChainAndSignatureBase64;
import gov.pr.celepar.tabeliao.util.PrivateKeyAndCertChain;
import gov.pr.celepar.tabeliao.util.XmlSigUtil;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import java.util.Locale;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.sun.org.apache.xml.internal.security.Init;
import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
import com.sun.org.apache.xml.internal.security.signature.ObjectContainer;
import com.sun.org.apache.xml.internal.security.signature.XMLSignature;
import com.sun.org.apache.xml.internal.security.transforms.TransformationException;
import com.sun.org.apache.xml.internal.security.transforms.Transforms;
import com.sun.org.apache.xml.internal.security.utils.Constants;
/**
* Classe para geracao do arquivo XML Assinado no formato Enveloping XML
* Criando as propriedades XADES reconhecidas pela ICP-BRASIL
* de acordo com os documentos DOC-ICP-15.05 e DOC-ICP-15.02
*
* @author Emerson Sachio Saito - GIC/CELEPAR
*
*/
public class GerarEnvelopingXML {
private GerarEnvelopingXML(){
}
/**
* Prepara o arquivo XML para assinatura e retorna o novo documento assinado
*
* @param aFile -> InputStream com XMLAssinador
* @param politicaId -> Id da politica de Assinatura
* @param politicaUri -> url onde se entra a politica de assinatura
* @param privateKeyAndCertChain -> KeyStore
* @see gov.pr.celepar.tabeliao.util.PrivateKeyAndCertChain
* @return Document
* @throws XMLSignatureException
*/
public static Document assinarArquivoEnvelopingXml(InputStream aFile, String politicaId, String politicaUri,
PrivateKeyAndCertChain privateKeyAndCertChain) throws XMLSignatureException
{
Document docAssinar;
try {
docAssinar = XmlSigUtil.carregarArquivoXML(aFile);
} catch (ParserConfigurationException e) {
String errorMessage = "Erro ao carregar o arquivo a ser assinado\n" +
"Anote este erro e contate com o respons�vel pelo sistema!\n" +
"Detalhes: " + e.getMessage();
throw new XMLSignatureException(errorMessage, e);
} catch (SAXException e) {
String errorMessage = "Erro ao carregar o arquivo a ser assinado\n" +
"Anote este erro e contate com o respons�vel pelo sistema!\n" +
"Detalhes: " + e.getMessage();
throw new XMLSignatureException(errorMessage, e);
} catch (IOException e) {
String errorMessage = "Erro ao carregar o arquivo a ser assinado\n" +
"Anote este erro e contate com o respons�vel pelo sistema!\n" +
"Detalhes: " + e.getMessage();
throw new XMLSignatureException(errorMessage, e);
}
Document signingResult = assinandoDocumentoEnvelopingXml(docAssinar, politicaId, politicaUri, privateKeyAndCertChain);
return signingResult;
}
/**
* Prepara o arquivo XML para assinatura e retorna o novo documento assinado
*
* @param documento -> objeto do tipo org.w3c.dom.Document
* @param politicaId -> Id da politica de Assinatura
* @param politicaUri -> url onde se entra a politica de assinatura
* @param privateKeyAndCertChain -> KeyStore
* @see gov.pr.celepar.tabeliao.util.PrivateKeyAndCertChain
* @return Document
* @throws XMLSignatureException
*/
public static Document assinarArquivoEnvelopingXml(Document documento, String politicaId, String politicaUri,
PrivateKeyAndCertChain privateKeyAndCertChain) throws XMLSignatureException
{
Document docAssinar = documento;
Document signingResult = assinandoDocumentoEnvelopingXml(docAssinar, politicaId, politicaUri, privateKeyAndCertChain);
return signingResult;
}
/**
* Prepara o arquivo XML para assinatura e retorna o novo documento assinado
*
* @param conteudo -> Conteudo para assinatura do tipo byte[]
* @param politicaId -> Id da politica de Assinatura
* @param politicaUri -> url onde se entra a politica de assinatura
* @param privateKeyAndCertChain -> KeyStore
* @see gov.pr.celepar.tabeliao.util.PrivateKeyAndCertChain
* @return Document
* @throws XMLSignatureException
*/
public static Document assinarArquivoEnvelopingXml(byte[] conteudo, String politicaId, String politicaUri,
PrivateKeyAndCertChain privateKeyAndCertChain) throws XMLSignatureException
{
Document docAssinar;
try {
docAssinar = XmlSigUtil.carregarArquivoXML(new ByteArrayInputStream(conteudo));
} catch (ParserConfigurationException e) {
String errorMessage = "Erro ao carregar o arquivo a ser assinado\n" +
"Anote este erro e contate com o respons�vel pelo sistema!\n" +
"Detalhes: " + e.getMessage();
throw new XMLSignatureException(errorMessage, e);
} catch (SAXException e) {
String errorMessage = "Erro ao carregar o arquivo a ser assinado\n" +
"Anote este erro e contate com o respons�vel pelo sistema!\n" +
"Detalhes: " + e.getMessage();
throw new XMLSignatureException(errorMessage, e);
} catch (IOException e) {
String errorMessage = "Erro ao carregar o arquivo a ser assinado\n" +
"Anote este erro e contate com o respons�vel pelo sistema!\n" +
"Detalhes: " + e.getMessage();
throw new XMLSignatureException(errorMessage, e);
}
Document signingResult = assinandoDocumentoEnvelopingXml(docAssinar, politicaId, politicaUri, privateKeyAndCertChain);
return signingResult;
}
/**
* Prepara o arquivo XML para assinatura e retorna o novo documento assinado
*
* @param conteudoString -> Conteudo para assinatura do tipo String
* @param politicaId -> Id da politica de Assinatura
* @param politicaUri -> url onde se entra a politica de assinatura
* @param privateKeyAndCertChain -> KeyStore
* @see gov.pr.celepar.tabeliao.util.PrivateKeyAndCertChain
* @return Document
* @throws XMLSignatureException
*/
public static Document assinarArquivoEnvelopingXml(String conteudoString, String politicaId, String politicaUri,
PrivateKeyAndCertChain privateKeyAndCertChain) throws XMLSignatureException
{
Document docAssinar;
try {
docAssinar = XmlSigUtil.carregarArquivoXML(conteudoString);
} catch (ParserConfigurationException e) {
String errorMessage = "Erro ao carregar o arquivo a ser assinado\n" +
"Anote este erro e contate com o respons�vel pelo sistema!\n" +
"Detalhes: " + e.getMessage();
throw new XMLSignatureException(errorMessage, e);
} catch (SAXException e) {
String errorMessage = "Erro ao carregar o arquivo a ser assinado\n" +
"Anote este erro e contate com o respons�vel pelo sistema!\n" +
"Detalhes: " + e.getMessage();
throw new XMLSignatureException(errorMessage, e);
} catch (IOException e) {
String errorMessage = "Erro ao carregar o arquivo a ser assinado\n" +
"Anote este erro e contate com o respons�vel pelo sistema!\n" +
"Detalhes: " + e.getMessage();
throw new XMLSignatureException(errorMessage, e);
}
Document signingResult = assinandoDocumentoEnvelopingXml(docAssinar, politicaId, politicaUri, privateKeyAndCertChain);
return signingResult;
}
/**
* Prepara o arquivo XML para assinatura e retorna o novo documento assinado
*
* @param conteudoInputSource -> Conteudo para assinatura do tipo org.xml.sax.InputSource
* @param politicaId -> Id da politica de Assinatura
* @param politicaUri -> url onde se entra a politica de assinatura
* @param privateKeyAndCertChain -> KeyStore
* @see gov.pr.celepar.tabeliao.util.PrivateKeyAndCertChain
* @return Document
* @throws XMLSignatureException
*/
public static Document assinarArquivoEnvelopingXml(InputSource conteudoInputSource, String politicaId, String politicaUri,
PrivateKeyAndCertChain privateKeyAndCertChain) throws XMLSignatureException
{
Document docAssinar;
try {
docAssinar = XmlSigUtil.carregarArquivoXML(conteudoInputSource);
} catch (ParserConfigurationException e) {
String errorMessage = "Erro ao carregar o arquivo a ser assinado\n" +
"Anote este erro e contate com o respons�vel pelo sistema!\n" +
"Detalhes: " + e.getMessage();
throw new XMLSignatureException(errorMessage, e);
} catch (SAXException e) {
String errorMessage = "Erro ao carregar o arquivo a ser assinado\n" +
"Anote este erro e contate com o respons�vel pelo sistema!\n" +
"Detalhes: " + e.getMessage();
throw new XMLSignatureException(errorMessage, e);
} catch (IOException e) {
String errorMessage = "Erro ao carregar o arquivo a ser assinado\n" +
"Anote este erro e contate com o respons�vel pelo sistema!\n" +
"Detalhes: " + e.getMessage();
throw new XMLSignatureException(errorMessage, e);
}
Document signingResult = assinandoDocumentoEnvelopingXml(docAssinar, politicaId, politicaUri, privateKeyAndCertChain);
return signingResult;
}
/**
* Assina o arquivo XML e retorna o documento
*
* @param aDocumentToSign -> Arquivo xml para assinatura
* @param politicaId -> Id da politica de Assinatura
* @param politicaUri -> url onde se entra a politica de assinatura
* @param privateKeyAndCertChain -> KeyStore
* @return Document
* @throws XMLSignatureException
*/
public static Document assinandoDocumentoEnvelopingXml(Document aDocumentToSign, String politicaId, String politicaUri,
PrivateKeyAndCertChain privateKeyAndCertChain) throws XMLSignatureException {
Init.init();
// Checa se a chave privada est� dispon�vel
PrivateKey privateKey = privateKeyAndCertChain.mPrivateKey;
if (privateKey == null) {
String errorMessage = "N�o achou a chave privada do smart card.";
throw new XMLSignatureException(errorMessage);
}
// Checa se certificado X.509 est� dispon�vel
Certificate[] certChain = privateKeyAndCertChain.mCertificationChain;
if (certChain == null) {
String errorMessage = "N�o achou o certificado p�blico.";
throw new XMLSignatureException(errorMessage);
}
// Criando o result object
CertificationChainAndSignatureBase64 signingResult =
new CertificationChainAndSignatureBase64();
// Salva a cadeia de certificados X.509 em Base64
try {
signingResult.mCertificationChain = Base64Utils.encodeX509CertChainToBase64(certChain);
} catch (CertificateException cee) {
String errorMessage = "Certificado inv�lido.";
throw new XMLSignatureException(errorMessage);
}
// Cria as constantes.
String xadesNS="http://uri.etsi.org/01903/v1.3.2#";
String varMimeType = "text/xml";
// cria um novo documento para que estar� envelopando os dados
Document xmlDocument = null;
try {
xmlDocument = XmlSigUtil.criarDocumentoXMl();
} catch (Exception e) {
String errorMessage = "Erro ao criar o documento enveloping: "+e.getMessage();
throw new XMLSignatureException(errorMessage);
}
Node oldDocument = xmlDocument.importNode(aDocumentToSign.getFirstChild(), true);
try {
Constants.setSignatureSpecNSprefix("");
} catch (XMLSecurityException e2) {
String errorMessage = "Erro ao setar prefixo: "+e2.getMessage();
throw new XMLSignatureException(errorMessage);
}
// cria o container e a assinatura para o novo documento
ObjectContainer obj = null;
XMLSignature xmlSignature = null;
try {
xmlSignature = new XMLSignature(xmlDocument, "", XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);
xmlDocument.appendChild(xmlSignature.getElement());
obj = new ObjectContainer(xmlDocument);
obj.appendChild((Element)oldDocument);
xmlSignature.appendObject(obj);
} catch (XMLSecurityException se) {
String errorMessage = "Erro ao criar os objetos: "+se.getMessage();
throw new XMLSignatureException(errorMessage);
}
// Verifica se h� outras assinaturas, isso influenciar� no Id do Objeto.
String idObjeto = "";
NodeList xmlSignatureElements = aDocumentToSign.getElementsByTagName("Signature");
if (xmlSignatureElements.getLength() > 0){
// recupera a ultima assinatura que est� envelopando o objeto
Element sigElement = (Element) xmlSignatureElements.item(0);
XMLSignature assinatura;
try {
assinatura = new XMLSignature(sigElement, "");
} catch (XMLSecurityException e) {
String errorMessage = "Erro ao criar elemento assinatura: "+e.getMessage();
throw new XMLSignatureException(errorMessage);
}
// Verifica se existe o objeto envelopando
if (assinatura.getObjectLength() > 0){
idObjeto = assinatura.getObjectItem(0).getId()+xmlSignatureElements.getLength();
}
}else{
idObjeto="object";
}
// gera o objeto de propriedades assinadas.
//
X509Certificate cert = (X509Certificate)certChain[0];
Element QPElement = XmlSigUtil.criarElemento(xmlDocument,"QualifyingProperties",null,xadesNS);
Element SPElement = XmlSigUtil.criarElemento(xmlDocument, "SignedProperties", null,xadesNS);
SPElement.setAttributeNS(null, "Id", "SignedProperties");
QPElement.appendChild(SPElement);
Element SSPElement = XmlSigUtil.criarElemento(xmlDocument, "SignedSignatureProperties", null,xadesNS);
SPElement.appendChild(SSPElement);
Element STElement = XmlSigUtil.criarElemento(xmlDocument, "SigningTime", null,xadesNS);
Locale locale = new Locale("pt","BR");
GregorianCalendar calendar = new GregorianCalendar();
SimpleDateFormat formatador = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",locale);
STElement.setTextContent(formatador.format(calendar.getTime()));
SSPElement.appendChild(STElement);
Element SCElement = XmlSigUtil.criarElemento(xmlDocument, "SigningCertificate", null,xadesNS);
Element certElement = XmlSigUtil.criarElemento(xmlDocument, "cert", null,xadesNS);
Element certDigestElement = XmlSigUtil.criarElemento(xmlDocument, "CertDigest", null,xadesNS);
Element DigestMethodElement = XmlSigUtil.criarElemento(xmlDocument, "DigestMethod", null,xadesNS);
DigestMethodElement.setAttributeNS(null,"Algorithm", cert.getSigAlgName());
certDigestElement.appendChild(DigestMethodElement);
Element DigestValueElement = XmlSigUtil.criarElemento(xmlDocument, "DigestValue", null,xadesNS);
DigestValueElement.setTextContent(Integer.toString(cert.hashCode()));
certDigestElement.appendChild(DigestValueElement);
certElement.appendChild(certDigestElement);
Element certIssuerSerial = XmlSigUtil.criarElemento(xmlDocument, "IssuerSerial", null,xadesNS);
Element X509IssuerName = XmlSigUtil.criarElemento(xmlDocument, "X509IssuerName", null,xadesNS);
X509IssuerName.setTextContent(cert.getIssuerDN().getName());
certIssuerSerial.appendChild(X509IssuerName);
Element X509SerialNumber = XmlSigUtil.criarElemento(xmlDocument, "X509SerialNumber", null,xadesNS);
X509SerialNumber.setTextContent(cert.getSerialNumber().toString());
certIssuerSerial.appendChild(X509SerialNumber);
certElement.appendChild(certIssuerSerial);
SCElement.appendChild(certElement);
SSPElement.appendChild(SCElement);
if (politicaId != null){
if (politicaId.trim().length() > 0 && !politicaId.trim().equalsIgnoreCase("null")){
Element SPIElement = XmlSigUtil.criarElemento(xmlDocument, "SignaturePolicyIdentifier", null,xadesNS);
Element SPIdElement = XmlSigUtil.criarElemento(xmlDocument, "SignaturePolicyId", null,xadesNS);
Element SiPIdElement = XmlSigUtil.criarElemento(xmlDocument, "SigPolicyId", null,xadesNS);
SiPIdElement.setTextContent(politicaId);
//Element SPHElement = XmlSigUtil.criarElemento(xmlDocument, "SigPolicyHash", null,xadesNS);
Element SPQElement = XmlSigUtil.criarElemento(xmlDocument, "SigPolicyQualifiers", null,xadesNS);
Element SPQrElement = XmlSigUtil.criarElemento(xmlDocument, "SigPolicyQualifier", null,xadesNS);
Element SPUriElement = XmlSigUtil.criarElemento(xmlDocument, "SPURI", null,xadesNS);
SPUriElement.setTextContent(politicaUri);
SPQrElement.appendChild(SPUriElement);
SPQElement.appendChild(SPQrElement);
SPIdElement.appendChild(SiPIdElement);
//SPIdElement.appendChild(SPHElement);
SPIdElement.appendChild(SPQElement);
SPIElement.appendChild(SPIdElement);
SSPElement.appendChild(SPIElement);
}
}
//Element SPPElement = XmlSigUtil.criarElemento(xmlDocument, "SignatureProductionPlace", null,xadesNS);
//SSPElement.appendChild(SPPElement);
//Element SRElement = XmlSigUtil.criarElemento(xmlDocument, "SignerRole", null,xadesNS);
//SSPElement.appendChild(SRElement);
Element SDOPElement = XmlSigUtil.criarElemento(xmlDocument, "SignedDataObjectProperties", null,xadesNS);
SPElement.appendChild(SDOPElement);
Element DOFElement = XmlSigUtil.criarElemento(xmlDocument, "DataObjectFormat", null,xadesNS);
Element mimetype = XmlSigUtil.criarElemento(xmlDocument,"MimeType",null,xadesNS);
mimetype.setTextContent(varMimeType);
DOFElement.appendChild(mimetype);
SDOPElement.appendChild(DOFElement);
obj.appendChild(QPElement);
obj.setId(idObjeto);
try {
xmlSignature.appendObject(obj);
} catch (com.sun.org.apache.xml.internal.security.signature.XMLSignatureException e1) {
String errorMessage = "Erro ao inserir objeto: "+e1.getMessage();
throw new XMLSignatureException(errorMessage);
}
Transforms transforms = new Transforms(xmlDocument);
try {
transforms.addTransform(Transforms.TRANSFORM_C14N_WITH_COMMENTS);
} catch (TransformationException e1) {
String errorMessage = "Erro ao criar os transformadores: "+e1.getMessage();
throw new XMLSignatureException(errorMessage);
}
try {
xmlSignature.addDocument("#" + idObjeto, transforms, Constants.ALGO_ID_DIGEST_SHA1);
} catch (com.sun.org.apache.xml.internal.security.signature.XMLSignatureException e) {
String errorMessage = "Erro ao adicionar os objetos: "+e.getMessage();
throw new XMLSignatureException(errorMessage);
}
try {
xmlSignature.addKeyInfo(cert);
} catch (XMLSecurityException e) {
String errorMessage = "Erro ao adicionar o KeyInfo do Certificado: "+e.getMessage();
throw new XMLSignatureException(errorMessage);
}
try {
xmlSignature.sign(privateKey);
} catch (com.sun.org.apache.xml.internal.security.signature.XMLSignatureException e) {
String errorMessage = "Erro assinar o documento Enveloping: "+e.getMessage();
throw new XMLSignatureException(errorMessage);
}
return xmlDocument;
}
}