5

Environment: VS 2019, Core 3.1, C# 8.0

I'm getting the following error while trying to add a .cer and .key file to my httpClientHandler:

    {"ASN1 corrupted data."}
        Data: {System.Collections.ListDictionaryInternal}
        HResult: -2146233087
        HelpLink: null
        InnerException: null
        Message: "ASN1 corrupted data."
        Source: "System.Security.Cryptography.Algorithms"
        StackTrace: "   at System.Security.Cryptography.Asn1.AsnReader.CheckExpectedTag(Asn1Tag tag, Asn1Tag expectedTag, UniversalTagNumber tagNumber)\r\n   at System.Security.Cryptography.Asn1.AsnReader.ReadSequence(Asn1Tag expectedTag)\r\n   at System.Security.Cryptography.Asn1.RSAPrivateKeyAsn.Decode(AsnReader reader, Asn1Tag expectedTag, RSAPrivateKeyAsn& decoded)\r\n   at System.Security.Cryptography.Asn1.RSAPrivateKeyAsn.Decode(Asn1Tag expectedTag, ReadOnlyMemory`1 encoded, AsnEncodingRules ruleSet)\r\n   at System.Security.Cryptography.Asn1.RSAPrivateKeyAsn.Decode(ReadOnlyMemory`1 encoded, AsnEncodingRules ruleSet)\r\n   at System.Security.Cryptography.RSAKeyFormatHelper.FromPkcs1PrivateKey(ReadOnlyMemory`1 keyData, AlgorithmIdentifierAsn& algId, RSAParameters& ret)\r\n   at System.Security.Cryptography.RSA.ImportRSAPrivateKey(ReadOnlySpan`1 source, Int32& bytesRead)\r\n   at BnyMellon.Program.CreateFromCertFile(String cerFile, String keyFile) in C:\\Users\\bbernzweig.AD\\source\\repos\\HttpClientExample\\
    BnyMellon\\Program.cs:line 150"
        TargetSite: {Void CheckExpectedTag(System.Security.Cryptography.Asn1.Asn1Tag, System.Security.Cryptography.Asn1.Asn1Tag, System.Security.Cryptography.Asn1.UniversalTagNumber)}

Error is raised here on line rsa.ImportRSAPrivateKey(privateKeyBytes, out _);:

private static X509Certificate2 CreateFromCertFile(string cerFile, string keyFile)
{
    try
    {
        var cert = new X509Certificate2 (cerFile);
        var privateKeyBytes = LoadPrivateKeyBytes(keyFile);

        using var rsa = RSA.Create();
        rsa.ImportRSAPrivateKey(privateKeyBytes, out _);
        var certWithKey = cert.CopyWithPrivateKey(rsa);

        cert.Dispose();
        return certWithKey;
    }
    catch(Exception e)
    {
        Console.WriteLine(e);
    }

    return null;
}

Called from:

var clientCertificate = new X509Certificate2();
clientCertificate = CreateFromCertFile(certificateFile, keyFile);  
httpClientHandler.ClientCertificates.Add(clientCertificate);

Note: I'm able to make the request using both of these files via curl and Postman without any problem.

I'm trying to attaching both files to the request so not tied to this specific approach. If there is a better way I'm interested in hearing about it.

dbc
  • 104,963
  • 20
  • 228
  • 340
MyDisplayName
  • 223
  • 5
  • 12
  • 1
    Your key is probably in the PKCS#8 format ("BEGIN PRIVATE KEY", vs "BEGIN RSA PRIVATE KEY"). So you want ImportPkcs8PrivateKey, not ImportRSAPrivateKey. – bartonjs Jan 30 '20 at 18:07
  • 1
    That now gives me a new error: `{"An error occurred during encode or decode operation."} Data: {System.Collections.ListDictionaryInternal} Message: "An error occurred during encode or decode operation." Source: "System.Security.Cryptography.Algorithms" StackTrace: " at System.Security.Cryptography.CngKeyLite.ImportKeyBlob(String blobType, ReadOnlySpan`1 keyBlob, Boolean encrypted, ReadOnlySpan`1 password)\r\n ` – MyDisplayName Jan 30 '20 at 18:56
  • Relooked at this and confirmed that it is "BEGIN RSA PRIVATE KEY". Also tried the code here (https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#cryptographic-key-importexport) and it raises the error: System.Security.Cryptography.CryptographicException: 'ASN1 corrupted data'. – MyDisplayName Feb 03 '20 at 21:33

1 Answers1

6

Super late to this, and faced the same problem ASN1 corrupted data and managed to resolve my problem from both your question and the question answered by @bartonjs

The advice on Create X509Certificate2 from Cert and Key, without making a PFX file question is

using (RSA rsa = RSA.Create())
{
    rsa.ImportRSAPrivateKey(binaryEncoding, out _);
    // do stuff with the key now
}

The clue for me was binaryEncoding, the answer is commented as part of the same question is...

if you had a PEM you need to "de-PEM" it, by extracting the contents between the BEGIN and END delimiters and running it through Convert.FromBase64String in order to get binaryEncoding

So based on your code... the following imports the PEM file without issue.

        private static byte[] LoadPrivateKeyBytes(string keyFile)
        {
            // remove these lines
            // -----BEGIN RSA PRIVATE KEY-----
            // -----END RSA PRIVATE KEY-----
            var pemFileData = File.ReadAllLines(keyFile).Where(x => !x.StartsWith("-"));

            // Join it all together, convert from base64
            var binaryEncoding = Convert.FromBase64String(string.Join(null, pemFileData));

            // this is the private key byte data
            return binaryEncoding;
        }

        private static X509Certificate2 CreateFromCertFile(string cerFile, string keyFile)
        {
            try
            {
                var cert = new X509Certificate2(cerFile);
                var privateKeyBytes = LoadPrivateKeyBytes(keyFile);

                using var rsa = RSA.Create();
                rsa.ImportRSAPrivateKey(privateKeyBytes, out _);
                var certWithKey = cert.CopyWithPrivateKey(rsa);

                cert.Dispose();
                return certWithKey;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

#pragma warning disable CS8603 // Possible null reference return.
            return null;
#pragma warning restore CS8603 // Possible null reference return.
        }
0909EM
  • 4,761
  • 3
  • 29
  • 40
  • 2
    I ended up using the RestSharp library. Couldn't believe how hard it was to find an answer (even posted on MS's GitHub). – MyDisplayName Aug 21 '20 at 18:26
  • 1
    Took a lot of googling! – 0909EM Aug 22 '20 at 21:45
  • 1
    Thank you for this. It is super simple.. but at the same time.. i had no idea why it wasn't working. If only they would have told us.. or better yet took the standard file in and loaded the bytes and stuff for us. – DoomVroom Mar 15 '22 at 23:31