I have some code on Android that makes use of URL.openStream. For internal test purposes I need to be able to point it to a server that uses a private CA. We already have our CA bundles in PEM format (as we're also using libcurl from NDK), and would like to be able to just read the PEM files directly into whatever KeyStore (or similar) that URL.openStream uses.
So this question is a multi-part thing:
How do you get the key storage used by URL.openStream? Or should I just be using HttpClient directly?
How do you add a PEM certificate to said key storage? (even if using HttpClient)
Thanks.
I can't speak for Android specifically, but at least standard desktop Java has a default keystore that is used by all instances of the JVM, located at /lib/security/cacerts.
In many cases, this file should not be modified globally for all instances of the JVM, but on a case-by-case basis, as you already eluded to. To do this, you can't call .openStream directly. Instead, get a HttpsURLConnnection by calling URLConnection.openConnection() (and casting it do a HttpsURLConnection). Before performing any other operations on this connection, set a custom SSLSocketFactory by calling HttpsURLConnection.setSSLSocketFactory. From here, you'll need to work with a custom SSLContext and TrustManagers.
Some additional details around this are already answered at How can I use different certificates on specific connections?.
If you want to use HttpClient, additional references are available at http://hc.apache.org/httpclient-3.x/sslguide.html and How to handle invalid SSL certificates with Apache HttpClient?.
Related
I recently joined a project that has an application running in Tomcat that uses a single file as both the KeyStore and the TrustStore. In other words, it includes both entries of types trustedCertEntry and PrivateKeyEntry.
While upgrading from Tomcat 8.5.6 to 8.5.20, I realized catalina.out was giving me
java.lang.IllegalArgumentException: java.security.KeyStoreException: Cannot store non-PrivateKeys
The solution was to make to remove the trustedCertEntry entries from the keystore.
To me, this seems fairly obvious that you would want to keep these separate. My question is, are there any possible security consequences to using the same file as a keystore and truststore? If so, why does Java (or SSL) allow these to be kept in the same file?
SSL and TLS are interoperable protocols; by IETF policy and tradition they say nothing about storage of anything and everything at either or any endpoint. "That's a local matter."
Java historically used one file format (JKS) for both TrustedCert's and PrivateKey's, not only for SSL/TLS but for all public-key crypto (and optionally with JCEKS some symmetric crypto also), and Java9 is switching to PKCS12 for both. Using the same format doesn't mean you must use the same file, and I would say it's preferable to use separate files, but I don't see an actual security problem in using a single file as long as you keep any file containing a privatekey restricted to one system, or as few systems as absolutely necessary, plus appropriate backup; however that's not really a programming Q and you might try for better answers on security.SX.
Tomcat 8.5 sorta-kinda combines the previously separate and (often confusingly) different config for Java-JSSE and APR=OpenSSL stacks, and I believe this restriction that the keystore can only contain PrivateKey's is a result of that change.
I have a Netty-based server that uses PEM-encoded certificate files that are periodically re-issued (by Let's Encrypt). Netty fully supports loading the PEM crypto material, but when the certificate (.cer file) is later re-issued, the server needs to be restarted to see it.
I have handled this up until now by adding a custom channel init handler to add the logic to reload the cert and add an appropriate SSLHandler built from that. But now I'm wanting to use Aleph, and it expects a Netty SSLContext object for TLS.
This seems like a topical and general problem with the growing popularity of Let's Encrypt and its relatively short-lived certs, and I'd like to solve it properly. Which means a Netty-compatible way to create an SSLContext that will reload its certificate(s) if they change on disk.
Some approaches I've come up with:
Make a dynamic trust manager/trust store, then plug that into the Netty SSLContextBuilder. Could use this is a starting point https://jcalcote.wordpress.com/2010/06/22/managing-a-dynamic-java-trust-store/, and take some of the code to load the key/cert from Programmatically Obtain KeyStore from PEM (Netty’s PEM -> KeyStore logic is not public in the SSLContext class). Upside: works outside Netty too. Downside: complicated and doesn’t reuse Netty’s existing logic to load PEM keys and certs.
Add this as a Netty-supported option.
Can anyone point me to a solution, or suggest the best way forward to building one?
Answering my own question.
The answer is: don't do it at this level. Instead, have something outside the Netty stack monitor the cert, and when the cert changes remove the existing SSL handler from the pipeline and replace it with a new one with a SSLContext created from the new cert.
I'm writing a server application that identifies it's clients by SSL-Client-Auth. Every Client should create it's own KeyPair and Certificate to connect to this server. Any unknown client (identified by a new public key) will be thread as a new client and registered with this public key. I don't want to sign client certs serverside (since this is would not increase security).
But it seems (after studing hundreds of pages) that I can't create the necessary files (or objects) programatically in plain Java, since the KeyStore would need at least self-signed client-certificates (which I can't create without BouncyCastle lib).
Am i wrong or is there really no way to do this?
And please provide me with a link or code. Java SSL semms to be VERY overcomplicated and has a bad documentation.
As far as I know, there is nothing in the JSSE API (including JSSE and JCE) to issue an X.509 certificate indeed. Dealing with the X.509 structures manually is actually quite complex, and you'd certainly need to read a lot more if you want to replicate what BouncyCastle does, without using BouncyCastle.
BouncyCastle is by far the most convenient way to achieve what you want. You could also use the sun.* packages (since keytool uses them to produce self-signed certificates), but using these packages is usually bad practice, since they're not part of the public JSSE API. They are not documented, rely on a specific implementation of the JSSE, and are subject to change. In contrast, BouncyCastle is meant to be used as a library.
I don't want to sign client certs serverside (since this is would not
increase security).
Since your server will only use the public key (and not the certificate) to perform the authentication (based on whatever mapping between public key and user you choose to implement), issuing the certificate on the server side or the client side doesn't matter in terms of security. The client could self-sign anything it wants, to the server can only rely on the public key anyway, not the rest of the certificate. The reason you'd need to "bundle" the public key into an X.509 certificate is because it's the only kind of client certificate supported (for example, the JSSE doesn't support OpenPGP certificates).
Having a service on your server that receives a public key and sends an X.509 certificate (with any dummy attributes, signed by any private key) might be the easiest option. In addition, if you use a mini CA internal to that server, this would simplify the way you'd need to tweak the trust managers to get the self-signed certificates through. (You'd still need to check the actual public key with your internal mapping, if you want to design such a security scheme.)
I'm running Apache Tomcat locally and have installed a self signed certificate using OpenSSL. I also have a servlet running.
What I want to do is the following:
The servlet takes in POST parameters and will echo back the parameters signed using the PrivateKey of the server. That is, treat the input parameter as an integer and raise it to the power of the private key.
The problem: Is it even possible to access the server's PrivateKey from the servlet? If deployed on some other hosting, it's probably not possible to access it directly. So is there any way that I can request that the server 'sign' some piece of data with its Private key?
Thanks in advance.
If I were writing a weberver I'd go to great lengths to prevent code from reading from the certificate store - I certainly wouldn't provide an API call for it!
Usually the cert is stored as a file on the webserver's filesystem (not always) but for a site with any serious security on it, this would be encrypted and require a passphrase to decrypt. Since you are using a self-signed certificate its probably not encrypted - just import the cert from the file into the keystore.
This depends on the way the container is configured. In the general case, the SSL configuration of the container will not be accessible by a servlet it contains. For example, in Apache Tomcat, that connector's SSL configuration can be completely independent of the settings accessible by a servlet. (In addition, SSL may be handled by APR or an Apache Httpd front-end, for example, which won't have much to do with the Java keystore configuration).
You would probably be able to gain access to the keystore if they are configured using the javax.net.ssl.* properties. However, that's not necessarily the way the SSLContext of the server connector is configured from. It's not generally a good idea to pass those parameters on the command line either in a production environment.
What you may be able to do is to load the keystore used by the container, from your servlet, but you'd have to know where it is, in advance. In addition, I would suppose that a hosting service would run Tomcat with a security manager turned on, which may prevent you from doing this.
Note that you could use your own keystore, shipped within your webapp (it can even be loaded from the classpath as a resource stream). Whether this keystore will contain the same private key as the one use by the server's SSL layer is up to the server's administrators (if they let you have it).
If you use a Java keystore you can access it from your servlet, as long as it knows the keystore location and password.
Servlet can access any data on your machine including keys. The only situation can be when Apache and Tomcat are running from different user names and keys are locked to be accessed only by Apache user name. You can do a trick in this case as su a process under Apache user name and read the file.
See related question.
I have a PEM file provided to me and was told that it will be needed in establishing a SSL socket that connects to a c++ server for some API calls. Does anyone know how I can read in the PEM file and connect? I was also given the parapharse password.
It sounds like the PEM file is a client cert for you to use to login to the server. If it is the client cert, and it sounds like it is, you will likely need a ca cert file also to use in validating the servers certificate in order to establish a connection.
The CA certs need to go into a truststore and your client certs need to go into a keystore. In Java, both of these will be JKS (although it has limited support for PKCS12.) There are default keystore/truststore locations for the JRE as well as for each user. You can also specify external locations for these files in your code, as in the examples below. The commons-ssl library seems to be able to support PEM directly, without the need for JKS, but I haven't used it.
The default passphrase for these keystores in Java is "changeit" without the quotes.
This page shows you have to read the PEM into your keystore/truststore. Here is another example.
Once you have your truststore and keystore set up properly, you need to pass the following JSSE system properties to your JVM:
javax.net.ssl.keyStore
javax.net.ssl.keyStoreType
javax.net.ssl.keyStorePassword
javax.net.ssl.trustStore
javax.net.ssl.trustStoreType
javax.net.ssl.trustStorePassword
You may specify them as -D parameters to the JRE or, as in the examples below, programatically.
Once you finish that, heres a commons-ssl example of creating a socket. Also, heres the Java api for SSLSocket. Heres also an example that doesn't use any apache commons.
You need a library that handles SSL. As John Ellinwood noted, some frameworks (such as Java 2 SE) offers these built-in, for others you'd need to use 3rd party libraries.
C developers often use openssl directly, but it can't be said to be easy and when using C++ there are several "gotchas" that are easy to fall into.
I suggest you use a C++ network library with support for SSL, such as QT's network library, or Poco NetSSL. See here for some tutorial documentation and here for the API documentation - you probably want to take a look at initializeClient which takes a PEM file directly.