wakeupneo wakeupneo - 2 months ago 72
C# Question

Generate self signed certificate on the fly

I searched around but didn't find a clear example.
I want to create a self signed (self)Trusted certificate programmatically(c#), following this step:

STEP1:
create root CA cert on the fly and add it to the certificate store in the folder "Trusted Root certification Authorities"

I want to do exactly what this command line tool does:

makecert.exe -sk RootCA -sky signature -pe -n CN=MY_CA -r -sr LocalMachine -ss Root MyCA.cer

STEP2:
create a cert based on the previously created root CA cert and put it in the certificate store, in the folder "Personal"

I want to do exactly what this command line tool does:

makecert.exe -sk server -sky exchange -pe -n CN=127.0.0.1 -ir LocalMachine -is Root -ic MyCA.cer -sr LocalMachine -ss My MyCertificate.cer

I want to obtain this:

enter image description here

I did that(see following code - STEP1), don't know how to make STEP2, any help would be appreciated. Target machines is Windows XP/Seven.
I tried both pure .net approach and BouncyCastle library.

//STEP1
mycerRoot=generateRootCertV1("MY_CA"); //tried also generateRootCertV2(BouncyCastle)
addCertToStore(mycerRoot, StoreName.Root, StoreLocation.LocalMachine);

//STEP2
mycer=generateCert("127.0.0.1",mycerRoot);//?????? <-- Something like that How to implement generateCert???
addCertToStore(mycer, StoreName.My, StoreLocation.LocalMachine);

public static Org.BouncyCastle.X509.X509Certificate generateRootCertV2(string certName)
{
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();

X509Name CN = new X509Name("CN=" + certName);

RsaKeyPairGenerator keypairgen = new RsaKeyPairGenerator();
keypairgen.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 1024));

AsymmetricCipherKeyPair keypair = keypairgen.GenerateKeyPair();

certGen.SetSerialNumber(BigInteger.ProbablePrime(120, new Random()));
certGen.SetIssuerDN(CN);
certGen.SetNotAfter(DateTime.MaxValue);
certGen.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0)));
certGen.SetSubjectDN(CN);
certGen.SetPublicKey(keypair.Public);
certGen.SetSignatureAlgorithm("MD5WithRSA");

Org.BouncyCastle.X509.X509Certificate newCert = certGen.Generate(keypair.Private);

return newCert;
}

public static X509Certificate2 GenerateRootCertV1(string HostNameOrIP_or_CertName)
{
X509Certificate2 cert = null;

try
{

using (CryptContext ctx = new CryptContext())
{
ctx.Open();
cert = ctx.CreateSelfSignedCertificate(
new SelfSignedCertProperties
{
IsPrivateKeyExportable = true,
KeyBitLength = 4096,
Name = new X500DistinguishedName("cn=" + HostNameOrIP_or_CertName),
ValidFrom = DateTime.Today.AddDays(-1),
ValidTo = DateTime.Today.AddYears(20),
});
}

}
catch (Exception ex)
{
}

return cert;
}

public static bool addCertToStore(X509Certificate2 cert, StoreName st, StoreLocation sl)
{
bool bRet = false;

try
{
X509Store store = new X509Store(st, sl);
store.Open(OpenFlags.ReadWrite);

if (cert != null)
{
byte[] pfx = cert.Export(X509ContentType.Pfx);
cert = new X509Certificate2(pfx, (string)null, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);

if (!certExists(store, cert.SubjectName.Name))
{
store.Add(cert);
bRet = true;
}
}
store.Close();
}
catch
{

}

return bRet;
}

Answer

