Asked  6 Months ago    Answers:  5   Viewed   22 times

I understand that the keystore would usually hold private/public keys and the trust store only public keys (and represents the list of trusted parties you intend to communicate with). Well, that's my first assumption, so if that's not correct, I probably haven't started very well...

I was interested though in understanding how / when you distinguish the stores when using keytool.

So, far I've created a keystore using

keytool -import -alias bob -file bob.crt -keystore keystore.ks

which creates my keystore.ks file. I answer yes to the question do I trust bob but it is unclear to me if this has created a keystore file or a truststore file? I can set up my application to use the file as either.

-Djavax.net.ssl.keyStore=keystore.ks -Djavax.net.ssl.keyStorePassword=x
-Djavax.net.ssl.trustStore=keystore.ks -Djavax.net.ssl.trustStorePassword=x

and with System.setProperty( "javax.net.debug", "ssl") set, I can see the certificate under trusted certifications (but not under the keystore section). The particular certificate I'm importing has only a public key and I intend to use it to send stuff over an SSL connection to Bob (but perhaps that's best left for another question!).

Any pointers or clarifications would be much appreciated. Is the output of keytool the same whatever you import and its just convention that says one is a keystore and the other a trust store? What's the relationship when using SSL etc?

 Answers

72

The terminology is a bit confusing indeed, but both javax.net.ssl.keyStore and javax.net.ssl.trustStore are used to specify which keystores to use, for two different purposes. Keystores come in various formats and are not even necessarily files (see this question), and keytool is just a tool to perform various operations on them (import/export/list/...).

The javax.net.ssl.keyStore and javax.net.ssl.trustStore parameters are the default parameters used to build KeyManagers and TrustManagers (respectively), then used to build an SSLContext which essentially contains the SSL/TLS settings to use when making an SSL/TLS connection via an SSLSocketFactory or an SSLEngine. These system properties are just where the default values come from, which is then used by SSLContext.getDefault(), itself used by SSLSocketFactory.getDefault() for example. (All of this can be customized via the API in a number of places, if you don't want to use the default values and that specific SSLContexts for a given purpose.)

The difference between the KeyManager and TrustManager (and thus between javax.net.ssl.keyStore and javax.net.ssl.trustStore) is as follows (quoted from the JSSE ref guide):

TrustManager: Determines whether the remote authentication credentials (and thus the connection) should be trusted.

KeyManager: Determines which authentication credentials to send to the remote host.

(Other parameters are available and their default values are described in the JSSE ref guide. Note that while there is a default value for the trust store, there isn't one for the key store.)

Essentially, the keystore in javax.net.ssl.keyStore is meant to contain your private keys and certificates, whereas the javax.net.ssl.trustStore is meant to contain the CA certificates you're willing to trust when a remote party presents its certificate. In some cases, they can be one and the same store, although it's often better practice to use distinct stores (especially when they're file-based).

Tuesday, June 1, 2021
 
commonpike
answered 6 Months ago
62

This is due to how Java handles keystores so it's not an Android specific issue. The reason though is because access to a store such as adding/viewing trust relationships is a separate task from creating and signing keys/certs.

In short, you may trust someone to view/update your keystore but not sign things with a key you store in the keystore. Plus, keys could be stored in multiple keystores and you want your keys locked down individually.

Monday, August 2, 2021
 
suneet
answered 4 Months ago
15

I have got this sorted out. I was using my password that is 'password' to update cacerts keystore in JDK while default password for cacerts keystore is 'changeit'

Sunday, August 8, 2021
 
Abdel
answered 4 Months ago
38

This is more or less the same problem as in this question. You need to prepare a file representing the certificate chain, each certificate followed by the CA certificate that issued it.

-----BEGIN CERTIFICATE-----
MIICajCCAdOgAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJVSzEa
....
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICkjCCAfugAwIBAgIJAKm5bDEMxZd7MA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNV
....
-----END CERTIFICATE-----

You may need to export your EEC (End Entity Certificate) from your keystore first (keytool -exportcert ...). Then, use the text editor of your choice (vi, emacs, gedit, ...) or cat to concatenate your EEC and the intermediate certificate(s) in order. Then import the resulting file into your keystore against the alias that contains your private key (keytool -importcert -alias ...).

Tuesday, August 17, 2021
 
hjalpmig
answered 4 Months ago
77

You are right, *_anon_* ciphers are used for a complete unauthenticated connection (both server and client are anonymous). With these cipher suites no certificate is required. I wrote a small code to test:

ServerSocketFactory sf = SSLServerSocketFactory.getDefault();
final SSLServerSocket socket = (SSLServerSocket)sf.createServerSocket(443);
System.out.println(Arrays.toString(socket.getSupportedCipherSuites()));
System.out.println(Arrays.toString(socket.getEnabledCipherSuites()));

socket.setEnabledCipherSuites(new String[] {"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"});

Thread t = new Thread() {
    public void run() {
        try {
            Socket client = socket.accept();
            client.getOutputStream().write("Hello Worldn".getBytes("ASCII"));
            client.close();
        } catch (IOException ioe) {
        }
    }
};

t.start();
Thread.sleep(2000);
SSLSocket client = (SSLSocket) SSLSocketFactory.getDefault().createSocket("localhost", 443);
client.setEnabledCipherSuites(new String[] {"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"});
InputStream in = client.getInputStream();
byte[] data = new byte[1024];
int len = in.read(data);
System.out.println(new String(data, 0, len));

I know that this code is not perfect but I successfully exchange data between the client and the server. Maybe your server or client socket is not well configured. Can you give the full stacktrace you got?

Note that these ciphers are deprecated since there are vulnerable to man-in-the-middle attacks.

UPDATE : I found the issue. The anonCipherSuitesSupported array length is too long. Therefore after adding the *_anon_* the array is ending with a bunch of null values. And the implementation does not seem to accept null in the enabled cipher list.

String[] supported = server.getSupportedCipherSuites();
List<String> list= new ArrayList<String>();

for(int i = 0; i < supported.length; i++)
{
    if(supported[i].indexOf("_anon_") > 0)
    {
        list.add(supported[i]);
    }
}
String[] anonCipherSuitesSupported = list.toArray(new String[0]);
Tuesday, November 23, 2021
 
cody
answered 7 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share