141 lines
6.3 KiB
C#
141 lines
6.3 KiB
C#
|
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<X509Certificate>(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<AsymmetricCipherKeyPair>(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-----";
|
||
|
|
||
|
}
|