6

I'm trying to use C# and the built in Crypto libraries to verify a signature created using an EC key + SHA256. Here's what I'm doing.

I've created a private key and corresponding certificate using openssl:

$ openssl ecparam -genkey -name prime256v1 -out ca.key
$ openssl req -x509 -new -SHA256 -nodes -key ca.key -days 36500 -out ca.crt

Here are the keys I'm using (don't worry, they're not important):

$ cat ca.key 
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHd3OvRV1nEnoDxGzzemX1x8l2rHasWH3L/LflUGg5vloAoGCCqGSM49
AwEHoUQDQgAE7f1xwQL5m/UcN4zL+zsly6V1g3/wNcL5TdCfWt0XfnUfg0x+RsIf
1uerBnhrmhH0cN9o0xfXg5B3hURFlXVuEQ==
-----END EC PRIVATE KEY-----

$ cat ca.crt 
-----BEGIN CERTIFICATE-----
MIIB4TCCAYegAwIBAgIUKt0WdaKI2eRXBO2nVk+OF6AZqHMwCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMDA1MDcxMzM2MTNaGA8yMTIwMDQx
MzEzMzYxM1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAf
BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABO39ccEC+Zv1HDeMy/s7JculdYN/8DXC+U3Qn1rdF351H4NMfkbC
H9bnqwZ4a5oR9HDfaNMX14OQd4VERZV1bhGjUzBRMB0GA1UdDgQWBBRGuUmsyB2h
JCXMRTVMRTcdoWZQaDAfBgNVHSMEGDAWgBRGuUmsyB2hJCXMRTVMRTcdoWZQaDAP
BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIGG8tQZlh7aJaI34Y7jq
44SmSc/ule9MgjIX+Gg+i5vwAiEA9Jb/304KO4t9OMqFMQeWZXIHdzhDFBwx7FWz
78+UsnY=
-----END CERTIFICATE-----

I then have a simple data file containing the string "Hello". I then sign that file using openssl as follows:

$ openssl dgst -sha256 -sign ca.key data.txt > sig
$ base64 sig 
MEUCIQD5593C/NBhHA1DILT72gjhGj/lKjom9vYP+JbuypBrxQIgNAjYT1LihEpPbUhe1n9ccUHQ
vw676bGqOTEU/25qcRQ=

I can then verify the signature by first extracting the public key from the certificate and then using that to verify:

$ openssl x509 -pubkey -noout -in ca.crt > ca.pub
$ cat ca.pub 
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7f1xwQL5m/UcN4zL+zsly6V1g3/w
NcL5TdCfWt0XfnUfg0x+RsIf1uerBnhrmhH0cN9o0xfXg5B3hURFlXVuEQ==
-----END PUBLIC KEY-----
$ openssl dgst -verify ca.pub -sha256 -signature sig data.txt 
Verified OK

I then try and use C# (.NET Core 3.1) to verify the signature. The code is as follows:

