Created
November 11, 2023 17:40
-
-
Save micah686/a88f61f44c0aa12d5d1c8cfd56fce9a6 to your computer and use it in GitHub Desktop.
Create X509Cert
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Globalization; | |
using System.Net; | |
using System.Security.Cryptography; | |
using System.Security.Cryptography.X509Certificates; | |
internal class CertHelper | |
{ | |
internal static void CreateCerts() | |
{ | |
var rootCA = CreateX509Cert(CertTypes.RootCA); | |
var normalCert = CreateX509Cert(CertTypes.UtilitiesAPI, "ReflectTube.RootCA.key"); | |
var normalCert2 = CreateX509Cert(CertTypes.DataAPI, "ReflectTube.RootCA.key"); | |
var result = ValidateCertificates(rootCA, normalCert); | |
var rootca = new X509Certificate2(File.ReadAllBytes("ReflectTube.RootCA.crt")); | |
var secondary = new X509Certificate2(File.ReadAllBytes("ReflectTube.UtilitiesAPI.crt")); | |
var isValid = rootca.GetPublicKeyString().Equals(secondary.GetPublicKeyString()); | |
} | |
public static X509Certificate2 CreateX509Cert(CertTypes certType, string? rsaKeyFile = "") | |
{ | |
const string ORGANIZATION = "ReflectTube"; | |
string countryCode = RegionInfo.CurrentRegion.TwoLetterISORegionName; | |
string oid = "1.3.6.1.5.5.7.3.1"; //http://www.oid-info.com/cgi-bin/display?oid=1.3.6.1.5.5.7.3.1&a=display | |
var sanBuilder = new SubjectAlternativeNameBuilder(); | |
sanBuilder.AddIpAddress(IPAddress.Loopback); | |
sanBuilder.AddIpAddress(IPAddress.IPv6Loopback); | |
sanBuilder.AddDnsName(Environment.MachineName); | |
using (var rsa = RSA.Create(4096)) | |
{ | |
if(!string.IsNullOrEmpty(rsaKeyFile) && File.Exists(rsaKeyFile)) | |
{ | |
rsa.ImportFromPem(File.ReadAllText(rsaKeyFile)); | |
oid = "1.3.6.1.5.5.7.3.2"; | |
} | |
string dn = $"""CN="{ORGANIZATION}.{certType}",OU="{ORGANIZATION}.{certType}, Copyright (c) {DateTime.UtcNow:yyyy}",O="{ORGANIZATION}",C={countryCode}""";//raw string literal | |
X500DistinguishedName distinguishedName = new X500DistinguishedName(dn); | |
var certRequest = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1); //matches except 512 vs 256 | |
certRequest.CertificateExtensions.Add(new X509KeyUsageExtension( | |
X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation, false)); //uses Data and Key | |
certRequest.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new(oid) }, false)); //marked as not critical/false | |
certRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certRequest.PublicKey, false)); //I added this | |
certRequest.CertificateExtensions.Add(sanBuilder.Build()); | |
var selfSigned = certRequest.CreateSelfSigned(DateTimeOffset.UtcNow.AddDays(-1), DateTimeOffset.UtcNow.AddYears(50)); | |
string certPem = new string(PemEncoding.Write("CERTIFICATE", selfSigned.RawData)); | |
File.WriteAllText($"{ORGANIZATION}.{certType}.crt", certPem); | |
using (var certRSA = selfSigned.GetRSAPrivateKey()) | |
{ | |
if (certRSA != null) | |
{ | |
File.WriteAllText($"{ORGANIZATION}.{certType}.key", certRSA.ExportRSAPrivateKeyPem()); | |
} | |
else | |
{ | |
throw new InvalidOperationException("Couldn't export private key!"); | |
} | |
} | |
return selfSigned; | |
} | |
} | |
public enum CertTypes | |
{ | |
RootCA, | |
DataAPI, | |
AccountAPI, | |
QueryAPI, | |
MessagingAPI, | |
UtilitiesAPI | |
} | |
public static bool ValidateCertificates(X509Certificate2 rootCA, X509Certificate2 certToCheck) | |
{ | |
using (var chain = new X509Chain | |
{ | |
ChainPolicy = | |
{ | |
RevocationMode = X509RevocationMode.NoCheck, | |
RevocationFlag = X509RevocationFlag.ExcludeRoot, | |
VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority, | |
VerificationTime = DateTime.Now | |
} | |
}) | |
{ | |
chain.ChainPolicy.ExtraStore.Add(rootCA); | |
if (!chain.Build(certToCheck)) | |
{ | |
//Errorhandling | |
} | |
//Root certificate should always be last in the X509ChainElements collection | |
var isSignedByCorrectRootCert = | |
chain.ChainElements | |
.Cast<X509ChainElement>() | |
.Last() | |
.Certificate.Thumbprint == rootCA.Thumbprint; | |
return isSignedByCorrectRootCert; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment