-
Notifications
You must be signed in to change notification settings - Fork 181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Signature value Issue #77
Comments
How are you loading the document in both cases? Typically the problem with different signatures is a result of some differing whitespace which often happens when copying and moving the document around on the filesystem, editing, etc.. which often leads to addition spaces or differing linefeeds in many cases. I would first see what the result of the canonicalization of the document is between the two and make sure they are the same. |
Actually I use bhartkosh Payment and he told me you sign xml documents with cdsco.p12 certificate and he give me url for sending sign xml documents, i ask with this matter he told me i don't have knowledge of php, using System; public partial class b : System.Web.UI.Page
} Please help me |
I sign xml documents with xmlseclib and the result signed xml is online payment testing-Local15 [email protected] waliullahkhanA-621/a,New ashok nagar110096delhidelhidelhiIndia9643603701waliullahkhanA-621/a,New ashok nagar110096delhidelhidelhiIndia9643603701Waliullah KhanEpRiYzJ7rtywFsX3MCju0b8d2wQ=ZfAciFa/diWpSOHNLrpzeBrV0Wt+rFvyhkMhwtfFJDKv6mWV3PCfeMY/lx76QuB1fBlRMYxSesmoRPB/EHZM1HCerWyEfIlFHsgayxBRZBGTkvi62uXlGLm8BZR8fQwcyYPhhKE41J0FEQoVzPmEM5cvgxgaXs+ZHGvCdn279II= MIIDHzCCAoigAwIBAgIJAKQGxAcskoRVMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAklOMQ4wDAYDVQQIEwVERUxISTEXMBUGA1UEBxMOSVRPLCBLT1RBIFJPQUQxDjAMBgNVBAoTBUNEU0NPMREwDwYDVQQLEwhDRFNDTyBIUTEOMAwGA1UEAxMFQ0RTQ08wHhcNMTUwOTA5MTExMzE1WhcNMTYwOTA4MTExMzE1WjBpMQswCQYDVQQGEwJJTjEOMAwGA1UECBMFREVMSEkxFzAVBgNVBAcTDklUTywgS09UQSBST0FEMQ4wDAYDVQQKEwVDRFNDTzERMA8GA1UECxMIQ0RTQ08gSFExDjAMBgNVBAMTBUNEU0NPMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6905X4RXREf/+ZXe0Bhc4M49cCcg7sBK5ZmypHZ2Aaz9T0z456TZ4X7pGWNANJZ3GCmqIZH1o9k8zMMDghtcEKp4gVridei8Gr52XF94i465WyHeRn3n0UGmAm4CJa/gSkz3OL5ttBS2wD1v77mJedFeen8+J6Ga2vawnhS6LkQIDAQABo4HOMIHLMB0GA1UdDgQWBBTCjmDcyWWV306y1l+Mc1gu8audrDCBmwYDVR0jBIGTMIGQgBTCjmDcyWWV306y1l+Mc1gu8audrKFtpGswaTELMAkGA1UEBhMCSU4xDjAMBgNVBAgTBURFTEhJMRcwFQYDVQQHEw5JVE8sIEtPVEEgUk9BRDEOMAwGA1UEChMFQ0RTQ08xETAPBgNVBAsTCENEU0NPIEhRMQ4wDAYDVQQDEwVDRFNDT4IJAKQGxAcskoRVMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAb1kkFWKByuiapHIOWpihILx7vxb6AqQr5mf4rZdTSMQqBRF2bAvfswr4vnE6tb5RmFrTa5O2yZfCgaVtDmGuUGKTfxTD11fIZ1CAWChwfSWDYOPXpwYhZ/SnHVBGvRMQT6sksDlkaLrEMZHkTyDA89hm6Hzh9ic5k0PyFq7u7og=uvdOV+EV0RH//mV3tAYXODOPXAnIO7ASuWZsqR2dgGs/U9M+Oek2eF+6RljQDSWdxgpqiGR9aPZPMzDA4IbXBCqeIFa4nXovBq+dlxfeIuOuVsh3kZ959FBpgJuAiWv4EpM9zi+bbQUtsA9b++5iXnRXnp/Piehmtr2sJ4Uui5E=AQAB when i send this document i found the response is System.NullReferenceException: Object reference not set to an instance of an object. |
Please help if any see the post |
For me the trick was changing:
to
The change changes canonicalization because C14N return different result if Signature node is allready part of main doc vs. Signature node is added after signing is complete. |
@wallii Did that suggestion work for you? It's hard to diagnose without the entire xml documents (post signed) from both systems |
I, too, am having the issue where an XML document signed with XMLSecLibs won't validate on the client-side using C#/.NET. I wonder if anyone could point me to some minimal, working code to try and help me find where I am going wrong? |
@JD-Robbs Can you send me your C# code so I can take a look? |
Hello @robrichards, Thanks so much for offering to take a quick peek, but don't feel obliged to. Please see the relevant verification extract from my C# code below. Essentially, the digest is the same whether I generate it in PHP or C# - and the That said, I don't think this should affect the verification as what's being verified is simply the integrity of the XML document that was signed - and that's where my code appears to fail. Most likely just a misstep somewhere. In both cases, PHP and C#, the resulting XML is 100% identical (except for formatting) - the same namespaces, the same attributes (I'm using SHA1/etc. to emulate the exact settings of my C# signing code) in the digest & signature sections and the same contents. Verification public static void ParseFromBase64(string xmlString, byte[] certPubKeyData)
{
try
{
var certificate = new X509Certificate2(certPubKeyData);
var rsaKey = (RSACryptoServiceProvider) certificate.PublicKey.Key;
rsaKey.PersistKeyInCsp = false; // Fix for multiple request scenarios in Azure
var xmlDocument = new XmlDocument {PreserveWhitespace = false};
xmlDocument.LoadXml(Encoding.UTF8.GetString(Convert.FromBase64String(xmlString)));
if (VerifyXml(xmlDocument, rsaKey))
{
var nodeList = xmlDocument.GetElementsByTagName("Signature");
xmlDocument.DocumentElement?.RemoveChild(nodeList[0]);
var signedXmlToBeUsed = xmlDocument.OuterXml;
// Deserialising the XML here and doing stuff [...]
}
else
{
// Not valid
}
}
catch (Exception ex)
{
// Not valid; logging here...
}
// All good; using the xml (in reality, it's `out`ed from the try block; this part is simply used to return true (not void as in this example)
}
private static bool VerifyXml(XmlDocument xmlDocument, AsymmetricAlgorithm key)
{
if (xmlDocument == null)
{
throw new ArgumentException(nameof(xmlDocument));
}
if (key == null)
{
throw new ArgumentException(nameof(key));
}
var signedXml = new SignedXml(xmlDocument);
var nodeList = xmlDocument.GetElementsByTagName("Signature");
if (nodeList.Count <= 0)
{
throw new CryptographicException("Verification failed: No Signature was found in the document.");
}
if (nodeList.Count >= 2)
{
throw new CryptographicException(
"Verification failed: More than one signature was found for the document.");
}
signedXml.LoadXml((XmlElement) nodeList[0]);
return signedXml.CheckSignature(key); // It fails here (returns false)
} The public key data comes from a certificate embedded in the assembly (I'm aware this is not ideal; but works when verifying C#-generated signatures): private static void SetCertificatePublicKeyData(Assembly assembly)
{
using (var mem = new MemoryStream())
{
assembly.GetManifestResourceStream(assembly.GetName().Name + ".MyCert.cer")?.CopyTo(mem);
_certificatePublicKeyData = mem.ToArray();
}
} SigningThe private key data is procured similarly to the above, just with a password. Everything uses the same certificates as the PHP code, just that the PHP code uses a *.pem generated from a *.pfx. public static string GenerateBase64String(TypeToSign xmlToSign, byte[] certPrivateKeyData,
SecureString certFilePwd)
{
var xmlDocument = new XmlDocument {PreserveWhitespace = false};
using (var writer = new StringWriter())
{
var serializer = new XmlSerializer(typeof(TypeToSign), new[] { xmlToSign.GetType()});
serializer.Serialize(writer, xmlToSign);
xmlDocument.LoadXml(writer.ToString());
}
// Set storage flags to ensure it runs on Azure/IIS
var cert = new X509Certificate2(certPrivateKeyData, certFilePwd, X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable);
var rsaKey = (RSACryptoServiceProvider) cert.PrivateKey;
rsaKey.PersistKeyInCsp = false; // Fix for multiple request scenarios in Azure
SignXmlDocument(xmlDocument, rsaKey);
return Convert.ToBase64String(Encoding.UTF8.GetBytes(xmlDocument.OuterXml));
} PHP Code (If Required)use RobRichards\XMLSecLibs\XMLSecurityDSig;
use RobRichards\XMLSecLibs\XMLSecurityKey;
$xmlDoc = new DOMDocument('1.0', 'utf-16');
$xmlDoc->encoding = 'utf-16';
$xmlDoc->preserveWhiteSpace = true;
$xmlDoc->formatOutput = false;
$rootNode = $xmlDoc->createElement('MyBaseXmlElement');
$rootNode->setAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema');
$rootNode->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$rootNode->setAttribute('xsi:type', 'MyType');
$xmlData = [
];
foreach ($xmlData as $k => $v) {
$dataRow = $xmlDoc->createElement($k, $v);
$rootNode->appendChild($dataRow);
}
$xmlDoc->appendChild($rootNode);
$signature = new XMLSecurityDSig('');
$signature->setCanonicalMethod(XMLSecurityDSig::C14N);
$signature->addReference(
$xmlDoc,
XMLSecurityDSig::SHA1,
['http://www.w3.org/2000/09/xmldsig#enveloped-signature'],
['force_uri' => true]
);
$signatureKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private'));
$signatureKey->passphrase = 'PASS';
$signatureKey->loadKey(__DIR__ . '/keys/MyCert.pem', true);
$signature->sign($signatureKey, $xmlDoc->documentElement);
die($xmlDoc->saveXML()); |
Just saw there's a 'Prepare for release' commit. Just wondering if the upcoming release might potentially help with the above? I started porting my app to ASP.NET Core, but am slowly beginning to realise how many features it is lacking (EF, Identity, etc.). So I'd much rather stick with my PHP app for the server. |
Alternatively, maybe a different encryption algorithm works to sign in PHP and validate in .NET? Happy to change my client side code. |
I didn't get a chance yet to take a look but just glancing at the code above are you treating whitespace the same in each? In PHP code there is $xmlDoc->preserveWhiteSpace = true; while in C# you are doing var xmlDocument = new XmlDocument {PreserveWhitespace = false}; That will make the world of difference if those are handled differently |
No problem at all and thanks a lot for the pointer. Setting But just for my own understanding: not sure why white space, or even the content of the XML would make a difference when verifying the signature in C#. After all, it only verifies that the XML (as at the time of signing it) has not been tampered with. All this being said, you wouldn't, by any chance, have a working/minimal example flying around somewhere that signs XML in PHP and verifies it in .NET? I'd love to take a look and compare it to my code to see what the culprit is - maybe it could yield a test case. |
Well it does in a manner as the signature value is calculated over the canonicalization of the SignedInfo node and children so whitespace there would come into play. I will look around for some of my C# code. The majority was using WSE as I tested the XMLDSig in conjunction with SOAP interoperability. Do you happen to have a copy of the raw generated SignedInfo elements from both C# and PHP? |
Oh right - well, thanks for the edification! In that case, white space may well be the issue as you mentioned. From the below, you can see that the PHP version contains extra white space between nodes that doesn't exist in the version signed by C# (this example was run with It looks like this might be the culprit, although I'm not sure if there are configuration options to make the two play ball. Signed by C#:
Signed by PHP:
|
No those spaces don't matter. just the ones between nodes themselves. Can you try using exclusive canonicalization? $objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N); That is a much simpler method of canonicalizing and am wondering if there is some compatibility issue/bug going on there for some reason? |
Ah yes |
@robrichards Thanks a lot for looking into it here's a PasteBin of the raw text since it appears that GitHub removed some of the white space. There's actually more (including newlines). Looking at the base template in the code, it is formatted. I'll change that in my version and will check if that makes a difference. I will also look into using the other canonicalisation method you mentioned - if I manage to work-out the right counterpart in .NET, that is. |
The exclusive canonicalisation method didn't work in my case, and having removed white space from the certificate node template yielded the same result. I'll try a few more/different things and will report back if anything changes. |
@robrichards - success! When removing the white space form the XML template in the library, I forgot to also amend the namespaced version. After making the following changes, I am able to verify the signature in .NET:
I'd send a pull request, but I am not sure if this change might have unintended consequences for other folks. Alternatively, how about a configuration flag that removes the white space? |
Just an addendum: to be precise, the aforementioned change makes it work with the |
That is really odd. I will need to play around with this more. At least EXC_C14N is the preferred method of canonicalization due to its compactness |
Thanks, though, for getting me onto the right track! At least it's all working now that I've locally changed the template and am using |
Hi @JD-Robbs can you share the complete code in c# |
@robrichards wow cannot believe this open issue hit me after almost 8 years of being opened, and there WAS PR to fix this #221. 🤦♂️ Now there are two - #248 |
i sign a xml document with this library: my digest value is
EpRiYzJ7rtywFsX3MCju0b8d2wQ= and verify with c# digest value same but signature value is different
in php signature value is
fFOdzfsLC9MJsnqDdvpT1/NKrzNvjbq0dJxmOfsYU3K4mZy3gzqllF/EOqh6B3gf9DP8lr4j9I34LI4RIOeR3VdnT5bAhuGNiZtC94DU4qRm5JcRmUpAH16h6FovUMPxF2s3rdAINAHpE5dBYEoMHscQvmS5buR/o9+qxjOvhwA=
but in c# signature value is
a+S3u56Z9UbWi8AI+aQDYrYwHY4u6ZWt1OREsi5gCVOctO0noXABK8ORw3UnnMhB8IpmSt0l1Dko
W4Ks4bUk59dcSg4t12K2g/8BAxbvC0e/pvbINS4cUWHPBXs5kby4ysiF1lST2ui1GJ5XHih58zfq
kfKc40U814CXxt8mkkg=
i see the class of XMLSecurityKey
and see the method of calculating signature value some doubt are found
i print the $objDSig->sign($objKey);
and result is
RobRichards\XMLSecLibs\XMLSecurityKey Object
(
[cryptParams:RobRichards\XMLSecLibs\XMLSecurityKey:private] => Array
(
[library] => openssl
[method] => http://www.w3.org/2000/09/xmldsig#rsa-sha1
[padding] => 1
[type] => private
)
)
$sigValue = base64_encode($this->signData($objKey, $data));
$objkey
RobRichards\XMLSecLibs\XMLSecurityKey Object
(
[cryptParams:RobRichards\XMLSecLibs\XMLSecurityKey:private] => Array
(
[library] => openssl
[method] => http://www.w3.org/2000/09/xmldsig#rsa-sha1
[padding] => 1
[type] => private
)
)
$data "is the digestvalue"
EpRiYzJ7rtywFsX3MCju0b8d2wQ=
please help me if any how i calculate valid signature value
i want to sign a xmldocument with cdsco.p12 file and dd certificate
problem occur in signature value
Please help me
The text was updated successfully, but these errors were encountered: