Skip to content

Commit

Permalink
Support Windows based ECDSA SignedCms
Browse files Browse the repository at this point in the history
Supports SignedCms signatured with an ECDSA key created by the Windows
API or .NET Framework. These signatures store an EC public key OID
rather than a hash specific ECDSA OID used in newer versions of dotnet.

Fixes dotnet#77377
  • Loading branch information
jborean93 committed Aug 27, 2023
1 parent f5881e5 commit f6a9b2c
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ static partial void PrepareRegistrationECDsa(Dictionary<string, CmsSignature> lo
lookup.Add(Oids.ECDsaWithSha3_384, new ECDsaCmsSignature(Oids.ECDsaWithSha3_384, HashAlgorithmName.SHA3_384));
lookup.Add(Oids.ECDsaWithSha3_512, new ECDsaCmsSignature(Oids.ECDsaWithSha3_512, HashAlgorithmName.SHA3_512));
#endif
lookup.Add(Oids.EcPublicKey, new ECDsaCmsSignature(null, default));
lookup.Add(Oids.EcPublicKey, new ECDsaCmsSignature(null, null));
}

private sealed partial class ECDsaCmsSignature : CmsSignature
{
private readonly HashAlgorithmName _expectedDigest;
private readonly HashAlgorithmName? _expectedDigest;
private readonly string? _signatureAlgorithm;

internal override RSASignaturePadding? SignaturePadding => null;

internal ECDsaCmsSignature(string? signatureAlgorithm, HashAlgorithmName expectedDigest)
internal ECDsaCmsSignature(string? signatureAlgorithm, HashAlgorithmName? expectedDigest)
{
_signatureAlgorithm = signatureAlgorithm;
_expectedDigest = expectedDigest;
Expand All @@ -56,7 +56,7 @@ internal override bool VerifySignature(
ReadOnlyMemory<byte>? signatureParameters,
X509Certificate2 certificate)
{
if (_expectedDigest != digestAlgorithmName)
if (_expectedDigest != null && _expectedDigest != digestAlgorithmName)
{
throw new CryptographicException(
SR.Format(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ internal static class Oids
public const string RsaPss = "1.2.840.113549.1.1.10";
public const string Esdh = "1.2.840.113549.1.9.16.3.5";
public const string Dh = "1.2.840.10046.2.1";
public const string EcPublicKey = "1.2.840.10045.2.1";
public const string EcdsaSha256 = "1.2.840.10045.4.3.2";

// Cryptographic Attribute Types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,20 @@ public static void ExistingDocument_Rsa_Sha3_512()
}
}

[Fact]
public static void ExistingDocument_Ecdsa_Sha256_FromNetFX()
{
SignedCms cms = new SignedCms();
cms.Decode(SignedDocuments.Ecdsa_Sha256_FromNetFX_SignedDocument);

cms.CheckSignature(true); // Assert.NoThrow
Assert.Single(cms.SignerInfos);

SignerInfo signerInfo = cms.SignerInfos[0];
Assert.Equal(Oids.Sha256, signerInfo.DigestAlgorithm.Value);
Assert.Equal(Oids.EcPublicKey, signerInfo.SignatureAlgorithm.Value);
}

private static void VerifyWithExplicitPrivateKey(X509Certificate2 cert, AsymmetricAlgorithm key)
{
using (var pubCert = new X509Certificate2(cert.RawData))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1789,5 +1789,38 @@ internal static class SignedDocuments
"F11C632B4F605A41821A3F15B4F537FD5F0EE3426A7A03732AC946C3B435" +
"776A873A3DAE93FB8312C681144CF51F05CE37A0DB4C1544E178F88E421C" +
"0B5456D18C13B335DA808CE60C4E35F507").HexToByteArray();

// produced with the below PowerShell code using the pfx Certificates.ECDsaP256Win
// $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
// [System.Convert]::FromBase64String($Certificates_ECDsaP256Win),
// 'Test',
// 'EphemeralKeySet')
// $signer = [System.Security.Cryptography.Pkcs.CmsSigner]::new('IssuerAndSerialNumber', $cert)
// $signer.IncludeOption = 'ExcludeRoot'
// $signer.DigestAlgorithm = '2.16.840.1.101.3.4.2.1'
// $contentInfo = [System.Security.Cryptography.Pkcs.ContentInfo]::new([byte[]]@(0))
// $signedCms = [System.Security.Cryptography.Pkcs.SignedCms]::new($contentInfo, $false)
// $signedCms.ComputeSignature($signer, $true)
// $signedCms.Encode()
internal static readonly byte[] Ecdsa_Sha256_FromNetFX_SignedDocument = (
"3082023106092A864886F70D010702A08202223082021E020101310F300D" +
"06096086480165030402010500301006092A864886F70D010701A0030401" +
"00A082015C308201583081FFA003020102021035428F3B3C5107AD49E776" +
"D6E74C4DC8300A06082A8648CE3D04030230153113301106035504030C0A" +
"45434453412054657374301E170D3135303530313030333730335A170D31" +
"36303530313030353730335A30153113301106035504030C0A4543445341" +
"20546573743059301306072A8648CE3D020106082A8648CE3D0301070342" +
"00047590F69CA114E92927E034C997B7C882A8C992AC00CEFB4EB8319015" +
"36F291E1B515263BCD20E1EA32496FDAC84E2D8D1B703266A9088F6EAF65" +
"2549D9BB63D5A331302F300E0603551D0F0101FF040403020388301D0603" +
"551D0E0416041411218A92C5EB12273B3C5CCFB8220CCCFDF387DB300A06" +
"082A8648CE3D040302034800304502201AFE595E19F1AE4B6A4B231E8851" +
"926438C55B5DDE632E6ADF13C1023A65898E022100CBDF434FDD197D8B59" +
"4E8026E44263BADE773C2BEBD060CC4109484A498E7C7E31819530819202" +
"0101302930153113301106035504030C0A45434453412054657374021035" +
"428F3B3C5107AD49E776D6E74C4DC8300D06096086480165030402010500" +
"300B06072A8648CE3D020105000446304402203557687B26E650E4F86F4B" +
"77A5BF5851350C96F01142696CC1391632CB95C3370220017FD4D9329F00" +
"1EC74210CD34CAEE3878B2302602DB7930347E104679734291").HexToByteArray();
}
}

0 comments on commit f6a9b2c

Please sign in to comment.