6

With the help of the MSDN site about SignedXml, I can easily verify if an XML DSig is correct. It works perfectly if the signature method sha1 was used.

However, when I receive the SignatureMethod RSA-SHA512 (http://www.w3.org/2001/04/xmldsig-more#rsa-sha512), CheckSignature() breaks with an CryptograhicException: SignatureDescription could not be created for the signature algorithm supplied.

It seems like CheckSignature() is not able to verify RSA-SHA512 signatures.

Does anyone know how to check these kind of signatures?

The code, taken from the MSDN site, is:

public static bool VerifyXml(XmlDocument doc, bool removeSignatureElement = false)
{
    // Check arguments.
    if (doc == null)
        throw new ArgumentException("doc");

    // Create a new SignedXml object and pass it the XML document class.
    SignedXml signedXml = new SignedXml(doc);

    // Find the "Signature" node and create a new XmlNodeList object.
    XmlNodeList nodeList = doc.GetElementsByTagName("Signature", Constants.NamespaceDSig);

    // Throw an exception if no signature was found.
    if (nodeList.Count < 1)
    {
        throw new CryptographicException("Verification failed: No Signature was found in the document.");
    }

    // This example only supports one signature for the entire XML document.  Throw an exception if more than one signature was found.
    if (nodeList.Count > 1)
    {
        throw new CryptographicException("Verification failed: More that one signature was found for the document.");
    }

    // Load the first <signature> node.  
    signedXml.LoadXml((XmlElement)nodeList[0]);

    // Check the signature and return the result.
    bool signedCorrectly = signedXml.CheckSignature(); // throws the Exception!!!

    return signedCorrectly;
}

The signed XML is:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Notification xmlns="http://www.xxxxxxxxxxx.xx/xxxxx">
    <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Content"> ... </xenc:EncryptedData>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"/>
            <ds:Reference URI="">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <ds:DigestValue>WsHcyNL7Jh8HSzR9ArzTqomBkHs=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
pWDatSEbypIUVQR9NFmLkB9kKWjMb6rKWGFFvGqT5tOUILeDhMHUqjCRB9v/g6yYdogC9TRWouhz
...VoZAIBs7EqCbLt7RgpB4GHWc9E3qp65NaCgluw==
        </ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>
MIIG+zCCBOOgAwIBAgIHAe2+sRfTfDANBgkqhkiG9w0BAQUFADCBkTELMAkGA1UEBhMCQVQxDTAL
...tvawqBjOfkw1yeDzsDMJHfMuAcpYfrEL
                </ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
</Notification>
chanser
  • 181
  • 2
  • 8
  • 1
    Can you possibly show an example of your signed document? In particular, what is the content of the KeyInfo? What form is used to pass the certificate information? – Wiktor Zychla Dec 10 '13 at 16:03
  • Thanks for your hint, I added the XML. KeyInfo contains the certificate, base64 decoded. – chanser Dec 11 '13 at 11:18
  • 1
    Unfortunately, according to my research, the RSA-SHA512 is just not supported. I get the very exact exception. Decompile the `CryptoConfig` class, especially the `DefaultNameHT` property for a list of supported algorithms. – Wiktor Zychla Dec 11 '13 at 13:46
  • Hi Wiktor, I'm afraid you're right. I decompiled `SignedXml` and only can find a namespace for rsa-sha1: `XmlDsigRSASHA1Url`. I think you could post this as an answer; it'll be use ful for others. – chanser Dec 11 '13 at 14:59
  • Would you know any other way to successfully verify a RSA SHA512 signature? – chanser Dec 11 '13 at 15:00
  • Edited my answer. I probably found a way to make it work. – Wiktor Zychla Dec 11 '13 at 15:22

2 Answers2

9

You can verfify RSA SHA512 signatures but you'll have to implement and register the signature description by yourself.

Signature description:

public sealed class RSAPKCS1SHA512SignatureDescription : SignatureDescription
{
    public RSAPKCS1SHA512SignatureDescription()
    {
        KeyAlgorithm = typeof( RSACryptoServiceProvider ).FullName;
        DigestAlgorithm = typeof( SHA512Managed ).FullName;
        FormatterAlgorithm = typeof( RSAPKCS1SignatureFormatter ).FullName;
        DeformatterAlgorithm = typeof( RSAPKCS1SignatureDeformatter ).FullName;
    }

    public override AsymmetricSignatureDeformatter CreateDeformatter( AsymmetricAlgorithm key )
    {
        if( key == null )
        {
            throw new ArgumentNullException( "key" );
        }

        var deformatter = new RSAPKCS1SignatureDeformatter( key );
        deformatter.SetHashAlgorithm( "SHA512" );
        return deformatter;
    }

    public override AsymmetricSignatureFormatter CreateFormatter( AsymmetricAlgorithm key )
    {
        if( key == null )
        {
            throw new ArgumentNullException( "key" );
        }

        var formatter = new RSAPKCS1SignatureFormatter( key );
        formatter.SetHashAlgorithm( "SHA512" );
        return formatter;
    }
}

In your code you'll have to register this description with CryptoConfig:

const string XmlDsigRsaSha512 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512";
CryptoConfig.AddAlgorithm( typeof( RSAPKCS1SHA512SignatureDescription ), XmlDsigRsaSha512 );

I tested it with .Net 4.0 on Windows 7 64 Bit.

BitSchupser
  • 432
  • 3
  • 13
1

According to my research, only following signature methods are supported by the SignedXml implementation:

http://www.w3.org/2000/09/xmldsig#hmac-sha1
http://www.w3.org/2001/04/xmldsig-more#hmac-sha256
http://www.w3.org/2001/04/xmldsig-more#hmac-sha384
http://www.w3.org/2001/04/xmldsig-more#hmac-sha512
http://www.w3.org/2001/04/xmldsig-more#hmac-md5
http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160

These can be used to both sign and verify. Unfortunately, the

http://www.w3.org/2001/04/xmldsig-more#rsa-sha512

used as your signature algoritm is not supported.

Ultimately, all crypto methods go down to CryptoConfig.CreateFromName where the rsa-sha512 returns null.

Edit: I might have just found a way to make it work. Following snippet works for me:

        Dictionary<string, object> ht =
            (Dictionary<string, object>)typeof( CryptoConfig ).InvokeMember( 
            "DefaultNameHT", System.Reflection.BindingFlags.GetProperty | 
            System.Reflection.BindingFlags.Static | 
            System.Reflection.BindingFlags.NonPublic, null, typeof( CryptoConfig ), 
            null );

        var o = ht["http://www.w3.org/2000/09/xmldsig#rsa-sha1"];
        ht["http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"] = o;

This should be called before you sign/validate.

This is based on the observation that the actual hash verification comes from the certificate and the algorithm name is only used as a guard. If you trick the configuration to think that the RSA-SHA512 is supported (by pointing to the same RSA-SHA1 formatter which is not used), things start to work.

Edit2: After further investigation involving consulting sources

http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/clr/src/ManagedLibraries/Security/System/Security/Cryptography/Xml/SignedXml@cs/1305376/SignedXml@cs

I think that the above solution will not work. What it does it only changes the signature name in the signed document, however unfortunately the signature is still computed using RSA-SHA1.

The only way to make it work would be to implement the RSA-SHA512 as KeyedHashAlgoritm as both signing and verification seem to support it with overloaded versions:

signedXml.ComputeSignature( KeyedHashAlgorithm hash );
signedXml.CheckSignature( KeyedHashAlgorithm hash );
Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
  • It unfortunately does not work. if I use it. How do use it before signing? ht does not seem to be connected to SignedXml. Could you maybe share more code? – chanser Dec 11 '13 at 16:20
  • It is not connected but the SignedXml uses it internally. Do tou still get the exception or the validation just fails? – Wiktor Zychla Dec 11 '13 at 16:25
  • CheckSignature() just return false, and I know that the signature is okay, because a public webservice that I trust (http://www.buergerkarte.at/signature-verification/) tells me so. And when I sign an XML with the changed ht, still the code produces sha1. – chanser Dec 11 '13 at 16:42
  • Finally, I switched to Java because it looked like to much work to do it in C#. An easy Java example directly were able to verify the signature: http://docs.oracle.com/javase/7/docs/technotes/guides/security/xmldsig/Validate.java – chanser Dec 12 '13 at 07:47
  • I've edited my answer. After quite a struggle, I finally gave up. Sorry to give you false hope. – Wiktor Zychla Dec 12 '13 at 07:50