'Validate with Bouncy Castle ECDsaSigner
I am trying validate the message digest hash using eCDsaSigner with R and S but VerifySignature returns false . Is it possible to get more information as to why eCDsaSigner fails? I am sure the hash is correct as I recreated it and compared it to the extracted version. Anyone able to throw some light on this? Thank you
// R and S
byte[] der = Hex.Decode("3044021f4043e112eebe8c92c6aee9132f24af6f73c61353dbd1b1cdde2a5429ba4e290221009caf197c3cf9838e72068097409ee23b6648b1b14d44a38a5825495893dcd629");// 3043021f1acda88726e28dbdfcea74e403e7424ba9cba588777e810e42caa5d274135502207283b90135ef09e5847516a9163f4f6a4d403abb9d7632c77397e37165632619");// 3045022100bb3435689a49cb00a04b64fbd7c886d5c67eb406781b43b4ca18bb778df6d35e02201e54c928da6c4867e2b8aafb7703b00784971ef47837433bdf8a6ecb4cdbebcd");
Asn1Sequence seq = Asn1Sequence.GetInstance(der);
BigInteger r = DerInteger.GetInstance(seq[0]).PositiveValue;
BigInteger s = DerInteger.GetInstance(seq[1]).PositiveValue;
// Signature Hash
var signedDataDer = Convert.FromBase64String("MIAGCS...");
var signers = new CmsSignedData(signedDataDer).GetSignerInfos().GetSigners();
var signersEnumerator = signers.GetEnumerator();
signersEnumerator.MoveNext();
SignerInformation signerInfo = (SignerInformation)signersEnumerator.Current;
var messageDigestDer = signerInfo.SignedAttributes[CmsAttributes.MessageDigest].GetDerEncoded();
var messageDigestHash = Asn1OctetString.GetInstance(Asn1Set.GetInstance(Asn1Sequence.GetInstance(messageDigestDer)[1])[0]).GetOctets();
// Verify time
const string clientCertStr = "MIID2D ...";
var clientCertBytes = Convert.FromBase64String(clientCertStr);
var clientCert = new X509Certificate2(clientCertBytes);
Org.BouncyCastle.X509.X509Certificate myx509Certificate = DotNetUtilities.FromX509Certificate(clientCert);
Org.BouncyCastle.Crypto.AsymmetricKeyParameter keyParam = myx509Certificate.GetPublicKey();
Org.BouncyCastle.Crypto.Signers.ECDsaSigner eCDsaSigner = new ECDsaSigner();
eCDsaSigner.Init(false, keyParam);
bool doesItVerify = eCDsaSigner.VerifySignature(messageDigestHash, r, s);
Solution 1:[1]
Your approach assumes that the message digest attribute value has been signed. However, in the presence of signed attributes (signedAttrs), these (including the message digest attribute) are hashed and signed, see here, here and for more details RFC5652, sec. 5.1. SignedData Type, 5.3. SignerInfo Type and 5.4. Message Digest Calculation Process, respectively.
So if you consider the signed attributes instead of the message digest attribute alone, verification is successful:
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Cms;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.X509.Store;
using System;
using System.Collections;
using System.Security.Cryptography;
...
// Get signature, get signed attributes
byte[] signedDataDer = Convert.FromBase64String("MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIID3DCCA9gwggNdoAMCAQICEyEAAZd0HpR/sCxFvssAAgABl3QwCgYIKoZIzj0EAwMwRDEVMBMGCgmSJomT8ixkARkWBWxvY2FsMRcwFQYKCZImiZPyLGQBGRYHdGVzdGxhYjESMBAGA1UEAxMJRUNDLVN1YkNBMB4XDTIyMDUwMTE3Mzk1N1oXDTIyMTExNzEwNTQwNVowGjEYMBYGA1UEAxMPQ049RjcxU1Y4UFVIRzdHMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyLhOpn3E9fLRUmyQjqj4oqYaZCas5XUSFdpybQHlWQdyzG/wpjeIuQmivBtv+UyVUFPiGjDSe10MybZA3FKWw6OCAlYwggJSMB0GA1UdDgQWBBQF6gHIAKZ7RNI2+QmPPrJdFfnUrzAfBgNVHSMEGDAWgBTrjUtVuyh/arwAVWt6WlIqUdpj3jCBzgYDVR0fBIHGMIHDMIHAoIG9oIG6hoG3bGRhcDovLy9DTj1FQ0MtU3ViQ0EoMiksQ049bGFiLXNydjUyLENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPXRlc3RsYWIsREM9bG9jYWw/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MIG9BggrBgEFBQcBAQSBsDCBrTCBqgYIKwYBBQUHMAKGgZ1sZGFwOi8vL0NOPUVDQy1TdWJDQSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz10ZXN0bGFiLERDPWxvY2FsP2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MA4GA1UdDwEB/wQEAwIHgDA9BgkrBgEEAYI3FQcEMDAuBiYrBgEEAYI3FQiD9Z8LhfLocYaBhR+ExrEgg/3he2mC9OoQg8uQBgIBZAIBRTATBgNVHSUEDDAKBggrBgEFBQcDAjAbBgkrBgEEAYI3FQoEDjAMMAoGCCsGAQUFBwMCMAoGCCqGSM49BAMDA2kAMGYCMQCgll9gISIWnd2jYtwZ93dNPyOF8zjlenB2tqOuYzdAQpXrcATLs1qOxvicaX4AaYACMQD/MZP41sJRnw9Pef/gajTZbi2dK8VT+SoxZ9q5bpeFcjoTOkuFcAT/DWWliuLWb0IxggEiMIIBHgIBATBbMEQxFTATBgoJkiaJk/IsZAEZFgVsb2NhbDEXMBUGCgmSJomT8ixkARkWB3Rlc3RsYWIxEjAQBgNVBAMTCUVDQy1TdWJDQQITIQABl3QelH+wLEW+ywACAAGXdDAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjIwNTAxMjAzOTEyWjAjBgkqhkiG9w0BCQQxFgQUhuUgvhtjs/rNrdTNLtWkN7itQg0wCQYHKoZIzj0EAQRHMEUCICZOO0TCJadjqMkTT8InOY+ARfImn0PISSNOWXIw3N9BAiEA2CaoUofu5Z4YYaM7s6x2ZYpI8e99FnaigfeT+DFjfEgAAAAAAAA=");
var signedData = new CmsSignedData(signedDataDer);
var signers = signedData.GetSignerInfos().GetSigners();
IEnumerator signersEnumerator = signers.GetEnumerator();
signersEnumerator.MoveNext();
SignerInformation signerInfo = (SignerInformation)signersEnumerator.Current;
byte[] signatureDer = signerInfo.GetSignature();
byte[] signedAttribs = signerInfo.GetEncodedSignedAttributes(); // message digest attribute included
// Extract r and s from DER signature
Asn1Sequence seq = Asn1Sequence.GetInstance(signatureDer);
BigInteger r = DerInteger.GetInstance(seq[0]).PositiveValue;
BigInteger s = DerInteger.GetInstance(seq[1]).PositiveValue;
// Get certificate (or import the certificate itself as in the posted code)
IX509Store x509Store = signedData.GetCertificates("Collection");
ICollection x509Coll = x509Store.GetMatches(new X509CertStoreSelector());
IEnumerator x509Enumerator = x509Coll.GetEnumerator();
x509Enumerator.MoveNext();
X509Certificate x509 = (X509Certificate)x509Enumerator.Current;
// Verify
AsymmetricKeyParameter keyParameter = x509.GetPublicKey();
ECDsaSigner eCDsaSigner = new ECDsaSigner();
eCDsaSigner.Init(false, keyParameter);
bool doesItVerify = eCDsaSigner.VerifySignature(SHA1.HashData(signedAttribs), r, s); // Fix: consider SHA1 hash of signed attributes
Console.WriteLine(doesItVerify); // true
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |