FrameworkDemoiselle.gov.brCommunity Documentation

Capítulo 6. Funcionalidades

6.1. Assinatura Digital no Formato PKCS1
6.2. Assinatura Digital no Formato PKCS#7/CAdES sem o conteúdo anexado (detached)
6.3. Assinatura Digital no Formato PKCS#7/CAdES com conteúdo anexado (attached)
6.4. Criação de Assinatura Digital enviando apenas o resumo (hash) do conteúdo
6.5. Co-Assinatura em arquivo único de assinatura .
6.5.1. Com envio de conteúdo
6.5.2. Enviando apenas o Hash do conteúdo
6.6. Validação de assinatura PKCS7 sem o conteúdo anexado (detached)
6.7. Validação de assinatura PKCS7 com o conteúdo anexado (attached)
6.8. Validação de assinatura PKCS7 enviando apenas o resumo (Hash) do conteúdo
6.9. Tratando os resultados da valiação
6.10. Leitura do conteúdo anexado (Attached) a uma assinatura PKCS7
6.11.

Este componente provê mecanismos de assinatura digital baseado nas normas ICP-Brasil e implementa mecanismos de assinatura digital em dois formatos: PKCS1 e PKCS7. A maior diferença entre esses dois mecanismos está na forma de envelopamento da assinatura digital, onde o PKCS1 não possui um formato de envelope, sendo o resultado da operação de assinatura a própria assinatura, já o PKCS7 possui um formato de retorno que pode ser binário (especificado na RFC5126) ou XML.

A interface org.demoiselle.signer.policy.impl.cades.Signer especifica o comportamento padrão dos mecanismos de GERAÇÃO de assinatura digital. O componente especializa essa interface em mais duas, são elas: org.demoiselle.signer.policy.impl.cades.pkcs1.PKCS1Signer para implementações de mecanismos PKCS1 e org.demoiselle.signer.policy.impl.cades.pkcs7.PKCS7Signer para implementações de mecanismos de envelopamento PKCS7.

Para as funções de VALIDAÇÃO A interface org.demoiselle.signer.policy.impl.cades.Checker especifica as funções de validação de assinatura digital. O componente especializa essa interface em mais duas, são elas: org.demoiselle.signer.policy.impl.cades.pkcs1.PKCS1Checker para implementações de mecanismos PKCS1 e org.demoiselle.signer.policy.impl.cades.pkcs7.PKCS7Checker para implementações de mecanismos de envelopamento PKCS7.

Este componente, até a presente versão, permite assinar dados representados por um array de bytes. Então se for necessário a assinatura de um arquivo, por exemplo, a aplicação deverá montar um array de bytes com o conteúdo do arquivo e enviar este para o componente poder assiná-lo. Também é possível enviar apenas o Hash já calculado deste arquivo. Veja nas sessões abaixo como fazê-los.

Para assinar um dado através do componente demoiselle-signer é preciso executar alguns passos.

A seguir temos um fragmento de código que demonstra uma assinatura no formato PKCS1.



/* conteudo a ser assinado */
byte[] content = "conteudo a ser assinado".getBytes();
/* chave privada */
PrivateKey chavePrivada = getPrivateKey(); /* implementar metodo para pegar chave privada */
/* construindo um objeto PKCS1Signer atraves da fabrica */
PKCS1Signer signer = PKCS1Factory.getInstance().factory();
/* Configurando o algoritmo */
signer.setAlgorithm(SignerAlgorithmEnum.SHA1withRSA);
/* Configurando a chave privada */
signer.setPrivateKey(chavePrivada);
/* Assinando um conjunto de bytes */
byte[] signature = signer.doSign(content);

O formato PKCS#7 define o tipo de arquivo para assinatura. Já a ICP-Brasil define um conjunto mínimo de informações básicas para as assinaturas digitais para o padrão CAdES. São elas: Tipo de conteúdo, data da assinatura, algoritmo de resumo aplicado e a política de assinatura. O componente policy-impl-cades já monta o pacote final com três atributos obrigatórios: tipo de conteúdo, data da assinatura e o algoritmo de resumo. Então, para montar um PKCS7 padrão CAdEs ICP-Brasil é necessário informar ao objeto PKCS7Signer qual a política de assinatura a ser aplicada. Uma das formas de gerar a assinatura digital é criar um novo arquivo com a extensão .p7s (PKCS#7) que contém apenas a assinatura, assim independente do arquivo original. Porém para validação da assinatura, será necessário informar tanto o arquivo de assinatura quanto o conteúdo original.

