Click here to Skip to main content
16,013,747 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hi, I have one big problem and spend a lot of time for this...

I need to sign xml with XAdES template. I am using 2 references. The problem is with second, if I add Transform, it will work fine (signedXml.CheckSignature() return True), without this transform it will return False.

I even modified this project (http://xadesnet.codeplex.com/[^]) but still same problem.

Should I paste all code?
C#
System.Security.Cryptography.Xml.Reference reference2; 
System.Security.Cryptography.Xml.SignedXml signedXml;
... 
reference2 = new Reference();
reference2.Type = "http://uri.etsi.org/01903/v1.1.1#SignedProperties";
reference2.Uri = "#SignedPropertiesId";
//reference2.AddTransform(new XmlDsigExcC14NTransform()); IF I COMMENT THIS LINE IT WONT WORK
signedXml.AddReference(reference2);

signedXml.ComputeSignature();
XmlElement xmlDigitalSignature = signedXml.GetXml();
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));

signedXml.CheckSignature(); //return false if dont use Transform in second REF


Signature should look like this one (so, without transforms), it can be all in one line:
HTML
<ds:Signature Id="SignatureId">
  <ds:SignedInfo>
    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
    <ds:Reference Type="http://www.gzs.si/shemas/eslog/racun/1.5#Racun" URI="#data">
      <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
      <ds:DigestValue>gvhK+4+omtrJ6zIQrTlKse+H8P2s=</ds:DigestValue>
    </ds:Reference>
    <ds:Reference Type="http://uri.etsi.org/01903/v1.1.1#SignedProperties" URI="#SignedPropertiesId">
      <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
      <ds:DigestValue>cmbsiUG07eZmIoZBTc1rs7TRUIqU=</ds:DigestValue>
    </ds:Reference>
  </ds:SignedInfo>
  <ds:SignatureValue>signature value...</ds:SignatureValue>
  <ds:KeyInfo>
    <ds:X509Data>
      <ds:X509Certificate>cert...</ds:X509Certificate>
    </ds:X509Data>
  </ds:KeyInfo>
  <ds:Object>
    <xds:QualifyingProperties Target="#SignatureId">
      <xds:SignedProperties Id="SignedPropertiesId">
        <xds:SignedSignatureProperties>
          <xds:SigningTime>2011-09-05T09:11:24.268Z</xds:SigningTime>
          <xds:SigningCertificate>
            <xds:Cert>
              <xds:CertDigest>
                <xds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1">
                </xds:DigestMethod>
                <xds:DigestValue>Le0DZovyhX7oXFyNs/rc4DHjQ3Lo=</xds:DigestValue>
              </xds:CertDigest>
              <xds:IssuerSerial>
                <ds:X509IssuerName>OU=svigen-ca,O=state-institutions,C=si</ds:X509IssuerName>
                <ds:X509SerialNumber>994015377</ds:X509SerialNumber>
              </xds:IssuerSerial>
            </xds:Cert>
          </xds:SigningCertificate>
          <xds:SignaturePolicyIdentifier>
            <xds:SignaturePolicyImplied>
            </xds:SignaturePolicyImplied>
          </xds:SignaturePolicyIdentifier>
        </xds:SignedSignatureProperties>
      </xds:SignedProperties>
    </xds:QualifyingProperties>
  </ds:Object>
</ds:Signature>


Thanks.
Posted
Updated 1-Mar-12 13:19pm
v2

hi,

first I don't have used XAdES template so far, so this is not a final answer I think. It seems it is really needed to transform your XML to work properly.

Try adding xmlDoc.PreserveWhitespace = true .

Unfortunately, just my only idea at the moment.

Regards
 
Share this answer
 
I use XAdESSignedXml class from http://xadesnet.codeplex.com/[^]...

i have problem with references when use -> reference2.Uri = "#SignedPropertiesId"; if Uri is some xml data it works well (as my first reference)

try on this XML http://www.2shared.com/document/DilKQ4Fk/racun_1202017254742.html[^][^], remove signature from it.

XAdESSignedXml : SignedXml
C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography.Xml;
using System.Xml;

namespace TestProject1
{
    internal sealed class XAdESSignedXml : SignedXml
    {
        private readonly List<dataobject> _dataObjects = new List<dataobject>();
        public const string XadesSignaturePropertiesNamespace = "http://uri.etsi.org/01903/v1.1.1#SignedProperties";

        public XAdESSignedXml(XmlDocument document) : base(document) { }

