I'd like to know is there any way to check default keystore if necessary key is not found in specified keystore or how to set keystores checking order.
For example - I have two keystores:
Global java default keystore (like cacerts)
"Folder1/mykestore.jks" which contains my uploaded self-signed certificates.
I set property in my program:
System.setProperty("javax.net.ssl.keyStore","Folder1/mykeystore.jks");
And programs tries to connect with certificate from mykeystore.jks, but doesn't found it, so throws exception. Now I'd like to oblige my program to check also global default keystore or any other keystore if exists.
I ned to do it in my application, where user can defines some mailboxes and can upload self-signed certificates. Application works good with self-signed certificates, but doesn't works with public mailboxes (like GMail) with official certs, because they are not exists in mykestore.jks. (When I try to connect without specify keyStore property, it connects without any problems)
Probably the easiest way is something like:
try{
System.setProperty("javax.net.ssl.keyStore","Folder1/mykeystore.jks");
store.connect(host,login,password)
catch{
//Set default keystore
//try store.connect() again
}
but the problem is I dont know how to set default java keystore (it is an gralils app, and I don't know path to default keystore).
Maybe is there another, better way, you could recomend me?
Regards,
Artur
The simplest thing would be to just make a copy of the default keystore from the JDK and use that as the initial keystore for your application, adding more certificates to it as necessary.
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.
I'm working on an application that calls a third-party webservice over https. So I need to add this certificate to the truststore of my application. I can see 3 solutions to fix my problem:
add this certificate to $JAVA_HOME/jre/lib/security/cacerts
create a custom truststore and launch my JVM with -Djavax.net.ssl.trustStore= ...
programatically load this truststore when starting my application
Which solution do you recommend/discourage me to use?
I'd prefer the second one. Because;
For the first one; when you change your java version you need to do extra work (you must add these ssl certs to cacerts again).
For the third one; when you need to add another ssl cert. you must change your code.
So, the second is the best choice because; you will not need to change your code when new ssl comes (You will just add it to external trustStore) and you will do nothing for these certs when you upgrade your java version.
I have found the following post, which I think I may help because I need a way of verifying my website (that my java application connects to) without having to use the java keystore:
http://www.mombu.com/programming/java/t-ssl-for-java-without-keystores-1366416.html
However, I'm quite new to the world of SSL and don't know which files and passwords I need to use, so if anybody can point me in the right direction that would be great. If you didn't guess, I got my SSL certificate from StartSSL, who are ran/owned/something by StartCom Ltd. Here is a post I used for putting the details into the keystore:
https://forum.startcom.org/viewtopic.php?t=1390
Thanks in Advance!
Alternitively, is there any way for me to use a custom keystore. i.e I'll do what I need with the default keystore and then copy the keystore into the .JAR so that I can tell my application to use the one in the .JAR instead of the one in the Java install directory, etc...
Yes, you can create and use your own keystore for your app using the keytool utility which comes with the JDK.
Basically, a keystore is a datastore for your keys & certificates, which will be used in your app either to authenticate yourself to another entity or to digitally sign your messages or any other data.
A distinct keystore called trustore is used to keep the public key certificates of the entities you trust.
You can have these keystores placed in your classpath and specify the path in your app in code like (these are VM params which will affect all apps running in this VM):
Properties properties = System.getProperties();
properties.put("javax.net.ssl.keyStore", path/to/keystorefile);
properties.put("javax.net.ssl.keyStorePassword", keyStorePassword);
properties.put("javax.net.ssl.trustStore", path/to/truststore);
properties.put("javax.net.ssl.trustStorePassword", trustStorePassword);
EDIT:
Yes, you can specify the keystore & trustore locations and their passwords in a property file and load the properties file as myProperties.load(myProperties.getClass().getResourceAsStream("/path/to/proertyfile.properties")); and then use it in your code as (exception handling omitted)(this will not affect any other app):
KeyStore mykeystore = KeyStore.getInstance("JKS");
InputStream is = new FileInputStream("/path/from/myproperties");
mykeystore.load(is, myKeystorePasswordFromProperties.toCharArray());
I am running a servlet in Weblogic 10.3 with two-way SSL enabled. When I try to get the following attributes from the HTTPServletRequest, both are null:
- javax.servlet.request.X509Certificate
- weblogic.servlet.request.SSLSession
How then do I access the user's certificate from the servlet? I have searched online with no luck.
I would take a look at how your keystore is set up. From my experience, this kind of error can occur if the user's or server's signed certificate isn't imported into the keystore correctly.
To verify this, run keytool on your keystore to determine which alias in the keystore contains a private key. Then, take a look at that alias and see if it has the signed (approved) certificate associated with it, or if the signed certificate has another alias associated with it.
This kind of error is common when using applications which will only look for a specific alias in your keystore for validation. Normally this is configurable so that you can ensure that your certificates all have unique "names" in the certificate. It is common, for example, to use a linux box' hostname in the certificate name, and then to create an alias that is the hostname.
I've got a java applet that loads some pre-installed native code extensions to display custom content in the browser. Some of this content may include native code to be loaded by the JVM. Obviously, this is a security concern. I'd like to enforce that all content comes only from authorized servers.
The path I've been following to accomplish this is to create a keystore that contains just one SSL certificate. I set the keystore location and password and turned on debug output.
System.setProperty("javax.net.ssl.keyStore", "C:\\keys\\keystore");
System.setProperty("javax.net.ssl.keyStorePassword", "changeit");
System.setProperty("javax.net.debug", "ssl");
I was under the impression that this would mean that the JVM would have access to only the one keystore file and consequently the one key inside it. In fact, the SSL debug info lists something like 75 CA keys in addition to the one key I added. Clearly, this isn't going to keep anyone from sending us untrusted code.
Is there a way to tell the SSL system to only use a single certificate? Should I be using a completely different approach?
Update:
Changing the cacerts file isn't really an option here. The JVM should continue to function normally for other applications using it. Is there a way, at runtime, to elect not to load that file? I'm looking at the TrustManager and KeyManager classes but I don't really understand how to use them.
You need to set the javax.net.ssl.trustStore system property to point to a keystore with your one certificate in it. The keystore is for your authentication credentials, not your peer's.
The very question is wrong here. A certificate is only a proof of identity. You don't authorize certificates, you authorize identities. What if the same client comes up with a new certificate?
The correct answer is to install a HandshakeCompletedListener that checks the peer identity. The truststore is only there for authentication, i.e. is that person who they said they were. What you are doing is authorization, which is a different thing completely. You shouldn't use the truststore (or any PKI mechanism) for authorization.
You also have the global keystore installed with the JRE, which is where all the CA's are stored. Try to rename it and see what happens.
You still "see" the CA certificates of the system-wide JRE cacerts file located in java.home/jre/lib/security, which is normal.
Now, quoting the keytool documentation about this file:
IMPORTANT: Verify Your cacerts File
Since you trust the CAs in
the cacerts file as entities for
signing and issuing certificates to
other entities, you must manage the
cacerts file carefully. The cacerts
file should contain only certificates
of the CAs you trust. It is your
responsibility to verify the trusted
root CA certificates bundled in the
cacerts file and make your own trust
decisions. To remove an untrusted CA
certificate from the cacerts file, use
the delete option of the keytool
command. You can find the cacerts file
in the JRE installation directory.
Contact your system administrator if
you do not have permission to edit
this file.
In your case, it might be easier to entirely replace the cacerts with your own key store instead of removing all 75 entries if this is really what you want. If not, then you should use a different approach indeed (why don't you just restrict or hard code the list of authorized servers?).