1

I want to sign XML using the pkcs11Interop library, I am using below code to sign XML but signature verification fails.

when I use System.Security.Cryptography.Xml.SignedXml to sign it passes signature verification.

The DigestValue generated by my method and SignedXml are same but signatures are different, even though I am using the same certificate to sign.

Steps Followed

  1. Generate XmlDsigC14NTransform and create the sha1 hash.
  2. Sign hash using pkcs11interop.

Code

public static string SignXml(string xmlValueToSign)
{
        try
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xmlValueToSign);

            XmlDsigC14NTransform xmlDsigC14NTransform = new XmlDsigC14NTransform();
            xmlDsigC14NTransform.LoadInput(xmlDoc);
            using (Stream xmlDsigC14NTransformStream = (Stream)xmlDsigC14NTransform.GetOutput(typeof(Stream)))
            {
                SHA1 sha1 = SHA1.Create();
                byte[] hash = sha1.ComputeHash(xmlDsigC14NTransformStream);

                string base64DigestString = Convert.ToBase64String(hash);
                string xmlSignatureValue = "";

                //Get session 
                //get private key handle

                using (Mechanism mechanism = new Mechanism(CKM.CKM_RSA_PKCS))
                    xmlSignatureValue = Session.Sign(mechanism, PrivateKeyHandle, hash);

                string base64CertificateValue = Convert.ToBase64String(x509Certificate2.RawData);

                string nameSpace = "http://www.w3.org/2000/09/xmldsig#";

                XmlDocument signatureDoc = new XmlDocument();

                XmlElement signatureElement = signatureDoc.CreateElement(string.Empty, "Signature", nameSpace);
                signatureDoc.AppendChild(signatureElement);

                //SignedInfo
                XmlElement signedInfoElement = signatureDoc.CreateElement(string.Empty, "SignedInfo", nameSpace);
                signatureElement.AppendChild(signedInfoElement);

                //CanonicalizationMethod
                XmlElement canonicalizationMethodElement = signatureDoc.CreateElement(string.Empty, "CanonicalizationMethod", nameSpace);
                canonicalizationMethodElement.SetAttribute("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
                signedInfoElement.AppendChild(canonicalizationMethodElement);

                //SignatureMethod
                XmlElement signatureMethodElement = signatureDoc.CreateElement(string.Empty, "SignatureMethod", nameSpace);
                signatureMethodElement.SetAttribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
                signedInfoElement.AppendChild(signatureMethodElement);

                //Reference
                XmlElement referenceElement = signatureDoc.CreateElement(string.Empty, "Reference", nameSpace);
                referenceElement.SetAttribute("URI", "");
                signedInfoElement.AppendChild(referenceElement);

                //Transforms
                XmlElement transformsElement = signatureDoc.CreateElement(string.Empty, "Transforms", nameSpace);
                referenceElement.AppendChild(transformsElement);

                //Transform
                XmlElement transformElement = signatureDoc.CreateElement(string.Empty, "Transform", nameSpace);
                transformElement.SetAttribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#enveloped-signature");
                transformsElement.AppendChild(transformElement);

                //DigestMethod
                XmlElement digestMethodElement = signatureDoc.CreateElement(string.Empty, "DigestMethod", nameSpace);
                digestMethodElement.SetAttribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
                referenceElement.AppendChild(digestMethodElement);

                //DigestValue
                XmlElement digestValueElement = signatureDoc.CreateElement(string.Empty, "DigestValue", nameSpace);
                XmlText digestValue = signatureDoc.CreateTextNode(base64DigestString);
                digestValueElement.AppendChild(digestValue);
                referenceElement.AppendChild(digestValueElement);

                //SignatureValue
                XmlElement signatureValueElement = signatureDoc.CreateElement(string.Empty, "SignatureValue", nameSpace);
                XmlText signatureValue = signatureDoc.CreateTextNode(xmlSignatureValue);
                signatureValueElement.AppendChild(signatureValue);
                signatureElement.AppendChild(signatureValueElement);

                //KeyInfo
                XmlElement keyInfoElement = signatureDoc.CreateElement(string.Empty, "KeyInfo", nameSpace);
                signatureElement.AppendChild(keyInfoElement);

                //X509Data 
                XmlElement x509DataElement = signatureDoc.CreateElement(string.Empty, "X509Data", nameSpace);
                keyInfoElement.AppendChild(x509DataElement);

                //X509Certificate  
                XmlElement x509CertificateElement = signatureDoc.CreateElement(string.Empty, "X509Certificate", nameSpace);
                XmlText x509CertificateValue = signatureDoc.CreateTextNode(base64CertificateValue);
                x509CertificateElement.AppendChild(x509CertificateValue);

                x509DataElement.AppendChild(x509CertificateElement);

                xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(signatureElement, true));
                var signedXml = xmlDoc.OuterXml;
                return signedXml;
            }
        }
        catch (Exception)
        {
            throw;
        }
    }
Prashanth
  • 507
  • 5
  • 25
  • Is there any reason why you are building the whole signed XML structure yourself instead of using `System.Security.Cryptography.Xml.SignedXml`? – jariq Jan 02 '18 at 08:10
  • If I use `System.Security.Cryptography.Xml.SignedXml` there will be a UI dialog to enter the password for the token, as this method will be running as windows service we cannot display any UI to enter the password. – Prashanth Jan 02 '18 at 09:08
  • 2
    Pkcs11Interop can be easily integrated with `SignedXml` class using [Pkcs11Interop.X509Store](https://github.com/Pkcs11Interop/Pkcs11Interop.X509Store) library. For more details see [my previous answer to similar question](https://stackoverflow.com/a/46440711/3325704). – jariq Jan 02 '18 at 11:20
  • thanks @jariq it was very helpful – Prashanth Jan 10 '18 at 07:07

0 Answers0