I battled to find a simple tutorial / sample code to create a self-signed certificate and then add that with the private key into the Windows computer store. So here is one to get you going.

There is a great library maintained by the folks at Bouncy Castle. Check them out here.

The entire specification can be found here.

Here is a high level summary of what we are going to accomplish in the code sample below:-

Note:- Bouncy Castle doesn’t care if you are Windows or whatever so it lacks the necessary interfaces to do things like install into the Windows Computer store. For that we’ll convert our Bouncy Castle X509 at the end.

  • Generate some random number generators
  • Create an instance of the awesome certificate generator from Bouncy Castle
  • Populate the mandatory settings such as the subject name and expiration date
  • Generate a public / private key pair
  • Create a Bouncy Castle certificate
  • Convert the Bouncy Castle certificate to Microsoft’s X509 certificate
  • Install the certificate into the computer store along with the private key

Lets get going on a simple “end-to-end” code sample.

// Stage One - Create a Certificate

// Random number generators
var _randomGenerator = new CryptoApiRandomGenerator();
var _random = new SecureRandom(_randomGenerator);

// Create a bouncy certificate generator
var _certificateGenerator = new X509V3CertificateGenerator();

// Create a random serial number compliant with 
var _serialNumber =
    BigIntegers.CreateRandomInRange(
        BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), _random);
            _certificateGenerator.SetSerialNumber(_serialNumber);

// Define signature algorithm
const string _signatureAlgorithm = "SHA256WithRSA";
_certificateGenerator.SetSignatureAlgorithm(_signatureAlgorithm);

// Define the subject name
string _subjectName = "C=ZA,O=SALT Africa,OU=Cloud Services,CN=Password Client";  

// Define the subject DN
//  because its self signed lets set the issuer as the subject 
var _subjectDN = new X509Name(_subjectName);
var _issuerDN = _subjectDN;

// Update the certificate generator with the Issuer and Subject DN
_certificateGenerator.SetIssuerDN(_issuerDN);
_certificateGenerator.SetSubjectDN(_subjectDN);

// Define certificate validity
var _notBefore = DateTime.UtcNow.Date;
var _notAfter = _notBefore.AddYears(5);

// Update the certificate generator with certificate validity
_certificateGenerator.SetNotBefore(_notBefore);
_certificateGenerator.SetNotAfter(_notAfter);

// Define the strength of the Key Pair
const int strength = 2048;
var _keyGenerationParameters = new KeyGenerationParameters(_random, strength);

// Create a new RSA key 
var _keyPairGenerator = new RsaKeyPairGenerator();
_keyPairGenerator.Init(_keyGenerationParameters);
var _subjectKeyPair = _keyPairGenerator.GenerateKeyPair();

// Add the public key to the certificate generator
_certificateGenerator.SetPublicKey(_subjectKeyPair.Public);

// Add the private key to the certificate generator
var _issuerKeyPair = _subjectKeyPair;
var _certificate = _certificateGenerator.Generate(_issuerKeyPair.Private, _random);

// Stage Two - Convert and add certificate to local certificate store.

// Bouncy castle does not provide a mechanism to interface with the local certificate store.
// so we create a PKCS12 store (a .PFX file) in memory, and add the public and private key to that.
var store = new Pkcs12Store();

// What Bouncy Castle calls "alias" is the same as what Windows terms the "friendly name".
string friendlyName = _certificate.SubjectDN.ToString();

// Add the certificate.
var certificateEntry = new X509CertificateEntry(_certificate);
store.SetCertificateEntry(friendlyName, certificateEntry);

// Add the private key.
store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(_subjectKeyPair.Private), new[] { certificateEntry });

// Convert it to an X509Certificate2 object by saving/loading it from a MemoryStream.
const string password = "Rand0mPa55word!";
var stream = new MemoryStream();
store.Save(stream, password.ToCharArray(), _random);

var convertedCertificate =
    new X509Certificate2(stream.ToArray(),
                            password,
                            X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);

// Add the certificate to the certificate store
X509Store _CertificateStore = new X509Store(StoreName.My,StoreLocation.LocalMachine);
_CertificateStore.Open(OpenFlags.ReadWrite);
_CertificateStore.Add(convertedCertificate);
_CertificateStore.Close();

And there you have it. Hope this helps….