Inserting Certificate (with privatekey) in Root, LocalMachine certificate store fails in .NET 4

后端 未结 6 521
清酒与你
清酒与你 2020-11-30 08:12

I\'m having problems inserting a new CA certificate with privatekey in the Root certificate store of the localmachine.

This is what happens:

//This          


        
6条回答
  •  Happy的楠姐
    2020-11-30 08:32

    The basic problem is that the .NET certificates API is just a wrapper around the C++ advapi32 certificate manager api, so you don’t get to specify all the options that get passed to this api that is actually responsible for sticking the cert into the Windows cert store and persisting the keys. The bottom line is that the “UseMachineStore” option needs to get passed to the CspProviderFlags which in turn gets passed to the CAPI.CRYPT_MACHINE_KEYSET. This is the little guy that determines whether the key gets persisted for real or not. There seem to be several different reasons why this option doesn’t get set even though you set the X509KeyStorageFlags.PersistKeySet and MachineKeySet and Exportable. All these options only live as long as the stupid key stays in the C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\ folder. If CRYPT_MACHINE_KEYSET doesn’t get set at time of import then advapi32 blows the key away as soon as the certificate handle gets disposed by GC.

    Solution: Add the certificate to the Trusted Root BEFORE you import the certificate into the Personal machine store. In reading the logs from CAPI2, I actually see two calls to “X509 Objects” every time the Certificate is “Imported”. One always has the , (what we want) but the other does not UNLESS “Verify Chain Policy” returns no errors. So it looks like advapi32 is checking the “validity” of the cert and either returns an exception that gets swallowed by X509Certificate2 (I love how many empty catch blocks they have in that code) or advapi32 just unilaterally decides to not persist the keys for untrusted certificates. (By the way, I suspect this is a behavior change between 2008 and 20012, but I haven’t proven that.) To work around this, I added an If-check to my code to add the certificate that if the Issuer equals the Subject (it is a self-signed cert) then add the cert to the Root before adding it to My.

        if (certificate.Issuer.Equals(certificate.Subject))
        {
            using (X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine)) { 
                store.Open(OpenFlags.ReadWrite);
                store.Add(certificate);
                store.Close();
            }
        }
    
        using (X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine)){ 
            store.Open(OpenFlags.ReadWrite);
            store.Add(certificate);
            store.Close();
        }
    

    Note: I have found that this is unneccessary if using a certificate that does not have a Subject Key Identifier already in it. Somehow when you trigger the api to actually generate the SKI instead of handing it in, it triggers the conditional to pass the magic CRYPT_MACHINE_KEYSET flag to advapi32.

提交回复
热议问题