Reputation: 7963
I'm trying to use SignedCms.CheckSignature
in .NET Framework 4.7.2 to validate a message I know is valid using a certificate I know is valid. I'm using the following code to do this:
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using System.Collections.Generic;
public class VerifySignature {
public static void Main(string [] args) {
byte[] signature = FromHexString(secKey);
byte[] certBytes = FromHexString(sCert);
var certificate = new X509Certificate2(certBytes);
var collection = new X509Certificate2Collection(certificate);
var verifyCms = new SignedCms();
verifyCms.Decode(signature);
verifyCms.CheckSignature(collection, true);
}
// Disposable certificate + secKey
private const string sCert = @"3082045406092A864886F70D010702A082044530820441020101310B300906052B0E03021A0500300B06092A864886F70D010701A08202FF308202FB308202BB020720110818132047300906072A8648CE3804033064310B3009060355040613024445311C301A060355040A131353415020547275737420436F6D6D756E69747931133011060355040B130A5341502057656220415331143012060355040B130B4930313230303033343131310C300A06035504031303494433301E170D3131303831383133323034375A170D3338303130313030303030315A3064310B3009060355040613024445311C301A060355040A131353415020547275737420436F6D6D756E69747931133011060355040B130A5341502057656220415331143012060355040B130B4930313230303033343131310C300A06035504031303494433308201B73082012C06072A8648CE3804013082011F02818100FFF96C9CDD661022E93DF5B27DB6C6C9FF34358366D2C7C3C37838703E4A4876429227017338D65A73617D5640C6764C67B2E5BE771F4937C6AC43E96780A57CA64C47ADE6C6D0336E5CA39D77035EA1F836A45CA1C0255D7AC473C9C9B09E40C07D2AC3B0C72F27273AA9F0B0221CB484A5A3E565D3540531A170E7E9ACFD4302150095C9AE5339A3D29AAA7A3705C884166335740DD302818100F808A1CE9A4C20F2FA4470BD5D9AAA4E69E18E5F5F182272770050B86EFD750011EBF938ADA9F63E6956F533E2B829C28A407A2D5735F41E020E36D1CBA8092000C597BE2A6022AED8BC95C720CE8465EAD415B19F1560964EC0422A9A5C9DADDC373AAF8F90AB6E6248A74F3A51EF4A5E06346FE3270449E7E8B2E88178450E038184000281806A7DE80E4DAAE5CB95DC79D7C3C2B15EDE1973453E09AF4EBDCDFF55ADA9256C0FC4E98EE443D5916D9CB6C54BD7D9612A02693BEF866BE4C4777E159121EE285A6199FF30AF309E675B4E1ADAE95E4A5254CBC37C49C77EC9A3169B5BDA1D7FFB24C27334B7A0E3E6FBEC4257C0C1C3F6CDAE5D3F8748F52607B399BCF0A61C300906072A8648CE380403032F00302C02144AC6E9813C2F7EFEEFED0A9FE60E4816DA964B9F02145327E3FE9FA347864ABCCC0198E519AEEE678C7E3182011D30820119020101306F3064310B3009060355040613024445311C301A060355040A131353415020547275737420436F6D6D756E69747931133011060355040B130A5341502057656220415331143012060355040B130B4930313230303033343131310C300A06035504031303494433020720110818132047300906052B0E03021A0500A05D301806092A864886F70D010903310B06092A864886F70D010701301C06092A864886F70D010905310F170D3230303132393139343630355A302306092A864886F70D01090431160414B858CB282617FB0956D960215C8E84D1CCF909C6300906072A8648CE380403042E302C02143DED3FA580EF178F0190EB66033EF0E2FFD647CC02146857D6E9123802BC9589D3B7D52BB8A11C348081";
private const string secKey = @"3082015106092A864886F70D010702A08201423082013E020101310B300906052B0E03021A0500300B06092A864886F70D0107013182011D30820119020101306F3064310B3009060355040613024445311C301A060355040A131353415020547275737420436F6D6D756E69747931133011060355040B130A5341502057656220415331143012060355040B130B4930313230303033343131310C300A06035504031303494433020720110818132047300906052B0E03021A0500A05D301806092A864886F70D010903310B06092A864886F70D010701301C06092A864886F70D010905310F170D3230303132393232323635385A302306092A864886F70D010904311604141A1A7B63F70EA93616A10297BA4D27FB9255753B300906072A8648CE380403042E302C0214323B9B50FAAD0823C14A6565B0CA291DBC0A967B0214511F586BFB544E63256CD49DA1FF03FF2984F640";
private byte[] FromHexString(string hexString) {
var bytes = new List<byte>();
int by = 0;
int hexDigits = 0;
for (int i = 0; i < hexString.Length; ++i) {
char c = hexString[i];
if ('0' <= c && c <= '9') {
by = (by << 4) | (c - '0');
++hexDigits;
} else if ('A' <= c && c <= 'F') {
by = (by << 4) | (c - 'A' + 10);
++hexDigits;
}
if (hexDigits == 2) {
bytes.Add((byte)by);
hexDigits = 0;
}
}
return bytes.ToArray();
}
}
I have verified that the X509Certificate2
is valid, and the secKey
is correctly decoded. And yet, when I call SignedCms.CheckSignature
I get an cryptographic exception with the message "The hash value is not correct."
Are my expectations that this code should work incorrect?
Upvotes: 1
Views: 2024
Reputation: 33238
Your CMS SignedData value from secKey
is built with detached content, meaning it's just the signature. The way you're trying to verify it, it is verifying that the signature applies to new byte[0]
.
new byte[0]
has a SHA-1 hash of DA39A3EE5E6B4B0D3255BFEF95601890AFD80709You need to find the content, and change your document construction to
ContentInfo detachedData = new ContentInfo(data);
SignedCms verifyCms = new SignedCms(detachedData, detached: true);
// rest of code goes here.
Once the internal digest can be verified, the signature will successfully verify given the public key (based on some data manipulation within a debugger).
Upvotes: 3