2 Replies Latest reply on Jun 20, 2019 3:52 PM by Michael Sonsini

    WildFly Elytron SSL client certificate key password configuration

    Michael Sonsini Newbie

      First, I am using Thorntail 2.4.0.Final (WildFly Core 7.0.0.Final) with Elytron 1.7.0.Final on Java 1.8.0_212 so please let me know if I should be or would more likely get help posting in another forum.

       

      6/17/2019 Update: I received a recommendation to limit this post to the minimum Elytron configuration related to the two-way SSL/TLS so the configuration has been truncated.

       

      I am attempting to get SSL client certification working and running into needing to specify a key password so I doubt I have configured Elytron correctly.

       

      I attempted to follow the Enable Two-way SSL/TLS in WildFly for Applications instructions (adapted for Thorntail configuration) and also consulted the WildFly Elytron Security documentation 4.1.5 Configure Authentication with Certificates, 4.1.8 Configure Applications to Use Elytron or Legacy Security for Authentication, and 16.15 SSL with Client Cert Migration sections.

       

      However, I receive the following error (within Thorntail) after extracting a common name from a presented client certificate to obtain an alias for retrieving a certificate from the client truststore.

       

      2019-06-11 10:50:25,951 TRACE [default task-1] <> org.wildfly.security (getEntry 135) - KeyStoreRealm: Obtaining entry [Test Client Certificate] from KeyStore failed: java.security.UnrecoverableKeyExc

      eption: requested entry requires a password

              at java.security.KeyStoreSpi.engineGetEntry(KeyStoreSpi.java:459)

              at java.security.KeyStore.getEntry(KeyStore.java:1521)

              at org.wildfly.security.auth.realm.KeyStoreBackedSecurityRealm.getEntry(KeyStoreBackedSecurityRealm.java:129)

              at org.wildfly.security.auth.realm.KeyStoreBackedSecurityRealm.access$100(KeyStoreBackedSecurityRealm.java:55)

              at org.wildfly.security.auth.realm.KeyStoreBackedSecurityRealm$KeyStoreRealmIdentity.exists(KeyStoreBackedSecurityRealm.java:211)

              at org.wildfly.security.auth.server.ServerAuthenticationContext.exists(ServerAuthenticationContext.java:447)

              at org.wildfly.security.ssl.SecurityDomainTrustManager.doClientTrustCheck(SecurityDomainTrustManager.java:92)

              at org.wildfly.security.ssl.SecurityDomainTrustManager.checkClientTrusted(SecurityDomainTrustManager.java:72)

              at sun.security.ssl.ServerHandshaker.clientCertificate(ServerHandshaker.java:1970)

              at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:232)

              at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)

              at sun.security.ssl.Handshaker$1.run(Handshaker.java:970)

              at sun.security.ssl.Handshaker$1.run(Handshaker.java:967)

              at java.security.AccessController.doPrivileged(Native Method)

              at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1459)

              at io.undertow.protocols.ssl.SslConduit$5.run(SslConduit.java:1072)

              at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)

              at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)

              at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)

              at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1378)

              at java.lang.Thread.run(Thread.java:748)

       

      The abbreviated Thorntail configuration converted to WildFly XML configuration follows.

       

      <server xmlns="urn:jboss:domain:9.0">

          ...

          <profile>

              ...

              <subsystem xmlns="urn:wildfly:elytron:5.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">

                  ...

                  <security-domains>

                      ...

                      <security-domain name="clientCertSecurityDomain" default-realm="ksRealm" permission-mapper="default-permission-mapper" principal-decoder="cnDecoder" role-mapper="constantClientCertRole">

                          <realm name="ksRealm"/>

                      </security-domain>

                  </security-domains>

                  <security-realms>

                      ...

                      <key-store-realm name="ksRealm" key-store="clientTrustStore"/>

                  </security-realms>

                  <mappers>

                      ...

                      <x500-attribute-principal-decoder name="cnDecoder" oid="2.5.4.3" maximum-segments="1"/>

                      ...

                      <constant-role-mapper name="constantClientCertRole">

                          <role name="ServiceClient"/>

                      </constant-role-mapper>

                  </mappers>

                  ...

                  <http>

                      ...

                      <http-authentication-factory name="certHttpAuth" security-domain="clientCertSecurityDomain" http-server-mechanism-factory="global">

                          <mechanism-configuration>

                              <mechanism mechanism-name="CLIENT_CERT"/>

                              <mechanism>

                                  <mechanism-realm realm-name="applicationDomain"/>

                              </mechanism>

                          </mechanism-configuration>

                      </http-authentication-factory>

                      ...

                  </http>

                  ...

                  <tls>

                      <key-stores>

                          <key-store name="serverKeyStore">

                              <credential-reference clear-text="password"/>

                              <implementation type="pkcs12"/>

                              <file required="true" path="server_cert"/>

                          </key-store>

                          <key-store name="clientTrustStore">

                              <credential-reference clear-text="password"/>

                              <implementation type="pkcs12"/>

                              <file required="true" path="client_cert"/>

                          </key-store>

                      </key-stores>

                      <key-managers>

                          <key-manager name="serverKeyManager" key-store="serverKeyStore">

                              <credential-reference clear-text="password"/>

                          </key-manager>

                      </key-managers>

                      <trust-managers>

                          <trust-manager name="clientTrustManager" key-store="clientTrustStore"/>

                      </trust-managers>

                      <server-ssl-contexts>

                          <server-ssl-context name="twoWaySSC" security-domain="clientCertSecurityDomain" protocols="TLSv1.2" need-client-auth="true" authentication-optional="false" key-manager="serverKeyManager" trust-manager="clientTrustManager"/>

                      </server-ssl-contexts>

                  </tls>

              </subsystem>

              ...

              <subsystem xmlns="urn:jboss:domain:undertow:8.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other">

                  ...

                  <server name="default-server">

                      ...

                      <https-listener name="default-https" socket-binding="https" ssl-context="twoWaySSC" enable-http2="true"/>

                      ...

                  </server>

                  ...

                  <application-security-domains>

                      <application-security-domain name="applicationDomain" http-authentication-factory="certHttpAuth"/>

                  </application-security-domains>

              </subsystem>

              ...

          </profile>

          ...

      </server>

       

      In the "clientTrustStore" key-store, I have only figured out how to use a credential-reference/clear-text element to specify a store password and do not see how to specify a key password. I looked into defining a credential store but then found the KeyStoreCredentialStore javadoc contains the following.

       

      This credential store cannot convert an arbitrary key store into a credential store; it can only understand entries that it itself has added. Entries not understood by this credential store will be ignored (and a log message will be generated indicating the presence of unknown credentials).

       

      A vendor may provide their own client certificate/CSR in this case so I may not be able to let Elytron create the keystore.

       

      Then, I looked at the source code and found the KeyStoreBackedSecurityRealm.getEntry implementation for Elytron 1.7.0.Final. Line 129 is as follows.

       

      KeyStore.Entry entry = keyStore.getEntry(name, null);

       

      This is using the java.security.KeyStore.getEntry method taking the certificate (entry) alias and a KeyStore.ProtectionParameter instance as parameters. The KeyStore.ProtectionParameter interface has a KeyStore.PasswordProtection implementation so I think I may not have the correct approach for client certificate validation. The KeyStoreBackedSecurityRealm.getEntry implementation will never pass a password and keytool requires key passwords to contain at least six characters so I cannot make the password a blank string. openssl has a similar limitation of a minimum four character key password.

       

      I have attached a maven project I am using to test configurations with. Currently, I am using Maven 3.5.4 but can update as needed. From the project root directory (containing the pom.xml file) I execute the following to build and run the Thorntail server.

       

      %M2_HOME%\bin\mvn clean verify && "%JAVA_HOME%\bin\java.exe" -Djavax.net.debug=all -jar target\client-cert-test-thorntail.jar -ssrc\main\resources\project-qa.yml

       

      Also, I am using Postman 7.1.1 to send the following test message to the Thorntail server (running at https://localhost:8443/v0.0.1-SNAPSHOT/test) with a application/JSON Content-Type.

       

      {

        "message": "test"

      }

       

      The client certificate is in the client_cert keystore in the project root directory, as are the server keystore and server side client truststore.

       

      My question is, how should I be configuring Elytron to use client certificate validation and/or specify a key password for the server side client truststore?

       

      Thank you,

      Mike Sonsini

        • 1. Re: WildFly Elytron SSL client certificate key password configuration
          Farah Juma Expert

          From a quick look at this, it looks like the client certificate may not have been imported into the server truststore correctly. The following line indicates that the "Test Client Certificate" entry is not a KeyStore.TrustedCertificateEntry:

           

          2019-06-11 10:50:25,951 TRACE [default task-1] <> org.wildfly.security (getEntry 135) - KeyStoreRealm: Obtaining entry [Test Client Certificate] from KeyStore failed: java.security.UnrecoverableKeyException: requested entry requires a password

           

          An UnrecoverableKeyException occurs for a PrivateKeyEntry or SecretKeyEntry for which the correct password has not been provided. However, the client certificate should be a TrustedCertificateEntry in the server's truststore. This type of entry is not password protected.

           

          Here's an example of how to import a trusted client certificate into the server's truststore:

           

          keytool -importcert -keystore server.truststore.jks -storepass secret -alias client -trustcacerts -file client.cer
          • 2. Re: WildFly Elytron SSL client certificate key password configuration
            Michael Sonsini Newbie

            Farah,

             

            Thank you, I was trying to use the client keystore temporarily as the server truststore and now see that would not work due to the private key.

             

            After extracting the certificates to create the actual truststore, I successfully validated the client certificate.

             

            Mike