How to create self-signed certificate programmatically for WCF service?

I could not make this work, but I found an alternate solution. (Update December 2014: I have now gotten it to work using the accepted answer.)

I was able to use the PluralSight.Crypto library to achieve what I need. I had to modify the source code slightly to get the private key to store in the LocalMachine store. The changes I made were to the file CryptContext.cs. I changed the CreateSelfSignedCertificate method. Following is a snippet of code including the change that I made. In essence, I set the Flags member of the CryptKeyProviderInformation structure to set it to 0x20 (CRYPT_MACHINE_KEYSET) if the CryptContext object contains this value in its Flags.

        byte[] asnName = properties.Name.RawData;
        GCHandle asnNameHandle = GCHandle.Alloc(asnName, GCHandleType.Pinned);

        int flags = 0;                    // New code
        if ((this.Flags & 0x20) == 0x20)  // New code
            flags = 0x20;                 // New code

        var kpi = new Win32Native.CryptKeyProviderInformation
        {
            ContainerName = this.ContainerName,
            KeySpec = (int)KeyType.Exchange,
            ProviderType = 1, // default RSA Full provider
            Flags = flags                 // New code
        };

Then I use the function in my own code like this:

        using (Pluralsight.Crypto.CryptContext ctx = new Pluralsight.Crypto.CryptContext()) {

            ctx.Flags = 0x8 | 0x20;
            ctx.Open();

            X509Certificate2 cert = ctx.CreateSelfSignedCertificate(
                new Pluralsight.Crypto.SelfSignedCertProperties
                {
                    IsPrivateKeyExportable = true,
                    KeyBitLength = 4096,
                    Name = new X500DistinguishedName("CN=" + subjectName),
                    ValidFrom = DateTime.Today,
                    ValidTo = DateTime.Today + expirationLength,
                });

            return cert;
        }

Notice that I set the Flags for the CryptContext object to be 0x8 | 0x20 (CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET).

I wish I could figure out what was wrong with my original solution. But I need something to work and in my testing this solution does what I need. I hope it helps someone else along the way.


I had the same issue using the equivalent code in PowerShell. It appears that sometime the private key just disappears. I used Process Monitor and you can see the key file being deleted.

The way I solved this was to add X509KeyStorageFlags.PersistKeySet to the X509Certificate2 constructor.


You can also use the CLR Security library on CodePlex (https://clrsecurity.codeplex.com/). Here is sample code which creates a self signed certificate, and tests it with SSLStream.

        var machineName = Environment.MachineName;
        var keyCreationParameters = new CngKeyCreationParameters();
        keyCreationParameters.KeyUsage = CngKeyUsages.AllUsages;
        keyCreationParameters.KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey;
        keyCreationParameters.Parameters.Add(new CngProperty("Length", BitConverter.GetBytes(4096), CngPropertyOptions.None));
        var cngKey = CngKey.Create(CngAlgorithm2.Rsa, "Test", keyCreationParameters);

        var x500DistinguishedName = new X500DistinguishedName("CN=" + machineName);
        x500DistinguishedName.Oid.Value = "1.3.6.1.5.5.7.3.1";
        var certificateCreationParameters = new X509CertificateCreationParameters(x500DistinguishedName);
        certificateCreationParameters.SignatureAlgorithm = X509CertificateSignatureAlgorithm.RsaSha512;
        certificateCreationParameters.TakeOwnershipOfKey = true;
        certificateCreationParameters.CertificateCreationOptions = X509CertificateCreationOptions.None;
        certificateCreationParameters.EndTime = new DateTime(9999, 12,31, 23, 59, 59, 999, DateTimeKind.Utc);
        var certificate = cngKey.CreateSelfSignedCertificate(certificateCreationParameters);

        var certificateStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
        certificateStore.Open(OpenFlags.ReadWrite);
        certificateStore.Add(certificate);
        certificateStore.Close();


        var tcpListener = TcpListener.Create(6666);
        tcpListener.Start();
        var client = new TcpClient("localhost", 6666);
        var acceptedClient = tcpListener.AcceptTcpClient();
        var acceptedClinetSslStream = new SslStream(
            acceptedClient.GetStream(), false);
        var serverAuthTask = acceptedClinetSslStream.AuthenticateAsServerAsync(certificate,
                            false, SslProtocols.Tls, true);

        SslStream clientSslStream = new SslStream(
            client.GetStream(),
            false,
            delegate(object o, X509Certificate x509Certificate, X509Chain chain, SslPolicyErrors errors)
                {
                    if (errors == SslPolicyErrors.None)
                        return true;

                    Console.WriteLine("Certificate error: {0}", errors);

                    // Do not allow this client to communicate with unauthenticated servers. 
                    return false;
                },
            null);
        var clientAuthTask = clientSslStream.AuthenticateAsClientAsync(machineName);

        Task.WaitAll(serverAuthTask, clientAuthTask);