using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace security_sandbox
{
    class Program
    {
        static void Main(string[] args)
        {
            var certData = Encoding.ASCII.GetBytes(
                @"-----BEGIN CERTIFICATE-----
MIIB4TCCAYegAwIBAgIUKt0WdaKI2eRXBO2nVk+OF6AZqHMwCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMDA1MDcxMzM2MTNaGA8yMTIwMDQx
MzEzMzYxM1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAf
BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABO39ccEC+Zv1HDeMy/s7JculdYN/8DXC+U3Qn1rdF351H4NMfkbC
H9bnqwZ4a5oR9HDfaNMX14OQd4VERZV1bhGjUzBRMB0GA1UdDgQWBBRGuUmsyB2h
JCXMRTVMRTcdoWZQaDAfBgNVHSMEGDAWgBRGuUmsyB2hJCXMRTVMRTcdoWZQaDAP
BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIGG8tQZlh7aJaI34Y7jq
44SmSc/ule9MgjIX+Gg+i5vwAiEA9Jb/304KO4t9OMqFMQeWZXIHdzhDFBwx7FWz
78+UsnY=
-----END CERTIFICATE-----");

            var cert = new X509Certificate2(certData);
            var ecdsa = cert.GetECDsaPublicKey();

            var data = Encoding.ASCII.GetBytes("Hello");
            var signature = Convert.FromBase64String("MEUCIQD5593C/NBhHA1DILT72gjhGj/lKjom9vYP+JbuypBrxQIgNAjYT1LihEpPbUhe1n9ccUHQvw676bGqOTEU/25qcRQ=");

            var success = ecdsa.VerifyData(data, signature, HashAlgorithmName.SHA256);

            if (success)
            {
                Console.WriteLine("Verified");
            } else
            {
                Console.WriteLine("Failed");
            }
        }
    }
}

Unfortunately, it always fails the verification. Where is the mistake?

3
  • 3
    The signatures have different formats. If the signature in the C# code is passed in the right format, the verification is successful, s. here. Commented May 7, 2020 at 14:56
  • 2
    Yes, presented signature is ASN-encoded. You have to use ASN tools (there are no built-in in .NET) to extract r and s components of signature, normalize (remove leading zeroes, if any) and concatenate. Then you verify signature against concatenated binary string. Commented May 7, 2020 at 15:19
  • 3
    If you use a preview build for .NET 5 (or it's the future and .NET 5 has been released), you could call ecdsa.VerifyData(data, signature, HashAlgorithmName.SHA256, DSASignatureFormat.Rfc3279DerSequence). Commented May 7, 2020 at 15:57

1 Answer 1

5

The lack of PEM/OpenSSL-compatible manipulation tools in .NET proved to be extremely frustrating. I ended up using Bouncy Castle to load the certificate or public key and then use that to verify my ASN signature. Here's a full working code sample demonstrating how to perform the signature verification using both the certificate and the PEM public key and working with an ASN-encoded signature.

using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;

namespace security_sandbox
{
    class Program
    {
        static void Main(string[] args)
        {

            var certificateString =  @"-----BEGIN CERTIFICATE-----
MIIB4TCCAYegAwIBAgIUKt0WdaKI2eRXBO2nVk+OF6AZqHMwCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMDA1MDcxMzM2MTNaGA8yMTIwMDQx
MzEzMzYxM1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAf
BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABO39ccEC+Zv1HDeMy/s7JculdYN/8DXC+U3Qn1rdF351H4NMfkbC
H9bnqwZ4a5oR9HDfaNMX14OQd4VERZV1bhGjUzBRMB0GA1UdDgQWBBRGuUmsyB2h
JCXMRTVMRTcdoWZQaDAfBgNVHSMEGDAWgBRGuUmsyB2hJCXMRTVMRTcdoWZQaDAP
BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIGG8tQZlh7aJaI34Y7jq
44SmSc/ule9MgjIX+Gg+i5vwAiEA9Jb/304KO4t9OMqFMQeWZXIHdzhDFBwx7FWz
78+UsnY=
-----END CERTIFICATE-----";
            var pemreader = new PemReader(new StringReader(certificateString));
            var cert = (X509Certificate)pemreader.ReadObject();

            // Alternatively, load the public key directly
            var pubkeyString = 
@"-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7f1xwQL5m/UcN4zL+zsly6V1g3/w
NcL5TdCfWt0XfnUfg0x+RsIf1uerBnhrmhH0cN9o0xfXg5B3hURFlXVuEQ==
-----END PUBLIC KEY-----";
            pemreader = new PemReader(new StringReader(pubkeyString));
            var pubkey = (AsymmetricKeyParameter)pemreader.ReadObject();

            var data = "Hello";
            var signature = Convert.FromBase64String("MEUCIQD5593C/NBhHA1DILT72gjhGj/lKjom9vYP+JbuypBrxQIgNAjYT1LihEpPbUhe1n9ccUHQvw676bGqOTEU/25qcRQ=");

            // Verify using the public key
            var signer = SignerUtilities.GetSigner("SHA-256withECDSA");
            signer.Init(false, pubkey);
            signer.BlockUpdate(Encoding.ASCII.GetBytes(data), 0, data.Length);
            var success = signer.VerifySignature(signature);

            if (success) {
                Console.WriteLine("Signature verified successfully using public key");
            } else {
                Console.WriteLine("Failed to verify signature using public key");
            }

            // Verify using the certificate - the certificate's public key is extracted using the GetPublicKey method.
            signer.Init(false, cert.GetPublicKey());
            signer.BlockUpdate(Encoding.ASCII.GetBytes(data), 0, data.Length);
            success = signer.VerifySignature(signature);

            if (success) {
                Console.WriteLine("Signature verified successfully using certificate");
            } else {
                Console.WriteLine("Failed to verify signature using certificate");
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.