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

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?

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.

If anyone is still interested, I found an easier solution based on the demo that Fiddler provides. This demo simply calls CertMaker.trustRootCert(), and strangely enough, it sticks! The first time it will ask whether you want to install the certificate, but after that, the function just returns true and will not cause the pop-up to show.
Unlike your and mine original program, the certificate sticks without having to go to the trouble of letting it stick yourself, so I analysed the differences with the demo. One of the differences I noticed was that the demo didn't have a reference to CertMaker.dll and BCMakeCert.dll. After removing these references from my own solution, I got the same behaviour as the demo.
Unfortunately, I don't have an explanation to why this works, but I hope this still helps some people.

Related

Trust anchor for certification path not found Hue Certificate

I would like to ask you something related with Philips Hue Smart Lamps integration with Kotlin.
I am working with Hue API v2 and after follow all the steps I was able to connect my mobile with Hue bridge and send orders to lights without problems, at least for me.
After generate the PROD application, some teammates have found problems during the bridge linking, they are receiving the error:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
This error happen when Android can’t find the trusted certificated to make the bridge call (This call attacks an IP with HTTPS, so make sense the error), however, I am adding the expected certificated into the network_security_config file (Hue certificate is .crt file) and as I said, this works for me and I tested it on 6 different devices.
The point here is, how is possible that some user have problems to generate the trusted certificate and other don’t have any problems? I checked mobile specs for each use case and I couldn’t find a pattern, OS version isn’t related (mobiles with the same OS works and fails), model is not representative either...
My only option about this... could this be related with user's Wifi? Because when an user said that it is not working, the user can’t do the flow in any device, all of them fails, but, when it works (like my case) I can install and do the flow in all my devices.
I tried to obtain the Hue certificate in differents ways, first time I did this:
`
private fun createCertificate(trustedCertificateIS: InputStream): SSLContext? {
val cf = CertificateFactory.getInstance("X.509")
val ca: Certificate = trustedCertificateIS.use { trustedCertificateIS ->
cf.generateCertificate(trustedCertificateIS)
}
// creating a KeyStore containing our trusted CAs
val keyStoreType = KeyStore.getDefaultType()
val keyStore = KeyStore.getInstance(keyStoreType)
keyStore.load(null, null)
keyStore.setCertificateEntry("ca", ca)
// creating a TrustManager that trusts the CAs in our KeyStore
val tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm()
val tmf = TrustManagerFactory.getInstance(tmfAlgorithm)
tmf.init(keyStore)
// creating an SSLSocketFactory that uses our TrustManager
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, tmf.trustManagers, null)
return sslContext
}
`
This works for me without problems, the app is able to find the Hue file and use it to generate the SSLContext, but, this is not working for some users.
In order to find another solution, I created a network_security_config file, same result.
`
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="#raw/huecert"/>
<certificates src="system"/>
</trust-anchors>
</base-config>
</network-security-config>
`
At this point, I am not sure what else can I try... so, if you have any feedback or idea about this I would really appreciate it.
Thanks!

Reload Netty Server's SSL Context for gRPC

Can someone tell me how to reload the SSLContext when a server certificate it refreshed/renewed without restarting the gRPC server?
I have this code to build and start a gRPC server.
The method certificateRefreshed() gets called whenever a certificate changes which is when I create a new SSL context, but this doesn't work unless I restart the grpc server.
public class ServerWithTls {
Server server;
SslContext sslContext;
public ServerWithTls() {
this.sslContext = getSslContext();
NettyServerBuilder serverBuilder = NettyServerBuilder
.forPort(settings.port())
.executor(executorService)
.addService(myService);
.sslContext(this.sslContext);
server = serverBuilder.build();
server.start();
}
public io.netty.handler.ssl.SslContext getSslContext() {
// returns ssl context based on cert and key
}
// gets notified when a server cert changes
public void certificateRefreshed() {
// create a new SSL context when cert changes
this.sslContext = getSslContext();
}
}
I'm unsure if there are easier alternatives, but I see two potentially possible ways.
Make your own SslContext, mimicking DelegatingSslContext. You would swap to a different SslContext (especially during newEngine) when you want a different certificate.
Use a KeyManagerFactory whose key material can change over time. I'm not aware of a pre-existing implementation of such a factory, so you probably would need to implement a KeyManagerFactorySpi that delegates to a KeyManagerFactory. You could then swap out the KeyManagerFactory over time.
I will warn that it would have been easy for me to miss something that would invalidate the approaches.
This question is similar to this question: Reloading a java.net.http.HttpClient's SSLContext
This option is unfortunately not available by default. After you have supplied the SSLContext to the Server and build the Server you cannot change the SSLContext. You will need to create a new SSLContext and a new Server.
I had the same challenge for one of my projects and I solved it by using a custom trustmanager and keymanager which wraps around the actual trustmanager and keymanager while having the capability of swapping the actual trustmanager and trustmanager. So you can use the following setup if you still want to accomplish it without the need of recreating the Server and SSLContext:
SSLFactory baseSslFactory = SSLFactory.builder()
.withDummyIdentityMaterial()
.withDummyTrustMaterial()
.withSwappableIdentityMaterial()
.withSwappableTrustMaterial()
.build();
Runnable sslUpdater = () -> {
SSLFactory updatedSslFactory = SSLFactory.builder()
.withIdentityMaterial(Paths.get("/path/to/your/identity.jks"), "password".toCharArray())
.withTrustMaterial(Paths.get("/path/to/your/truststore.jks"), "password".toCharArray())
.build();
SSLFactoryUtils.reload(baseSslFactory, updatedSslFactory);
};
// initial update of ssl material to replace the dummies
sslUpdater.run();
// update ssl material every hour
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(sslUpdater, 1, 1, TimeUnit.HOURS);
SslContext sslContext = NettySslUtils.forServer(sslFactory).build();
Server server = NettyServerBuilder
.forPort(8443)
.executor(executorService)
.addService(myService)
.sslContext(sslContext)
.build();
server.start();
See here for the documentation of this option: Reloading ssl at runtime
And here for an actual working example with Jetty (similar to Netty): Example swapping certificates at runtime with Jetty Server
You can add the library to your project with:
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-netty</artifactId>
<version>7.4.4</version>
</dependency>
You can view the full documentation and other examples here: GitHub - SSLContext Kickstart
By the way I need to add a small disclaimer I am the maintainer of the library.

