首页 > 解决方案 > 如何使用使用 Microsoft 增强型 RSA 和 AES 加密提供程序的 CertificateRequest 创建自签名证书

问题描述

我正在使用 dotnet core 构建一个证书,如下所示:

    private X509Certificate2 buildSelfSignedServerCertificate(string CertificateName,string password,string dns)
    {
        SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();
        sanBuilder.AddIpAddress(IPAddress.Loopback);
        sanBuilder.AddIpAddress(IPAddress.IPv6Loopback);
        if (!string.IsNullOrEmpty(dns))
        {
            sanBuilder.AddDnsName(dns);
        }
      // 
      //  sanBuilder.AddDnsName(Environment.MachineName);

        X500DistinguishedName distinguishedName = new X500DistinguishedName($"CN={CertificateName}");

        using (RSA rsa = RSA.Create(2048*2))
        {
            var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

            //request.CertificateExtensions.Add(
            //    new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false));


            //request.CertificateExtensions.Add(
            //   new X509EnhancedKeyUsageExtension(
            //       new OidCollection { new Oid("1.3.6.1.5.5.7.3.1"), new Oid("1.3.6.1.5.5.7.3.2") }, false));

            request.CertificateExtensions.Add(sanBuilder.Build());

            var certificate = request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), new DateTimeOffset(DateTime.UtcNow.AddDays(3650)));
             bool isWindows = System.Runtime.InteropServices.RuntimeInformation
                           .IsOSPlatform(OSPlatform.Windows);
            if(isWindows)
                certificate.FriendlyName = CertificateName;

            return certificate;
           // return new X509Certificate2(certificate.Export(X509ContentType.Pfx, password), password, X509KeyStorageFlags.MachineKeySet);
        }
    }

并且它不适用于服务结构,并且从我读到的以下评论中:

如果输出包含如下内容: Provider = Microsoft Software Key Storage Provider 那么这确实是 CNG 证书(由 Key Storage Provider 颁发)。

我认为证书是使用 New-SelfSignedCertificate PowerShell cmdlet 创建的,除非另有说明,否则它将使用 CNG 提供程序。如果是这种情况,并且您可以创建另一个用于此集群的证书,您可以尝试以下操作:

证书输出看起来像这样,确实提供者是错误的。有没有办法修复我上面的 c# 方法来解决这个问题?使用“Microsoft 增强型 RSA 和 AES 加密提供程序”

================ Certificate 1 ================
X509 Certificate:
Version: 3
Serial Number: 5963adde77be6b83
Signature Algorithm:
    Algorithm ObjectId: 1.2.840.113549.1.1.11 sha256RSA
    Algorithm Parameters:
    05 00
Issuer:
    CN=sf-gw-win-13mar2019
  Name Hash(sha1): 660160d3b7e821d759d865d20e22f0f0c9b448da
  Name Hash(md5): 2161360e8739cdf9b660479f2176505c

 NotBefore: 3/12/2019 9:14 AM
 NotAfter: 3/10/2029 9:14 AM

Subject:
    CN=sf-gw-win-13mar2019
  Name Hash(sha1): 660160d3b7e821d759d865d20e22f0f0c9b448da
  Name Hash(md5): 2161360e8739cdf9b660479f2176505c

Public Key Algorithm:
    Algorithm ObjectId: 1.2.840.113549.1.1.1 RSA
    Algorithm Parameters:
    05 00
