Justin
Justin

Reputation: 2999

c# X509Certificate2 add certificate how mark as exportable

I have a .NET 4.0 program which is running localhost on port 9000. I want to support SSL and have a .pfx certificate to import.

Because the program is running at multiple computers the programm itself is responsible to store the certificate and register the its port.

When imported and registered by the program, everything works. But when I reboot the computer the https connection does not work any.. more..

The event viewer gives the following error:

A fatal error occurred when attempting to access the SSL server credential private key. The error code returned from the cryptographic module is 0x8009030D. The internal error state is 10001.

and

An error occurred while using SSL configuration for endpoint 0.0.0.0:9000. The error status code is contained within the returned data.

I found some solutions which state that you need to mark the certificate as 'exportable' while importing but I can't find how I do that in code.

Website 1 and Website 2

Storing the certificate:

String path = String.Concat(IOHelper.AssemblyPath, @"\certificate.pfx");
X509Certificate2 cert = new X509Certificate2(path, "password");

X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);

if(!store.Certificates.Contains(cert))
{
    store.Add(cert);
}

Registering the host:

netsh http add sslcert ipport=0.0.0.0:9000 certhash=<cert hash> appid=<app id>

Upvotes: 5

Views: 4696

Answers (3)

jonmeyer
jonmeyer

Reputation: 848

When using Azure to download from a Key Vault, you need to specify the options to allow exportable

IAzureClientFactory<CertificateClient> _certificateClientFactory = ...
var certificateClient = _certificateClientFactory.CreateClient("ClientName");
var certificate = certificateClient.DownloadCertificate(new DownloadCertificateOptions("CertName")
{
    KeyStorageFlags = X509KeyStorageFlags.Exportable
});

Upvotes: 0

Roberto Bonini
Roberto Bonini

Reputation: 7303

Further to Madeillei's answer, you can pass the following flags:

var cert = new X509Certificate2(path, "password", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable| X509KeyStorageFlags.MachineKeySet);

If you are storing the cert in the CurrentUser store rather than in the LocalMachine store, do the following:

var cert = new X509Certificate2(path, "password", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable| X509KeyStorageFlags.UserKeySet);

The Key set flags indicate the following:

    //
    // Summary:
    //     Private keys are stored in the current user store rather than the local computer
    //     store. This occurs even if the certificate specifies that the keys should go
    //     in the local computer store.
    UserKeySet = 1,
    //
    // Summary:
    //     Private keys are stored in the local computer store rather than the current user
    //     store.
    MachineKeySet = 2,

The private key needs to be in the same place as the rest of the certificate for it to work.

Upvotes: 2

Ebbelink
Ebbelink

Reputation: 764

To mark a X509Certificate2 as exportable is actually quite simple. You add a third parameter (X509KeyStorageFlags.Exportable) which indicates that the certificate is exportable.

var cert = new X509Certificate2(path, "password", X509KeyStorageFlags.Exportable);

Upvotes: 4

Related Questions