I have a question about the usage of ssl in java.
My need is quite simple, to connect to a server (https, ldaps, ...), using the CA certificate of the server (pem format)
When using api as curl or many other I guess, in C++ or command line, you can specify a single CA certificate (in pem format for instance) when performing a connection.
If I well searched (hum), in java (i mean with standard librararies) it's slightly different.
either you add your certificate into a trustore, having to manage it by external application as keytool (of course you could programmatically manage your trustore, but it's not my point)
[and additionally, you can specify a trustore with System property, but you can't specify a cert directly]
either you have to code a little, like overloading the SslContext or the TrustManager class, to enable to add a certificate "on the fly".
Am I missing a simpler way, like method "connection.setCA(String caCertPath)" ?
Thank you,
RE: "Am I missing a simpler way, like method "connection.setCA(String caCertPath)" ?"
I guess it depends on the java class you use to implement the application.
But as far as my knowledge goes the answer is: no. You indeed need to first store the certificate in a keystore to be consumed by the class you are using.
I am not aware of any class that would work the way you expect the certificates to be consumed, but I guess you could just write that class to sit on top of the class you don't like.
Related
I would like to understand the Java runtime's requirement for SSL certificates storage in general.
I understand it can be copied to the host's /etc/ssl/certs folder but for Java, does it need to import to a specific Keystore for a runtime to be able to use and consume in any SSL verification process by the application?
E.g.
If I have a JRE client that requires packaging of a root/intermediate certificates to make web client internally to site1.foo.com, I will need the root and intermediate certificates dependent on the chain to verify the request.
With various other runtime environments, it seems I can just place them in the /etc/ssl/certs folder:
NodeJS => How to add custom certificate authority (CA) to nodejs
Go => Where is Golang picking up root CAs from?
However, presumably for usage in Java, I need to go an extra step and use keytool and import into a specific Keystore?
Presumably, it can't just pick up from a common directory as per above?
Hope my question makes sense.
In Java, collections of certificates are usually accessed through a KeyStore interface.
As remarked in the comments the default SSLContext will read the certificates from a PKCS12 (or JKS) file located in $JRE_HOME/lib/security/cacerts.
However that is not the only possibility and you don't have to call keytool to add trusted certificates:
on Debianoids you can use -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts (cf. this question) to use the the PKCS12 file provided by the ca-certificates-java package. It is updated whenever you call update-ca-certificates. Therefore you just need to add a *.crt file in /usr/local/share/ca-certificates and run update-ca-certificates.
if you don't use the default SSLContext you can init it with a different TrustManager (cf. this question). That's how Tomcat 8.5+ loads certificates in PEM format.
Unfortunately there is no implementation of KeyStore that reads certificates from a directory, but that can easily be written.
Edit: On Debianoids the packaged JREs already use /etc/ssl/java/cacerts, so no further configuration is needed.
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
I have developed a webservice in Java. This webservice will be called by other servers, which will have been assigned a certificate from us.
Now I don't know much about SSL, and I have been given a
Root CA
Issuing CA
And I need to check that the certificate provided (when the webservice is called), is "a chain from the root ca". What would be the best way to go about this?
I've read a lot about trustmanagers and keystores, but it's quite confusing and I haven't found anything which is very similar to my question.
I also need to extract a line from the certificate (the 'issued to' field) to use in my application.
Thanks in advance
I have been given a
Root CA
Issuing CA
I need to check that the certificate provided (when the webservice is called), is "a chain from the root ca"
Just put those files, and no others, into your truststore. No code required. See the JSSE Reference Guide.
I also need to extract a line from the certificate (the 'issued to' field) to use in my application
You mean dynamically? when the peer connects? You can get the certificate from the javax.servlet.request.X509Certificate request attribute, and you then just use the certificate API to get the IssuerDN.
I am implementing a VB.NET desktop application which consumes a web service.
The web service implemented in Java and I currently using Tomcat on my localhost to host the web service.
The web service requires secure communication with the client and so I have followed instructions that outlined how to use Java's keytool.exe to create two .jks keystores (one for the client and one for the server) and then create two .cer certificates (one for the client and one for the server)
I have placed the keystores and certificates generate into the directory where the web service is expecting them (according to the instructions)
I have installed the certificates into TrustedPeople and have attempted to use the certificate by setting the ClientCredentials.ClientCertificates property like this:
myServiceProxy.ClientCredentials.ClientCertificate.SetCertificate(storeLocation.CurrentUser, StoreName.TrustedPeople, X509FindType.FindByIssuerName, "name")
I keep getting the following error message when I try to call any method:
An error was discovered processing the <wsse:Security> header
My problem is that I don't know how to use this in the VB.NET client application that is consuming the web service. I could be doing this completely wrong. Any guidance on this topic would be greatly appreciated.
Thank you,
-Frinny
While I haven't coded VB for 10 years, this should get you started: http://www.example-code.com/vbdotnet/ssl_client_certificate.asp
especially this looks like it is loading the file containing the certificate:
certStore.LoadPfxFile("chilkat_secret.pfx","secret")
and this extracts the certificate and uses it for the connection:
Dim cert As Chilkat.Cert
cert = certStore.FindCertBySubjectCN("Chilkat Software, Inc.")
If (cert Is Nothing ) Then
MsgBox(certStore.LastErrorText)
Exit Sub
End If
socket.SetSslClientCert(cert)
When I had to work with certificates and WS, I had lots of issues with the them too. Use the certificates MMC and verify:
That you placed the certificate in the correct place. Note that there is a CurrentUser store, Machine Store etc. Make sure you put the certificate in the correct one according to your code.
Which user is running your application? Is the certificate located in it's store? The certificate must be visible to the user.
Open the certificate and make sure it is trusted (you will see a warning if not). You may need to put your CA's certificate in Trusted Certification Authorities store.
Make sure that the algorithms you use on each side are supported by the other side.
Note that you are looking for the certificate by issuer name X509FindType.FindByIssuerName, "name" open the certificate, make sure the issuer name matches (I guess not since it seems like copy&paste from example).
If all of this fails, try to experiment with the certificate location (I vaguely remember some issue with being able to use certificates from one location and not the other), and with the property you use to search for the certificates.
Plus, since you asked about certificates I answered about certificates. It's a good idea to check if there's an inner exception and see - it may be another problem.
I use SSL to communicate between two components written in Java. I can't use a CA, so I have to self-sign everything. Unfortunately, this means that when I try to handshake, I get a SunCertPathBuilderException. I can create my own X509TrustManager that just trusts everything, but that sort of defeats the purpose of having a signed cert.
I would like, when first making the connection, to prompt the user with "SSL handshake with invalid cert. Add cert to store?" or something so they could have it added for them to their certificate store, like web browsers do at sites with invalid certs. I can find plenty of examples online of adding a cert to the store through the commandline, but I can't figure out how to do it programmatically. Is there a way to do this?
Yes it is possible.
There is some code here that I've used before. I had to modify it to do what I wanted and I suspect that you will too but this should get you close - you aren't trying to import a key so theoretically you should be able to simplify things. In any case you can get an idea of what you'll need.
The JDK JavaDoc for java.security.KeyStore is pretty useful too.
Why don't you create your own CA and sign your certificates with that? Then all you would need to do is install the CA own certificate on the machines and every certificate signed by that CA would validate.
Why would you need to do this, you are not validating that the client is who they say they are you are only using the certs to encrypt the comms, so a custom trust manager that allows all certs is all you need.
What you are asking is possible and from memory also involves a custom trust manager to validate the certificates and store them in the keystore. I can't remember the details, but at least you know it is possible to do it.