Nfse.Signature (nfse v0.1.0)

Copy Markdown View Source

Uso interno da biblioteca: não faz parte da API pública.

Assinatura XMLDSig envelopada, com C14N inclusiva, da DPS, do pedido de registro de evento e da NFS-e de decisão judicial.

Por que não há canonicalização aqui

O XMLDSig digere a forma canônica do que assina, não os bytes que vão pela rede. O OTP não traz C14N, e as dependências da biblioteca também não. Então a biblioteca vai pelo outro caminho: o escritor do leiaute (Nfse.Schema.Runtime.encode/4) já escreve na forma canônica, sem espaço entre tags, sem <x/> e com o namespace só na raiz, e sign/4 digere os bytes literais. Para essa forma, a C14N de uma subárvore é a própria subárvore, com uma exceção.

A exceção: o namespace herdado

A C14N inclusiva escreve no topo do que canonicaliza todo namespace em escopo. O infDPS herda o namespace da NFS-e da DPS e não o declara, mas o digest é calculado sobre

<infDPS xmlns="http://www.sped.fazenda.gov.br/nfse" Id="DPS...">...

Assinar o <infDPS Id="DPS..."> literal dá uma assinatura bem formada sobre os bytes errados, e a Sefin responde só "assinatura inválida". Por isso sign/4 injeta o namespace antes de digerir. Daí vem a exigência sobre a raiz: ela declara o namespace da NFS-e como padrão e nenhum outro, porque cada namespace a mais que ela declarasse também entraria no topo da forma canônica.

A mesma regra vale um nível abaixo: o SignedInfo herda o namespace do XMLDSig da Signature, então os bytes que o RSA assina levam um xmlns que os da rede não levam.

Onde a assinatura entra

A Signature devolvida vai logo depois do elemento assinado, como irmã dele dentro da raiz. Ela fica fora da subárvore digerida, e a transformação enveloped-signature não tira nada dali.

Cada documento leva uma assinatura só. A NFS-e de decisão judicial carrega a DPS sem assinatura própria (o Signature do TCDPS é opcional) e só o infNFSe é assinado: o digest dele cobre a DPS embutida.

Summary

Functions

O algoritmo que a biblioteca usa quando o chamador não escolhe outro.

Assina element e devolve a <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> que vai logo depois dele, como irmã dentro da raiz.

Types

algorithm()

@type algorithm() :: :rsa_sha1 | :rsa_sha256

Functions

default_algorithm()

@spec default_algorithm() :: algorithm()

O algoritmo que a biblioteca usa quando o chamador não escolhe outro.

É :rsa_sha1 até a conferência na produção restrita.

sign(element, id, certificate, algorithm)

@spec sign(binary(), String.t(), Nfse.Certificate.t(), algorithm()) :: binary()

Assina element e devolve a <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> que vai logo depois dele, como irmã dentro da raiz.

element são os bytes literais e canônicos do elemento, exatamente como vão aparecer no documento final, e id é o valor do atributo Id dele, para onde a Reference aponta. A raiz que recebe o elemento declara o namespace da NFS-e como padrão e nenhum outro.

Levanta ArgumentError quando element não está na forma que este módulo sabe digerir. É de propósito: cada um desses casos daria uma assinatura de aparência válida sobre os bytes errados, e o único retorno seria a recusa da Sefin, dias depois.