I edited the answer to do root cert first and then issue an end entity certificate. Here is some example of generating self sign certificate through bouncy:

    public static X509Certificate2 GenerateSelfSignedCertificate(string subjectName, string issuerName, AsymmetricKeyParameter issuerPrivKey,  int keyStrength = 2048)
{
    // Generating Random Numbers
    var randomGenerator = new CryptoApiRandomGenerator();
    var random = new SecureRandom(randomGenerator);

    // The Certificate Generator
    var certificateGenerator = new X509V3CertificateGenerator();

    // Serial Number
    var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
    certificateGenerator.SetSerialNumber(serialNumber);

    // Signature Algorithm
    const string signatureAlgorithm = "SHA256WithRSA";
    certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);

    // Issuer and Subject Name
    var subjectDN = new X509Name(subjectName);
    var issuerDN = issuerName;
    certificateGenerator.SetIssuerDN(issuerDN);
    certificateGenerator.SetSubjectDN(subjectDN);

    // Valid For
    var notBefore = DateTime.UtcNow.Date;
    var notAfter = notBefore.AddYears(2);

    certificateGenerator.SetNotBefore(notBefore);
    certificateGenerator.SetNotAfter(notAfter);

    // Subject Public Key
    AsymmetricCipherKeyPair subjectKeyPair;
    var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
    var keyPairGenerator = new RsaKeyPairGenerator();
    keyPairGenerator.Init(keyGenerationParameters);
    subjectKeyPair = keyPairGenerator.GenerateKeyPair();

    certificateGenerator.SetPublicKey(subjectKeyPair.Public);

    // Generating the Certificate
    var issuerKeyPair = subjectKeyPair;

    // selfsign certificate
    var certificate = certificateGenerator.Generate(issuerPrivKey, random);

    // correcponding private key
    PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);


    // merge into X509Certificate2
    var x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());

    var seq = (Asn1Sequence)Asn1Object.FromByteArray(info.PrivateKey.GetDerEncoded());
    if (seq.Count != 9)
        throw new PemException("malformed sequence in RSA private key");

    var rsa = new RsaPrivateKeyStructure(seq);
    RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
        rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);

    x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
    return x509;

}


public static AsymmetricKeyParameter GenerateCACertificate(string subjectName, int keyStrength = 2048)
{
    // Generating Random Numbers
    var randomGenerator = new CryptoApiRandomGenerator();
    var random = new SecureRandom(randomGenerator);

    // The Certificate Generator
    var certificateGenerator = new X509V3CertificateGenerator();

    // Serial Number
    var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
    certificateGenerator.SetSerialNumber(serialNumber);

    // Signature Algorithm
    const string signatureAlgorithm = "SHA256WithRSA";
    certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);

    // Issuer and Subject Name
    var subjectDN = new X509Name(subjectName);
    var issuerDN = subjectDN;
    certificateGenerator.SetIssuerDN(issuerDN);
    certificateGenerator.SetSubjectDN(subjectDN);

    // Valid For
    var notBefore = DateTime.UtcNow.Date;
    var notAfter = notBefore.AddYears(2);

    certificateGenerator.SetNotBefore(notBefore);
    certificateGenerator.SetNotAfter(notAfter);

    // Subject Public Key
    AsymmetricCipherKeyPair subjectKeyPair;
    var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
    var keyPairGenerator = new RsaKeyPairGenerator();
    keyPairGenerator.Init(keyGenerationParameters);
    subjectKeyPair = keyPairGenerator.GenerateKeyPair();

    certificateGenerator.SetPublicKey(subjectKeyPair.Public);

    // Generating the Certificate
    var issuerKeyPair = subjectKeyPair;

    // selfsign certificate
    var certificate = certificateGenerator.Generate(issuerKeyPair.Private, random);
    var x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());
    // Add CA certificate to Root store
    addCertToStore(cert, StoreName.Root, StoreLocation.CurrentUser);

    return issuerKeyPair.Private;

}

and add to store (your code slightly modified):

public static bool addCertToStore(System.Security.Cryptography.X509Certificates.X509Certificate2 cert, System.Security.Cryptography.X509Certificates.StoreName st, System.Security.Cryptography.X509Certificates.StoreLocation sl)
{
    bool bRet = false;

    try
    {
        X509Store store = new X509Store(st, sl);
        store.Open(OpenFlags.ReadWrite);
        store.Add(cert);

        store.Close();
    }
    catch
    {

    }

    return bRet;
}

and usage:

var caPrivKey = GenerateCACertificate("CN=root ca");
var cert = GenerateSelfSignedCertificate("CN=127.0.01", "CN=root ca", caPrivKey);
addCertToStore(cert, StoreName.My, StoreLocation.CurrentUser);

I have not compiled this example code after @wakeupneo comments. @wakeupneo you might to slightly edit the code and add proper extensions to each certificate.