1. Livro: Pro PHP XML and Web Services
Introdução a Estrutura Xml Signature
As assinaturas XML podem verificar a integridade e a origem dos dados e se os dados não foram
alterados de seu estado original. Isso é feito usando chaves. Um dos métodos mais comuns usados é
o método de envelopamento com chaves públicas e privadas. O autor de um documento usaria uma
chave privada para assinar os dados. Isso criaria uma assinatura digital, que é então adicionada a um
documento XML. O destinatário, que deve ter uma cópia da chave pública do autor, usaria essa
chave para verificar os dados assinados. Após uma verificação bem-sucedida, o destinatário sabe
três coisas:
• O autor é o originador genuíno do documento, conhecido como
autenticação do assinador.
• Os dados não foram alterados em sua forma original, que é chamada de integridade.
• Nem os dados nem a soma de verificação foram adulterados, o que pode ocorrer se alguém está
tentando alterar os dados, mantendo a integridade dos dados, a fim de enganar o receptor dos dados.
Isso é comumente conhecido como autenticação de mensagem.
A especificação de sintaxe e processamento de assinatura XML (http://www.w3.org/TR/
xmldsig-core/) especifica as regras de sintaxe e processamento para criar e representar
assinaturas. É chamado assim porque usa a sintaxe XML para a assinatura. Você pode aplicar
assinaturas XML para praticamente qualquer tipo de dados digitais, incluindo dados em um
documento XML como recursos remotos acessíveis a partir de um URI.
Entendendo os Tipos de Assinaturas
Existem três tipos de assinaturas XML: assinaturas envelopadas (enveloped signatures), assinaturas
envolvidas (enveloping signatures) e assinaturas destacadas (detached signatures).
Assinaturas Envelopadas (Enveloped Signatures)
Assinaturas envelopadas são assinaturas contidas no conteúdo XML que está sendo
assinado. Em termos simples, uma assinatura envelopada é uma estrutura de assinatura XML que é
uma ficha de um documento assinado. Por exemplo:
<mydocument>
<mydata1>some data</mydata1>
<mydata2>more data</mydata2>
<Signature>
<!-- Signature Data -->
</Signature>
</mydocument>
A assinatura XML, é definida pelo elemento Signature e seu conteúdo, e é colocada dentro
do documento que está sendo assinado. Neste caso, os dados incluiriam os dados do elemento
mydocument e todo o seu conteúdo, mas exclui a estrutura de assinatura XML real, que começa
com o elemento Signature.
1
2. Assinaturas Envolvidas (Enveloping Signatures)
Assinaturas XML também podem ser envolvidas. Isso significa que os dados que estão sendo
assinados residem na estrutura de assinatura XML:
<mydocument>
<mydata2>more data</mydata2>
<Signature>
<!-- Signature Data including the reference to the Object element
-->
<Object Id="mydata">
<mydata1>some data</mydata1>
</Object>
</Signature>
</mydocument>
Embora a estrutura da assinatura XML não precise ser incorporada em um XML documento desde a
sua estrutura está no formato XML, eu mostrei desta forma porque você não foi introduzido na
estrutura e como uma assinatura envolvente pode ser encapsulada dentro de outro documento, para
o qual o documento de encapsulamento não tem tendo na assinatura. Nesse caso, a assinatura
incluiria uma referência ao elemento Object. Os dados dentro do elemento Object são os dados
que estão sendo assinados. Vou explicar como dados de referência mais adiante na seção
“Apresentando a Estrutura de Assinatura XML”.
Assinaturas Destacadas (Detached Signatures)
Assinaturas envelopadas significa que a assinatura é encapsulada em um documento que está sendo
assinado.
Não é necessário que todo o documento seja assinado, e é bem possível que você tenha apenas
um único elemento no documento assinado. De fato, também é bem possível que os dados
ser assinado nem mesmo vive dentro do documento e reside remotamente e é acessível
através de um URI. Assinaturas destacadas são usadas apenas para esses propósitos:
<mydocument>
<mydata2>more data</mydata2>
<Signature>
<!-- Signature Data including the reference to the Object element
-->
</Signature>
<Object Id="mydata">
<mydata1>some data</mydata1>
</Object>
</mydocument>
Com este exemplo, os dados dentro do elemento Object estão sendo assinados novamente. Desta
vez, no entanto, o elemento está fora da assinatura e a assinatura está sendo aplicada apenas a
esse elemento em particular e não o documento inteiro:
<Signature>
<!-- Signature Data including the reference to remote data -->
</Signature>
Este exemplo refere-se aos dados que estão sendo assinados e que residem inteiramente fora do
documento. Em vez que referenciando o elemento Object dos exemplos anteriores, a assinatura
2
3. XML, neste exemplo, faz referência a dados remotos usando um URI. Mais uma vez, explicarei isso
em detalhes na seção "Apresentando a Estrutura de Assinatura XML" quando eu dividir a estrutura.
Assim como no exemplo anterior, também seria válido encapsular a assinatura XML em um
documento, e o documento não tem relação com a assinatura ou os dados referenciados.
Apresentando a estrutura de assinatura XML
A estrutura das assinaturas XML pode ficar bastante complexa. Um livro inteiro poderia ser escrito
sobre este assunto. Por esse motivo, vou manter as coisas simples e cobrir apenas a sintaxe
principal.
Este capítulo apresentará como criar e verificar assinaturas XML básicas usando o PHP. Depois de
você entender isso, você deverá ser capaz de implementar assinaturas mais avançadas com base
nas especificações.
O documento na Listagem 12-2 ilustra uma assinatura de envelope válida.
Os dados que estão sendo assinados neste caso é o elemento Object. Ele fica dentro do elemento
Signature, criando assim uma assinatura envolvente. Usando este exemplo, você verá agora como o
XML assinatura é composta e estruturada.
3
4. Elemento Signature
O elemento Signature é a raiz de uma assinatura XML e está vinculado ao namespace
http://www.w3.org/2000/09/xmldsig#. Este elemento contém todas as informações necessárias para
verificar Assinatura XML.
Elemento SignatureValue
O elemento SignatureValue contém o valor codificado em Base64 da assinatura digital real,
que na Listagem 12-2 é o valor OUubDO2l6XUIODuLSjKAtjYlaTk =. Explicarei como calcular
este valor mais tarde na seção "Gerando uma assinatura", bem como quando você entrar na verdade
gerando uma assinatura XML.
Elemento SignedInfo
O elemento SignedInfo é um elemento contêiner que fornece informações sobre como
uma assinatura é processada, a localização dos dados assinados e o valor da integridade dos dados.
Esse elemento também aceita um atributo Id opcional. Usando este atributo permite que o elemento
ser referenciado por outras assinaturas ou objetos.
Elemento CanonicalizationMethod
O elemento CanonicalizationMethod define o tipo de canonização que deve ser aplicado
ao elemento SignedInfo ao processar uma assinatura digital. As implementações devem pelo menos
suporte a XML canônico sem comentários, conforme observado pelo valor
http://www.w3.org/TR/2001/REC-xml-c14n-20010315.
Outros valores possíveis incluem, mas não estão limitados a, http://www.w3.org/TR / 2001 / REC-
xml-c14n-20010315 # ComComments, que é XML canônico com comentários e
http://www.w3.org/TR/xml-exc-c14n/, que é XML canônico exclusivo.
Conforme mostrado na Listagem 12-2, o valor para este elemento é
http://www.w3.org/TR/2001/REC-xml-c14n-20010315, então canonical XML processará o
elemento SignedInfo.
Elemento SignatureMethod
O elemento SignatureMethod especifica o algoritmo usado para criar e verificar a assinatura digital.
Dependendo do algoritmo usado, esse elemento pode ter elementos filho, como
HMACOutputLength, para fornecer informações adicionais para o algoritmo. Você especifica o real
algoritmo a ser utilizado no atributo Algorithm. Os algoritmos são especificados por URI e definem
a regra. Você pode encontrar alguns dos valores possíveis em http://www.w3.org/TR/xmldsig-core/
# sec-AlgID dentro da especificação. O valor usado na Listagem 12-2 é http://www.w3.org/2000/
09/xmldsig#hmac-sha1, que corresponde ao HMAC-SHA1. Então, agora é seguro assumir que
o HMAC-SHA1 é o algoritmo usado neste capítulo para assinaturas digitais.
Elemento Reference
Elementos de referência especificam quais dados são assinados. Você pode usar mais de um
elemento de referência.
Para o bem deste capítulo, no entanto, as assinaturas digitais usadas aqui conterão apenas um unico
4
5. Elemento de referência. Esse elemento pode pegar qualquer um dos três atributos opcionais. Você
pode usar um ID atributo para que o elemento possa ser facilmente referenciado a partir de outros
locais. O atributo Type é um URI que especifica o tipo de dados. Por exemplo, o atributo pode ser
Type = "http://www.w3.org/2000/09/xmldsig#Object" ou Type =
"http://www.w3.org/2000/09/xmldsig#Manifest" . O valor não tem qualquer influência sobre como
a assinatura é gerada. Pode, no entanto, ser usado por um aplicativo para seu próprio propósito. O
último atributo opcional é o URI. Isso tem muito mais impacto nos dados do que os outros
atributos.
O atributo URI identifica o local do objeto de dados, usando um URI como seu valor. o
atributo é considerado opcional, porque é possível que uma aplicação já saiba onde
os dados residem. Por exemplo, se a mesma estrutura XML é sempre usada, pode ser acordado
tanto pelo autor como pelo destinatário do documento, um determinado elemento no documento
será sempre assinado. Normalmente, porém, é mais seguro incluir sempre um URI. O exemplo em
A Listagem 12-2 está usando dados que estão localizados no documento. O atributo URI tem o
valor #objeto. Isso identifica o conjunto de nós que contém o elemento com um ID, definido pelo
atributo Id, do objeto.
Nota: O elemento Transforms, que é um filho opcional de um elemento Reference, será omitido do
este capítulo. Seu uso está fora do escopo, porque é um pouco avançado neste momento tentar usar
o atual Funcionalidade XML em PHP.
Elemento DigestMethod
O elemento DigestMethod define o algoritmo aplicado aos dados que estão sendo assinados. Você
especifica o algoritmo real usando um URI para o valor do atributo Algorithm. Este atributo
funciona da mesma maneira que aquele localizado no elemento SignatureMethod. O exemplo
na Listagem 12-2 usou o valor http://www.w3.org/2000/09/xmldsig#sha1. O resumo será
calculado usando um hash SHA1.
Elemento DigestValue
O elemento DigestValue contém o valor codificado em Base64 do resumo. Usando a assinatura da
Listagem 12-2, o resumo é simplesmente o hash SHA1 da forma canônica dos dados
sendo assinado. Não se preocupe se você não entender completamente isso neste momento. Isso
será feito extremamente claro quando formos criar e verificar as assinaturas nas sessões “Criando
uma Assinatura” e “Verificando uma Assinatura”.
Elemento KeyInfo
O elemento KeyInfo é um elemento opcional que pode permitir que os destinatários obtenham as
chaves, certificados ou informações de gerenciamento de chaves públicas. A assinatura XML neste
capítulo usa a string "secret", que é privada e conhecida apenas pelo autor e destinatário porque
do algoritmo especificado no elemento SignatureMethod. Outros algoritmos usam público / privado
pares de chaves, tornando perfeitamente viável incluir chaves públicas, certificados ou informações
sobre acessando uma chave pública dentro da assinatura XML.
Esse elemento serve como um contêiner para fornecer as informações necessárias, que podem estar
5
6. contidas em qualquer número de possíveis elementos filho. O conteúdo de um elemento KeyName
é uma string contendo um identificador de chave para o destinatário. Indica à informação do
destinatário que chave para usar no documento. Um elemento KeyValue define uma única chave
pública, como DSA ou RSA chaves públicas, que podem verificar e validar a assinatura. Você pode
usar um elemento Retrieval para informações de referência KeyInfo armazenadas em outro local.
Tem um atributo URI e Type e funciona da mesma maneira que um elemento de referência. Os
restantes elementos possíveis, X509Data, PGPData, SPKIData e MgmtData são usados dependendo
do tipo de algoritmo usado.
Por exemplo, você pode usar certificados X509 e um elemento X509Data pode conter certificado
cadeias, listas de revogação ou um SubjectKeyIdentifier. Mais uma vez, esses elementos estão fora
do escopo deste capítulo, mas são abordadas com mais detalhes na especificação em
http://www.w3.org/TR / xmldsig-core / # sec-KeyInfo.
Elemento ObjectElemento Object
Um elemento Object é um contêiner para armazenar qualquer tipo de dado. Tem três atributos
opcionais.
O atributo Id é um ID usado para referenciar o elemento. A assinatura XML na Listagem 12-2
usa o objeto de nome para o atributo Id, que é então referenciado pelo elemento Reference
através do seu atributo URI. Um atributo MimeType especifica o tipo MIME dos dados. O valor
que deve ser um tipo MIME válido, conforme definido no RFC 2045
(http://www.ietf.org/rfc/rfc2045.txt).
O último atributo é Encoding. O valor define a codificação usada no objeto. Os atributos MimeType
e Encoding são puramente informativos. É completamente até o aplicativo se eles precisam ser
usados.
Criando uma Assinatura
Criar uma assinatura envolve gerar os elementos Reference e SignatureValue. O resto
das informações dentro de um elemento Signature define como os valores são gerados ou, quando
usando uma assinatura envolvente, podem ser dados que estão sendo assinados. Os primeiros passos
são determinar o tipo de algoritmo de criptografia que será usado e determinar quais regras devem
ser usado quando a assinatura é criada; eles também determinam as regras que um aplicativo deve
seguir para verificar a assinatura.
Nesse caso, a assinatura XML que está sendo criada é aquela na Listagem 12-2. A seguir
uma lista de regras que serão usadas para criar a assinatura:
• A assinatura será envolvente. O elemento Reference se referirá a um elemento Object
com o objeto Id dentro do documento. Especificamente, o elemento Object será um filho
do elemento Signature.
• A canonização XML será usada. Isso determina o valor do atributo Algorithm no elemento
CanonicalizationMethod.
• HMAC SHA1, usando a string "secret" para a chave, será usado para a assinatura. este
determina o valor do atributo Algorithm no elemento SignatureMethod.
• SHA1 será usado para a integridade da mensagem. Isso determina o valor do Algorithm
atributo no elemento DigestMethod.
6
7. Com base nessa lista, você pode criar uma assinatura esquelética, conforme mostrado na Listagem
12-3.
Listing 12-3. Skeleton Enveloping Signature Document
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-
20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1" />
<Reference URI="#object">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
</Reference>
</SignedInfo>
<Object Id="object">Hello World!</Object>
</Signature>
Nota: Um elemento Reference é criado para cada objeto de dados que está sendo assinado. Este
exemplo tem apenas um único objeto de dados, de modo que o elemento de referência foi criado
com o esqueleto geral em vez de gerá-los porque os elementos DigestValue são calculados para
cada objeto de dados.
A única informação dentro do esqueleto não mencionada na lista é o texto
Hello World!; esse texto, bem como o elemento Object, é a mensagem a ser
assinada. As últimas etapas aqui são para gerar o DigestValue e gerar a assinatura real.
Gerando a Referência
De acordo com a especificação, os DigestValues são criados enquanto os elementos Reference são
criados.
A razão para isso é que vários objetos podem ser usados em uma única assinatura XML. Nesse
caso, os dados são simples e o elemento de referência que aponta para os dados já foi criado.
Nenhuma transformação está sendo usada, portanto, você pode mover diretamente para o cálculo
DigestValue.
Isso é calculado executando as seguintes etapas:
1. Obtenha os dados brutos especificados pelo elemento Reference. Neste caso, é o Object
elemento.
2. Aplique quaisquer transformações. Este exemplo não usa nenhum.
3. Se as transformações (ou os dados brutos no evento não houver transformações definidas)
resultarem em conjunto de nós, use o XML canônico para serializar o conjunto de nós. Neste
exemplo, não há mudança, e os dados brutos são o elemento Object. Canonicalização realizada
neste passo é verdadeiro XML canônico, que significa inclusivo. O valor do método do elemento
canonização não tem nenhuma influência nesta etapa porque esse elemento pertence à geração de
assinatura e não à geração de referência.
4. Usando o algoritmo especificado pelo elemento DigestMethod, calcule o DigestValue
usando os dados resultantes da etapa 3.
7
8. 5. Adicione o DigestValue à árvore. Novamente, as especificações criam o elemento Reference
durante essas etapas, portanto, se você decidir seguir esse método ou tiver uma assinatura complexa
exigindo que as etapas sejam executadas dessa maneira, crie o elemento Referência
e seus filhos neste momento e anexá-lo como filho ao elemento SignedInfo.
Na etapa 1, os dados brutos são o elemento Object. Para este exemplo, vou usar a variável
$ doc, que representa a assinatura esquelética da Listagem 12-3. Isso pode ser carregado
de um arquivo ou ser construído manualmente usando os métodos DOM do Capítulo 6.
Cuidado Ao criar o documento de assinatura manualmente usando a API do DOM, o elemento
Signature define o namespace padrão http://www.w3.org/2000/09/xmldsig#. Elementos dentro de
seu escopo devem ser criado usando métodos de reconhecimento de namespace, como
createElementNS, para que isso funcione corretamente.
For example:
$xPath = new DOMXpath($doc);
/* Following line split into two lines because of length */
$query = '//*[local-name()="Reference" and '.
'namespace-uri()="http://www.w3.org/2000/09/xmldsig#"]';
$nodeset = $xPath->query($query);
$refElement = $nodeset->item(0);
$dataURI = $refElement->getAttribute("URI");
Isso retorna o valor #object. Como um DTD não foi especificado, você não consegue
recupera o elemento Object usando o método getElementByID do DOM. Você deve fazer isso
manualmente. Você pode usar o seguinte código para executar esta operação. Note que ele assume o
O valor do URI contém um ID e não um URL para dados externos:
$ID = substr ($dataURI, 1);
$query = '//*[@Id="'.$ID.'"]';
$nodeset = $xPath->query($query);
$Object = $nodeset->item(0);
A variável $ Object resultante deve ser um objeto DOMElement que referencia o objeto
elemento no documento. Serialização usando $ doc-> saveXML ($ Object) deve produzir o
Segue:
<Object Id="object">Hello World!</Object>
Não há Transformações e o resultado da primeira etapa é um conjunto de nós contendo o Object
elemento. Este conjunto de nós (read: element) deve ser serializado em forma canônica:
<Object xmlns="http://www.w3.org/2000/09/xmldsig#"
Id="object">some text</Object>
O XML canônico é usado aqui, o que é inclusivo. Isso significa que o namespace padrão
definido pelo elemento Signature, que é um ancestral do elemento Object, é serializado
com o nó Object. Uma maneira rápida e simples de canonizar esse elemento é copiá-lo para
outro documento e serializando o novo documento. A cópia deve ser uma cópia profunda para que
8
9. todos os atributos e filhos são copiados. Durante a cópia, como esse nó se torna o nó de nível
superior, o namespace padrão herdado é recriado na cópia. Por causa da estrutura
da assinatura XML e dos dados com os quais você está trabalhando, essa é a única coisa que você
precisa fazer antes da serialização para resultar na forma canônica correta. Para estruturas mais
complexas, você precisaria usar as técnicas descritas na seção “Introdução à Canonical XML”:
$dom = new DOMDocument();
$copyObject = $dom->importNode($Object, TRUE);
$dom→appendChild($copyObject);
Cuidado Isso funciona apenas porque o conteúdo do elemento Object é um texto simples e não um
XML subárvore. Se o conteúdo fosse uma subárvore, você precisaria aplicar as regras e técnicas
descritas na “Introdução à XML canônica”, de modo que os namespaces e os atributos em particular
sejam gerados corretamente.
Usando o algoritmo do elemento DigestMethod, a forma canônica dos dados gera o resumo. Este
valor é então codificado usando codificação Base64 e definido como o conteúdo de
o elemento DigestValue:
$query = '//*[local-name()="DigestMethod" and ' . 'namespace-
uri()="http://www.w3.org/2000/09/xmldsig#"]';
$nodeset = $xPath->query($query);
$digMethod = $nodeset->item(0);
$algorithm = $digMethod->getAttribute("Algorithm");
if ($algorithm == "http://www.w3.org/2000/09/xmldsig#sha1")
{
$canonical = $dom->saveXML($copyObject);
/* Create SHA1 hash of the canonical form of the Object element */
$hash = sha1($canonical);
$bhash = pack("H*", $hash);
$digValue = base64_encode($bhash);
/* Following is done in example only to add proper whitespacing */
$addPrev = NULL;
$addPost = NULL;
if ($digMethod->previousSibling->nodeType == XML_TEXT_NODE)
{
$addPrev = clone $digMethod->previousSibling;
}
if ($digMethod->nextSibling->nodeType == XML_TEXT_NODE)
{
$addPost = clone $digMethod->nextSibling;
}
/* End custom whitespaces */
/* Create DigestValue element, and append to parent of DigestMethod */
$digestValue = $doc->createElementNS("http://www.w3.org/2000/09/xmldsig#",
"DigestValue", $digValue);
$digMethod->parentNode->appendChild($digestValue);
/* Following is done in example only to add proper whitespacing */
if ($addPrev)
{
$digMethod->parentNode->insertBefore($addPrev, $digestValue);
$digMethod->parentNode->removeChild($digMethod->nextSibling);
}
if ($addPost)
{
$digMethod->parentNode->appendChild($addPost);
9
10. }
/* End addition of whitespaces */
}
else
{
print "Unhandled Encoding";
exit;
}
Esse trecho de código encontra o algoritmo para o resumo e, se puder ser manipulado, ele continua
o processamento. Neste caso, você está lidando apenas com SHA1. O hash SHA1 da forma
canônica anteriormente obtido é convertido em forma binária. A função sha1 () está sendo usada,
porque é disponível por padrão no PHP. Para evitar a conversão do valor em formato binário, você
pode usar mhash, $ bhash = mhash (MHASH_SHA1, $ canonical) ;, porque retorna o hash como
um binário do que como um hexadecimal. Em qualquer caso, o valor binário é então codificado em
Base64. Um elemento DigestValue é criado usando o método createElementNS e passando o valor
codificado.
O código adicional para manipulação de espaços em branco não é necessário ao gerar uma
assinatura.
A razão pela qual foi adicionado neste exemplo é porque o espaço em branco é significativo em
termos canônicos.
Formato. Para apresentar um documento em uma forma facilmente apresentável, como a mostrada
na Listagem 12-2, Eu adicionei espaços em branco. Esses espaços em branco estão incluídos em
uma assinatura para apresentar você com um formato legível, bem como valores corretos para o
DigestValue e SignatureValue elementos.
Gerando uma Assinatura
Geração de assinatura envolve o uso da chave, que neste caso é a string "secreta", para aplicar
o algoritmo especificado pelo Algorithm no elemento SignatureMethod para o SignedInfo
elemento em forma canônica. Desta vez, a forma canônica é gerada usando o método especificado
pelo elemento CanonicalizationMethod. Em vez de explicar cada passo no processo, porque você
deve ter experiência suficiente neste momento para encontrar nós e valores, vou demonstrar apenas
os passos específicos para gerar a assinatura. Dito isto, o as seguintes variáveis e valores serão
assumidos:
• $canonMethod: "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
• $signedInfo: DOMElement for SignedInfo element
• $Object: DOMElement for Object element
• $key: "secret";
A Listagem 12-4 define uma função HMAC genérica. Para usar a função sha1 () sem dependências
adicionais, usarei a função na Listagem 12-4 dentro do exemplo.
Listing 12-4. Generic HMAC Function
function hmac($key, $data)
{
$b = 64; // byte length
if (strlen($key) > $b) {
$key = pack("H*", sha1($key));
10
11. }
$key = str_pad($key, $b, chr(0x00));
$ipad = str_pad('', $b, chr(0x36));
$opad = str_pad('', $b, chr(0x5c));
$k_ipad = $key ^ $ipad;
$k_opad = $key ^ $opad;
return sha1($k_opad . pack("H*", sha1($k_ipad . $data)));
}
O processo para gerar a assinatura é semelhante a gerar o resumo. Diferente o conjunto de nós é
usado e o HMAC SHA1 está sendo executado; no entanto, neste exemplo, o elemento SignedInfo
está sendo convertido em sua forma canônica e o algoritmo de assinatura é aplicado.
O valor resultante é então definido como o conteúdo para o elemento SignatureValue e anexado
como um filho para o elemento de assinatura. Por exemplo:
$dom = new DOMDocument();
$copyInfo = $dom->importNode($signedInfo, TRUE);
$dom→appendChild($copyInfo);
/*
A seguir funciona apenas com o PHP 5.1 e superior. LIBXML_NOEMPTYTAG usado para
Crie tags de início e fim para elementos vazios. Elemento do documento $
copyInfo passado para despejar o nó, que não gera uma saída de declaração XML
*/
$canonical = $dom->saveXML($copyInfo, LIBXML_NOEMPTYTAG);
/* Calculate HMAC SHA1 */
$hmac = hmac($key, $canonical);
print $hmac . "n";
$bhmac = base64_encode(pack("H*", $hmac));
/* Handle whitespaces for presentation layout */
$addPrev = NULL;
$addPost = NULL;
if ($Object->previousSibling->nodeType == XML_TEXT_NODE) {
$addPrev = clone $Object->previousSibling;
}
if ($Object->nextSibling->nodeType == XML_TEXT_NODE) {
$addPost = clone $Object->nextSibling;
}
/* END Handle whitespaces for presentation layout */
/*
Create and append the SignatureValue element as child of Signature element
insertBefore used with whitespacing to generate output in Listing 12-2.
*/
$sigValue = $doc->createElementNS("http://www.w3.org/2000/09/xmldsig#",
"SignatureValue", $bhmac);
if ($addPrev) {
$Object->parentNode->insertBefore($sigValue, $Object->previousSibling);
}
else {
$Object->parentNode->insertBefore($sigValue, $Object);
}
11
12. /* Following is done in example only to add proper whitespacing */
if ($addPost) {
$Object->parentNode->insertBefore($addPrev, $sigValue);
}
print $doc->saveXML();
O documento resultante deve ser exatamente igual ao documento da Listagem 12-2, até
os mesmos espaços em branco usados.
Tradução: Diogo Rocha
12