using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Operators; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.X509; namespace InnovEnergy.OpenVpnCertificatesServer.PKI; public static class CertificateAuthority { private const Int32 KeySize = 2048; private const Double DaysPerYear = 365.25; private static X509Certificate CaCertificate { get; } = Pem.Decode(CaCertificatePem); private static RsaKeyPairGenerator KeyGenerator { get; } = new RsaKeyPairGenerator(); private static SecureRandom Rng { get; } = new SecureRandom(); static CertificateAuthority() { var parameters = new KeyGenerationParameters(Rng, KeySize); KeyGenerator.Init(parameters); } public static AsymmetricCipherKeyPair CreateKeyPair() { Console.WriteLine("Creating key pair"); return KeyGenerator.GenerateKeyPair(); } public static X509Certificate CreateCertificate(String subjectName, AsymmetricCipherKeyPair subjKeyPair) { Console.WriteLine($"issuing certificate for {subjectName}"); var caKey = Pem.Decode(CaKeyPem, "max helfried harald ursin"); if (caKey == null) throw new Exception("Failed to decode the CA key!"); var subjectDn = new X509Name("CN=" + subjectName); var issuerDn = CaCertificate.IssuerDN; var notBefore = DateTime.UtcNow; var notAfter = notBefore.Add(TimeSpan.FromDays(DaysPerYear*100)); var serialNo = BigInteger.ValueOf(Rng.Next()); var cg = new X509V3CertificateGenerator(); cg.SetIssuerDN(issuerDn); cg.SetSubjectDN(subjectDn); cg.SetSerialNumber(serialNo); cg.SetNotAfter(notAfter); cg.SetNotBefore(notBefore); cg.SetPublicKey(subjKeyPair.Public); var algorithm = PkcsObjectIdentifiers.Sha256WithRsaEncryption.ToString(); var sign = new Asn1SignatureFactory(algorithm, caKey.Private); var subjCert = cg.Generate(sign); if (!Validate(subjCert, caKey.Public)) throw new Exception("Failed to validate newly created certificate!"); return subjCert; } private static Boolean Validate(X509Certificate cert, ICipherParameters pubKey) { cert.CheckValidity(DateTime.UtcNow); var tbsCert = cert.GetTbsCertificate(); // To Be Signed var sig = cert.GetSignature(); var signer = SignerUtilities.GetSigner(cert.SigAlgName); signer.Init(forSigning: false, parameters: pubKey); signer.BlockUpdate(input: tbsCert, inOff: 0, // offset length: tbsCert.Length); return signer.VerifySignature(sig); } private const String CaKeyPem = @"-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,C0B37765BDFC7D269C7057A3A463AB63 gSajHtV+qhJHBONKDktf3XoGS2Vwp0dHpk9sr1dRIThxLf6D7O1dYcTjIXJ/Iz+M DkV7vnyigADH//9Hv7BwEyJCnie44ChTVxfIGLIwtxlp2oKBVuNmOJRtl+VFgKeG zzzPxhMpgZJjpRm/jmdLp2YII374+P0fix+ZCTlzWDE5nbjnuumfK5+f+xtQMC4l F1QoiZSe6k80Li7e/9Qd+e7i8nMNwCrS7jA6ayGIr7/vLWDjMtEjLF6YGAzGGHzQ 3JHb8rsmUX1I6KApYjlZVYHsdnqtN34TZen9zcWyqijSJS6S+hQLf0i+F8hY0Z/J Y5fHk6br61n/6ZeEY7ijklVUeesbpc+JbjWAhYsg8wyVFTEQGVlLy7D0okO0x6J7 ej/aYUd9Fo2Jnl1I5BZYLXgg9WDsL4hu8u8EqbM4j4oIFxg6wlClMb4gS4iIl26v 36gisNzUY0xNVffLGKyAHsfi6pU8NSbh4Oil/TJcYR9jYu6GhB9Yvpnunc2/ae0W 1uRz6LP+RV9KWme2Diz3Kw1A049eiRC4qCJCsCGAJZzrKq6Anc7Ia47FDEC9J2yC +5vaPPv6j+pWJJv3wbopl8AStm0hTjg26HAyju3BYFqawP/XcjmVsO+y675vclaH g+Anr8gi3K4YNzOOLSOl2Fe/IK1BnMpHvabKy4Jo+NYfEIHUnWW1YBRAL6lWE2j2 wuZ5u+mhBYGkdQvhRCpJbe9GmXORjy5GJF/Pkyh27KHU/BxsnceY5OW12wk7nGBf HUajeFI5G9DyftJvVJ/WyACe5915JoujVIgSnYM3z/kg3VzOB8OdvUYkNBj+Xj3i Bwd1k3Due1HSlPnrW4JlCkMGQV2uhoOSZhHgxkUw/JRmBNBll6qyyqdyeRFFFIMD KaELfoCSpjlh6uA6zgS2MO1KdilINgTevyrSeMMqPY7YlH9YyEknyqSpwXNqyDfb itHs03n9lrksPgKQGstG9yrbKBan6dDn5rXnbvWrkEIUfrer/1YteCy1IYG49uZZ /jo82FEO/h7fyApevk/CHWMBt52EgXzAzAqz9okRNp93aGoc6jWFvfdAxp/vxIOp NGNN3LMvFwROr2y1d7VFKe45skCjFsYSGKqjnMZfUGHyFJSKV7LiOj9N32Mt9pj8 6nN8JFW2NmhOOPJd1CK7r1zXv4UWwnFFNlqzQkLujTNUUmhJhrqPCsbWOcVT9kqp 6GyyE4XO0u02ORpcA9WdniJmua5lTVF25BVZ8lwErJ5hlYaOPYpTbIlJGNZo9e1A 73ZfmANg/5TO4FqI0NJrUJN7ZIwwUPU8qH1wZcsTrnhSqaEKES+xqP6GfORMgIaE J3aLMd7BRVPWC05/6ki98LJz8+/ZURS9oGVNKwy4S7rCi0me2Vi/shzmEk6cRH4R uthELMaGMFCUjjKGclIdsT8MfMHPZ3VvzTEZANTMWSljdVat4UUcEj+MAQr5Q9uL VcaAe/AweVaVI3hmXORzph3Uv4o8Im0eWss+IHUziE1uqwOrLhXIljNUNztrD2hP kF20s1oGUKZ/V+lC/az7V7aZP8PreYV0P5mvP+v8gNepx62yCPLcyks9+IINz349 -----END RSA PRIVATE KEY-----"; public const String CaCertificatePem = @"-----BEGIN CERTIFICATE----- MIIDNDCCAhygAwIBAgIJAOtFlqoxtDSsMA0GCSqGSIb3DQEBCwUAMBUxEzARBgNV BAMMCjQ4VEwyMDBfY2EwIBcNMTgxMTE5MTUxMjQ5WhgPMjExODExMjAxNTEyNDla MBUxEzARBgNVBAMMCjQ4VEwyMDBfY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCyPY+iqCVOwIEulgIwKktMA4RpGPwHxDXKBak+M2/uG2skW1DnoaaK taWxcGBJrxsRJQEoAKkYDZAmleBwRcd7oaVK/NcRtyA83y7GJ4y77HxvVKYxwBMB 37EgkUXnBUcnUedrITVDZ6Fr+JYzRzfTb5M0x06W3RZvkTfyirq27CdnZ9SJXHC1 cgeyqnJzlPqH7etmxdUnqPeuRMa6g1lsGGjz0p03Fqbu5rjkB+TXGSkUqPbAho4b Qg+7XFR1El5MP0u83rmRyID+6k5yt2KLPlr6VH0xUL/EQzezNmEgwuFv5AWt33HT /VCpo5TDXkZBvgjxlBvoeoswuKYv9wR7AgMBAAGjgYQwgYEwHQYDVR0OBBYEFKtA pTzAM02NhCrCtEuuw+x9S08gMEUGA1UdIwQ+MDyAFKtApTzAM02NhCrCtEuuw+x9 S08goRmkFzAVMRMwEQYDVQQDDAo0OFRMMjAwX2NhggkA60WWqjG0NKwwDAYDVR0T BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAJPK22mlvUA2 yKnNJKC+91AVtclwuVB+862RyGb1d1RwI2+fB7KkqyBUXaIqvDS3c5R/gXksx2Nj nDZT0wUZpuSK8jCS6vaibQZOeucq1hYdTJUuPW34LWVUQs8LD4kaF9CNbiWMtuUg UOKul0yD2xVhbR+ZfBqdp836gYQmR44SRNRd7IwZJsuopciQKnoVPZPXk6isyusK hvx12IpeWtmc0n2ubOhDKhiK8kVU6QKQvCcuhiNqPKc7FvUyHrVBUhUuHluxXy2T TltkEV+VSpv5sA/c25zp8hGyLtV+LirphEMUZgBG3cE2dX2O0PUFDBTVJUDUTCQw aO2cAFGrouw= -----END CERTIFICATE-----"; }