        public override XmlElement GetIdElement(XmlDocument doc, string id)
        {
            if (String.IsNullOrEmpty(id)) return null;

            XmlElement xmlElement = base.GetIdElement(doc, id);
            if (xmlElement != null) return xmlElement;

            //if (_dataObjects.Count == 0) return null;
            foreach (DataObject dataObject in _dataObjects)
            {
                XmlElement nodeWithSameId = findNodeWithAttributeValueIn(dataObject.Data, "Id", id);
                if (nodeWithSameId != null)
                    return nodeWithSameId;
            }
            if (KeyInfo != null)
            {
                XmlElement nodeWithSameId = findNodeWithAttributeValueIn(KeyInfo.GetXml().SelectNodes("."), "Id", id);
                if (nodeWithSameId != null)
                    return nodeWithSameId;
            }
            return null;
        }
        public new void AddObject(DataObject dataObject)
        {
            base.AddObject(dataObject);
            _dataObjects.Add(dataObject);
        }

        public XmlElement findNodeWithAttributeValueIn(XmlNodeList nodeList, string attributeName, string value)
        {
            if (nodeList.Count == 0) return null;
            foreach (XmlNode node in nodeList)
            {
                XmlElement nodeWithSameId = findNodeWithAttributeValueIn(node, attributeName, value);
                if (nodeWithSameId != null) return nodeWithSameId;
            }
            return null;
        }

        private XmlElement findNodeWithAttributeValueIn(XmlNode node, string attributeName, string value)
        {
            string attributeValueInNode = getAttributeValueInNodeOrNull(node, attributeName);
            if ((attributeValueInNode != null) && (attributeValueInNode.Equals(value))) return (XmlElement)node;
            return findNodeWithAttributeValueIn(node.ChildNodes, attributeName, value);
        }

        private string getAttributeValueInNodeOrNull(XmlNode node, string attributeName)
        {
            if (node.Attributes != null)
            {
                XmlAttribute attribute = node.Attributes[attributeName];
                if (attribute != null) return attribute.Value;
            }
            return null;
        }
    }
}
</dataobject></dataobject>


AND my method:
C#
private string signEracun(string xml, X509Certificate2 certificate)
{
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.PreserveWhitespace = false;
    xmlDoc.LoadXml(xml);

    #region signing

    TestProject1.XAdESSignedXml signedXml = new TestProject1.XAdESSignedXml(xmlDoc);
    signedXml.Signature.Id = "SignatureId";

    #region object -> signatureProperties
    XmlElement signaturePropertiesRoot;
    XmlElement qualifyingPropertiesRoot;
    string URI = "http://uri.etsi.org/01903/v1.1.1#";
    qualifyingPropertiesRoot = xmlDoc.CreateElement("xds", "QualifyingProperties", URI);
    qualifyingPropertiesRoot.SetAttribute("Target", "#SignatureId");

    signaturePropertiesRoot = xmlDoc.CreateElement("xds", "SignedProperties", URI);
    signaturePropertiesRoot.SetAttribute("Id", "SignedPropertiesId");

    XmlElement SignedSignatureProperties = xmlDoc.CreateElement("xds", "SignedSignatureProperties", URI);

    XmlElement timestamp = xmlDoc.CreateElement("xds", "SigningTime", URI);
    timestamp.InnerText = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); //2011-09-05T09:11:24.268Z
    SignedSignatureProperties.AppendChild(timestamp);

    XmlElement SigningCertificate = xmlDoc.CreateElement("xds", "SigningCertificate", URI);
    XmlElement Cert = xmlDoc.CreateElement("xds", "Cert", URI);
    XmlElement CertDigest = xmlDoc.CreateElement("xds", "CertDigest", URI);
    SHA1 cryptoServiceProvider = new SHA1CryptoServiceProvider();
    byte[] sha1 = cryptoServiceProvider.ComputeHash(certificate.RawData);
    XmlElement DigestMethod = xmlDoc.CreateElement("xds", "DigestMethod", URI); DigestMethod.SetAttribute("Algorithm", SignedXml.XmlDsigSHA1Url);
    XmlElement DigestValue = xmlDoc.CreateElement("xds", "DigestValue", URI); DigestValue.InnerText = Convert.ToBase64String(sha1);
    CertDigest.AppendChild(DigestMethod);
    CertDigest.AppendChild(DigestValue);
    Cert.AppendChild(CertDigest);

    XmlElement IssuerSerial = xmlDoc.CreateElement("xds", "IssuerSerial", URI);
    XmlElement X509IssuerName = xmlDoc.CreateElement("ds", "X509IssuerName", "http://www.w3.org/2000/09/xmldsig#"); X509IssuerName.InnerText = certificate.IssuerName.Name;
    XmlElement X509SerialNumber = xmlDoc.CreateElement("ds", "X509SerialNumber", "http://www.w3.org/2000/09/xmldsig#"); X509SerialNumber.InnerText = certificate.SerialNumber;
    IssuerSerial.AppendChild(X509IssuerName);
    IssuerSerial.AppendChild(X509SerialNumber);
    Cert.AppendChild(IssuerSerial);

    SigningCertificate.AppendChild(Cert);
    SignedSignatureProperties.AppendChild(SigningCertificate);

    signaturePropertiesRoot.AppendChild(SignedSignatureProperties);
    qualifyingPropertiesRoot.AppendChild(signaturePropertiesRoot);
    DataObject dataObject = new DataObject
    {
        Data = qualifyingPropertiesRoot.SelectNodes("."),
    };
    signedXml.AddObject(dataObject);
    #endregion

    // Add the key to the SignedXml document.
    signedXml.SigningKey = certificate.PrivateKey;

    KeyInfo keyInfo = new KeyInfo();
    KeyInfoX509Data keyInfoX509Data = new KeyInfoX509Data(certificate, X509IncludeOption.ExcludeRoot);
    keyInfo.AddClause(keyInfoX509Data);
    signedXml.KeyInfo = keyInfo;

    //Reference 1
    Reference reference2 = new Reference();
    reference2.Type = "http://www.gzs.si/shemas/eslog/racun/1.5#Racun";
    reference2.Uri = "#data";
    signedXml.AddReference(reference2);

    //Reference 2
    reference2 = new Reference();
    reference2.Type = "http://uri.etsi.org/01903/v1.1.1#SignedProperties";
    reference2.Uri = "#SignedPropertiesId";
    //reference2.AddTransform(new XmlDsigExcC14NTransform());
    signedXml.AddReference(reference2);

    // Compute the signature.
    signedXml.ComputeSignature();

    // Get the XML representation of the signature and save
    // it to an XmlElement object.
    XmlElement xmlDigitalSignature = signedXml.GetXml();

    xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
    #endregion

    //check XML signature, return false if dont use transorm in seckont reference
    bool checkSign = signedXml.CheckSignature();

    return xmlDoc.OuterXml;

}



