CertGenerator.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net;
  5. using System.Security.Cryptography;
  6. using System.Security.Cryptography.X509Certificates;
  7. namespace FastGithub.HttpServer.Certs
  8. {
  9. /// <summary>
  10. /// 证书生成器
  11. /// </summary>
  12. static class CertGenerator
  13. {
  14. private static readonly Oid tlsServerOid = new("1.3.6.1.5.5.7.3.1");
  15. private static readonly Oid tlsClientOid = new("1.3.6.1.5.5.7.3.2");
  16. /// <summary>
  17. /// 生成ca证书
  18. /// </summary>
  19. /// <param name="subjectName"></param>
  20. /// <param name="notBefore"></param>
  21. /// <param name="notAfter"></param>
  22. /// <param name="rsaKeySizeInBits"></param>
  23. /// <param name="pathLengthConstraint"></param>
  24. /// <returns></returns>
  25. public static X509Certificate2 CreateCACertificate(
  26. X500DistinguishedName subjectName,
  27. DateTimeOffset notBefore,
  28. DateTimeOffset notAfter,
  29. int rsaKeySizeInBits = 2048,
  30. int pathLengthConstraint = 1)
  31. {
  32. using var rsa = RSA.Create(rsaKeySizeInBits);
  33. var request = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
  34. var basicConstraints = new X509BasicConstraintsExtension(true, pathLengthConstraint > 0, pathLengthConstraint, true);
  35. request.CertificateExtensions.Add(basicConstraints);
  36. var keyUsage = new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.CrlSign | X509KeyUsageFlags.KeyCertSign, true);
  37. request.CertificateExtensions.Add(keyUsage);
  38. var oids = new OidCollection { tlsServerOid, tlsClientOid };
  39. var enhancedKeyUsage = new X509EnhancedKeyUsageExtension(oids, true);
  40. request.CertificateExtensions.Add(enhancedKeyUsage);
  41. var dnsBuilder = new SubjectAlternativeNameBuilder();
  42. dnsBuilder.Add(subjectName.Name[3..]);
  43. request.CertificateExtensions.Add(dnsBuilder.Build());
  44. var subjectKeyId = new X509SubjectKeyIdentifierExtension(request.PublicKey, false);
  45. request.CertificateExtensions.Add(subjectKeyId);
  46. return request.CreateSelfSigned(notBefore, notAfter);
  47. }
  48. /// <summary>
  49. /// 生成服务器证书
  50. /// </summary>
  51. /// <param name="issuerCertificate"></param>
  52. /// <param name="subjectName"></param>
  53. /// <param name="extraDnsNames"></param>
  54. /// <param name="notBefore"></param>
  55. /// <param name="notAfter"></param>
  56. /// <param name="rsaKeySizeInBits"></param>
  57. /// <returns></returns>
  58. public static X509Certificate2 CreateEndCertificate(
  59. X509Certificate2 issuerCertificate,
  60. X500DistinguishedName subjectName,
  61. IEnumerable<string>? extraDnsNames = default,
  62. DateTimeOffset? notBefore = default,
  63. DateTimeOffset? notAfter = default,
  64. int rsaKeySizeInBits = 2048)
  65. {
  66. using var rsa = RSA.Create(rsaKeySizeInBits);
  67. var request = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
  68. var basicConstraints = new X509BasicConstraintsExtension(false, false, 0, true);
  69. request.CertificateExtensions.Add(basicConstraints);
  70. var keyUsage = new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment, true);
  71. request.CertificateExtensions.Add(keyUsage);
  72. var oids = new OidCollection { tlsServerOid, tlsClientOid };
  73. var enhancedKeyUsage = new X509EnhancedKeyUsageExtension(oids, true);
  74. request.CertificateExtensions.Add(enhancedKeyUsage);
  75. var authorityKeyId = GetAuthorityKeyIdentifierExtension(issuerCertificate);
  76. request.CertificateExtensions.Add(authorityKeyId);
  77. var subjectKeyId = new X509SubjectKeyIdentifierExtension(request.PublicKey, false);
  78. request.CertificateExtensions.Add(subjectKeyId);
  79. var dnsBuilder = new SubjectAlternativeNameBuilder();
  80. dnsBuilder.Add(subjectName.Name[3..]);
  81. if (extraDnsNames != null)
  82. {
  83. foreach (var dnsName in extraDnsNames)
  84. {
  85. dnsBuilder.Add(dnsName);
  86. }
  87. }
  88. var dnsNames = dnsBuilder.Build();
  89. request.CertificateExtensions.Add(dnsNames);
  90. if (notBefore == null || notBefore.Value < issuerCertificate.NotBefore)
  91. {
  92. notBefore = issuerCertificate.NotBefore;
  93. }
  94. if (notAfter == null || notAfter.Value > issuerCertificate.NotAfter)
  95. {
  96. notAfter = issuerCertificate.NotAfter;
  97. }
  98. var serialNumber = BitConverter.GetBytes(Random.Shared.NextInt64());
  99. using var certOnly = request.Create(issuerCertificate, notBefore.Value, notAfter.Value, serialNumber);
  100. return certOnly.CopyWithPrivateKey(rsa);
  101. }
  102. private static void Add(this SubjectAlternativeNameBuilder builder, string name)
  103. {
  104. if (IPAddress.TryParse(name, out var address))
  105. {
  106. builder.AddIpAddress(address);
  107. }
  108. else
  109. {
  110. builder.AddDnsName(name);
  111. }
  112. }
  113. private static X509Extension GetAuthorityKeyIdentifierExtension(X509Certificate2 certificate)
  114. {
  115. #if NET7_0_OR_GREATER
  116. return X509AuthorityKeyIdentifierExtension.CreateFromCertificate(certificate, true, false);
  117. #else
  118. var extension = certificate.Extensions.OfType<X509SubjectKeyIdentifierExtension>().First();
  119. var subjectKeyIdentifier = extension.RawData.AsSpan(2);
  120. var rawData = new byte[subjectKeyIdentifier.Length + 4];
  121. rawData[0] = 0x30;
  122. rawData[1] = 0x16;
  123. rawData[2] = 0x80;
  124. rawData[3] = 0x14;
  125. subjectKeyIdentifier.CopyTo(rawData);
  126. return new X509Extension("2.5.29.35", rawData, false);
  127. #endif
  128. }
  129. }
  130. }