7

I'm currently running IIS on my server using an app instantiating certificates.

By doing this code, for instance :

X509Certificate2 myX509Certificate = new 
X509Certificate2(Convert.FromBase64String(byteArrayRawCertificate), passwordCertificate, 
X509KeyStorageFlags.Exportable | 
X509KeyStorageFlags.MachineKeySet | 
X509KeyStorageFlags.PersistKeySet);

The code works fine. But I encounter a problem on my computer, on the following folder :

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

3KB RSA files keep on being added on that folder. For now, I have more than a million files like those ones :

enter image description here

I would like to delete those files, but :

  • IIS uses one of them for encryption of password, or perhaps for other purposes and I don't know which one,
  • Deleting such a large folder can take time (like days)

    1. Is there a simple way not to create those files again and again ? (if I don't mention "MachineKeySet" while instanciating my certificate, this won't work)
    2. If not, is there a way to remove the created files without deleting IIS ones ?
    3. Is there a way to detect which files are used by IIS ?

Thanks in advance for your help.

Thordax
  • 1,673
  • 4
  • 28
  • 54

3 Answers3

7

There is some work for you. At first, you *MUST NOT* instantiate X509Certificate2 object from PFX file each time you need to access it. It is very BAD idea. This causes a new key file generated in the MachineKeys folder. Instead, you have to install the certificate to local certificate store once and then reference installed certificate.

Use X509Store.Add() method to install certficate to local store:

X509Certificate2 myX509Certificate = new 
X509Certificate2(Convert.FromBase64String(byteArrayRawCertificate), passwordCertificate, 
X509KeyStorageFlags.MachineKeySet);
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(myX509Certificate);
store.Close()

Next time you need to access your certificate and private key, use same X509Store class as follows:

X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2 myCert = store.Certificates.Find(blablabla);
store.Close()

Instead of "blablabla", specify search filter: X509Certificate2Collection.Find(). You can use various filter options to locate your certificate. Most common used is by thumbprint.

Regarding large folder. If you are sure that there are no other certificates in the LocalMachine\My store, you can simply purge all contents and then install your certificate by using the code above.

Steve Dunn
  • 21,044
  • 11
  • 62
  • 87
Crypt32
  • 12,850
  • 2
  • 41
  • 70
  • Thanks for the info. By the way, I also use many multiple certificates and for some rare cases, I use myX509Certificate.Reset(); to clean the used file. – Thordax Dec 31 '15 at 09:23
  • 2
    This doesn't seem to answer the question: "How to delete unneeded files from RSA\MachineKeys". Am I missing something? – mistika Jan 27 '17 at 18:39
  • Last paragraph gives some insights. Isn't it? – Crypt32 Jan 27 '17 at 18:59
  • Well, there're other apps that store there their keys. How can I distinguish ones from others? That's where the problem – mistika Feb 08 '17 at 19:29
  • 1
    @mistika This is the answer to the "is there a way not to create those files again?" question. It shows you a way to avoid the problem in the first place. And since there's no easy way to determine which files can be deleted safely, it should be accepted as the alternative answer.. – Duoc Tran Mar 14 '17 at 23:15
6

Had the same problem, and was quite afraid to delete something, as I did read on other sources, that there are some system-critical files in there. By deleting those few you could end up with messed up IIS or other software.

As I had 8'000'000 of files there, I could not even open the folder - what I did was make small program in C# that delete files judging by OWNER - the user who created them! If they were created by IIS user, it would be safe to do this (please be sure you understand what you are doing!)

        var userNameToDeleteBy = "IIS_App_Pool_User_Goes_here!";

        var allFiles = (new DirectoryInfo(Directory.GetCurrentDirectory()).EnumerateFiles());

        var i = 0;

        foreach (var file in allFiles)
        {

            var fname = file.FullName;
            string user = System.IO.File
                .GetAccessControl(fname)
                .GetOwner(typeof(System.Security.Principal.NTAccount))
                .ToString();

            if(user.Contains(userNameToDeleteBy))
            {
                File.Delete(fname);
                i++;
            }

            //output only every 1k files, as this is the slowest operation
            if (i % 1000 == 0) Console.WriteLine("Deleted: " + i); 
        }

Also, if you really need to load cert from file, here is the answer on how to leave folder garbage-free:

Prevent file creation when X509Certificate2 is created?

halloweenlv
  • 490
  • 6
  • 14
0

This is a Powershell script that deletes all machine keys that are owned by a specific application pool user.

It basically does the same as the C# program made by @halloweenlv (a powershell script seemed more practical)

param(
  [ValidateNotNullOrEmpty()]
  [Parameter(Mandatory=$true)]
  [string] $ApplicationPoolName,
  [string] $MachineKeysDirectory = "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys"
)

$nrOfKeysDeleted = 0;

foreach ($keyPath in [IO.Directory]::EnumerateFiles($MachineKeysDirectory)) {
  $owner = Get-Acl -Path $keyPath | Select-Object -ExpandProperty "Owner";

  if ($owner -eq "IIS APPPOOL\$ApplicationPoolName") {
    [System.IO.File]::Delete($keyPath)
    $nrOfKeysDeleted++;
  }

  if ($nrOfKeysDeleted  -gt 0 -and $nrOfKeysDeleted % 1000 -eq 0) {
    Write-Output -Verbose "Deleted $nrOfKeysDeleted keys";
  }
}

Write-Output -Verbose "Deleted $nrOfKeysDeleted keys";

The machine keys in this directory are system files. As mentioned before, some files are critical for the system so simply deleting everything is not a good idea.

The performance is OK but not great. On my server it took about 5 seconds to delete 1000 keys. That's about one hour and half for a million keys.

MonkeyDreamzzz
  • 3,978
  • 1
  • 39
  • 36