Business-BR-NFSe
view release on metacpan or search on metacpan
lib/Business/BR/NFSe.pm view on Meta::CPAN
# --- 4. Digest do infDPS ---
# O elemento sendo assinado herda o namespace do pai no documento final,
# então adicionamos o xmlns explicitamente antes do hash.
(my $inf_dps_for_hash = $inf_dps) =~ s/<infDPS/<infDPS xmlns="$NS"/;
my $digest_b64 = encode_base64(sha256(encode('UTF-8', $inf_dps_for_hash)), '');
# --- 5. SignedInfo ---
# Precisa fechar tags explicitamente (nada de auto-fechar) porque o servidor verifica
# as tags contra o formulário canônico exc-c14n#WithComments, que expande <Bla/> em <Bla></Bla>.
my $signed_info = join '',
q(<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">),
q(<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"></CanonicalizationMethod>),
q(<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"></SignatureMethod>),
qq(<Reference URI="#$id_dps">),
q(<Transforms>),
q(<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform>),
q(<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"></Transform>),
q(</Transforms>),
q(<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>),
qq(<DigestValue>$digest_b64</DigestValue>),
q(</Reference>),
q(</SignedInfo>);
# --- 6. Assinatura RSA-SHA256 sobre os bytes SignedInfo ---
my $rsa = Crypt::PK::RSA->new(\$self->{key_pem});
my $sig_b64 = encode_base64($rsa->sign_message(encode('UTF-8', $signed_info), 'SHA256', 'v1.5'), '');
# --- 7. Monta o XML final ---
my $xml = join '',
q(<?xml version="1.0" encoding="UTF-8"?>),
qq(<DPS xmlns="$NS" versao="$VERSAO">),
$inf_dps,
q(<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">),
$signed_info,
qq(<SignatureValue>$sig_b64</SignatureValue>),
qq(<KeyInfo><X509Data><X509Certificate>$self->{cert_b64}</X509Certificate></X509Data></KeyInfo>),
q(</Signature>),
q(</DPS>);
# --- 8. GZip + base64 ---
my $xml_bytes = encode('UTF-8', $xml);
my $gzipped;
gzip(\$xml_bytes, \$gzipped) or croak "gzip failed: $GzipError";
( run in 0.447 second using v1.01-cache-2.11-cpan-5fbc6bb55f2 )