Public Key Length: 4096 bits
Public Key: UnusedBits = 0
    0000  30 82 02 0a 02 82 02 01  00 ca 8c 25 62 ca b1 60
    0010  54 91 3e bb 45 21 1d db  79 46 01 4f 8c 05 de 7f
    0020  f0 8a 7f 3b f0 68 b9 7f  a6 53 cb d6 b8 cb 81 90
    0030  b5 70 8d cc e0 8f eb f4  cc e5 cd 9c 83 31 9d 25
    0040  2c ac 9b 91 9a f8 47 f1  d9 e1 49 21 3e f7 e4 ca
    0050  32 4c ff 72 0c de b0 b9  c2 16 85 fa bf 37 2f ca
    0060  ed bc 8a 4b 30 81 e9 f8  2a ef 46 48 0f 2d 42 65
    0070  78 b5 76 ae a5 bf c1 f4  ae 8d a2 11 5e dd 95 f1
    0080  7c 49 c1 81 a4 a5 ee 3a  60 39 51 28 40 11 de 37
    0090  e6 57 30 71 ea d1 13 59  82 69 c7 a0 bf 74 b6 5b
    00a0  1f 15 1f b0 aa 3a 85 5b  54 bc 30 8c 08 6b 0a 92
    00b0  3a 9f 28 06 21 10 d2 a3  a9 dc 64 ce 2d 08 67 c3
    00c0  92 f5 c4 c8 c8 59 da a5  a8 a1 5f 3d a1 55 d2 41
    00d0  d7 c7 88 5c db 2b d2 91  0a 9e cc 7f da 0c b1 28
    00e0  6a 55 b9 38 45 00 e2 39  04 27 a4 24 09 88 36 ce
    00f0  be 72 63 d3 11 4d a8 50  12 c9 4e df 45 7f 1b 17
    0100  26 7b 63 1a a6 76 e1 0e  41 95 b8 9c dc eb 4d b2
    0110  e1 7c ee 8f 72 00 94 62  a7 84 45 2a 75 06 2d b9
    0120  b4 d6 3d 6f 81 6c 73 de  48 fe 8b 85 76 0c c4 df
    0130  0c c9 67 ca cd 89 08 7c  89 b5 89 f3 23 d4 fc 29
    0140  07 ac cc 87 c6 3d 34 63  fa f7 3b 52 ea 48 a3 0c
    0150  2a 23 ad cd 84 c0 9a 4b  a1 97 41 78 7c ed f8 e0
    0160  25 1e 88 28 96 be e8 1e  24 3c 80 69 dc 4f 21 27
    0170  72 eb 4d 1f d3 83 44 6b  d3 8d d7 0b d1 1f 2c 37
    0180  fe 08 03 fb 88 a3 cd 37  e5 7e 44 60 a8 51 b8 c8
    0190  e3 a5 86 90 0f d0 c0 74  25 b9 79 20 d4 b8 a5 8a
    01a0  01 0c a8 17 ba eb e9 34  35 5f b1 69 75 48 9f 41
    01b0  dd ac 7c 0a 1a 95 f2 8e  34 84 73 f5 cb 81 5a a1
    01c0  e9 f5 00 f9 c8 6a 07 7c  84 4d c7 25 87 ff dd f7
    01d0  81 ad 04 e2 79 1e 7f e9  f2 49 ac c3 cb e1 09 25
    01e0  7c 0e a1 79 0f 83 6c cf  54 cc 12 d4 c4 72 ae e7
    01f0  8e c2 f2 c8 fc 2e d7 ee  50 79 fa d6 17 c1 bc fa
    0200  48 2b f1 9b 07 b7 4f 79  f5 02 03 01 00 01
Certificate Extensions: 3
    2.5.29.15: Flags = 0, Length = 4
    Key Usage
        Digital Signature, Key Encipherment, Data Encipherment (b0)

    2.5.29.37: Flags = 0, Length = 16
    Enhanced Key Usage
        Server Authentication (1.3.6.1.5.5.7.3.1)
        Client Authentication (1.3.6.1.5.5.7.3.2)

    2.5.29.17: Flags = 0, Length = 4d
    Subject Alternative Name
        IP Address=127.0.0.1
        IP Address=0000:0000:0000:0000:0000:0000:0000:0001
        DNS Name=sf-gw-win-13mar2019.westeurope.cloudapp.azure.com

Signature Algorithm:
    Algorithm ObjectId: 1.2.840.113549.1.1.11 sha256RSA
    Algorithm Parameters:
    05 00
