Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SignedCms.CheckSignature fails on ECDSA signatures signed by Win32 #91168

Closed
jborean93 opened this issue Aug 27, 2023 · 3 comments
Closed

SignedCms.CheckSignature fails on ECDSA signatures signed by Win32 #91168

jborean93 opened this issue Aug 27, 2023 · 3 comments

Comments

@jborean93
Copy link
Contributor

jborean93 commented Aug 27, 2023

Description

When signing a file using the Windows APIs with a signature using an ECDSA key Windows will set the signatureAlgorithm in the SignerInfo to the OID 1.2.840.10045.2.1 (ECC) unlike dotnet 5+ which sets it to the OID to the hash algorithm specific OID in the namespace 1.2.840.10045.4.3.. This is a problem when it comes to validating the signature as CmsSignature.ECDsa tries to verify the hash algorithm OID with associated hash algorithm of this value which for 1.2.840.10045.2.1 there is none.

if (_expectedDigest != digestAlgorithmName)
{
throw new CryptographicException(
SR.Format(
SR.Cryptography_Cms_InvalidSignerHashForSignatureAlg,
digestAlgorithmOid,
_signatureAlgorithm));
}

Is the check that is failing where if SHA256 was used when generating the signature the digestAlgorithmName will be HashAlgorithmName.SHA256 and _expectedDigest is going to be default as a CmsSignature created from the ECC OID 1.2.840.10045.2.1 is created with default

lookup.Add(Oids.EcPublicKey, new ECDsaCmsSignature(null, default));

Reproduction Steps

using System;
using System.Security.Cryptography.Pkcs;

namespace ECDsaTesting;

public static class Repo
{
    public static void CheckSignature()
    {
        string cmsData = "MIIDsgYJKoZIhvcNAQcCoIIDozCCA58CAQExDzANBglghkgBZQMEAgEFADB5BgorBgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLGKX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAp8D/xfac6foOh2152tIkU0NKrrta4U/dQa4koGMiK4aCCAcYwggHCMIIBSaADAgECAhAd3t00MU7jlkH6busjriLsMAoGCCqGSM49BAMCMBoxGDAWBgNVBAMMD1NlbGZTaWduZWQtUDM4NDAeFw0yMzA4MjYyMjE1MDhaFw0yNDA4MjYyMjM1MDhaMBoxGDAWBgNVBAMMD1NlbGZTaWduZWQtUDM4NDB2MBAGByqGSM49AgEGBSuBBAAiA2IABJgs3Gp2QiFXbQM2PWOUJ5ZTkfYk1BQMo1FOd7XDcXR+tFDR1DfCw2FO0ecc9TknF1/mTSMSDVcHCgUgItGnZpDWDsIsmrZADK7zDPNVzQ1g0jTCgynPxRq375ez17orMKNUMFIwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFDnvEQtGNdrQeyTPlx5llx8qfMOpMAoGCCqGSM49BAMCA2cAMGQCMFFR1JJyuXk8dLQLVPwpETtf9tvegjNpOoDnoAloPX8LfQTYCwkwMhMtUh6bRfEstgIwWU8RCqznSfGdShOSSa17TKihv5EFKunGqdENBePENEZnG0xgkVlxK3mrYx/HGQZPMYIBQjCCAT4CAQEwLjAaMRgwFgYDVQQDDA9TZWxmU2lnbmVkLVAzODQCEB3e3TQxTuOWQfpu6yOuIuwwDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQghZ+zk9aK9SuWZXvyaO4FeJlETeyDb92dWnunLLkMsGowCwYHKoZIzj0CAQUABGYwZAIwHpr18RzesnNn5EBaOgem8zxhQ04MG9TSfSwgESIcSfOt2AwXhopjy6sDLOfUDd3DAjAL1POEajSy+ITCEd7SxW+ed9uDM2BQhUs05Chw1ZPrvn8kjc5YolQQjZG0ykmQibg=";

        SignedCms signInfo = new();
        signInfo.Decode(Convert.FromBase64String(cmsData));
        signInfo.CheckSignature(true);
    }
}

