How do I find my server's public key info to do certificate pinning in OkHttp? - https

I have a server with a custom certificate on it issued by my own personal certificate authority. It's not on a public domain so it's not possible to use a standard certificate authority. I want to get an Android client to connect to this server using OkHttp. According to the docs, the code should look like this:
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("myserver.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
.build();
Where the SHA256 hash is, quoting the docs: "a hash of a certificate’s Subject Public Key Info, base64-encoded and prefixed with either sha256/ or sha1/". I have the cert and the key files for the server, but how can I get the required hash?
I'm using OkHttp 3.

Try making a request to your server with the configuration above to see how that fails. The exception should tell you which pins were found.
You must do certificate pinning in coordination with your server team! Otherwise a change they make will prevent your client from being able to reach the server.

Related

PCF Container TrustManager adds certificates, but TrustManagerFactory loads certificates twice

I run a spring boot app on PCF with an apache-httpclient 4.x. The client creates a ssl context:
final SSLContext sslcontext = SSLContext.getInstance(algorithm);
sslcontext.init(keymanagers, trustmanagers, params.getSecureRandom());
I get the trustmanagers as follows:
final TrustManagerFactory tmfactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmfactory.init((KeyStore) null);
I log the number of certificates it finds and I log the found CN's. However I found it list every certificate twice!
If I provide a keystore with 1 certificate:
tmfactory.init((KeyStore) truststore);
It will log that certificate + all environment certificates. As follows:
private static void logAcceptedIssuers(TrustManager[] trustmanagers) {
log.info("Adding the following trusted certificates to the SSL context: ");
Arrays.stream(trustmanagers)
.filter(X509TrustManagerWrapper.class::isInstance)
.map(X509TrustManagerWrapper.class::cast)
.map(X509TrustManagerWrapper::getAcceptedIssuers)
.forEach(SSLContextFactory::logAcceptedIssuers);
}
private static void logAcceptedIssuers(final X509Certificate[] certificates) {
final int certificatesCount = certificates.length;
final String prefix = "Trusted certificates (total=" + certificatesCount + "): \n";
final String certDNs = Arrays.stream(certificates)
.map(X509Certificate::getSubjectDN)
.map(Principal::getName)
.map(SSLContextFactory::extractCommonName)
.collect(Collectors.joining(" |#| ", prefix, "\n"));
log.info(certDNs);
}
#VisibleForTesting
static String extractCommonName(String principalName) {
... Some code for extracting commonname from principal name...
return cn;
}
Where does the TrustManagerFactory find the pcf trusted certificates?
How can I check if those pcf certificates are available & loaded, or where can I get the pcf-certificates-only TrustManager. My worry is that it might cause issues if I load it twice, but I have no indication it is causing issues (but now I have 288 instead of 144 certificates in my SSLContext, does that impact performance? Can it cause issues?)).
Regards,
Rick
The Java buildpack adds a component called the Container Security Provider. This is what adds the functionality to automatically load Platform/Bosh trusted CA certificates, as well as the container instance ID cert and key.
To ensure platform/Bosh trusted CA certificates are trusted, the Container Security Provider adds a TrustManagerFactory. This looks at the file /etc/ssl/certs/ca-certificates.crt and trusts everything in that file.
This is in addition to the default behavior of the JVM.
I log the number of certificates it finds and I log the found CN's. However I found it list every certificate twice!
You didn't share the code to show how you're doing this, so I can only speculate. My suspicion is that you're seeing duplicates because the Container Security Provider does not replace the default behavior for trusting CA certs in the JVM, it adds an additional TrustManager.
Pair that with the fact that there is probably a lot of overlap between what's in /etc/ssl/certs/ca-certificates.crt and what's in the JVM's default trust store. I guess I could see there being duplicates.
If I provide a keystore with 1 certificate:
It will log that certificate + all environment certificates.
This further's my suspicion because when you override the default JVM truststore, it sounds like the duplicates go away. That would mean you're left with your custom truststore plus what's added by the CSP.
Where does the TrustManagerFactory find the pcf trusted certificates.
https://github.com/cloudfoundry/java-buildpack-security-provider/blob/main/src/main/java/org/cloudfoundry/security/CloudFoundryContainerTrustManagerFactory.java#L41
How can I check if those pcf certificates are available & loaded, or where can I get the pcf-certificates-only TrustManager. I want this to prevent loading the certificates twice.
Is there a larger problem here? I get what you're saying about seeing certificates listed twice, but is that actually causing a problem with your application? If so, please update your question and explain what is happening? That might help to provide some more context.
Aside from that:
You can disable the CSP. Set and env variable JBP_CONFIG_CONTAINER_SECURITY_PROVIDER='{trust_manager_enabled: false}'.
https://github.com/cloudfoundry/java-buildpack/blob/main/docs/framework-container_security_provider.md#security-provider
Do understand that by disabling this, your application will not automatically trust platform/Bosh deployed CA certificates. This could cause failures. For example, if your application is binding to a CF marketplace service that is using certificates signed by a CA that is distributed through the platform/Bosh trusted CA certificates.
You could do the opposite & set the default Java truststore to point to an empty keystore. You'd need to create an empty keystore, probably under your application, then set -Djavax.net.ssl.keyStore=/home/vcap/app/empty.jks (/home/vcap/app is the root of your application, change the rest to point to where you store the empty keystore file).
https://stackoverflow.com/a/2138670/1585136
If my suspicion is true, either of those would result in the duplicates going away.