Signature: UnusedBits=0
    0000  55 c0 a0 25 ca f9 a9 06  5e f2 82 a3 50 10 73 f0
    0010  aa 09 3e c4 2a ee 40 74  b1 ef d9 e9 2b 1c eb e3
    0020  0d 1b ab 84 02 1d 5a 61  e0 e9 dd 05 52 60 e3 c7
    0030  69 53 c3 57 69 1f 0a 9e  a3 16 0e 7c b8 05 72 53
    0040  f6 03 a7 08 89 ed 70 57  1b cc f1 9b de b4 29 f4
    0050  84 d9 6a 28 d3 6c 32 e3  7a 2a f8 6c cd 0e e4 0e
    0060  7b 21 17 03 01 5c af f4  1f 54 c6 cc f5 42 dd 17
    0070  e8 3e 05 a7 db ac c9 97  e7 8d 1d a2 3b 11 a6 6f
    0080  75 26 9c b2 c6 7f ca b1  61 d7 75 e8 ce c2 2b ab
    0090  39 c6 66 da 80 2f 8e 92  1f 12 ef 78 ce 2a c2 76
    00a0  2e ad bc 5f a1 33 7f 5d  bf a3 42 54 ca 48 4f 27
    00b0  b4 c8 a0 3d 8e ce 69 f6  4b 82 2a 31 b3 e2 dc 06
    00c0  e4 14 09 5d 7a 0b 36 c7  1b 09 50 2d 3c 44 05 c6
    00d0  fe 73 d6 61 53 23 5a 5d  62 5a 00 52 e6 6f 9d a2
    00e0  05 0c c0 8d 2e 9b 73 35  5b f7 16 6e c9 59 61 44
    00f0  e4 c8 14 de 52 c5 98 49  af a0 f9 93 83 57 59 22
    0100  d9 08 04 3f ae d8 23 e0  c6 90 ec b7 cd 79 d9 f4
    0110  e6 0d 2b 3c bd b1 07 9e  1e dc 58 2d 67 17 82 48
    0120  eb 0c 1a d3 6f 21 8a ef  68 e8 60 09 25 d8 55 15
    0130  fd f7 b0 ca 31 90 66 a6  70 01 1a 59 f2 17 06 99
    0140  1b c1 81 c5 da ef 26 a9  ee 8e c8 04 4e 79 dc e2
    0150  c1 bb 51 7c 5f b1 06 63  64 27 ce b7 f9 40 c6 6a
    0160  bc 64 52 ce 0a 1a 6c 89  12 45 9e 80 3e 52 70 fc
    0170  b4 c8 2d d8 6e c6 f7 53  d6 53 3b 77 ee 50 d3 b0
    0180  16 e5 04 98 53 ef e2 15  c9 9b 04 79 06 67 6e d8
    0190  52 30 d8 96 c7 6d 43 d7  6e 11 6a e9 61 3e bf 9d
    01a0  2e 6f 33 21 f8 68 9c 11  79 e5 ae 0f f4 12 f5 fc
    01b0  ec e5 01 08 e5 11 4d 2a  da 0d c4 d9 29 f5 63 9b
    01c0  94 4f 45 b9 25 de ba 07  1a 75 fd 99 de 35 5d c1
    01d0  df 02 5a 9b f0 9b 10 82  4e 7f 13 19 6f 55 dd c8
    01e0  5f ed 55 e4 05 24 41 b2  94 ef 72 48 65 25 6a ca
    01f0  c3 ae c5 ad 57 7c e2 1b  e4 a7 77 7d 8c f1 3d 1e