How to debug NServiceBus ServiceControl instance

I've installed the ServiceControl Management Utility and I'm trying to add an instance.
I would like to run the instance under a service account because we use SQLServer transport but pmthe installation page I get the error "Invalid password".
The account is hosting another windows service on the same machine.
I've tried other admin accounts and creating the instance through the UI and Powershell scripts.
I'm 200% sure the password is correct.
Is there anyway I can increase the logging to determine what is failing?
Strangely, I can change the service account under the initial install and it works.. I was eventually able to get the service running using an SQL login but I would prefered to use integrated security and not keep the username and password in the connection string.
A patch that addresses this bug has been released. See - https://github.com/Particular/ServiceControl/releases/tag/1.7.3. Thanks Kye for making us aware of the issue
This is code that does the validation.
public bool CheckPassword(string password)
{
if (Domain.Equals("NT AUTHORITY", StringComparison.OrdinalIgnoreCase))
{
return true;
}
var localAccount = Domain.Equals(Environment.MachineName, StringComparison.OrdinalIgnoreCase);
var context = localAccount ? new PrincipalContext(ContextType.Machine) : new PrincipalContext(ContextType.Domain);
return context.ValidateCredentials(QualifiedName, password);
}
So in a multi-domain environment it might run into trouble.
Raise a bug here and we will be able to give you a better response.

Opening an SSL web-browser connection in HtmlUnit library

I've searched through web for couple hours on this issue, and none of the answers I found didn't really fit into my problem, so here's me, asking my first-ever question in SOF.
So, I'm trying to open a web-browser from a java program using the htmlunit library. The web site I need to connect requires SSL connection, and the certificate is stored in a USB key. Its iKey2023 product.
The system used to work(I did not write it), but one of the certificates in the USB key expired, so it automatically moved on to the next one (there were 4 certificates in total), and it suddenly stopped working.
It is giving me javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated error.
I'm back home now and I forgot the exact name of the method, but I remember the following.
Browser instance is created, using IE8
browser.setWebConnection method was called. This method, according to the API, is an internal API.
Make connection to the website by passing the URL as parameter
It's throwing the exception at step 3.
Some more details. The little details might be incorrect but I'm trying to describe a big picture.
At step 2, the method requites WebConnection object as a parameter, and there is a implementation of that interface. Within this implementation, a keystore is created using sun.security.pkcs11.SunPKCS11(configFileInputStream) (did I spell that correctly?)
It was sth like this.
Provider p = new sun.security.pkcs11.SunPKCS11(configFileInputStream);
Security.addProvider(p);
And create a keystore from this provider.
Using this keystore, within the WebConnection implementation, it creates a SSLSocket.
So, after the certificate has been switched to a new one, it's not picking up the certificate correctly.
Here's what I've tried.
I've tried to use different methods in the htmlunit library, something like setSecurityProvider, and I tried to put the Provider object created in above code snippet. I got class cast exception.
I tried to manually set the system properties(trustStore, trustStorePassword, keyStore, etc). In order to do this, I wanted to export the certificate out of the USB key, but it did not let me export the private key out from it, so I could not really create a valid PKCS12 file out of it (openSSL wanted a private key file along with .pem file for conversion, and I did not have that key file).
They did not work, and I'm so stuck right now.
I have a similar issue. In my case, an admin changed the certificate and I began encountering the same SSLPeerUnverifiedException.
I found that I can set the WebClient to use insecureSSL (prior to calling getPage())and I will no longer get the exception.
webClient.setUseInsecureSSL(true);
This however, doesn't resolve the issue as the server basically doesn't authenticate the client.
Its as if the WebClient is storing something that doesn't work with the new certificate.

Kohana Auth Library Deployment

My Kohana app runs perfectly on my local machine.
When I deployed my app to a server (and adjust the config files appropriately), I can no longer log into the app.
I've traced through the app login routine on both my local version and the server version and they both agree with each other all the way through until you get to the auth.php controller logged_in() routine where suddenly, at line 140 - the is_object($this->user) test - the $user object no longer exists!?!?!?
The login() function call that calls the logged_in() function successfully passes the following test, which causes a redirect to the logged_in() function.
if(Auth::instance()->login($user, $post['password']))
Yes, the password and hash, etc all work perfectly.
Here is the offending code:
public function logged_in()
{
if ( ! is_object($this->user))
{
// No user is currently logged in
url::redirect('auth/login');
}
etc...
}
As the code is the same between my local installation and the server, I reckon it must be some server setting that is messing with me.
FYI: All the rest of the code works because I have a temporary backdoor available that allows me to use the application (view pages of tables, etc) without being logged in.
Any ideas?
I solved the problem (DUH!).
The answer was that the cookie.php config file had $config['domain'] = 'localhost'. Setting this to the actual domain that the app is installed in magically made my life happy again!
Thanks everyone for your help and interest.