selective-php / xmldsig Goto Github PK
View Code? Open in Web Editor NEWSign XML Documents with Digital Signatures
License: MIT License
Sign XML Documents with Digital Signatures
License: MIT License
I'm facing a weird issue, I'm able to connect to the Soap service through SoapUI and send successful requests, here is the ws settings in SoapUI:
However when using this library I can NOT generate the same digest or signature as SoapUI generates them.
$xmlSigner = new XmlSigner();
$xmlSigner->loadPrivateKeyFile('path-to-private-key', '');
$xmlSigner->setReferenceUri('random-id');
$xmlSigner->signXml('<soapenv:Body>....</soapenv:Body>', DigestAlgorithmType::SHA1);
// The resulting digest is different from SoapUI, and result soap error Hash values do not match
Any idea what I'm missing here?
I added a test
/**
* Test.
*
* @dataProvider providerTestSignAndVerify
*
* @param string $privateKeyFile The key file
* @param string $publicKeyFile The key file
* @param string $password The file password
*
* @return void
*/
public function testSignAndVerifyPartial(string $privateKeyFile, string $publicKeyFile, string $password)
{
$files = [
__DIR__ . '/example4.xml',
];
$algos = [
Algorithm::METHOD_SHA1,
Algorithm::METHOD_SHA224,
Algorithm::METHOD_SHA256,
Algorithm::METHOD_SHA384,
Algorithm::METHOD_SHA512,
];
foreach ($files as $filename) {
foreach ($algos as $algo) {
$privateKeyStore = new PrivateKeyStore();
if (pathinfo($privateKeyFile, PATHINFO_EXTENSION) === 'p12') {
$privateKeyStore->loadFromPkcs12(file_get_contents($privateKeyFile), $password);
} else {
$privateKeyStore->loadFromPem(file_get_contents($privateKeyFile), $password);
}
$algorithm = new Algorithm($algo, $algo);
$cryptoSigner = new CryptoSigner($privateKeyStore, $algorithm);
$xmlSigner = new XmlSigner($cryptoSigner);
$xmlSigner->setReferenceUri('');
$xml = new DOMDocument();
$xml->preserveWhiteSpace = true;
$xml->formatOutput = false;
$xml->loadXML(file_get_contents($filename));
$xpath = new DOMXPath($xml);
$elementToSign = $xpath->query('/References/Book/Author')->item(0);
$signedXml = $xmlSigner->signDocument($xml, $elementToSign);
// verify
$publicKeyStore = new PublicKeyStore();
if (pathinfo($publicKeyFile, PATHINFO_EXTENSION) === 'p12') {
$publicKeyStore->loadFromPkcs12(file_get_contents($publicKeyFile), $password);
} else {
$publicKeyStore->loadFromPem(file_get_contents($publicKeyFile));
}
$cryptoVerifier = new CryptoVerifier($publicKeyStore);
$xmlSignatureVerifier = new XmlSignatureVerifier($cryptoVerifier);
$isValid = $xmlSignatureVerifier->verifyXml($signedXml);
$this->assertTrue($isValid, 'Could not validate partial signed xml document');
}
}
}
Which tests the partial (signDocument)
This is the xml output of the $signedXml
<?xml version="1.0"?>
<References>
<Book>
<Author>
<FirstName>Bruce</FirstName>
<LastName>Schneier</LastName>
</Author>
<Title>Applied Cryptography</Title>
</Book>
<Web>
<Title>XMLSec</Title>
<Url>http://www.aleksey.com/xmlsec/</Url>
</Web>
<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=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>JcCwDiYORvy5oZax2ZLPbtOMWeU=</DigestValue></Reference></SignedInfo><SignatureValue>feoBWMSYKSjh2/Vu5L/szUDL/7hpu6cxwy/LTlwP8XwKGzq3WFBYJRNO2s/CdDSCAyH2Gka2xTZslVlxnpcloeg8dVL36Z6OXoPNH/B8LppE+r4cB9ivXu/cCbes0SHnnP+zG4aRV5W9NRyevMWdlg9WdtNXUDtZ0aseWNnOjjI=</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>2smhWoycTnVVPvBI8Dt9Utl6jZmMcWx34lCTt8Noeezj1JCgHCnuRr7fYSWz029wuG5T0nDpHtkXsSp10u6QF128RZYFJWdECtCtqXZeefTkpq7R95jz/QSb7wzJcZHDY/fxHg/shnfBjf8k+j0w4fBv+JbMzly/rciiJAuGLP8=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue></KeyInfo></Signature></References>
Is this normal, or?
In some situations after veryfing xml for equal signatures method can return false, but signatures are correct. I think that it depends on your xml response.
To fix this, i changed $xml->preserveWhiteSpace
to false
in verifyXml
method. So my suggestion is to make an additional option for this method where we can choose value of $xml->preserveWhiteSpace
option.
this dont apears
what can i do ?
XmlSigner.php 432 line $signatureValue is not defined,
or I miss something.
Hi!
Is it possible to sign the xml having it only on memory not saved on a text file?
Hi,
We are working on UPI integration where we need to sign xml message before API call. We are using this library to sign xml. The signature is verified at our level but not getting verified at API level. They are verifying signature using java code. Can anyone help us. Below is the java code shared by API development team :
package olivecrypto.upi.xml;
import java.io.FileInputStream;
import java.io.StringReader;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class VerifySignature {
PublicKey publicKey;
public VerifySignature(String cer) throws Exception {
CertificateFactory certFact = CertificateFactory.getInstance("X509");
Certificate cert = certFact.generateCertificate(new FileInputStream(cer));
publicKey = cert.getPublicKey();
}
public boolean isXmlDigitalSignatureValid(String signedXml) throws Exception {
boolean validFlag = false;
System.out.println("signedXml" + signedXml);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse(new InputSource(new StringReader(signedXml)));
System.out.println("doc" + doc);
NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
if (nl.getLength() == 0) {
throw new Exception("No XML Digital Signature Found, document is discarded");
}
DOMValidateContext valContext = new DOMValidateContext(publicKey, nl.item(0));
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
XMLSignature signature = fac.unmarshalXMLSignature(valContext);
validFlag = signature.validate(valContext);
return validFlag;
}
}
How to sign with the .p12 file?
Hello Odan, i'm working for XAdES how can i add the namespace to your xml signature (ie. ds:Signature)
Hi,
i want to sign xml using 509 certificate and hash it but I am not getting a proper answer for the same
Hello,
Cant install your latest version on PHP 7.4 website. Downloading only version 2.2 with composer
Anyway, it works on PHP 7.4 version without installing via composer
Problem 1 - Installation request for selective/xmldsig ^2.3 -> satisfiable by selective/xmldsig[2.3.0]. - selective/xmldsig 2.3.0 requires php ^8.0 -> your PHP version (7.4.3) does not satisfy that requirement.
Can you set minimal version to 7.0?
I just installed the latest release and immediately wanted to try out your example with the PrivateKeyStore, but that class does not exist there. I've had to pull in "dev-master" directly, but I guess it would be better to be able to use the latest release instead :)
Hello,
I recently discovered the package and I'm in need for a XML signature package that signs only a part of the xml and not the xml itself. Is there a way with this package?
Hi!
Is it possible with your package to sign only a part of the document and not all of it ? For example, sign only the creditcard block ? As far as I can see, probably not, but it is better to ask than make assumptions. :-) However, if not, I think it is not difficult to achieve. Just in case you are interested, I changed a little bit those two parts of XmlSigner:
public function signXml(string $xmlContent, string $algorithm): string
{
// ...
if (!empty($this->referenceUri)) {
$xpath = new DOMXPath( $xml );
$elementToSign = $xpath->query( '//*[@Id="'.$this->referenceUri.'"]' )->item(0);
} else {
$elementToSign = $xml->documentElement;
}
$canonicalData = $elementToSign->C14N(true, false);
// ...
if (empty($this->referenceUri)) {
$this->appendSignature($xml, null, $digestValue);
} else {
$this->appendSignature($xml, $elementToSign, $digestValue);
}
// ...
}
private function appendSignature(DOMDocument $xml, ?DOMElement $elementToSign, string $digestValue)
{
// ...
if (!is_null($elementToSign)) {
$elementToSign->appendChild($signatureElement);
} else {
if (!$xml->documentElement) {
throw new UnexpectedValueException('Undefined document element');
}
$xml->documentElement->appendChild($signatureElement);
}
// ...
}
and it seems to work. Having this XML document:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<creditcard Id="pfx344c3c2b-40e6-e800-3187-f9db657d183b">
<number>19834209</number>
<expiry>02/02/2025</expiry>
</creditcard>
</root>
I just set the reference URI:
$xmlSigner->setReferenceUri('pfx344c3c2b-40e6-e800-3187-f9db657d183b');
and the signed document produced seems to be valid:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<creditcard Id="pfx344c3c2b-40e6-e800-3187-f9db657d183b">
<number>19834209</number>
<expiry>02/02/2025</expiry>
<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/2001/04/xmldsig-more#rsa-sha256"/><Reference URI="#pfx344c3c2b-40e6-e800-3187-f9db657d183b"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><DigestValue>xWanv02IJB42cNTbcThWYlM5JYU1bsLR79ZWajOvHeg=</DigestValue></Reference></SignedInfo><SignatureValue>XiAqHajBiv9zpfylk4IlSPkUMqIg7QNVxKFNh4QEQxdXSTvRnu8EWje8uBNwueKvrFJND7ytbSbKamkVp2p0H9tVK4CceuETUUtQBAEf1glYqXv7phw0gYVVcL+vme9WwDKWgfI6A4cJWMfn12ktdPDB/oCyI8rV8wLgsEDhLCt1quQXiaOBkX8lHpVRQgDb5rA0yMxQ6kSoCwmtFrmPsQ7uZx9baMtIRzo3r2pAa1LLC9TfV80h+OoR2bZAiZuBsaMrMhIgdwg2qvmXUSa+eDgSpGLv66kZ2EM4ahsJlfWC8MWieisO3j/1p7kbBpi/OsRpjI3r3NlckKNiegkL7A==</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>7bXTMjOSElQ9VM/gRwD68VSejdXmaJ34NwzL2VU9GcuuPqnF4/M7hwupaJQ7Hxpw/C1Lba2kO6gi/mxyqbPoYwIQkXceVnJ+Ig65RacRS+yDZ6+r3pM7AkOOQT1K75LBfRSmu8l+IkgwbrZj36E9eID5yLknvGOVHhnui5OrBdFoB8i/iZsTrt++yroWodqV2dfs+1eCSJTYHpibSpaq74BnrhPU2oHxh1C/QbmSuX1Mf0Ug1I6sVHilN337fXxiAGZdHXborQtjrb+Ha9YMS61JiPmWe+RZrXykE+0pkvdkFSNgeVgD5S9W5274ZGYssO5xRPkP8BidpshOESBY3Q==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue></KeyInfo></Signature></creditcard>
</root>
In the XmlSignatureValidator, I think the only change needed is when checking the digest. You need to see if there is any reference URI and, if there is, use it to fetch the node on which the digest will be calculated. Something like that:
$xpath = new DOMXPath( $xml );
$signedElement = $xpath->query( '//*[@Id="'.$referenceUri.'"]' )->item(0);
$canonicalData = $signedElement->C14N(true, false);
I haven't thoroughly analyzed your code so the changes above are just a proof of concept and nothing more. :-)
Salutations!
I was trying to use your library to sign some XML files in my project, but unfortunately i could not require it from composer, which gave me the message:
[InvalidArgumentException]
Could not find a matching version of package selective/xmldsig. Check the package spelling,
your version constraint and that the package is available in a stability which matches your
minimum-stability (stable).
So, i had to actually clone it. I never published a package to composer and such, so idk why this happens, so if you could publish it i would be happy, or if it's published, update your readme with the correct package name =).
I didn't test the library yet, hope it will be useful for my project.
Best regards,
Lúcio.
After digital sign I have child nodes not Latin values encoding issue.
here is a xml examnple
<?xml version="1.0"?> <MortgageRequest> <RequestReference> <RefNum>0000001127</RefNum> <OperationDate>01/01/2021 01:09:33</OperationDate> </RequestReference> <Լoans> <LoanContract> <ContractNumber>15L700568972265</ContractNumber> <ContractDate>21/06/2019</ContractDate> <MonthInfo> <InterestPaymentDate>20/11/2020</InterestPaymentDate> <InterestPaymentValue>199785.68</InterestPaymentValue> <InterestPaid>199785.68</InterestPaid> <DateOfPayment>19/12/2019</DateOfPayment> </MonthInfo> <MonthInfo> <InterestPaymentDate>20/11/2020</InterestPaymentDate> <InterestPaymentValue>199785.68</InterestPaymentValue> <InterestPaid>199785.68</InterestPaid> <DateOfPayment>19/12/2019</DateOfPayment> </MonthInfo> <QuarterInfo> <PaymentYear>2020</PaymentYear> <PaymentQuarter>4</PaymentQuarter> <QuarterPaidInterest>599357.04</QuarterPaidInterest> </QuarterInfo> <Borrower> <ssn>2707950378</ssn> <tin>11223344</tin> <FirstName>ԶԱՎԵՆ</FirstName> <LastName>ՄԵԼՔՈՆՅԱ</LastName> </Borrower> <Co_Borrowers> <Co_Borrower> <ssn>2707950378</ssn> <tin>11332244</tin> <FirstName>ԶԱՎԵՆ</FirstName> <LastName>ՄԵԼՔՈՆՅԱ</LastName> </Co_Borrower> </Co_Borrowers> </LoanContract> <LoanContract> <ContractNumber>15L700568972265</ContractNumber> <ContractDate>21/06/2019</ContractDate> <MonthInfo> <InterestPaymentDate>20/11/2020</InterestPaymentDate> <InterestPaymentValue>199785.68</InterestPaymentValue> <InterestPaid>199785.68</InterestPaid> <DateOfPayment>19/12/2019</DateOfPayment> </MonthInfo> <MonthInfo> <InterestPaymentDate>20/11/2020</InterestPaymentDate> <InterestPaymentValue>199785.68</InterestPaymentValue> <InterestPaid>199785.68</InterestPaid> <DateOfPayment>19/12/2019</DateOfPayment> </MonthInfo> <QuarterInfo> <PaymentYear>2020</PaymentYear> <PaymentQuarter>4</PaymentQuarter> <QuarterPaidInterest>599357.04</QuarterPaidInterest> </QuarterInfo> <Borrower> <ssn>4105939999</ssn> <tin>11223344</tin> <FirstName>ԶԱՎԵՆ</FirstName> <LastName>ՄԵԼՔՈՆՅԱ</LastName> </Borrower> <Co_Borrowers> <Co_Borrower> <ssn>2707950378</ssn> <tin>11332244</tin> <FirstName>ԶԱՎԵՆ</FirstName> <LastName>ՄԵԼՔՈՆՅԱ</LastName> </Co_Borrower> </Co_Borrowers> </LoanContract> </Լoans> <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/2001/04/xmldsig-more#rsa-sha512" /> <Reference URI=""> <Transforms> <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> </Transforms> <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha512" /> <DigestValue>zR4oiBFpFZzhwfLhB1qBd+ak8AlC8tE2or0SmdLd4OBDRHVMARjqS8+CXAecHADeGmwyDCBSvoAJ2BlVd+DAgA== </DigestValue> </Reference> </SignedInfo> <SignatureValue> ZdYo+o4VuebipAbPJCxHqbcMqf5Gg+eA0ZH6/rPuFk94EzPqSYCSRZKIQws+NrQOBu0rPNTJx+06VswrVs2+6fbR9//YgnkyOHJtwx6FiGQzyL/uO0jNrVAhbDxp9qChKq83amEYAj4Cpb/eRRc2NsG/MZHkHNVZllhxkW3gnx4kj2zfEGBapd5kbOInKKoFCxEhLt/mwb8oFwSryBQgd7sikT1C5OTkuWuj4W5KHYYLXRwPFz8kVHzOdF4x3qQO6rdHQYHSMEyHW28hZ9Yuts15VYWZFOuacnxU62QZg5ALVM7qKOGpZfX8CCLBzwrnXECQft2Gx85Ypkb3YXjjpw== </SignatureValue> <KeyInfo> <KeyValue> <RSAKeyValue> <Modulus> pd0UTDf72nh0dBWlpqM8Aci1iwUgkmuvYmXgobxuF4tXVYENJzUU83E1L+TuHI6N1FtYY3ALhHTPHssklrS0b4rDvMxzDDi0KZQGZyge74q6jlkEgIFq/+ltHt9g4uTzuxsjHpmyW8rODNpmP6eMG9DL0+NXLDlN8sR6gDUC6XW1D5ri6PdsAedkXQ055X+gmA/PdOqxG3fXTDapVBBlsWxOhbb96nll3YOWQQz3jEoMsu5z/qPn6uNAiBechyzzyzNsdic3pJcNPsoB9j2CP/uOMWq40O3XsSArQULYaTt73dUaEN+kff+YIKZYObaPcN/ekK5tgj4F4jlNP/VFjQ== </Modulus> <Exponent>AQAB</Exponent> </RSAKeyValue> </KeyValue> </KeyInfo> </Signature> </MortgageRequest>
Please look at the "FirstName", "LastName" node values.
How to fix that?
Thanks in advance
Is that possible to verify digital sign key without "password".
With x509 standards they don't need to have "password" for verify digital signature with public key.
How we can modify validator for support that?
I want to know if this proyect is abandoned, because on packagist appears abandoned.
Hi. First of all, thanks for your lib, in my initial test it work as expected.
Now, I'm looking to do a sightly different signature procedure, maybe you can enlighten me.
The tags used for the digital signature in your library are: Signature, SignedInfo, CanonicalizationMethod, SignatureMethod, etc...
I'm looking to renamed them like ds:Signature, ds:SignedInfo, ds:CanonicalizationMethod, ds:SignatureMethod, and so. Basically a prefix ds:
in each tag.
How can I do this customization with your library? It is possible?
Also. before I finish the root tag Signature, additional signature fields has to be added. My XML file has a bit more complex structure, and those fields has an special signing procedure. I need to retrieve additional tags like ds:KeyInfo, <ds:X509Data, ds:X509Certificate, ds:KeyValue, ds:RSAKeyValue, ds:Modulus.
Is this possible (retrieve those extra tags with additional information of the signing process) with your library?
Where can I start for the customization.
Just in case, are you available to accept such paid customization job? Which is increase the information given for the sign procedure.
Thanks for your support and help.
Regards.
After digital sign for security reason I have modified some xml node values and gave that modified xml to verify and it successfully pass verification. It's means that verifyXML method doesn't check xml content with digest value.
How can fix that ?
With standard certs works fine, but it doesn't support gost 3410 2012 certs.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.