Signature matches Public Key
Root Certificate: Subject matches Issuer
Key Id Hash(rfc-sha1): f9f756a3919d0b5dfa8e43ac43ea6414583ff71f
Key Id Hash(sha1): 81f9fb2ed9d259c4a40a634ab77ae99606a776c5
Key Id Hash(bcrypt-sha1): 151b830389beb8a5ed529dabd28c9d8e098fe3fa
Key Id Hash(bcrypt-sha256): d75be37ab42837b51c0a25111fdc6210eaf48e2bed19010ab5f71ddb488e3f2c
Key Id Hash(md5): 9f202798ceeb0d277d6b20cb97ccbcfd
Key Id Hash(sha256): cd77cd0f4ad33dc13bc41077359bf0965423ac1bd64633351aa8ac81c7d25567
Key Id Hash(pin-sha256): GSLM/gfacBd2FM3u2SkbsXR15PSRp62uLQnvGiNa2WM=
Key Id Hash(pin-sha256-hex): 1922ccfe07da70177614cdeed9291bb17475e4f491a7adae2d09ef1a235ad963
Cert Hash(md5): 377d5f5f05aa9c376063305a60933e35
Cert Hash(sha1): 6a7f2ca4244e4fa1c7699de9a2e55cc0bb6f6657
Cert Hash(sha256): 2f56cfcdad9a8da8ba79b34cd4383eab88bc001a6ace1d1dc9befb2154e59ca9
Signature Hash: bb32fdc4357935eafeeafa8384d4ce98f711ce9f6b60cbb147edda1aba39af7c

  CERT_SIGNATURE_HASH_PROP_ID(15) disallowedHash:
 bb32fdc4357935eafeeafa8384d4ce98f711ce9f6b60cbb147edda1aba39af7c

  CERT_SIGN_HASH_CNG_ALG_PROP_ID(89):
    RSA/SHA256

  CERT_KEY_IDENTIFIER_PROP_ID(20):
    81f9fb2ed9d259c4a40a634ab77ae99606a776c5

  CERT_SHA1_HASH_PROP_ID(3):
    6a7f2ca4244e4fa1c7699de9a2e55cc0bb6f6657

  CERT_KEY_PROV_INFO_PROP_ID(2):
    Key Container = {FBF56CC1-7B2A-46AD-8AF4-26FFA7549481}
  Unique container name: c08961a3547a2c6cddac263c86108d7c_1e5dd0bd-f8a7-46af-b76b-b93aacf81c8c
    Provider = Microsoft Software Key Storage Provider
    ProviderType = 0
  Flags = 20 (32)
    CRYPT_MACHINE_KEYSET -- 20 (32)
    KeySpec = 0 -- XCN_AT_NONE

  CERT_FRIENDLY_NAME_PROP_ID(11):
    sf-gw-win-13mar2019

  CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID(25):
    9f202798ceeb0d277d6b20cb97ccbcfd

  CERT_MD5_HASH_PROP_ID(4):
    377d5f5f05aa9c376063305a60933e35

  CERT_SUBJECT_PUB_KEY_BIT_LENGTH_PROP_ID(92):
    0x00001000 (4096)

  CERT_ACCESS_STATE_PROP_ID(14):
  AccessState = 6
    CERT_ACCESS_STATE_SYSTEM_STORE_FLAG -- 2
    CERT_ACCESS_STATE_LM_SYSTEM_STORE_FLAG -- 4

  Provider = Microsoft Software Key Storage Provider
  ProviderType = 0
  Unique container name: c08961a3547a2c6cddac263c86108d7c_1e5dd0bd-f8a7-46af-b76b-b93aacf81c8c
  AD(AT_NONE): f799d17e7d8a5d5a81599bb26ee3e7aceba62907
  AD(AT_KEYEXCHANGE): eca8f2abcda4d7d8db20107b071bdb60ea5b63df
  AD(AT_SIGNATURE): 43a9c8854a9dc659d5266748036a9658b9344557
  RSA
  Export Policy = 0
  Name: {FBF56CC1-7B2A-46AD-8AF4-26FFA7549481}
  Algorithm Group: RSA
  Algorithm Name: RSA
  Length: 4096 (0x1000)
  Lengths:
    dwMinLength = 512 (0x200)
    dwMaxLength = 16384 (0x4000)
    dwIncrement = 8 (0x8)
    dwDefaultLength = 1024 (0x400)
  Block Length: 512 (0x200)
  Export Policy: 0 (0x0)

  HWND Handle:Binary:
