Ok first I'll say what I know about how SSL works.
Most of all I need to understand how the client certificate works, because I was setting up mTls istio gateway and had trouble with it.
So, firstly I need key-pair, private and public. If I understood correctly, i create them next with the following command:
keytool -genkey -alias myKeyPair -keyalg RSA -keysize 2048 store.jks
If I look in the keystore there will be one PrivateKeyEntry. Next I create request for certificate:
keytool -certreq -keyalg RSA -alias myKeyPair -file request.csr -keystore store.jks
After a while, I received a signed client certificate client.cer
and certificate trusted CA ca.cer
.
Now there are questions:
First, i tried to send request from curl. But curl needs private key which stored in jks. I dont have openssl and cant get it, so i extract private key using java code. But the result was always the same: istio gateway: peer did not return a certificate
Second, I tried using java.net.http.HttpClient
with SSLContext
setting containing my jks. And it worked. But firstly I had to put ca.cer
and client.cer
in my jks. And this I cannot understand: why do I need to put ca.cer
? Because without ca.cer
stored in store.jks
i have error certificate validation.
Also when I put client.cer in jks, keytool displays a warning: Certificate already exists in keystore under alias <myKeyPair>. Do you still want to add it?
Why does it think privateKeyEntry and trustedCertEntry are the same?
Meta: a poor answer due to the vagueness of the question, but much too long for comments.
First, i tried to send request from curl. But curl needs private key which stored in jks. I dont have openssl and cant get it, so i extract private key using java code. But the result was always the same: istio gateway: peer did not return a certificate
Either your 'extract' was wrong or the way you provided it to curl was wrong, or both, and you described neither. First, to be clear, like any client doing client auth, curl actually needs the privatekey and certificate, and usually any applicable chain certificate(s). What file format(s) you must use, and whether a single combined file or separate files (added:) or none at all as it turns out, depends on the curl build you are using: curl supports seven SSL/TLS implementations, and the ways to provide client-key-and-cert vary among them. Use curl -V
(uppercase) to see how it was built, then look at the portions of the man page, on your system or on the web, that apply to that implementation.
Second, I tried using java.net.http.HttpClient with SSLContext setting containing my jks. And it worked. But firstly I had to put ca.cer and client.cer in my jks. And this I cannot understand: why do I need to put ca.cer? Because without ca.cer stored in store.jks i have error certificate validation.
Possibly it is a 'chain' or intermediate CA cert. An SSL/TLS client (like a server) is required by the standard to send any chain cert(s) needed to connect the end-entity (client or server) cert to normally a 'root' in the receiver's truststore. (Since RFC5280, and confirmed by RFC8446, it is actually possible to use an anchor that isn't a root, but it is rare to do so.) Possibly it is even a combination of chain cert(s) and root (or anchor). (Some reliers sometimes can still build the chain to validate a cert when it wasn't correctly sent; browsers especially tend to do this, but most servers not.)
Look at it and see. If it is PEM format you can see with any text display or edit program how many certs it contains. If it is a single cert you can display the details with keytool -printcert -file $file
-- or since you already imported it, keytool -list -v -alias name -keystore $ks [-storepass $pw]
. If it is multiple certs in PEM format you can break it apart with an editor and display each one separately. If it is multiple certs in DER format you won't be able to handle that easily, but fortunately that format is rarely used. openssl x509 [-inform pem|der] -text -noout
is also commonly used to display cert file details, but you say you can't use it.
Also when I put client.cer in jks, keytool displays a warning: Certificate already exists in keystore under alias . Do you still want to add it? Why does it think privateKeyEntry and trustedCertEntry are the same?
If you only did this once, and correctly, it shouldn't. Given separate cert
files, you should keytool -importcert
the client cert to the alias of the privatekey entry you created, and used to create the -certreq
, which in your example is myKeyPair
, after you keytool -importcert
any needed chain cert(s), and optionally the root or anchor, (each) to a different alias. (It is often convenient, but not required, to use simple words like root
, imed
, imed2
etc. as aliases.) Alternatively, if you have the whole chain as a single file, either PEM sequence or DER sequence, or 'p7b' (a dummy PKCS7 SignedData with no data and no signature, commonly used as a container for one or more certs, such as a chain) either PEM or DER, you should import that chain in a single operation.