2
0

CertGenerator.cs 6.1 KB

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