A seguir temos um fragmento de código que demonstra a utilização do pacote PKCS7 padrão.



byte[] content = readContent("texto.txt"); /* implementar metodo de leitura de arquivo */
PKCS7Signer signer = PKCS7Factory.getInstance().factoryDefault();
signer.setCertificates(certificateChain);
signer.setPrivateKey(privateKey);
byte[] signature = signer.doDetachedSign(this.content);

A seguir temos um fragmento de código que demonstra a utilização do pacote PKCS7 padrão com informação da política de assinatura. Neste caso podemos escolher uma das políticas (em vigor) que já acompanham o componente e referem-se à Assinatura Digital padrão CADES.



byte[] content = readContent("texto.txt"); /* implementar metodo de leitura de arquivo */
PKCS7Signer signer = PKCS7Factory.getInstance().factoryDefault();
signer.setCertificates(certificateChain);
signer.setPrivateKey(privateKey);
signer.setSignaturePolicy(PolicyFactory.Policies.AD_RB_CADES_2_3);
byte[] signature = signer.doDetachedSign(this.content);

Identica ao formato apresentado anteriormente, outra das formas de gerar a assinatura digital é incluir todo o conteúdo assinado no novo arquivo com a extensão .p7s (PKCS#7) Desta forma, tanto a assinatura quanto o conteúdo estarão dentro deste arquivo. A sua vantagem é que para validação da assinatura, basta enviar somente este arquivo. Porém, caso o arquivo original seja descartado, para ter acesso ao mesmo, será necessário o uso de um software especializado(como o próprio Demoiselle-Signer)

A seguir temos um fragmento de código que demonstra a utilização do pacote PKCS7 com o conteúdo anexado.



byte[] content = readContent("texto.txt"); /* implementar metodo de leitura de arquivo */
PKCS7Signer signer = PKCS7Factory.getInstance().factoryDefault();
signer.setCertificates(certificateChain);
signer.setPrivateKey(privateKey);
byte[] signature = signer.doAttachedSign(fileToSign);

Este procedimento visa facilitar a geração de assinaturas digitais em aplicações onde pode haver restrição de trafegar todo o conteúdo do arquivo pela rede, sendo necessário apenas o tráfego dos bytes do resumo do conteúdo original (HASH). Neste caso, é necessário gerar o HASH do conteúdo a ser assinado e passar para o assinador. Ao gerar o HASH, é importante dar atenção ao algoritmo a ser usado, pois na validação da assinatura será considerado o algoritmo da política escolhida. Então, para que esse procedimento funcione corretamente, é necessário escolher o algoritmo do HASH igual ao algoritmo da assinatura digital.




byte[] content = readContent("texto.txt"); /* implementar metodo de leitura de arquivo */
/* Gerando o HASH */
java.security.MessageDigest md = java.security.MessageDigest
                    .getInstance(DigestAlgorithmEnum.SHA_256.getAlgorithm());
byte[] hash = md.digest(content);
/* Gerando a assinatura a partir do HASH gerado anteriormente */
PKCS7Signer signer = PKCS7Factory.getInstance().factoryDefault();
signer.setCertificate(certificate);
signer.setPrivateKey(privateKey);
signer.setSignaturePolicy(PolicyFactory.Policies.AD_RB_CADES_2_3);
byte[] signature = signer.doHashSign(hash);

Como foi visto nas seções anteriores, um do modos de gerar a assinatura é criando um arquivo separado do conteúdo original, e a forma de validação está no fragmento de código abaixo.



byte[] content = readContent("texto.txt"); /* implementar metodo de leitura de arquivo */
byte[] signature = readContent("texto.pkcs7"); /* implementar metodo de leitura de arquivo */
CAdESChecker checker = new CAdESChecker();
List<SignatureInformations> signaturesInfo = checker.checkDetachedSignature(content, signature);

O retorno é um objeto do tipo org.demoiselle.signer.policy.impl.cades.SignatureInformations que possui os seguintes atributos



public class SignatureInformations {
    private LinkedList<X509Certificate> chain; // cadeia do certificado que gerou a assinatura 
    private Date signDate;  // data do equipamento no momento da gera��o das assinatura (n�o tem validade legal)
    private Timestamp timeStampSigner = null; // Carimbo de tempo da assinatura, quando a politica utilizada permitir
    private SignaturePolicy signaturePolicy; // Politica ICP-BRASIL usada para gera��o da assinatura
    private LinkedList<String> validatorErrors = new LinkedList<String>();  // Lista de erros que por ventura possam ter sido encontrados na valida��o da assinatura
    
    

A seguir temos um fragmento de código que demonstra a validação uma assinatura PKCS7 com o conteúdo anexado.



byte[] signature = readContent("texto.pkcs7"); /* implementar metodo de leitura de arquivo */
CAdESChecker checker = new CAdESChecker();
List<SignatureInformations> signaturesInfo = checker.checkAttachedSignature(signature);

Da mesma forma que possibilitamos a criação da assinatura enviando o resumo (hash) calculado do conteúdo, podemos também fazer a validação da mesma forma. Assim como na geração, é preciso saber qual foi o algoritimo de resumo (hash) que foi usado para gerar a assinatura, pois o mesmo deve ser informado para o método de validação. A seguir temos um fragmento de código que demonstra esta validação.



byte[] content = readContent("texto.txt"); /* implementar metodo de leitura de arquivo */
byte[] signature = readContent("texto.pkcs7"); /* implementar metodo de leitura de arquiv
CAdESChecker checker = new CAdESChecker();
// gera o hash do arquivo que foi assinado
md = java.security.MessageDigest
            .getInstance(DigestAlgorithmEnum.SHA_256.getAlgorithm());
byte[] hash = md.digest(content);
List<SignatureInformations> signaturesInfo = checker.checkSignatureByHash(SignerAlgorithmEnum.SHA256withRSA.getOIDAlgorithmHash(), hash, signature);

Como é possível que um mesmo arquivo possa contar várias assinaturas (PAdES principalmente), só será gerada exceção quando a assinatura estiver comprometida Nos demais casos, o Demoiselle-Signer irá devolver o resultado numa lista de objetos SignatureInformations. Essa classe contém os seguintes atributos:

Cabe ao sistema com base nos avisos ou erros, aceitar ou não a Assinatura. Apesar de existirem as políticas, qualquer tipo de Assinatura gerada com um certificado ICP-Brasil tem validade legal. A seguir temos um fragmento de código que demonstra esta validação.



List<SignatureInformations> signaturesInfo = checker
                .checkDetachedSignature(fileToVerify, signatureFile);
        if (signaturesInfo != null) {
            System.out.println("A assinatura foi validada. e retornou resultados");
            for (SignatureInformations si : signaturesInfo) {
                System.out.println(si.getSignDate());
                if (si.getTimeStampSigner() != null) {
                    System.out.println("Serial"
                            + si.getTimeStampSigner().toString());
                }
                System.out.println("informa��es do assinante:");
                BasicCertificate certificate = si.getIcpBrasilcertificate();
                if (!certificate.isCACertificate()) {
                    if (certificate.hasCertificatePF()) {
                        System.out.println("CPF: "+certificate.getICPBRCertificatePF().getCPF());
                        System.out.println("Titulo de Eleitor: "+certificate.getICPBRCertificatePF().getElectoralDocument());
                    }
                    if (certificate.hasCertificatePJ()) {
                        System.out.println("CNPJ: "+certificate.getICPBRCertificatePJ().getCNPJ());
                    }
                }
                // Carimbo do tempo
                if(si.getTimeStampSigner()!= null) {
                    
                    System.out.println(si.getTimeStampSigner().toString());
                }
                // A assinatura pode estar correta mas n�o foi poss�vel verificar algum atributo exigido pela ICP-Brasil
                for (String valErr : si.getValidatorErrors()) {
                    System.err.println("++++++++++++++ ERROS ++++++++++++++++++");
                    System.err.println(valErr);
                }
                //A assinatura pode estar correta mas n�o foi poss�vel verificar alguma condi��o de valida��o exigida pela ICP-Brasil
                for (String valWarn : si.getValidatorWarnins()) {
                    System.err.println("++++++++++++++ AVISOS ++++++++++++++++++");
                    System.err.println(valWarn);
                }
            }

A seguir temos um fragmento de código que demonstra a extração (recuperação) do conteúdo de um arquivo anexado à uma assinatura PKCS7. Essa funcionalidade pode ser útil quando é necessário retirar/extrair o conteúdo assinado, pois no formato anexado (attached) o conteúdo está empacotado na assinatura. Esta funcionalidade também permite que seja feita a validação da assinatura no momento da extração.



byte[] attachedSignature = readContent("texto.pkcs7"); /* implementar metodo de leitura de arquivo */
CAdESChecker checker = new CAdESChecker();
/* Para extrair o conteudo original validando a assinatura */
byte[] content = checker.getAttached(attachedSignature, true);
/* Para extrair o conteudo original sem validar a assinatura */
byte[] content = checker.getAttached(attachedSignature, false);