简体   繁体   中英

CheckSignature returns false

I have a problem that CheckSignature on simple signing, always fails. I am using SignXml to sign some external data (in my case parts of AS4 payloads) that will be stored as MIME attachments.

Here is the code (modified MS example):

static string flXML = @"D:\Test\Example.xml";
static string flSignedXML = @"D:\Test\SignedExample.xml";
private void button1_Click(object sender, EventArgs e)
{
    try
    {
        // Generate a signing key.
        RSACryptoServiceProvider Key = new RSACryptoServiceProvider();
        CreateSomeXml(flXML);
        SignXmlFile(flXML, flSignedXML, Key);
        bool result = VerifyXmlFile(flSignedXML, Key);

        if (result)
        {
            Console.WriteLine("The XML signature is valid.");
        }
        else
        {
            Console.WriteLine("The XML signature is not valid.");
        }
    }
    catch (CryptographicException ee)
    {
        Console.WriteLine(ee.Message);
    }
}

public static void CreateSomeXml(string FileName)
{
    File.WriteAllText(FileName, "<?xml version=\"1.0\" encoding=\"utf-8\"?><MyElement xmlns=\"samples\"></MyElement>");
}        
private static readonly FieldInfo RefTargetTypeField = typeof(Reference).GetField("m_refTargetType", BindingFlags.Instance | BindingFlags.NonPublic);
private static readonly FieldInfo RefTargetField = typeof(Reference).GetField("m_refTarget", BindingFlags.Instance | BindingFlags.NonPublic);
        public static void SignXmlFile(string FileName, string SignedFileName, RSA Key)
{
    XmlDocument doc = new XmlDocument();
    doc.Load(new XmlTextReader(FileName));
    SignedXml signedXml = new SignedXml(doc);
    signedXml.SigningKey = Key;

        byte[] Content = System.Text.Encoding.UTF8.GetBytes("1234567890asdfghjkl");
        Stream stream = new MemoryStream(Content);
        var attachmentReference = new Reference(uri: "cid:xml-sample") { DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256" };

        const int streamReferenceTargetType = 0;
        RefTargetTypeField.SetValue(attachmentReference, streamReferenceTargetType);
        RefTargetField.SetValue(attachmentReference, stream);

        signedXml.AddReference(attachmentReference);

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

    XmlElement xmlDigitalSignature = signedXml.GetXml();
    doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, true));
    if (doc.FirstChild is XmlDeclaration)
    {
        doc.RemoveChild(doc.FirstChild);
    }
    XmlTextWriter xmltw = new XmlTextWriter(SignedFileName, new UTF8Encoding(false));
    doc.WriteTo(xmltw);
    xmltw.Close();
}
public static Boolean VerifyXmlFile(String Name, RSA Key)
{
    XmlDocument xmlDocument = new XmlDocument();
    xmlDocument.Load(Name);
    SignedXml signedXml = new SignedXml(xmlDocument);
    XmlNodeList nodeList = xmlDocument.GetElementsByTagName("Signature");
    signedXml.LoadXml((XmlElement)nodeList[0]);
    {
        byte[] Content = System.Text.Encoding.UTF8.GetBytes("1234567890asdfghjkl");
        Stream stream = new MemoryStream(Content);
        var attachmentReference = new Reference(uri: "cid:xml-sample") { DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256" };

        const int streamReferenceTargetType = 0;
        RefTargetTypeField.SetValue(attachmentReference, streamReferenceTargetType);
        RefTargetField.SetValue(attachmentReference, stream);

        signedXml.AddReference(attachmentReference);
    }

    // Check the signature and return the result.
    signedXml.SigningKey = Key;
    return signedXml.CheckSignature();
}

Anyone knows what I do wrong? On a side note I know I can specify transformations for additional references. Question is, how do I get result of reference processed by SignedXml so I can store that as well ? For example, if I specify compression for transformation on reference, how can I get now the result of that compression ?

When signature verification fails, it is helpful to enable the logger that provides some more information on what went wrong.

You can enable it by adding this to your app.config file:

<system.diagnostics>
    <sources>
      <source name="System.Security.Cryptography.Xml.SignedXml" switchName="XmlDsigLogSwitch">
        <listeners>
          <add name="xmlDsigLogFile" />
        </listeners>
      </source>
    </sources>

    <switches>
      <add name="XmlDsigLogSwitch" value="Verbose" />
      <!-- possible values: Off (0) Error (1) Warning (2) Info (3) Verbose (4) -->
    </switches>

    <sharedListeners>
      <add name="xmlDsigLogFile" type="System.Diagnostics.TextWriterTraceListener" initializeData="XmlDsigLog.txt" />
    </sharedListeners>

    <trace autoflush="true">
      <listeners>
        <add name="xmlDsigLogFile" />
      </listeners>
    </trace>
  </system.diagnostics>

When your attachment is an XML attachment, you should use the XmlDsigExcC14NTransform transform. When the attachment is not an XML attachment, you should not use it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM