How to handle alias in TrustStore - java

I am running the Java process (Microservice) and trustStore configured in the JVM parameter. If the Microservice needs to connect the external URL which required the cert to be imported in trustStore.
Example:
example.co.uk -> examplecouk as alias in trustStore
example.com -> examplecom as alias in trustStore
example.in -> examplein as alias in trustStore
How does Java know that which certs and alias to be picked from the trustStore for the particular endpoint as I don't pass/mention the alias in the JVM params? Is it pick randomly?

user207421 is nearly correct. To be more exact:
When you as client open an SSL/TLS connection to a server, as part of the handshake the server sends its certificate 'chain' containing its own cert, plus usually one or more linked CA (Certificate Authority) certificates ending with a 'root' CA that should be trusted. See the neighboring Stack https://security.stackexchange.com/questions/20803/how-does-ssl-work/ for an epically complete explanation. Public servers normally use a cert issued and signed by a public CA like Digicert, GoDaddy, LetsEncrypt/ISRG which are already in the standard default truststore (for Java in the file JRE/lib/security/cacerts) so no action is needed. If a server uses a cert from a off-brand or private CA, or a self-signed cert (from no CA at all), then (for Java) some cert in the chain must be added to the client truststore, or otherwise overridden; this is only required to be the server cert in the case where the server cert is self-signed (which is a chain by itself and has no relevant CA certs).
Java/JSSE implements this through an SSLContext which contains among other things a TrustManager, more specifically an X509ExtendedTrustManager, which is initialized from a truststore. You can create an SSLContext explicitly in code from any set of trusted certs (which doesn't even need to be from a file), or use the default context which uses the default truststore file, which defaults to the filename above unless overridden by a system property.
When the server cert chain is received it is passed to the context's TrustManager for validation; among (many!) other checks, at each level of a normal chain, or the single level of a self-signed cert, the JSSE TrustManager looks for an anchor cert with the same Subject and (Subject)PublicKey and if so uses it to validate the cert chain. Note that a normal (CA-issued) leaf cert can have Subject empty if Subject Alternative Name is used instead -- see rfc5280 and rfc2818 -- but a self-signed cert cannot, because it has Subject = Issuer and Issuer must not be empty. Certs for different entities (e.g. different servers) normally are expected to have different keys, although a single entity can have multiple certs with either the same key or different keys, and might correspond to multiple server names and/or addresses.
If the certificate is determined valid in general, for some TLS applications, notably HTTPS, the validator also checks it is for the correct server, specifically that the CommonName attribute in the Subject field, or an entry in the Subject Alternative Name extension if present -- which for public CAs for at least a decade it is, matches the host DNS name or IP adddress in the URL. In older versions of Java (through 6 IIRC) this was not done in JSSE but rather in the calling application(s) or library, such as HttpsURLConnection, which as a legacy still has the option to use its own HostnameVerifier instead.
All of this can be altered by using a custom TrustManager in place of the standard one, and some things like Apache HttpClient do so validly, but you will find (too many) answers here and some other Stacks recommending you 'solve' TLS errors by using a neutered TrustManager that just accepts any cert, regardless of whether it is actually valid and correct, and thus happily connects and sends sensitive data to, or accepts changes from, any attacker who manages to intercept the IP traffic, which is often pretty easy nowadays.

Alias is a way to directly access the certificate but your keystore has other information regarding the certificate as well. X.509 certificates have a field called SAN (Subject Alternative name) which contains the DNS information of the certificate. When you try to connect to a specific URL, the keystore is looked up for the corresponding DNS name in SAN and correct certificate is picked up.
I hope it clarifies your doubt about java not asking for the alias. Rest assured, there is nothing random in this process.

Related

Which SSL certificate will be selected if client has multiple certificates in key store

Could you please help me on following two questions?
I have a FIX engine that connects to FIX servers. There is a FIX server that requires client to authenticate itself during SSL handshake. It also provides a SSL certificate that I need to use during SSL handshake as client side certificate.
Question#1: Can I store multiple certificates (private keys) in a keystore that I will load later in my FIX engine?
Question#2: If answer to #1 is yes, then how would the SSL context select a client certificate during SSL handshake when it establishes a SSL connection with the server?
Note- I am thinking of these questions because in future there may be another Servers that also have similar requirement.
Question#1: Can I store multiple certificates (private keys) in a keystore that I will load later in my FIX engine?
As far as Java is concerned, you definitely can have multiple privateKey entries, each containing a privatekey plus certificate or (usually) chain, in one keystore file or other storage object. (Note that if you use PKCS12 to interchange with other software that other software may not support multiple entries in one PKCS12. If you use PKCS12 only for better security in Java, or to silence the warnings in j9+, this is not a concern.)
I don't know what FIX engine you are using, or how it handles its key-and-cert info for TLS-formerly-SSL (or indeed how it handles TLS at all). If it simply loads a keystore file (or stream) as a KeyStore object, the the Java capability above applies. If it does something else, what it can do depends on that something else.
Question#2: If answer to #1 is yes, then how would the SSL context select a client certificate during SSL handshake when it establishes a SSL connection with the server?
In the TLS protocol, when a server requests that the client use a certificate, it specifies algorithm constraints (the leaf key algorithms through 1.2 and/or the chain signature algorithms in 1.2 and 1.3) and may specify a list of desired Certificate Authorities (CAs) (which may have issued any cert in the chain).
If your client (FIX engine) uses the Java-standard implementation of TLS (JSSE) with its standard (and default) 'SunX509' KeyManager, that will choose from the keystore an entry satisfying the above constraints from the server; if you select or configure the 'NewSunX509' or 'PKIX' KeyManager, it also checks any algorithm constraints defined for your JVM (for example Oracle JVMs since about 2017 prohibit certs using MD5- or SHA1-based signatures, or RSA keys less than 1024 bits), and gives preference to entries where the cert is not expired and does not have inappropriate KeyUsage or ExtendedKeyUsage extensions. Among multiple acceptable or preferred entries the selection is arbitrary -- however the keystore implementation enumerated them. Most servers support all standard (maybe and non-obsolete) algorithms and usually cannot be distinguished by that. If a server accepts certs from 'public' CAs like Digicert, GoDaddy, LetsEncrypt those also are not likely distinct, but if it uses a CA (or perhaps a few) specific to that server or its operator, such CA name(s) will often be unique and thus the key-and-cert will be selected only for that server.
If your client uses a custom KeyManager -- either explicitly in your application or via middleware (for example Apache HttpClient) -- it can do something different. It can even choose to use a key-and-cert the server will reject, although that would normally not be considered useful.
If your client uses a different TLS implementation, that could use the standard KeyManager structure, probably with the options above, or could do anything else.
if you use spring framework you can specify alias of certificate that you prefer to select by adding
-Dserver.ssl.key-alias=your_preffered_alias
You said that you have a FIX engine that connects to FIX server, then asked if private keys can be stored in a keystore for your FIX engine. This leads me to believe that the FIX engine is in a client application. You should NOT store private keys publicly in a keystore. Instead, you should be providing the client with a truststore, which just contains the certificate.
I don't have an answer for this, but this post might be helpful; https://stackoverflow.com/a/1710543/4417924

Determining which certificate to use in two way ssl

I'm having an issue sending our certificate (client) to another server during a web service call.
We're expected to return the certificate with the CN:
b2b-test
however whenever we receive the servers certificate and attempt to send our own, we're getting:
Unable to find valid certificate path to requested target
From my understanding, if I put our certificate b2b-test inside of our keystore jre/lib/security/cacerts, then when receiving the server request, it should send the appropriate certificate.
How does the client know which key from the keystore it should send to the server? Should I be specifying the exact certificate to send during my request, or is it enough for it to be in the keystore?
Currently the server is sending back the certificate
b2b-a
The certificate chain shows:
*** Certificate chain
chain [0] = [
[
Version: V3
Subject: CN=b2b-a, OU=Web Technologies
The URL for the service is:
https://b2b-a/service
If I configure it like one way ssl, and put the servers certificate into our cacerts, then it picks up their cert and fails the handshake (I'm assuming because it's expecting our cert and not theirs back due to it being a two way setup).
I'm a little stumped here. Any clarification on what I've said is greatly appreciated.
The "Unable to find valid certificate path to requested target" error usually occurs when one side passes a certificate for which the other side doesn't trust any of the certs in the chain. You'll generally (always?) see the error message on the side that's receiving the cert (the side that's missing the truststore).
If you're the client and they're the server, one-way SSL would send their cert from them to you and you would validate it (making sure that the hostname matches the content in the cert), but it would not send any cert from you to them nor would they do any validation.
You'll want to make sure you're configuring a truststore that contains either the b2b-a certificate or a certificate that was used to sign it (but that cert doesn't appear to have any root CAs, so you're stuck with directly importing the cert itself). So yes, you want to do what you wrote in your post and put their certificate into your cacerts. And you'll also need to make sure that the b2b-a service trusts the cert you're sending (or a root CA that was used to sign your cert, if any), so you'll need to put your cert into their cacerts as well, or do something equivalent.
Note that putting a cert in cacerts (or in a truststore JKS) DOES NOT send any certs to anyone; any truststore is used only to allow you to validate that you trust the certificate someone else provides you, either because you trust the cert or because you trust a CA cert that was used to sign the cert. No certs are picked out of the cacerts directory to send to another machine.
If you're using a JKS rather than the JRE directory (which is generally a better idea, since you can specify a different set of trusted certs for your process without changing the default set for anyone running a Java project within your JRE), it's possible to use the same JKS as both a keystore and a truststore (you'll just provide the same filename and password for both the keystore and the truststore properties), or you can have two separate files; either approach will work.
From my understanding, if I put our certificate b2b-test inside of our keystore jre/lib/security/cacerts, then when receiving the server request, it should send the appropriate certificate.
Certainly not. That's a truststore. A source of trusted certificates. Don't mess with it. It isn't used for the purpose you require and in any case it is updated every Java dot release, which clobbers your changes.
Your own certificate and private/public key pair should go in a file of your own, a keystore, which is defined to JSSE by the javax.net.ssl.keyStore and javax.net.ssl.keyStorePassword system properties, or by more complex means described in the JSSE Reference Guide.
The keystore is a precious and confidential file containing your private key. Guard and protect it. Private key leakage would compromise your security and identity.

Tomcat7 : how to deliver the correct certificate chain? [duplicate]

When I create an SSLServerSocket in Java 7 the server correctly uses my server certificate and key. The certificate was issued by a sub-ca of a ca. Therefore the complete chain from the root cert to the server cert has four certificates.
The complete chain is present in the keystore/truststore.
However when a client connects the server always sends only the server certificate itself.
This also applies to Java based web servers like Jetty.
Because most clients have only the root ca certificate installed and not the two sub-ca certificates this is a big problem.
How can I force Java to send the full certificate chain in the SSL/TLS handshake?
A key entry in a keystore isn't just for a single certificate, but for a certificate chain (see KeyStore.setKeyEntry, which takes a Certificate[] chain parameter).
If you want a specific chain to be used, it needs to be set up as a chain in the entry where you have the certificate and its private key. Whether the intermediate certificates are also in the same keystore, in different entries doesn't really matter.
This is a very similar problem to getting a client to send the full client-certificate chain. The same keystore configuration steps should also work from a server point of view, as described in this question.

Ensuring that issued certs don't issue certs on their own

I need some help ensuring that our PKI infrastructure is secure. This is how it works:
We have one (self-signed) CA cert that our server has full control over.
All clients (written in Java) are configured with a trust-store that only contains this CA-cert.
During installation of a client the server issues a client certificate (with it's client-id as CN) that is signed by our CA cert.
The clients are then able to connect to each other and when the connection is established a mutual client authentication is performed by validating the clients' respective cert. We initialize the TrustManager that handles the clients' authentication like this:
.
private TrustManager[] getClientCATrustManagers() throws NoSuchAlgorithmException, IOException, KeyStoreException, CertificateException {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
KeyStore trustStore = getClientCATrustStore();
trustManagerFactory.init(trustStore);
return trustManagerFactory.getTrustManagers();
}
getClientCATrustStore() returns the trust-store that only contains our CA.
This leads me to my question. My understanding of chain validation is that as long as the root of the chain is trusted and none of the certs along the chain have expired the chain is considered valid. What concerns me about this is that I then see the risk that the client will be able to use it's own cert to issue new certs. Is that a potential risk and if so, how do I prevent it? I see the two potential solutions:
I create my own TrustManager that prevents this. Are there any implementations that already does this?
When the client cert is issued by the server I somehow specify that the client cert is not allowed to issue it's own certs. Is this possible and if so, how?
You are correct about a certificate chain being valid and trusted if the root is trusted, and all the intermediate certs are present and valid.
And you are also correct about the potential risk of a client issuing another cert under their own. But there are ways to mitigate this risk.
X509 certificates (version 3) contain extensions that indicate what they are allowed to do or not do.
For example there are 2 specific sections that you would probably be interested in:
Basic Constraints
Key Usage
The Basic Constraints identifies if the certificate is a CA or not, which means it can only be used to verify a certificate signature if it is designated as a CA itself. It also specifies a path length. This limits the number of CA intermediate certs this CA can sign/issue. A good explanation of this path length is in this SO question. It sounds like you would want a path length of 0 on the CA certificate.
Key Usage indicates what this entity is allowed to do. Typically, CA certs have the following key usage attributes: Certificate Signing, CRL Signing. Whereas non-CA or "End entity" certificates can have: Digital Signature, Non-Repudiation, Key Encipherment, Data Encipherment.
These extensions are all governed by RFC5280.
And here is the important part. For these certificate extensions to mean anything, they have to be checked and enforced by the application using them.
Your client app can look at the extensions and verify that the path length of the other client's cert is 0 (meaning there are no intermediate certs between the CA and the client cert).

Java SSLSocket: How to send full server cert chain?

When I create an SSLServerSocket in Java 7 the server correctly uses my server certificate and key. The certificate was issued by a sub-ca of a ca. Therefore the complete chain from the root cert to the server cert has four certificates.
The complete chain is present in the keystore/truststore.
However when a client connects the server always sends only the server certificate itself.
This also applies to Java based web servers like Jetty.
Because most clients have only the root ca certificate installed and not the two sub-ca certificates this is a big problem.
How can I force Java to send the full certificate chain in the SSL/TLS handshake?
A key entry in a keystore isn't just for a single certificate, but for a certificate chain (see KeyStore.setKeyEntry, which takes a Certificate[] chain parameter).
If you want a specific chain to be used, it needs to be set up as a chain in the entry where you have the certificate and its private key. Whether the intermediate certificates are also in the same keystore, in different entries doesn't really matter.
This is a very similar problem to getting a client to send the full client-certificate chain. The same keystore configuration steps should also work from a server point of view, as described in this question.

Categories

Resources