sslhttpsfiddlerfiddlercore

How do I get FiddlerCore programmatic Certificate Installation to 'stick'?


I'm using FiddlerCore to capture HTTP requests. Everything is working including SSL Captures as long as the Fiddler certificate is manually installed. I've been using manual installation through Fiddler's Options menu and that works fine.

However, if I use the FiddlerCore provided CertMaker class static methods to add the Fiddler certificate I find that I can use the certificate added to the cert root only in the current session. As soon as I shut down the application and start back up, CertMaker.rootCertExists() returns false.

I use the following code to install the certificate for the current user (from an explicit menu option at this point):

public static bool InstallCertificate()
{
    if (!CertMaker.rootCertExists())
    {
        if (!CertMaker.createRootCert())
            return false;

        if (!CertMaker.trustRootCert())
            return false;
    }

    return true;
}

The cert gets installed and I see it in the root cert store for the current user. If I capture SSL requests in the currently running application it works fine.

However, if I shut down the running exe, restart and call CertMaker.certRootExists() it returns false and if I try to capture SSL requests the SSL connection fails in the browser. If I recreate the cert and then re-run the requests in the browser while the app stays running it works again. I now end up with two certificates in the root store.

After exiting and relaunching certMaker.certRootExists() again returns false. Only way to get it to work is to register the cert - per exe session.

What am I doing wrong to cause the installation to not stick between execution of the same application?


Solution

  • I was able to solve this problem and create persistent certificates that are usable across EXE sessions, by removing the default CertMaker.dll and BcMakeCert.dll assemblies that FiddlerCore installs and using and distributing the makecert.exe executable instead.

    makecert.exe appears to create certificates in such a way that they are usable across multiple runs of the an application, where the included assemblies are valid only for the current application's running session.

    Update:

    If you want to use the CertMaker.dll and BcMakeCert.dll that FiddlerCore installs by default, you have to effectively cache and set the certificate and private key, using Fiddlers internal preferences object. There are a couple of keys that hold the certificate after it's been created and you need to capture these values, and write them into some sort of configuration storage.

    In the following example I have a static configuration object that holds the certificate and key (persisted to a config file when the app shuts down):

    public static bool InstallCertificate()
    {
        if (!CertMaker.rootCertExists())           
        {
            if (!CertMaker.createRootCert())
                return false;
    
            if (!CertMaker.trustRootCert())
                return false;
    
            // persist Fiddlers certificate into app specific config
            App.Configuration.UrlCapture.Cert = 
               FiddlerApplication.Prefs.GetStringPref("fiddler.certmaker.bc.cert", null);
            App.Configuration.UrlCapture.Key = 
               FiddlerApplication.Prefs.GetStringPref("fiddler.certmaker.bc.key", null);
        }
    
        return true;
    }
    
    public static bool UninstallCertificate()
    {
        if (CertMaker.rootCertExists())
        {
            if (!CertMaker.removeFiddlerGeneratedCerts(true))
                return false;
        }
        // persist Fiddlers certificate into app specific config
        App.Configuration.UrlCapture.Cert = null;
        App.Configuration.UrlCapture.Key = null;
        return true;
    }
    

    After installing a certificate this code captures the certificate and private key into the configuration object which persists that value later. For uninstallation, the values are cleared.

    At the beginning of the application or the beginning of the capture process, prior to calling CertMaker.rootCertExists() the keys are set from the configuration values. I do this at the beginning of my capture form:

    public FiddlerCapture()
    {
        InitializeComponent();
    
        // read previously saved Fiddler certificate from app specific config
        if (!string.IsNullOrEmpty(App.Configuration.UrlCapture.Cert))
        {
            FiddlerApplication.Prefs.SetStringPref("fiddler.certmaker.bc.key", 
                                                   App.Configuration.UrlCapture.Key);
            FiddlerApplication.Prefs.SetStringPref("fiddler.certmaker.bc.cert", 
                                                   App.Configuration.UrlCapture.Cert);
        }
    }
    

    Using this mechanism for saving and then setting the capture settings makes the certificates persist across multiple EXE sessions when using CertMaker.dll.

    More detailed info is available this detailed blog post on FiddlerCore.