I have been provided with:
A private key (-----BEGIN RSA PRIVATE KEY-----)
Intermediate CA cert (-----BEGIN CERTIFICATE-----)
Root CA cert (-----BEGIN CERTIFICATE-----)
SSL connectivity exists and I have proven this successfully using curl;
curl -vv https://thirdparty.service.com --key private.pem --cert cert.crt
However, I wish to establish this SSL connection using Java. Given this, I know I need to import these certificates and key into my Java keystore.
I initially imported the Intermediate and Root CA certs only into my Java keystore but I could not establish a successful SSL connection to the third party service. Based on my curl command, I realised that I need to somehow import the private key into the Java keystore.
I have tried many openssl/keytool commands and this is the current combination/command I have running. I still cannot establish an SSL connection using Java.
cat cert.crt cachain.crt > import.pem
echo "pazzword" > pazzword.txt
openssl pkcs12 -export -in import.pem -inkey privkey.pem -name my_bundle -passout file:pazzword.txt > server.p12
${JAVA_HOME}/bin/keytool -importkeystore -srckeystore server.p12 -destkeystore ${JAVA_HOME}/jre/lib/security/cacerts -srcstoretype pkcs12 -srcstorepass pazzword -deststorepass changeit
Versions:
openjdk version "1.8.0_345"
OpenSSL 3.0.7 1 Nov 2022 (Library: OpenSSL 3.0.7 1 Nov 2022)
Can someone please help clarify what I should be doing with the certs and key I have above?
A successful SSL connection using my Java
I found that Kafka 2.7.0 supports PEM certificates and I decided to try setting up the broker with DigiCert SSL certificate. I used new options and I did everything like in example in KIP-651. But I get the error:
[2021-01-20 17:54:55,787] ERROR [KafkaServer id=0] Fatal error during KafkaServer startup. Prepare to shutdown (kafka.server.KafkaServer)
org.apache.kafka.common.config.ConfigException: Invalid value javax.net.ssl.SSLHandshakeException: no cipher suites in common for configuration A client SSLEngine created with the provided settings can't connect to a server SSLEngine created with those settings.
at org.apache.kafka.common.security.ssl.SslFactory.configure(SslFactory.java:98)
at org.apache.kafka.common.network.SslChannelBuilder.configure(SslChannelBuilder.java:72)
at org.apache.kafka.common.network.ChannelBuilders.create(ChannelBuilders.java:157)
at org.apache.kafka.common.network.ChannelBuilders.serverChannelBuilder(ChannelBuilders.java:97)
at kafka.network.Processor.<init>(SocketServer.scala:790)
at kafka.network.SocketServer.newProcessor(SocketServer.scala:415)
at kafka.network.SocketServer.$anonfun$addDataPlaneProcessors$1(SocketServer.scala:288)
at kafka.network.SocketServer.addDataPlaneProcessors(SocketServer.scala:287)
at kafka.network.SocketServer.$anonfun$createDataPlaneAcceptorsAndProcessors$1(SocketServer.scala:254)
at kafka.network.SocketServer.$anonfun$createDataPlaneAcceptorsAndProcessors$1$adapted(SocketServer.scala:251)
at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:553)
at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:551)
at scala.collection.AbstractIterable.foreach(Iterable.scala:920)
at kafka.network.SocketServer.createDataPlaneAcceptorsAndProcessors(SocketServer.scala:251)
at kafka.network.SocketServer.startup(SocketServer.scala:125)
at kafka.server.KafkaServer.startup(KafkaServer.scala:303)
at kafka.server.KafkaServerStartable.startup(KafkaServerStartable.scala:44)
at kafka.Kafka$.main(Kafka.scala:82)
at kafka.Kafka.main(Kafka.scala)
openssl x509 -in certificate.pem -text:
Certificate:
...
Signature Algorithm: ecdsa-with-SHA384
...
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
I've tried using different versions of Oracle JDK and OpenJDK, but no effect.
I also tried to set certificate with options:
ssl.keystore.type=PEM
ssl.keystore.location=/opt/kafka/certs/certificate.pem
ssl.key.password=null
And I got а new error:
[2021-01-23 20:33:21,552] ERROR [KafkaServer id=0] Fatal error during KafkaServer startup. Prepare to shutdown (kafka.server.KafkaServer)
org.apache.kafka.common.errors.InvalidConfigurationException: Failed to load PEM SSL keystore /opt/kafka/certs/certificate.pem
Caused by: org.apache.kafka.common.errors.InvalidConfigurationException: Invalid PEM keystore configs
Caused by: java.io.IOException: overrun, bytes = 111
at javax.crypto.EncryptedPrivateKeyInfo.<init>(EncryptedPrivateKeyInfo.java:92)
at org.apache.kafka.common.security.ssl.DefaultSslEngineFactory$PemStore.privateKey(DefaultSslEngineFactory.java:512)
at org.apache.kafka.common.security.ssl.DefaultSslEngineFactory$PemStore.createKeyStoreFromPem(DefaultSslEngineFactory.java:462)
at org.apache.kafka.common.security.ssl.DefaultSslEngineFactory$PemStore.<init>(DefaultSslEngineFactory.java:435)
at org.apache.kafka.common.security.ssl.DefaultSslEngineFactory$FileBasedPemStore.load(DefaultSslEngineFactory.java:412)
at org.apache.kafka.common.security.ssl.DefaultSslEngineFactory$FileBasedStore.<init>(DefaultSslEngineFactory.java:349)
at org.apache.kafka.common.security.ssl.DefaultSslEngineFactory$FileBasedPemStore.<init>(DefaultSslEngineFactory.java:405)
at org.apache.kafka.common.security.ssl.DefaultSslEngineFactory.createKeystore(DefaultSslEngineFactory.java:293)
at org.apache.kafka.common.security.ssl.DefaultSslEngineFactory.configure(DefaultSslEngineFactory.java:161)
at org.apache.kafka.common.security.ssl.SslFactory.instantiateSslEngineFactory(SslFactory.java:136)
at org.apache.kafka.common.security.ssl.SslFactory.configure(SslFactory.java:93)
at org.apache.kafka.common.network.SslChannelBuilder.configure(SslChannelBuilder.java:72)
at org.apache.kafka.common.network.ChannelBuilders.create(ChannelBuilders.java:157)
at org.apache.kafka.common.network.ChannelBuilders.serverChannelBuilder(ChannelBuilders.java:97)
at kafka.network.Processor.<init>(SocketServer.scala:790)
at kafka.network.SocketServer.newProcessor(SocketServer.scala:415)
at kafka.network.SocketServer.$anonfun$addDataPlaneProcessors$1(SocketServer.scala:288)
at kafka.network.SocketServer.addDataPlaneProcessors(SocketServer.scala:287)
at kafka.network.SocketServer.$anonfun$createDataPlaneAcceptorsAndProcessors$1(SocketServer.scala:254)
at kafka.network.SocketServer.$anonfun$createDataPlaneAcceptorsAndProcessors$1$adapted(SocketServer.scala:251)
at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:553)
at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:551)
at scala.collection.AbstractIterable.foreach(Iterable.scala:920)
at kafka.network.SocketServer.createDataPlaneAcceptorsAndProcessors(SocketServer.scala:251)
at kafka.network.SocketServer.startup(SocketServer.scala:125)
at kafka.server.KafkaServer.startup(KafkaServer.scala:303)
at kafka.server.KafkaServerStartable.startup(KafkaServerStartable.scala:44)
at kafka.Kafka$.main(Kafka.scala:82)
at kafka.Kafka.main(Kafka.scala)
But if convert this certificate to jks:
openssl pkcs12 -export -in certificate.pem -out certificate.p12
keytool -importkeystore -srckeystore certificate.p12 -srcstoretype pkcs12 -destkeystore certificate.jks
echo 'ssl.keystore.location=/opt/kafka/certs/certificate.jks' >>server.properties
echo 'ssl.keystore.password=password' >>server.properties
Broker works correctly.
Could this be a bug or am I doing anything wrong? Full log here
I think this might be because the private key you are using is encrypted with a PBES2 scheme. You can use OpenSSL to convert the original key and use PBES1 instead:
openssl pkcs8 -in old_kafka.key -passout "pass:password" -topk8 -v1 PBE-SHA1-3DES -out kafka.key
You can find more info of which PKCS#5 encryption algorithms are available with PBES1 and PBES2 in OpenSSL's PKCS#8 man page.
Also, PBES2 support in OpenJDK is mentioned in this issue.
I would like to have SSL termination on HAProxy, using my own self-signed certificates, and to validate client access using client certificates I create.
I create the server (which is also the CA) certificates the following way:
openssl genrsa -out ca.key 1024
openssl req -new -key ca.key -out ca.csr
openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt
and:
cat ca.crt ca.key > haproxy.pem
at HAProxy, I configure:
bind *:443 ssl crt /path/server.pem ca-file /path/ca.crt verify required crt-ignore-err all
I create the client certificates in a similar way:
openssl req -new -key client.key -out client.csr
openssl x509 -req -days 365 -in client.csr -signkey ca.key -out client.crt
cat client.crt client.key > client.pem
My logic is: I'm creating a client key, a certificate signing request for it, and then I sign it using the CA (which is also the server certificate, so there's a simple chain that the server would recognize).
To test, I first try with the server certificate as the client cert:
curl https://my.service:443/ping -E ./haproxy.pem -k
pong
ok, it works. Now I try with the client certificate as the client certificate:
curl https://my.service:443/ping -E ./client.pem -k
curl: (58) unable to set private key file: './client.pem' type PEM
My question:
1) I would like to create a client certificate that this server will accpet, and test it using curl.
2) I would like to import this certificate and the CA into a new java keystore / truststore using keytool, so that Java (Jersey client) code could access the same content.
I have spent 2 days on 1/2.
I'm pretty sure someone that's done this before could answer this in 5m. Or so I hope. :)
Thanks!
1. create client cert
wrong: openssl x509 -req -signkey creates a self-signed cert, which by definition means the key in the cert (the subject key) is the public half of the same key whose private half signs the cert. The documentation for the cert (not req) case is clear that it replaces the key previously in the cert with the signing key. The -req doc is less clear, but it does the same thing; it puts in the cert the subject name from the CSR, also as the issuer, and the key from -signkey. You have used a CSR containing the client name, but a -signkey containing the CA key, producing an unusable chimera.
right: to sign a "child" (not self-signed) cert with x509, use -CA and possibly -CAkey as described in the documentation https://www.openssl.org/docs/apps/x509.html#SIGNING-OPTIONS (or man [where] x509 on any Unix with openssl doc installed). If there is or ever will be more than one child cert for a given CA (defined by its DN), either use the serial-number file scheme to automatically and conveniently assign sequential serial numbers, or use -set_serial to manually assign unique serial numbers (sequential is the easiest way to do unique, but if you a prefer another way that's okay).
aside: for the self-signed CA (and server?!) cert, you don't need separate req -new and x509 -req -signkey steps, you can do it in one req -new -x509. See the doc/manpage for req. In fact you don't need a separate genrsa step, req -newkey [-nodes] -x509 can do that as well. One note: in OpenSSL 1.0.0+ this generates the generic PKCS#8 format keyfile instead of the "legacy" PKCS#1 format used by genrsa (and rsa); all OpenSSL functions can accept either, but some other things might not. In particular last I checked (a while ago) the Wireshark option to decrypt SSL/TLS using server key for akRSA (there are other options too) accepted only PKCS#1 not PKCS#8.
2. use in Java (Jersey). Note that any SSL/TLS client doing client authentication, including Java, needs both the certificate and the privatekey, and in most cases the certificate uses "chain" or "intermediate" certs which you need also. Some people (cough) Microsoft (cough) encourage you to misunderstand and ignore this important distinction, but if you try to use only a certificate it won't work at all. On the other hand a truststore entry needs only the certificate, almost always only the root (CA) certificate, and usually must have only the certificate. Your situation where the same person operates the CA and server and client(s) is somewhat unusual for PKC.
2a. maybe just convert to pkcs12. Java does not directly support the openssl format(s) for keys, but both Java and openssl support PKCS#12 (and so do Microsoft, Mozilla, Apple, and probably others). Since you combined client key and (leaf) cert in client.pem do
openssl pkcs12 -export <client.pem -CA ca.crt [-name whatever] >client.p12
# if you use separate key,cert files see the doc about -in and -inkey
Java crypto (JCE and JSSE) can use this PKCS#12 as a keystore, if you can configure the keystore "type" (as pkcs12). The default SSLSocketFactory supports this, and so do other apps I've used, but I don't use Jersey and don't know what it does here. PKCS#12 isn't generally supported to carry "separate" certs (without privatekey), but in your case the CA cert for the client is also the cert for the server, so it will happen to work as your truststore as well; otherwise you would need to import the server CA or server selfsigned cert (only cert not privatekey) into a JKS truststore (which might be the default truststore in JRE/lib/security/[jsse]cacerts).
2b. maybe further convert to JKS. If Jersey cannot use PKCS#12 directly, Java can convert it to JKS which any sane Java code can use, like:
keytool -importkeystore -srckeystore client.p12 -srcstoretype pkcs12 -destkeystore client.jks
UPDATE 2018: after this answer was written Java support of PKCS12 increased, making it less often necessary to convert to JKS. 8u60 released fall 2017 and up still defaults to keystore type JKS, but as a special feature(?) type JKS can actually read (though not write) PKCS12; see the release notes and item keystore.type.compat in file JRE/lib/security/java.security. Java9 released 2017 makes the default keystore type PKCS12 which (as expected) reads and writes PKCS12, although explicit JKS no longer reads PKCS12. But if you do need to convert with Java9 for some reason, you now need to specify -deststoretype jks but no longer need to specify -srcstoretype pkcs12.
Try as I might, I can't figure out how to use a .p12 file without a password in Java. I've tried setting javax.net.ssl.keyStorePassword to "" but whatever I do I get the following SSL error:
HTTP transport error: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
All my googling would suggest that the sun implementation will not allow an empty password and of course the keytool won't let you import any certificate without a password for the store.
The Sun API seems to require a password, so you will instead need to add a password to your .p12 file.
This page says that you can do this with openssl by converting the .p12 to a .pem, then converting back to a .p12 (but I have not tried it):
openssl pkcs12 -in cert.p12 -out temp.pem -passin pass: -passout pass:temppassword
openssl pkcs12 -export -in temp.pem -out cert-final.p12 -passin pass:temppassword -passout pass:newpassword
rm -f temp.pem
See also this related question.
I got the CA signed certificates and tried to import into the Oracle Wallet Manager for OHS SSL. Private Key and certificate request is generated using open ssl and so we have to create the pkcs12 cert first using the below -
openssl pkcs12 -export -name myservercert -in selfsigned.crt -inkey server.key -out keystore.p12
After that i converted this to JKS using below -
keytool -importkeystore -destkeystore mykeystore.jks -srckeystore keystore.p12 -srcstoretype pkcs12 -alias myservercert
and then imported the Intermediate certs in the JKS. After that when i am trying to convert jks to pkcs12 again using -
mw_home\oracle_common\bin\orapki wallet jks_to_pkcs12 -wallet ./ -pwd "mypassword" -keystore ./mykeystore.jks -jkspwd "mypassword"
I am getting the error - Exception : java.io.IOException: No self-signed cert in chain.
We are not using any self-signed certificate so wondering from where we are getting this issue.
I tried using the p12 keystore that i created in the very first step but there is no certificate request or certificates getting displayed in Oracle Wallet.
Please suggest what is wrong I am doing or is there any best way to import certificates in Oracle Wallet.
why did you use keytool to import intermediate certifcates and not orapki?
orapki wallet add -wallet -cert trustedcerts.crt -trusted_cert
You don't need to bother creating a JKS file. Oracle wallets are valid PKCS12 files. Just create a PEM file with full certificate chain (your private key, your cert, and the full certificate chain in a single file), then run
openssl pkcs12 -export -in certchain.pem -out ewallet.p12
The name 'ewallet.p12' is important. That is Oracle's requirement. Put this file in your wallet directory, then run
orapki wallet create -wallet . -pwd your_pass -auto_login
to create the cwallet.sso file.