11

We create a X509Certificate2 object in our ASP.NET app to make periodic outgoing connections. Every time one of these certificates is created a new file is created in:

C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys

That folder now has 4 million files that never get cleaned up. I've tried removing the Persist flag

new X509Certificate2(certBytes, p12Pwd, X509KeyStorageFlags.MachineKeySet);

//no X509KeyStorageFlags.PersistKeySet

but that doesn't help -- still get the 2Kb file on every call.

I got my hopes up when I saw this answer, but this is a 2008 R2 server, and the temp files are not 0 bytes, so it seems to be a different case.

How can we use a X509Certificate2 without filling up the disk?

Community
  • 1
  • 1
DougN
  • 4,407
  • 11
  • 56
  • 81

4 Answers4

6

Use .NET 4.6:

X509Certificate2 implements the IDisposable interface starting with the .NET Framework 4.6; in previous versions of the .NET Framework, the X509Certificate2 class does not implement this interface, and therefore the Dispose method does not exist.

Nick Westgate
  • 3,088
  • 2
  • 34
  • 41
  • 1
    It should also be noted that you also must not set X509KeyStorageFlags.PersistKeySet otherwise it will stick around. Even still, Microsoft should have provided a way better way to deal with this as it is not always easy to dispose of a certificate that has been loaded via some provider in a web environment, during shutdown. – Michael Brown May 05 '20 at 00:04
  • @MichaelBrown: Just FYI, at the time I posted this answer I was following [this issue](https://github.com/dotnet/runtime/issues/17166) which has an interesting discussion about "perphemeral" certificates - which broke things in our system when I tried it. The issue is closed now and I haven't been following it. – Nick Westgate May 05 '20 at 00:26
  • 1
    thanks for the follow up on that. I'm looking into that particular feature but I don't see any support for it in .Net Standard. X509KeyStorageFlags doesn't contain `EphemeralKeySet` and it appears they only added it to .Net Core for some reason. Will keep digging into it. – Michael Brown May 05 '20 at 01:37
6

I have the same issue on our server. The best way I found for now is to delete files from my code.

using System;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.IO;
using System.Security.Cryptography.X509Certificates;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Byte[] bytes = File.ReadAllBytes(@"D:\tmp\111111111111.p12");
            X509Certificate2 x509 = new X509Certificate2(bytes, "qwerty", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
            var privateKey = x509.PrivateKey as RSACryptoServiceProvider;
            string uniqueKeyContainerName = privateKey.CspKeyContainerInfo.UniqueKeyContainerName;
            x509.Reset();

            File.Delete(string.Format(@"C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\{0}", uniqueKeyContainerName));
        }
    }
}
5

To reproduce your problem I have created this sample code. My testing environment was Windows 8.1 64bit and the application was written in .NET 4.5.

using System.IO;
using System.Security.Cryptography.X509Certificates;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            var certBytes = File.ReadAllBytes(@"c:\cert.p12");
            var p12Pwd = "somepassword";

            for (var i = 0; i < 1000; i++)
            {
                var cert = new X509Certificate2(certBytes, p12Pwd, X509KeyStorageFlags.MachineKeySet);

                // this line helped keep filesize from growing   
                // cert.Reset(); 
            }
        }
    }
}

I was shocked that file size of C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys went up to 2MB. Then application exited and the filesize dropped down to 20K (that was probably its starting size).

Then I have added cert.Reset(); (I have commented it in the code above). This should be called when you no longer need the X509Certificate2 instance. After that, the filesize of C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys was flapping between 20K and 22K.

So my suggestion is to call cert.Reset(); when you no longer need the X509Certificate2 instance.

pepo
  • 8,644
  • 2
  • 27
  • 42
  • I was excited when I read your suggestion, but then found I already call Reset :( One difference might be that I pass the certificate to SslStream.AuthenticateAsClient, so I'm wondering if maybe that adds a reference to a file... ? Looking further. – DougN Apr 01 '14 at 13:39
  • FYI, when the cert garbage collects it has the same effect as calling Reset(). Calling reset is just a way to speed up the cleanup if you want that disk space NOW – Zain Rizvi Aug 21 '14 at 18:56
  • Thanks for the info. I didn't try with the reset method. – pepo Aug 22 '14 at 11:10
  • I don't think the garbage collector works in all the cases in here if it would work the issue should not happen. It is strange that X509Certificate2 has a Reset but no Dispose – Bogdan Sep 02 '16 at 17:26
  • 1
    @Bogdan, X509Certificate2 has a Dispose that calls Reset in .NET 4.6. – Nick Westgate Nov 10 '16 at 03:56
2

I have the same issue on our server. The best way I found for now is to delete files (except useful ones) via a script.

Exception list :

  • Microsoft Internet Information Server -> c2319c42033a5ca7f44e731bfd3fa2b5 ...
  • NetFrameworkConfigurationKey -> d6d986f09a1ee04e24c949879fdb506c ...
  • iisWasKey -> 76944fb33636aeddb9590521c2e8815a ...
  • WMSvc Certificate Key Container -> bedbf0b4da5f8061b6444baedf4c00b1 ...
  • iisConfigurationKey -> 6de9cb26d2b98c01ec4e9e8b34824aa2 ...
  • MS IIS DCOM Server -> 7a436fe806e483969f48a894af2fe9a1 ...
  • TSSecKeySet1 -> f686aace6942fb7f7ceb231212eef4a4 ...
  • https://forums.whirlpool.net.au/archive/1683713

via https://forums.iis.net/t/1224708.aspx?C+ProgramData+Microsoft+Crypto+RSA+MachineKeys+is+filling+my+disk+space

This solution remains a patch. It would be better to no generate files in MachineKeys folder.

BaptX
  • 561
  • 1
  • 7
  • 21
  • 1
    I am running into same issue. how were you able to identify these keys. I couldn't find IIS key. There is no machine key file starting with c2319c42033a5ca7f44e731bfd3fa2b5 on our server. – user3587767 May 23 '21 at 07:32