Categories
DevOps

How to use PKCS #12 as ZooKeeper truststore

PKCS #12 format works fine when used to provide ZooKeeper keystore, but additional steps are needed to use it for a dedicated truststore.

You will get the following error when you try to use PKCS #12 truststore.

2021-08-08 14:06:48,947 [myid:3] - WARN  [QuorumConnectionThread-[myid=3]-86:QuorumCnxManager@397] - Cannot open secure channel to 2 at election address zookeeper2.example.org/172.16.0.112:3888
org.apache.zookeeper.common.X509Exception$SSLContextException: Failed to create TrustManager
        at org.apache.zookeeper.common.X509Util.createSSLContextAndOptionsFromConfig(X509Util.java:371)
        at org.apache.zookeeper.common.X509Util.createSSLContextAndOptions(X509Util.java:328)
        at org.apache.zookeeper.common.X509Util.createSSLContextAndOptions(X509Util.java:282)
        at org.apache.zookeeper.common.X509Util.getDefaultSSLContextAndOptions(X509Util.java:262)
        at org.apache.zookeeper.common.X509Util.createSSLSocket(X509Util.java:517)
        at org.apache.zookeeper.server.quorum.QuorumCnxManager.initiateConnection(QuorumCnxManager.java:379)
        at org.apache.zookeeper.server.quorum.QuorumCnxManager$QuorumConnectionReqThread.run(QuorumCnxManager.java:458)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: org.apache.zookeeper.common.X509Exception$TrustManagerException: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
        at org.apache.zookeeper.common.X509Util.createTrustManager(X509Util.java:512)
        at org.apache.zookeeper.common.X509Util.createSSLContextAndOptionsFromConfig(X509Util.java:369)
        ... 9 more
Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
        at java.base/java.security.cert.PKIXParameters.setTrustAnchors(PKIXParameters.java:200)
        at java.base/java.security.cert.PKIXParameters.(PKIXParameters.java:157)
        at java.base/java.security.cert.PKIXBuilderParameters.(PKIXBuilderParameters.java:130)
        at org.apache.zookeeper.common.X509Util.createTrustManager(X509Util.java:489)
        ... 10 more

PKCS #12 truststore needs to contain a special attribute that cannot be added using OpenSSL utilities.

Export CA to the JKS format using keytool utility.

$ keytool -noprompt -storepass "capassword" -keystore server.truststore.jks -alias CARoot -import -file ca.pem
Certificate was added to keystore

Export it to PKCS #12 format using keytool utility. This the

$ keytool -importkeystore -srckeystore server.truststore.jks -destkeystore cacertificate.p12 -srcstoretype jks -deststoretype pkcs12 -srcstorepass capassword -deststorepass capassword
Importing keystore server.truststore.jks to cacertificate.p12...
Entry for alias caroot successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled

Inspect the CA stored using PKCS #12 format, notice additional 2.16.840.1.113894.746875.1.1 OID.

$ openssl pkcs12 -in cacertificate.p12  -info -password pass:capassword
MAC: sha1, Iteration 100000
MAC length: 20, salt length: 20
PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 50000
Certificate bag
Bag Attributes
    friendlyName: caroot
    2.16.840.1.113894.746875.1.1: <Unsupported tag 6>
subject=O = ZooKeeper, OU = Backend, emailAddress = admin@example.org

issuer=O = ZooKeeper, OU = Backend, emailAddress = admin@example.org

-----BEGIN CERTIFICATE-----
MIIDcTCCAlmgAwIBAgIUda8Vsl8cbWcIWTgR9B1Uews99uUwDQYJKoZIhvcNAQEL
BQAwSDESMBAGA1UECgwJWm9vS2VlcGVyMRAwDgYDVQQLDAdCYWNrZW5kMSAwHgYJ
KoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLm9yZzAeFw0yMTA4MDgxOTE0MDlaFw0z
MTA4MDYxOTE0MDlaMEgxEjAQBgNVBAoMCVpvb0tlZXBlcjEQMA4GA1UECwwHQmFj
a2VuZDEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5vcmcwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3CEu6v7tVlrnPAvUROHxw+Vikw/yIcCNu
zjUDEIP/ulytHuFVzo5TwuVrEluTObOtethMc9FoXmeYa7oqDmSvSRF3I510/lpc
qFmXgP+Ac0lnsWC3rlcwQuNxqkiE6DBNjNQYUmN1NyHW6WE1tjHXYKmcVq2ct2D2
fJu77qb0FIyHgdxaaX/1mapXw/spKrvduOgrjv/xXituT6kRo0vl1ww67w3/Sk3o
wejhDS9K2jwyn1XTn29AWxTcAIQwerNVPnCh+G+Sf0FRk2IA5HIZ3KIxmTCscqLZ
UEwRF/wQREiZQTwigW1CHCv8bklSAduZlOQWqVG9QFVUcZTco4MXAgMBAAGjUzBR
MB0GA1UdDgQWBBToWI35o5pnWgk9DnI67h7/UXYeYzAfBgNVHSMEGDAWgBToWI35
o5pnWgk9DnI67h7/UXYeYzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
A4IBAQAeUYNhUWNsR4+sIc6Ep+7dd2goY6UWxK2yMFqUW1JjgmudKS75kXlskrxj
3+mgIV2tgTde/9IGoV1sLjfp+TiOE87HoEX//HzlepwzaURLAYiDA+3TSSa8S0Nz
X2ceP+sksZhBPmb7KniDNclom4BnidUa7lCesHg2RTECxz5WCd0sFUcK4eRFzmf3
wLyHbvVPQx6O18H12V9ttHCkMRaW5JoEpbCsoKZEbpFIrlkKUaB3ndxmZEdaOOHm
4FF6iLnOyuRxJvfh6kYZfq62u1Cib2oaLXPHRH4/ZI8eolxbgC9dfTDKim8sjhpG
ioVIt9vMSfI6/fD9e9F7Im4xx+Sj
-----END CERTIFICATE-----

This is it. It will likely solve the same issue in different Java applications.