6
votes

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>
2
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
Thanks for your hint, I added the XML. KeyInfo contains the certificate, base64 decoded.chanser
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
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
Would you know any other way to successfully verify a RSA SHA512 signature?chanser

2 Answers

8
votes

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.

2
votes

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 );