Trust anchor for certification path not found Hue Certificate - kotlin

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!

Related

What are the hidden configurations that enable TLS communication with only CA info from Kafka cluster?

I have this code, it works with my Kafka cluster (I got it from my colleague and no idea how it is configured). I copied the content of cluster-ca-cert file into the file myca.ca.pem. My issue here is that I don't get why it works without many parameters necessary to establish an SSL connection.
from time import sleep
from json import dumps
from kafka import KafkaProducer
producer = KafkaProducer( bootstrap_servers='test-kafka.com:443',value_serializer=lambda x: dumps(x).encode('utf-8'), security_protocol='SSL', ssl_cafile = 'myca.ca.pem', ssl_check_hostname=False)
for e in range(1000):
data = {'number' : e}
producer.send('hello', value=data)
sleep(5)
I understand what and how pub/priv key or CA are used for, but when putting all these things in SSL and Kafka context, I have difficulties understanding. Many questions come up in my mind, e.g.
Where are pub/priv keys generated by the client? In the code, I don't expose either pub key or CA anywhere, how the server can trust the client?
Why does it work with only CA from the cluster, how about pub key generated at the servers side? Same, in the code, I only copy the CA from the server, not the public key.
Does it mean there is a configuration that allows using a default value from somewhere? I am sure there is, just want to know which part of the SSL handshake is configured.
Thanks in advance,

How to get the secret certificate from C# in a Service Fabric application on Unix?

I have the following in my applicationmanifest.xml:
<Principals>
<Users>
<User Name="IdentityService" AccountType="NetworkService" />
<User Name="ExplorerService" AccountType="NetworkService" />
</Users>
</Principals>
<Policies>
<SecurityAccessPolicies>
<SecurityAccessPolicy ResourceRef="IdentityCert" PrincipalRef="IdentityService" ResourceType="Certificate" />
<SecurityAccessPolicy ResourceRef="IdentityCert" PrincipalRef="ExplorerService" ResourceType="Certificate" />
</SecurityAccessPolicies>
</Policies>
<Certificates>
<SecretsCertificate X509FindValue="[IDENTITY_SERVICE_THUMBPRINT]" Name="IdentityCert" />
</Certificates>
On Windows clusters, I have been using the thumbprint to look up in localmachine
X509Certificate2 cert = X509.LocalMachine.My.Thumbprint.Find(options.Thumbprint, validOnly: false).FirstOrDefault();
without problems.
When deploying to a Unix cluster, I faced the following exception:
Unix LocalMachine X509Store is limited to the Root and CertificateAuthority stores. Unix LocalMachine X509Store is limited to the Root and CertificateAuthority stores.
I do understand what it is telling me; I can't use LocalMachine. But just to get this right, how would I locate the X509Certificate2 certificate on the Unix machines? (Is it a .NET Core or Service Fabric thing?)
From the docs:
Service Fabric generally expects X.509 certificates to be present in the /var/lib/sfcerts directory on Linux cluster nodes. This is true of cluster certificates, client certificates, etc. In some cases, you can specify a location other than the var/lib/sfcerts folder for certificates.
and..
Certificates specified in the application manifest, for example, through the SecretsCertificate or EndpointCertificate elements, must be present in the /var/lib/sfcerts directory. The elements that are used to specify certificates in the application manifest do not take a path attribute, so the certificates must be present in the default directory. These elements do take an optional X509StoreName attribute. The default is "My", which points to the /var/lib/sfcerts directory on Linux nodes. Any other value is undefined on a Linux cluster. We recommend that you omit the X509StoreName attribute for apps that run on Linux clusters.
I haven't done SF Linux in a while, so I don't have any script or snippet to help, but the docs should be straight forward.
The docs on Service Fabric Linux certificates are wrong - at least for a .NET Core service, StoreLocation.LocalMachine + StoreName.My provides no access to the cert files located at /var/lib/sfcerts. The docs may be correct for certificates used by the Service Fabric infrastructure, but they are misleading and plain wrong for SF services that require access to certificates.
The .NET Core document which acts as a public spec for X509Store support on Linux explicitly states that a new X509Store(StoreName.My, StoreLocation.LocalMachine) results in a CryptographicException, which is consistent with the original post and my experience.
So, you'll have to come up with an alternate approach to obtain the certificates. Two approaches seem viable to me:
Copy the cert files to a location where the SF service account can pick them up on startup, and either read them directly, or write them to new X509Store(StoreName.My, StoreLocation.CurrentUser) for subsequent use. You can use a SetupEntryPoint that runs as a user with AccountType="LocalSystem" to run the SetupEntryPoint as root on Linux. root is needed to read the files from /var/lib/sfcerts.
Obtain the certificate from another source, eg KeyVault. To secure this, you'll probably want to use the new Service Fabric support for Managed Service Identity.
Bottom line: It's definitely not trivial to obtain certificates from a Service Fabric service on Linux.

IBM MQ: Establishing an SSL connection

We're struggling to get IBM MQ to work across SSL.
We've been provided with the certificate chain for the remote host and installed into the Windows Certificate Store (Local Machine). These all look valid.
We're using the following connection properties:
connectionProperties.Add(MQC.SSL_PEER_NAME_PROPERTY, "other-server.com");
connectionProperties.Add(MQC.SSL_CIPHER_SUITE_PROPERTY, "TLS_RSA_WITH_AES_256_CBC_SHA256"); connectionProperties.Add(MQC.SSL_CIPHER_SPEC_PROPERTY, "TLS_RSA_WITH_AES_256_CBC_SHA256");
connectionProperties.Add(MQC.SSL_CERT_STORE_PROPERTY, "*SYSTEM");
connectionProperties.Add("CertificateLabel", "ibmwebspheremqmywindowsusernamewithoutdomain");
MQEnvironment.SSLCertRevocationCheck = true;
We've established that the "CertificateLabel" is the "Friendly name" in Windows parlance.
We've proven unencrypted communication and network-level configuration.
We're using 8.0.0.7 client.
These are the issues we've come across:
All secure communications fail with a 2538 error. (MQRC_HOST_NOT_AVAILABLE, https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.tro.doc/q045380_.htm)
No success setting the Friendly Name to ibmwebspheremq and ibmwebspheremqmywindowsusername#domain and ibmwebspheremqmywindowsusernamewithoutdomain
General questions:
Are we correct in assuming that we can install generated certificates exclusively in the Windows Certificate Store?
Is the 2538 error even related to SSL communications? It feels like a network error, though there is that final point in the referenced error documentation.
Is there anywhere we can look for more informative error information? eg. relating to the SSL trust chain to see if there is an issue there?
The issue was the following line:
connectionProperties.Add(MQC.SSL_PEER_NAME_PROPERTY, "otherserver.com");
Turns out that:
It needs it in a canonical format, so DN=, etc.
You don't even need that line
Though we did learn a few things along the way:
The line:
connectionProperties.Add("CertificateLabel", "ibmwebspheremqmyusername");
Is the string ibmwebspheremq plus your Windows username (without your domain) and the label should be set on the Friendly name of your client machine's outgoing certificate NOT including the username.
The various folders inside your Windows certificate store are significant. The intermediate CAs should be correctly filed.

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?
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.

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.