Keytool create a trusted self signed certificate
You would need to "establish trust" between your server and client (I'm assuming you only need to do server-side authentication). This is because you use self-signed certs. That involves importing your server's cert into the client trust store:
On the server side:
keytool -keystore <keystore file> -alias <alias> -export -file <certfilename>.cert
Copy the .cert file over to the client side and then:
keytool -keystore <truststore file> -alias <alias> -import -file <certfilename>.cert
You can't share the keystore between client and server, because the keystore contains the private key. When authenticating, the client skips the certificates with private keys. As said above you need to deploy a truststore on client side.
The certificates in a keystore don't behave the same way, depending on how you generated or imported them.
An imported certificate's entry type (seen when verbosely listing the whole keystore with -list -v
) is "trustedCertEntry". A generated certificate's entry type is "PrivateKeyEntry". When you export a certificate, you only export its public key, and an optional reference to its issuer.
Seems like you need to export the self-signed certificate in your keystore as a trusted certificate in your truststore (names make sense here).
I wouldn't do that, because SSL/TLS implementations probably don't support it. From a real world perspective it's like deploying the ultimately secret private key from Verisign on some obscure Web server to sign casual pages, while the only purpose of this private key is to remain in a safe and sign other certificates. SSL/TLS implementors probably won't pollute their code with such a use case, and anyways, the "KeyUsage" certificate extension may restrict a certificate usage to signing, preventing encipherment.
That's why I suggest to rebuild a chain of certificates for your test.
The keytool documentation contains an interesting part about creating a chain (-gencert
command) but it's a very skeletal example which doesn't cover the keystore-truststore relationship. I've enhanced it to simulate a third-party certification authority.
A temporary store their-keystore.jks
represents a certificate-emitting authority. I feed it with a certificate chain of ca2 -> ca1 -> ca
with ca
being considered as a root certificate. The chain appears with each non-root certificate (namely ca1
and ca2
) referencing their issuer as Certificate[2]
. Please note that every certificate is "PrivateKeyEntry".
Then I feed the my-keystore.jks
with those certificates in order: ca
, ca1
, ca2
. I import ca
with the -trustcacerts
option which means it becomes a root certificate. In my-keystore.jks
each imported certificate now is "trustedCertEntry" which means there is only the public key. The issuing relationship only appears in the "Issuer" field but it's OK because the trust relationship mattered most at the time of the import.
At this point my-keystore.jks
simulates an environment containing some trusted certificates, like a fresh JRE. The their-keystore.jks
simulates the owners of those certificates, who have the power to sign certificate requests.
So do I : I create a self-signed certificate e1
in my-keystore.jks
, get it signed by ca2
(through their-keystore.jks
) and import the signed result back into my-keystore.jks
. e1
is still a "PrivateKeyEntry" (because its private key remains in my-keystore.jks
) but now I've built the following chain : e1 -> ca2 -> ca1
. It seems that ca1 -> ca
is implicit with ca
being a certification authority.
To build the truststore I just import certificates ca
, ca1
and ca2
the same way I did for my-keystore.jks
. Please note I don't import e1
, as I expect the SSL/TLS client to validate it against ca2
.
I think this gets rather close of how things work in real world. What's nice here is you have full control on the certificates, and no dependency on JRE's cacerts.
Here is the code putting what I say in practice. Seems to work with Jetty (client and server) as long as you disable certificate revocation list (a topic left for another day).
#!/bin/bash
rm their-keystore.jks 2> /dev/null
rm my-keystore.jks 2> /dev/null
rm my-truststore.jks 2> /dev/null
echo "===================================================="
echo "Creating fake third-party chain ca2 -> ca1 -> ca ..."
echo "===================================================="
keytool -genkeypair -alias ca -dname cn=ca \
-validity 10000 -keyalg RSA -keysize 2048 \
-ext BasicConstraints:critical=ca:true,pathlen:10000 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
keytool -genkeypair -alias ca1 -dname cn=ca1 \
-validity 10000 -keyalg RSA -keysize 2048 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
keytool -genkeypair -alias ca2 -dname cn=ca2 \
-validity 10000 -keyalg RSA -keysize 2048 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
keytool -certreq -alias ca1 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -gencert -alias ca \
-ext KeyUsage:critical=keyCertSign \
-ext SubjectAlternativeName=dns:ca1 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -alias ca1 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
#echo "Debug exit" ; exit 0
keytool -certreq -alias ca2 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -gencert -alias ca1 \
-ext KeyUsage:critical=keyCertSign \
-ext SubjectAlternativeName=dns:ca2 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -alias ca2 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
keytool -list -v -storepass Storepass -keystore their-keystore.jks
echo "===================================================================="
echo "Fake third-party chain generated. Now generating my-keystore.jks ..."
echo "===================================================================="
read -p "Press a key to continue."
# Import authority's certificate chain
keytool -exportcert -alias ca \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -trustcacerts -noprompt -alias ca \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias ca1 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias ca1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias ca2 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias ca2 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
# Create our own certificate, the authority signs it.
keytool -genkeypair -alias e1 -dname cn=e1 \
-validity 10000 -keyalg RSA -keysize 2048 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -certreq -alias e1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -gencert -alias ca2 \
-ext SubjectAlternativeName=dns:localhost \
-ext KeyUsage:critical=keyEncipherment,digitalSignature \
-ext ExtendedKeyUsage=serverAuth,clientAuth \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -alias e1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -list -v -storepass Storepass -keystore my-keystore.jks
echo "================================================="
echo "Keystore generated. Now generating truststore ..."
echo "================================================="
read -p "Press a key to continue."
keytool -exportcert -alias ca \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -trustcacerts -noprompt -alias ca \
-keystore my-truststore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias ca1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias ca1 \
-keystore my-truststore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias ca2 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias ca2 \
-keystore my-truststore.jks -keypass Keypass -storepass Storepass
keytool -list -v -storepass Storepass -keystore my-truststore.jks
rm their-keystore.jks 2> /dev/null
You mustn't do that. A keystore is strictly private. If you leak it to anybody you have fatally compromised security. There is no point in doing this kind of thing just to get it working, because it isn't working - it is just a security breach. You have to do it right: export from the server's keystore into the client's truststore, and from the client's keystore if any to the server's keystore.