问题
I tested the final XML signature file and it sends, "invalid signatures", why? Information: I have prepared this inf. to be signed with XML signature:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><SolicitudRegistro
xmlns="http://www.cie.mx/SCG/Inilidad" IdMensaje="f2-8505d81914c">
<FechaEnvio>2013-02-26T21:08:36</FechaEnvio>
<Registrante EndPoint="https://200.34.175.46:443/InteropOPE
/MensajeidadService" Nombre="Instigua" NombreCorto="IMTA" URI="op.mx">
<DatosDeContacto AreaOficina="Informatica"
CorreoElect="req@tc.ia.mx" Nombre="Rafadina" Puesto="Subdirector nicaciones" >
<Telefonos>
<Telefono Extension=" " NumeroTelefonico="7773293644" />
</Telefonos>
</DatosDeContacto>
<CertificadoInstancia>MIIFETCCA/mgAwIBAgIUMDAwMDAwMDAwMDAwMD CERTIFICATE
WITH SENDER'S PUBLIC KEY=</CertificadoInstancia>
</Registrante>
<Reto>
<CadenaCifrada>Ln0BAsnwrNg6IzjW7hk2c/Nxx/x3LZ STRING ENCRYPTED
WITH PRIVATE KEY SO RECEIVER CAN AUTHENTICATE SOURCE WITH SENDER'S CERTIFICATE=
</CadenaCifrada>
</Reto>
</SolicitudRegistro>
So I stored all this in file results.xml, then I sign it with phpseclib functions, the code is:
<?php
require('xmlseclibs.php');
if (file_exists('./firmas/sign-basic-test_mio.xml')) {
unlink('./firmas/sign-basic-test_mio.xml');
}
$doc = new DOMDocument();
$doc->load('./firmas/results.xml');
$objDSig = new XMLSecurityDSig();
$objDSig->setCanonicalMethod(XMLSecurityDSig::C14N);
$objDSig->addReference($doc, XMLSecurityDSig::SHA1,
array('http://www.w3.org/2000/09/xmldsig#enveloped-signature',
array('http://www.w3.org/TR/1999/REC-xpath-19991116' =>
array("query" => "ancestor-or-self::*[local-
name()='SolicitudRegistro']"))),array("force_uri"=>true));
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private'));
/* load private key */
$objKey->loadKey('i.pem', TRUE);
$objDSig->sign($objKey);
/* Add associated public key */
$objDSig->add509Cert(file_get_contents('instancia_imta_ope.crt'));
$objDSig->appendSignature($doc->documentElement);
$doc->save('./firmas/sign-basic-test_mio.xml');
$sign_output = file_get_contents('./firmas/sign-basic-test_mio.xml');
$sign_output_def = file_get_contents('./firmas/sign-basic-test_mio.res');
if ($sign_output != $sign_output_def) {
echo "NOT THE SAME";
}
echo "DONE";
?>
This gives a complete XML signature that looks like (truncated some encrypted text):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SolicitudRegistro xmlns="http://www.cb.mx/SCG/Interlidad"
IdMensaje="f2e140eb-2b09-44ab-8504-87b25d81914c">
<FechaEnvio>2013-02-26T21:08:36</FechaEnvio>
<Registrante EndPoint="https://200.34.175.46:443/InteropOPE.....
<DatosDeContacto AreaOficina="Informatica" CorreoElectronico.....
<Telefonos>
<Telefono Extension=" " NumeroTelefonico="7773293644"/>
</Telefonos>
</DatosDeContacto>
<CertificadoInstancia>MIIFETCCA/mgAwIBAgIUMDAwMDY....=</CertificadoInstancia>
</Registrante>
<Reto>
<CadenaCifrada>Ln0BAsnwrNg6IzjW7hk.....</CadenaCifrada>
</Reto>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo><ds:CanonicalizationMethod
Algorithm="http://ww.org/TR/2001 /REC-xml-c14n-20010315"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI=""><ds:Transforms><ds:Transform Algorithm="http://www.
w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform
Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
<ds:XPath>ancestor-or-self::*[local-name()='SolicitudRegistro']</ds:XPath>
</ds:Transform></ds:Transforms><ds:DigestMethod
Algorithm="http://www.w3.org/2000/09 /xmldsig#sha1"
/><ds:DigestValue>GogFeLcUThvfAeyNrDBroTQaGhA=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo><ds:SignatureValue>N+Btck0X9H81ZUcmrIK3h7LR2CtA86BPaBFE=
</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIFETCCA/mgAwIB.....=</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
All this for 1 question, do you know any example how to validate this signature using PHPSECLIB? Or another library? the testing page that shows invalid signatures is: https://ope.gob.mx/BrokerInteropQA/Diagnostico/default.aspx
thanks, I apologize for so much information, but I tried to be clear in my doubt mario
回答1:
I'd use xmlseclibs (author-blog). Right now that's probably using the openssl_* functions but it could probably be rewritten to use phpseclib.
The reason phpseclib isn't sufficient is because, for XML Signatures, you need the XML to be canonicalized. and are gonna be interpreted the same way but phpseclib doesn't know that. To phpseclib it's just a text string and treated as text strings they're both different. But treated as XML strings they're not.
回答2:
I use the following with xmlseclibs, but it sent me FAILURE !!!!, what could be wrong?
<?php
require('xmlseclibs.php');
$doc = new DOMDocument();
$arTests = array('SIGN_TEST'=>'./firmas/sign-basic-test_mio.xml');
foreach ($arTests AS $testName=>$testFile) {
$doc->load($testFile);
$objXMLSecDSig = new XMLSecurityDSig();
$objDSig = $objXMLSecDSig->locateSignature($doc);
if (! $objDSig) {
throw new Exception("Cannot locate Signature Node");
}
$objXMLSecDSig->canonicalizeSignedInfo();
$objXMLSecDSig->idKeys = array('wsu:Id');
$objXMLSecDSig->idNS = array('wsu'=>'http://docs.oasis-open.org/wss/2004/01/oasis-
200401-wss-wssecurity-utility-1.0.xsd');
$retVal = $objXMLSecDSig->validateReference();
if (! $retVal) {
throw new Exception("Reference Validation Failed");
}
$objKey = $objXMLSecDSig->locateKey();
if (! $objKey ) {
throw new Exception("We have no idea about the key");
}
$key = NULL;
$objKeyInfo = XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig);
if (! $objKeyInfo->key && empty($key)) {
$objKey->loadKey('i.pem', TRUE);
}
if ($objXMLSecDSig->verify($objKey)) {
print "Signature validateddd!";
} else {
print "Failure!!!!!!!!";
}
print "\n";
}
?>
来源:https://stackoverflow.com/questions/15140200/how-to-validate-signature-with-phpseclib-in-a-xml-signature-message