无法将密钥文件添加到 X509Certificate2

Posted

技术标签:

【中文标题】无法将密钥文件添加到 X509Certificate2【英文标题】:Unable to add key file to X509Certificate2 【发布时间】:2020-01-30 17:12:09 【问题描述】:

环境:VS 2019,Core 3.1,C# 8.0

我在尝试将 .cer 和 .key 文件添加到我的 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)

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;

调用自:

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

注意:我可以毫无问题地通过 curl 和 Postman 使用这两个文件发出请求。

我正在尝试将这两个文件都附加到请求中,因此不依赖于这种特定方法。如果有更好的方法,我有兴趣了解它。

【问题讨论】:

您的密钥可能采用 PKCS#8 格式(“BEGIN PRIVATE KEY”与“BEGIN RSA PRIVATE KEY”)。所以你想要 ImportPkcs8PrivateKey,而不是 ImportRSAPrivateKey。 现在给了我一个新错误:"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, ReadOnlySpan1 keyBlob,布尔加密,ReadOnlySpan1 password)\r\n 重新查看并确认它是“BEGIN RSA PRIVATE KEY”。还尝试了这里的代码 (docs.microsoft.com/en-us/dotnet/core/whats-new/…),它引发了错误:System.Security.Cryptography.CryptographicException: 'ASN1 损坏的数据'。 【参考方案1】:

对此超级晚,遇到同样的问题ASN1 corrupted data 并设法从您的问题和@bartonjs 回答的问题中解决了我的问题

关于Create X509Certificate2 from Cert and Key, without making a PFX file问题的建议是

using (RSA rsa = RSA.Create())

    rsa.ImportRSAPrivateKey(binaryEncoding, out _);
    // do stuff with the key now

我的线索是binaryEncoding,答案被评论为同一问题的一部分......

如果你有一个 PEM,你需要“de-PEM”它,通过提取 BEGIN 和 END 分隔符之间的内容并通过Convert.FromBase64String 运行它以获得binaryEncoding

所以根据您的代码...以下导入 PEM 文件没有问题。

        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.
        

【讨论】:

我最终使用了 RestSharp 库。无法相信找到答案有多难(甚至发布在 MS 的 GitHub 上)。 用了很多谷歌搜索!

以上是关于无法将密钥文件添加到 X509Certificate2的主要内容,如果未能解决你的问题,请参考以下文章

openssl 怎样生成公钥和密钥 x509格式

RSAParameters 到 pfx (X509Certificate2) 的转换

sh 生成密钥对X509和SSH

OpenSSL之X509证书用法

X509Certificate - 密钥集不存在

在 c# 中将 Object 标记添加到 X509Certificate2