Changing Fiddler root certificate to successfully decrypt HTTPS

Is there a way to change the Fiddler's root certificate. I want it for a scenario when the client app uses certificate pinning and I have access to the keystore, whose certificate is being trusted by the client app.
I think you're asking "Can I change the certificate Fiddler uses for a particular site" rather than the root certificate, which is used for all sites.
Yes, if you really do have the private key for the certificate, you can configure Fiddler to use it. Inside Fiddler's Rules > Customize Rules > OnBoot function, you can call either:
CertMaker.StoreCert("example.com", certMyCert);
or
CertMaker.StoreCert("example.com", "C:\\temp\\cert.pfx", "TopSecretPassword");
The first call requires that your X509Certificate2 variable (certMyCert in this case) refer to a certificate that is already installed in your computer's Certificate Manager (certmgr.msc), so its private key can be found, while the second allows you to specify a PFX file from disk.

CXF STS client throws Request does not contain Security header/Response message does not contain WS-Addressing properties [duplicate]

When adding an STS reference, I input the my windows azure federation metadata URL and it gives me the error in the title. It works if I create a new namespace, but a lot of stuff is configured on the current namespace, so I can't delete it.
So for anyone that would get this error, it's a simple fix.
You need a X.509 certificate configured as primary in your ACS namespace.
To do this you go under your acs configurations, in certificates and keys then you add a X.509 by uploading a .pfx file to the server and entering the password.
You might also need a symmetric key also set as primary depending on your configuration.

SNIMatcher not returning correct certificate

I have a server and I've added an SNIMatcher based on this example
http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#SNIExamples
SSLServerSocket sslServerSocket = ...;
SNIMatcher matcher = SNIHostName.createSNIMatcher("www\\.example\\.(com|org)");
Collection<SNIMatcher> matchers = new ArrayList<>(1);
matchers.add(matcher);
SSLParameters params = sslServerSocket.getSSLParameters();
params.setSNIMatchers(matchers);
sslServerSocket.setSSLParameters(params);
I've added example.com and example.org in my hosts file to be 127.0.0.1
When I go to example.com and example.org they both get the same localhost certificate (I've created a separate certificate for example.org)
My question is what's the correct way to attach a SNIMatcher
do I need to create a separate matcher for each virtual host that has its own certificate? (I did that but I got an IllegalArgumentException because both hosts had the same type 0 (StandardConstants.SNI_HOST_NAME)
http://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLParameters.html#setSNIMatchers-java.util.Collection-
so I changed the way I am attaching and just did it the way example does (com|org) but it's returning the same certificate for both. Just wondering what's the correct way?
thank you
I believe it has to do with the x509 stuff (distinguished name) in the certs of the keys in the keystore used for the sslcontext that issued the sslserversocketfactory.
Choosing the key and presenting the x509 cert (given the "merely accepted" sni hostname) has to do with some DN in the x509 because that's the only mapping knowledge available. The host mapping is certainly not done with the keystore alias! The mapping information from the keystore has to be in the cert, a hostname that a certificate authority has signed.
AFAIK, the SNI server-side mechanism doesn't do that key selection, it only restricts the hostnames allowed for the entire keystore/keymanager hooked up.
PS: If you wanted to switch keystores, then you would have to essentially build an sslcontext with a X509KeyManager of your own that can provide all the material of all key stores. You would likely wrap an array of key managers out of a KeyManagerFactory... and the support ends here for me because it gets ugly too fast for what I recall!

X509 Certificate Purpose Setting

I would like to ask when is the purpose of a certificate, like Server Authentication, Client Authentication, set for the certificate.
Is it when we generate the CSR or when it is signed by the CA?
The CSR is a Certificate Signing Request. If it is a PKCS#10 request (by far the most common type) it can indicate which extensions are requested and that can include the Extended Key Usage (aka purpose). But the CA ultimately decides what to include when it creates and signs the cert. It could choose not to issue a cert. It could issue a cert with a subset of the requested attributes. It could issue a cert that is completely different. It could issue a cert that is exactly what the CSR requested.

Resources