尝试在 .NET 4.7.2 中使用带有 SHA1 的 CertificateRequest 创建自签名证书时出现 ArgumentOutOfRangeException

ArgumentOutOfRangeException when trying to create a self signed certificate using CertificateRequest with SHA1 in .NET 4.7.2

我需要为不支持 SHA256 的旧遗留系统生成 SHA1 散列证书。我很清楚不建议在加密场景中使用 MD5 和 SHA1 哈希,但这是外部要求。

我正在使用 .NET Framework 4.7.2 及其新 CertificateRequest class.

这里是相关的代码片段:

            using (var rsa = RSA.Create(2048))
            {
                var subjectName = "CN=sampleName";
                var certificateRequest = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
                var selfSignedCertificate = certificateRequest.CreateSelfSigned(DateTime.UtcNow, DateTime.UtcNow.AddYears(10));
                var certAsBytes = selfSignedCertificate.Export(X509ContentType.Pfx, "fakePassword");
                File.WriteAllBytes("cert-sha1.pfx", certAsBytes);
            }

调用certificateRequest.CreateSelfSigned时,抛出如下异常:

'SHA1' is not a known hash algorithm.
Parameter name: hashAlgorithm
Actual value was SHA1.

堆栈跟踪中的相关点是:

...
   at System.Security.Cryptography.X509Certificates.RSAPkcs1X509SignatureGenerator.GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlgorithm)
   at System.Security.Cryptography.X509Certificates.TbsCertificate.Encode(X509SignatureGenerator signatureGenerator, HashAlgorithmName hashAlgorithm)
   at System.Security.Cryptography.X509Certificates.TbsCertificate.Sign(X509SignatureGenerator signatureGenerator, HashAlgorithmName hashAlgorithm)
   at System.Security.Cryptography.X509Certificates.CertificateRequest.Create(X500DistinguishedName issuerName, X509SignatureGenerator generator, DateTimeOffset notBefore, DateTimeOffset notAfter, Byte[] serialNumber)
   at System.Security.Cryptography.X509Certificates.CertificateRequest.CreateSelfSigned(DateTimeOffset notBefore, DateTimeOffset notAfter)
   at Tests.Sha1Test()

从我正在使用的构造函数的 .NET API browser 来看,即使不推荐,我也看不出为什么这不起作用。使用 MD5 会引发类似的异常。 SHA256 及更高版本工作正常。

CertificateRequest class 也没有在 reference source 中显示(也许是因为它太新了?)所以我没主意了。

不支持 MD5 和 SHA-1 是有意的,基于 feedback from the feature pull request(打开 link 后,您必须等待几秒钟,同时页面加载足够的代码以找到锚点,然后重新-跳跃).

文档现已更新为:

Remarks

This method does not support using MD5 or SHA-1 as the hash algorithm for the certificate signature. If you need an MD5 or SHA-1 based certificate signature, you need to implement a custom X509SignatureGenerator and call Create(X500DistinguishedName, X509SignatureGenerator, DateTimeOffset, DateTimeOffset, Byte[]).

创建 X509SignatureGenerator 肯定很难,对吧?好吧,来自相同的反馈 link:

private sealed class RSASha1Pkcs1SignatureGenerator : X509SignatureGenerator 
{ 
     private readonly X509SignatureGenerator _realRsaGenerator; 

     internal RSASha1Pkcs1SignatureGenerator(RSA rsa) 
     { 
         _realRsaGenerator = X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1); 
     } 

     protected override PublicKey BuildPublicKey() => _realRsaGenerator.PublicKey; 

     public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlgorithm) 
     { 
         if (hashAlgorithm == HashAlgorithmName.SHA1) 
             return "300D06092A864886F70D0101050500".HexToByteArray(); 

         throw new InvalidOperationException(); 
     } 

     public override byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm) => 
         _realRsaGenerator.SignData(data, hashAlgorithm); 
} 

该代码还用于测试是否能够提供自定义生成器。