0000    10 00 01 00 00 00 00 00                            ........
  Key Usage: 16777215 (0xffffff)
    NCRYPT_ALLOW_DECRYPT_FLAG -- 1
    NCRYPT_ALLOW_SIGNING_FLAG -- 2
    NCRYPT_ALLOW_KEY_AGREEMENT_FLAG -- 4
    NCRYPT_ALLOW_KEY_IMPORT_FLAG -- 8
    NCRYPT_ALLOW_ALL_USAGES -- ffffff (16777215)

  Security Descr: D:P(A;;0xd01f01ff;;;SY)(A;;0x80120089;;;NS)(A;;0xd01f01ff;;;BA)
  Modified: 3/13/2019 9:48 AM
  Virtual Iso: 0 (0x0)
  Per Boot Key: 0 (0x0)
  Key Usage = ffffff (16777215)
    NCRYPT_ALLOW_DECRYPT_FLAG -- 1
    NCRYPT_ALLOW_SIGNING_FLAG -- 2
    NCRYPT_ALLOW_KEY_AGREEMENT_FLAG -- 4
    NCRYPT_ALLOW_KEY_IMPORT_FLAG -- 8
    NCRYPT_ALLOW_ALL_USAGES -- ffffff (16777215)

  D:P(A;;0xd01f01ff;;;SY)(A;;0x80120089;;;NS)(A;;0xd01f01ff;;;BA)

    Allow Write NT AUTHORITY\SYSTEM
    Allow Write NT AUTHORITY\NETWORK SERVICE
    Allow Write BUILTIN\Administrators

Private key is NOT exportable
Encryption test passed

================ 证书2 ================

标签: c#.net-corecertificate

解决方案


答案取决于您要对证书做什么。

PersistKeySet 行为

如果您想将其添加到X509Store它将“永远”停留的位置(因此您将其作为带有PersistKeySet标志的 PFX 导入),那么自我发现的解决方案是正确的:

using (RSA rsa = new RSACryptoServiceProvider(4096, new CspParameters(24, "Microsoft Enhanced RSA and AES Cryptographic Provider", Guid.NewGuid().ToString())))
{
     CertificateRequest req = ...;
     return req.CreateSelfSigned(...);
}

最重要的是,密钥被赋予了名称 ( Guid.NewGuid().ToString()),使其成为持久密钥。这允许对cert.CopyWithPrivateKey埋在里面的调用CreateSelfSigned附加到磁盘上的键上。

EphemeralKeySet 行为,具有受控的 PFX 导出

如果您对该方法的唯一调用是将其导出到 PFX,那么您希望做的事情略有不同。

using (RSACryptoServiceProvider rsa = <same as above>)
{
    // Delete this key on Dispose / finalization.
    rsa.PersistKeyInCsp = false;

    CertificateRequest req = ...;

    using (X509Certificate2 cert = req.CreateSelfSigned(...))
    {
        // At this line the persisted key still exists so it reports its name and CSP/KSP into the PFX.
        return cert.Export(X509ContentType.Pkcs12, password);
    }
}

再次,密钥被命名,使 CSP 和名称保留在 PFX/PKCS12 中。但是该对象被标记为自删除,因此它会自行清理。

如果您此时返回证书而不是导出,则证书将不再能够使用其私钥,并且以后的 PFX 导出将失败。

“PerphemeralKeySet”行为证书

如果您想暂时使用证书,并控制 PFX 导出,并且密钥不会永远存在...结合前两件事。

using (RSACryptoServiceProvider rsa = ...)
{
    rsa.PersistKeyInCsp = false;

    CertificateRequest req = ...;

    using (X509Certificate2 cert = req.CreateSelfSigned(...))
    {
        // Export the PFX using the current key.  Re-import it with no flags to
        // make it a normal "perphemeral" key behavior.
        return new X509Certificate2(cert.Export(X509ContentType.Pkcs12), "", X509KeyStorageFlags.Exportable);
    }
}

此处的 PFX 导入,因为它发生在原始密钥被释放/删除之前,它会移动到基于 GUID 的新密钥名称。如果您关心使用相同的名称,请byte[]在让 Dispose 调用密钥对象之前导出到 a,然后重新导入,并且将使用相同的密钥名称(在所有当前版本的 Windows 上)......但现在删除语义与证书的生命周期而不是 RSA 对象的生命周期相关联。


推荐阅读