I've been signing work-related xml for almost a year, and today i noticed that i was doing it wrong (please excuse my bad english, it's not my primary language)
I use the xmlseclibs library for php, and i want the signatures to be like this:
<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#rsa-sha1" />
<Reference URI="#XXXXX">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>... </DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>... </SignatureValue>
<KeyInfo>
<KeyValue>
</KeyValue>
<X509Data>
<X509Certificate>... </X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
The following example should help me to demonstrate what i want to do. We have the following xml file:
<node1>
<node2>
somedata
</node2>
</node1>
And after i sign it, looks like this:
<node1>
<node2>
somedata
</node2>
<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#rsa-sha1" />
<Reference URI="#XXXXX">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>... </DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>... </SignatureValue>
<KeyInfo>
<KeyValue>
</KeyValue>
<X509Data>
<X509Certificate>... </X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</node1>
Now, that's the structure i need, however, when i do this, the sign is applied over all the document (node1 and node2) but i only want to sign the node2 (that's the error im getting, i noticed it thanks to the DigestValue).
But when i do that, i got the following:
<node1>
<node2>
somedata
<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#rsa-sha1" />
<Reference URI="#XXXXX">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>... </DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>... </SignatureValue>
<KeyInfo>
<KeyValue>
</KeyValue>
<X509Data>
<X509Certificate>... </X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</node2>
</node1>
I've trying for days, but i can't place the signature where i want it to be (just under the tag that's been signed, not inside).
Any thoughts?
The function i'm using is something like this:
function firmarEnvio2($xmlr){
$doc = new DOMDocument();
$xml = file_get_contents($xmlr);
$doc->loadXML($xml);
$doc->preserveWhiteSpace = true;
$doc->encoding = 'ISO-8859-1';
$objDSig = new XMLSecurityDSig(FALSE);
$objDSig->setCanonicalMethod(XMLSecurityDSig::C14N);
echo "<pre>";
$options['prefix'] = '';
$options['prefix_ns'] = '';
$options['force_uri'] = TRUE;
$options['id_name'] = 'ID';
$objDSig->addReference($doc, XMLSecurityDSig::SHA1, array(XMLSecurityDSig::TR_ENV_SIG), $options);
/*
$objDSig->addReference($doc->documentElement, XMLSecurityDSig::SHA1,
array(
'http://www.w3.org/2000/09/xmldsig#enveloped-signature',
'http://www.w3.org/2001/10/xml-exc-c14n#'
),
array('id_name' => 'Id', 'overwrite' => false));
*/
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private'));
$pass = "some string";
$pfx = file_get_contents("someroute/certificate.pfx");
openssl_pkcs12_read($pfx, $key, $pass);
$objKey->loadKey($key["pkey"]);
$objDSig->add509Cert($key["cert"]);
$tag="x";
//the following is to compare the digest that i want with the one i always got
echo "<br><br>Digest1<br>";
print_r (base64_encode(sha1($doc->documentElement->C14N(), true)));
echo "<br><br>Digest2<br>";
print_r (base64_encode(sha1($doc->documentElement->getElementsByTagName($tag)->item(0)->C14N(), true)));
print_r ($firma);
$objDSig->sign($objKey, $doc->documentElement);
//print_r($doc);
$doc->save('test_s.xml');
return true;
}
does anybody knows how to do this?
I recently had the same issue with the xmlseclibs library. Here's what worked for me:
Hope it can be of help.