Björn Ranft thank you for your help.
Regards
 
Share this answer
 
Comments
El_Codero 8-Mar-12 19:44pm    
Hi, could you please write comments instead of posting new solutions? Second thing is we're alway trying to help but researching with debugger helps a lot. You're problem is specified, I think here are just a few people who're using this library, there are so many projects out there but normally they're easy to use. I think the Discussion forum from this library is the right place to ask for your problem. There're serveral lines of your code which I would proof for, but your goal is actually to get an output of the signed xml (for sure ;)).
I've just looked on codeplex project and this Class seems exactly to do what you need. Please give a feedback if it works for you.

http://xadesnet.codeplex.com/wikipage?title=XMLDSIG%20Sign&referringTitle=Documentation


With Best Regards, Björn
jaka88 19-Mar-12 8:44am    
It work but signedXml.CheckSignature() method return false.
signature is not valid...

for now I will use just first reference.

Regards
ChuckBorris 10-Mar-14 4:06am    
Thank you for sharing your solution jaka88!
Did you manage to solve problems with second reference?
I already try this, but same problem...

thank anyway.

Regards
 
Share this answer
 
Comments
El_Codero 1-Mar-12 18:43pm    
ok after diggin to problem it seems it's a bug. See last answer.
See http://stackoverflow.com/questions/5495336/problem-with-custom-namespace-with-signedxml
jaka88 2-Mar-12 2:07am    
so I can't do that with c#?
El_Codero 2-Mar-12 9:24am    
you can do it and it's needed to use XmlDsigExcC14NTransform Class, good example at msdn:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.xml.xmldsigexcc14ntransform.aspx
jaka88 2-Mar-12 9:53am    
I have a lot of xml files witch are signed without transform but still valid.

example:
http://www.2shared.com/document/DilKQ4Fk/racun_1202017254742.html[^]

Regards
El_Codero 4-Mar-12 16:57pm    
Could you share the whole project? I tried the MSDN Example with two refernces, works as it should be.
http://msdn.microsoft.com/de-de/library/system.security.cryptography.xml.xmldsigexcc14ntransform.aspx
What do you mean with "modified xadesnet project"?
Regards

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900