.netx509xml-dsig

How can I compare public keys in .NET?


I've got an X509Certificate2 containing a public key. I've got an RSACryptoServiceProvider (which came from calling SignedXml.CheckSignatureReturningKey), also containing a public key.

I want to find out if one came from the other. How can I compare the two?


Solution

  • You can compare the PublicKey property of signing certificates in the SignedXml.KeyIfo with signing key output from SignedXml.CheckSignatureReturningKey. This C# extension method does the job for me:

    public static bool CheckSignatureReturningCertificate(this SignedXml signedXml, out X509Certificate2 signingCertificate)
    {
        signingCertificate = null;
        AsymmetricAlgorithm signingKey;
        bool isValid = signedXml.CheckSignatureReturningKey(out signingKey);
        if (isValid)
        {
            IEnumerable<X509Certificate2> keyInfoCertificates =
                signedXml.KeyInfo.OfType<KeyInfoX509Data>()
                    .SelectMany(x => x.Certificates.Cast<X509Certificate2>());
    
            signingCertificate = keyInfoCertificates.FirstOrDefault(x => x.PublicKey.Key == signingKey);
            if (signingCertificate == null)
            {
                throw new Exception("Signing certificate not found in KeyInfo.");
            }
        }
    
        return isValid;
    }
    

    Use it like this:

    X509Certificate2 signingCertificate = null;
    bool isValid = signedXml.CheckSignatureReturningCertificate(out signingCertificate);
    if(isValid)
    {
        // signingCertificate now contains the certificate used to sign
    }