You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Cms signature created with .Net Framework cannot be verified with .Net Core for an elliptic curve certificate #77377
If you use CmsSigner to create a signature in .Net Framework 4.8 with an ECC certificate then the signature cannot be verified using CmsSigner in .Net Core 6.0.
The signature is created as follows:
using (var certificate = new X509Certificate2(CertificatePath, Password))
{
var cmsSigner = new CmsSigner(certificate);
cmsSigner.IncludeOption = X509IncludeOption.EndCertOnly;
var contentInfo = new ContentInfo(new Oid(PkcsObjectIdentifiersData), InputBytes);
var signedCms = new SignedCms(SubjectIdentifierType.Unknown, contentInfo, true);
signedCms.ComputeSignature(cmsSigner);
File.WriteAllBytes(SignaturePath, signedCms.Encode());
}
The signature is verified as follows.
var contentInfo = new ContentInfo(InputBytes);
var signedData = new SignedCms(contentInfo, true);
signedData.Decode(signatureBytes);
var signerInfos = signedData.SignerInfos;
signedData.CheckSignature(true);
Note that it is possible to verify the signature in .Net Framework.
We have tried to generate the ECC certificate using .Net and using Java and it the verification fails in both cases. We have tried to reproduce the issue using RSA certificates. Then it works fine.
We noticed that the signature algorithm is SignedCms.SignerInfos is not the same if we try to generate the signature using .Net Framework and .Net Core which is not what we expected.
This runs different combinations of .Net Framework and .Net Core and certificate key algorithms.
It gives the following output
Test create signature in .Net Framework. Verify in .Net Framework using elliptic curve.
Verification ok
Test create signature in .Net Core. Verify in .Net Core using elliptic curve.
Verification ok
Test create signature in .Net Framework. Verify in .Net Core using RSA.
Verification ok
Test create signature in .Net Framework. Verify in .Net Core using elliptic curve.
Verification failed
Exception: SignerInfo digest algorithm '2.16.840.1.101.3.4.2.1' is not valid for signature algorithm ''.
Expected behavior
All combinations of .Net Framework and .Net Core and certificate key algorithms should work.
Actual behavior
The case where the signature is created in .Net Framework but verified in .Net Core does not work for ECC certificates.
Regression?
No response
Known Workarounds
No response
Configuration
We have tried .Net Framework 4.8 and .Net Core 6.0 on Windows.
I think the right fix here for maintaining compat with .NET Framework is to skip the hash algorithm check if we are using .NET Framework's signature algorithm identifier. Basically change the check to:
As a matter of an update to this, even once we get past the hash algorithm check, the digest that gets signed and verified differs between .NET Framework and .NET 6+. So this will take a little more time for me to understand exactly what .NET Framework is doing differently.
I'm moving this to Future as we won't be able to further investigate it during .NET 8. I'm also going to label this as
help wanted[up-for-grabs] Good issue for external contributors
since more investigation is needed to get to a root cause and proposed fix for this issue.
@vcsjones I tested out skipping the check if the EcPublicKey OID was in the signature and I found it worked just fine #91183.
As a matter of an update to this, even once we get past the hash algorithm check, the digest that gets signed and verified differs between .NET Framework and .NET 6+
Do you remember how you verified this? From testing I can generate a signature from both .NET and the Win32 API directly with an ECDSA key and the code is able to check the digest just fine. Even the test the PR adds is fine with the new changes.
I do have a user report with a problematic signature signed by signtool.exe where these changes do fail with the below stacktrace:
System.Security.Cryptography.CryptographicException: Invalid signature.
at System.Security.Cryptography.Pkcs.SignerInfo.Verify(X509Certificate2Collection extraStore, X509Certificate2 certificate, Boolean verifySignatureOnly)
at System.Security.Cryptography.Pkcs.SignerInfo.CheckSignature(X509Certificate2Collection extraStore, Boolean verifySignatureOnly)
at System.Security.Cryptography.Pkcs.SignerInfo.CheckSignature(Boolean verifySignatureOnly)
...
I don't think they are related as even Windows fails to verify the signature but I've yet to figure out why
Activity
vcsjones commentedon Oct 24, 2022
Okay, I think I see what is going on here. In .NET Framework, the signature algorithm is 1.2.840.10045.2.1 (EcPublicKey).
When we lookup the signature info here:
runtime/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.ECDsa.cs
Line 20 in 36df7cc
We use a
defaulthash algorithm name. When we compare the digest with thedefaultdigest of what we are expecting the comparison fails here:runtime/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.ECDsa.cs
Line 52 in 36df7cc
I think the right fix here for maintaining compat with .NET Framework is to skip the hash algorithm check if we are using .NET Framework's signature algorithm identifier. Basically change the check to:
(or make
_expectedDigestnullable, etc).@bartonjs does this sound reasonable?
bartonjs commentedon Oct 24, 2022
seems like the right fix to me.
vcsjones commentedon Nov 14, 2022
As a matter of an update to this, even once we get past the hash algorithm check, the digest that gets signed and verified differs between .NET Framework and .NET 6+. So this will take a little more time for me to understand exactly what .NET Framework is doing differently.
jeffhandley commentedon Jun 28, 2023
I'm moving this to Future as we won't be able to further investigate it during .NET 8. I'm also going to label this as help wanted[up-for-grabs] Good issue for external contributors
since more investigation is needed to get to a root cause and proposed fix for this issue.
Support Windows based ECDSA SignedCms
jborean93 commentedon Aug 27, 2023
@vcsjones I tested out skipping the check if the
EcPublicKeyOID was in the signature and I found it worked just fine #91183.Do you remember how you verified this? From testing I can generate a signature from both .NET and the Win32 API directly with an ECDSA key and the code is able to check the digest just fine. Even the test the PR adds is fine with the new changes.
I do have a user report with a problematic signature signed by
signtool.exewhere these changes do fail with the below stacktrace:I don't think they are related as even Windows fails to verify the signature but I've yet to figure out why
Support Windows based ECDSA SignedCms
Support Windows based ECDSA SignedCms (#91247)