The base64 data is the CMS payload generated by the PowerShell cmdlet Set-AuthenticodeSignature using a certificate with an ECDSA key.

Expected behavior

I expect SignedCms.CheckSignature to be able to validate a signature that has been created by Windows.

Actual behavior

The exception and stacktrace when attempting to check the signature affected by this

System.Security.Cryptography.CryptographicException: SignerInfo digest algorithm '2.16.840.1.101.3.4.2.1' is not valid for signature algorithm ''.
   at System.Security.Cryptography.Pkcs.CmsSignature.ECDsaCmsSignature.VerifySignature(ReadOnlySpan`1 valueHash, ReadOnlyMemory`1 signature, String digestAlgorithmOid, HashAlgorithmName digestAlgorithmName, Nullable`1 signatureParameters, X509Certificate2 certificate)
   at System.Security.Cryptography.Pkcs.SignerInfo.VerifySignature(CmsSignature signatureProcessor, X509Certificate2 certificate, Boolean compatMode)
   at System.Security.Cryptography.Pkcs.SignerInfo.Verify(X509Certificate2Collection extraStore, X509Certificate2 certificate, Boolean verifySignatureOnly)

Regression?

Not sure, most like this worked in .NET Framework as AFAIK it used the same Win32 APIs to verify the signature.

Known Workarounds

There are no known workarounds.

Configuration

Tested with net7 but the code is unchanged for net6 and net8 so I assume it also suffers from the same problem.

Other information

I'm not sure if the code should just skip this check if the _expectedDigest is default or whether more logic needs to be applied for this particular OID being in the signatureAlgorithm.

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Aug 27, 2023
@ghost
Copy link

ghost commented Aug 27, 2023

Tagging subscribers to this area: @dotnet/area-system-security, @bartonjs, @vcsjones
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

When signing a file using the Windows APIs with a signature using an ECDSA key Windows will set the signatureAlgorithm in the SignerInfo to the OID 1.2.840.10045.2.1 (ECC) unlike dotnet 5+ which sets it to the OID to the hash algorithm specific OID in the namespace 1.2.840.10045.4.3.. This is a problem when it comes to validating the signature as CmsSignature.ECDsa tries to verify the hash algorithm OID with associated hash algorithm of this value which for 1.2.840.10045.2.1 there is none.

if (_expectedDigest != digestAlgorithmName)
{
throw new CryptographicException(
SR.Format(
SR.Cryptography_Cms_InvalidSignerHashForSignatureAlg,
digestAlgorithmOid,
_signatureAlgorithm));
}

Is the check that is failing where if SHA256 was used when generating the signature the digestAlgorithmName will be HashAlgorithmName.SHA256 and _expectedDigest is going to be default as a CmsSignature created from the ECC OID 1.2.840.10045.2.1 is created with default

lookup.Add(Oids.EcPublicKey, new ECDsaCmsSignature(null, default));

Reproduction Steps

using System;
using System.Security.Cryptography.Pkcs;

namespace ECDsaTesting;

public static class Repo
{
    public static void CheckSignature()
    {
        string cmsData = "MIIDsgYJKoZIhvcNAQcCoIIDozCCA58CAQExDzANBglghkgBZQMEAgEFADB5BgorBgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLGKX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAp8D/xfac6foOh2152tIkU0NKrrta4U/dQa4koGMiK4aCCAcYwggHCMIIBSaADAgECAhAd3t00MU7jlkH6busjriLsMAoGCCqGSM49BAMCMBoxGDAWBgNVBAMMD1NlbGZTaWduZWQtUDM4NDAeFw0yMzA4MjYyMjE1MDhaFw0yNDA4MjYyMjM1MDhaMBoxGDAWBgNVBAMMD1NlbGZTaWduZWQtUDM4NDB2MBAGByqGSM49AgEGBSuBBAAiA2IABJgs3Gp2QiFXbQM2PWOUJ5ZTkfYk1BQMo1FOd7XDcXR+tFDR1DfCw2FO0ecc9TknF1/mTSMSDVcHCgUgItGnZpDWDsIsmrZADK7zDPNVzQ1g0jTCgynPxRq375ez17orMKNUMFIwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFDnvEQtGNdrQeyTPlx5llx8qfMOpMAoGCCqGSM49BAMCA2cAMGQCMFFR1JJyuXk8dLQLVPwpETtf9tvegjNpOoDnoAloPX8LfQTYCwkwMhMtUh6bRfEstgIwWU8RCqznSfGdShOSSa17TKihv5EFKunGqdENBePENEZnG0xgkVlxK3mrYx/HGQZPMYIBQjCCAT4CAQEwLjAaMRgwFgYDVQQDDA9TZWxmU2lnbmVkLVAzODQCEB3e3TQxTuOWQfpu6yOuIuwwDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQghZ+zk9aK9SuWZXvyaO4FeJlETeyDb92dWnunLLkMsGowCwYHKoZIzj0CAQUABGYwZAIwHpr18RzesnNn5EBaOgem8zxhQ04MG9TSfSwgESIcSfOt2AwXhopjy6sDLOfUDd3DAjAL1POEajSy+ITCEd7SxW+ed9uDM2BQhUs05Chw1ZPrvn8kjc5YolQQjZG0ykmQibg=";

        SignedCms signInfo = new();
        signInfo.Decode(Convert.FromBase64String(cmsData));
        signInfo.CheckSignature(true);
    }
}

The base64 data is the CMS payload generated by the PowerShell cmdlet Set-AuthenticodeSignature using a certificate with an ECDSA key.

Expected behavior

I expect SignedCms.CheckSignature to be able to validate a signature that has been created by Windows.

Actual behavior

The exception and stacktrace when attempting to check the signature affected by this

System.Security.Cryptography.CryptographicException: SignerInfo digest algorithm '2.16.840.1.101.3.4.2.1' is not valid for signature algorithm ''.
   at System.Security.Cryptography.Pkcs.CmsSignature.ECDsaCmsSignature.VerifySignature(ReadOnlySpan`1 valueHash, ReadOnlyMemory`1 signature, String digestAlgorithmOid, HashAlgorithmName digestAlgorithmName, Nullable`1 signatureParameters, X509Certificate2 certificate)
   at System.Security.Cryptography.Pkcs.SignerInfo.VerifySignature(CmsSignature signatureProcessor, X509Certificate2 certificate, Boolean compatMode)
   at System.Security.Cryptography.Pkcs.SignerInfo.Verify(X509Certificate2Collection extraStore, X509Certificate2 certificate, Boolean verifySignatureOnly)

Regression?

Not sure, most like this worked in .NET Framework as AFAIK it used the same Win32 APIs to verify the signature.

Known Workarounds

There are no known workarounds.

Configuration

Tested with net7 but the code for net6 and net8 has the same problem so I assume it's also broken.

Other information

No response

Author: jborean93
Assignees: -
Labels:

area-System.Security, untriaged

Milestone: -

@vcsjones
Copy link
Member

Closing as a duplicate of #77377, as that issue covers the same underlying issue that .NET Framework signed CMS cannot be validated by .NET when ECDSA is involved.

@vcsjones vcsjones closed this as not planned Won't fix, can't repro, duplicate, stale Aug 27, 2023
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Aug 27, 2023
@jborean93
Copy link
Contributor Author

jborean93 commented Aug 27, 2023

Ah my apologies I did a basic search for the error but nothing came up. I’ll try and build a local copy and see what happens when we skip the check. If it works I’ll open a PR, if not I’ll try and share more info on that issue.

@ghost ghost locked as resolved and limited conversation to collaborators Sep 26, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants