Reinitializing a Trust Manager through a Two-Way SSL

In WildFly 14, you are able to dynamically reload trust managers using the Elytron subsystem, for trust managers using one of multiple of file and LDAP backed keystores. This blog post will give an overview of how to use this new operation through an example in the WildFly CLI.

Pre-requirements

Before any of the following operations can be done in the CLI, the keystores will first have to be created. As mentioned, these can either be file or LDAP backed keystores. In the following examples, the keystores will be stored in WildFly's standalone/configuration directory.

File Backed Keystores

First, generate the client and server keystores:

keytool -genkeypair -alias client -keyalg RSA -keysize 1024 -validity 365 -keystore client.keystore.jks -dname cn=client,ou=Users,dc=jboss,dc=org -keypass secret -storepass secret;
keytool -genkeypair -alias server -keyalg RSA -keysize 1024 -validity 365 -keystore server.keystore.jks -dname CN=server,ou=Users,dc=jboss,dc=org -keypass secret -storepass secret;

Next, export the client certificate:

keytool -exportcert -keystore client.keystore.jks -alias client -keypass secret -storepass secret -file client.cer;

Next, import the certificates into the server truststore, making sure to enter "yes" when prompted:

keytool -importcert -keystore server.truststore.jks -storepass secret -alias client -trustcacerts -file client.cer;

Finally, export the certificate in PKCS12 format for importing into a browser's keystore:

keytool -importkeystore -srckeystore client.keystore.jks -srcstoretype jks -destkeystore client.keystore.pkcs12 -deststoretype pkcs12

LDAP Backed Keystores

If you will be using a LDAP keystore for either the keystore or truststore, then you will need to also do the following, entering "secret" for all password prompts:

ldif -b "usercertificate" < client.cer
openssl crl2pkcs7 -nocrl -certfile client.cer -out client.p7b
ldif -b "userSMIMECertificate" < client.p7b
keytool -importkeystore -srckeystore client.keystore.jks -srcstoretype jks -destkeystore client.p12 -deststoretype pkcs12
ldif -b "userPKCS12" < client.p12
ldif -b "usercertificate" < server.cer
openssl crl2pkcs7 -nocrl -certfile server.cer -out server.p7b
ldif -b "userSMIMECertificate" < server.p7b
keytool -importkeystore -srckeystore server.keystore.jks -srcstoretype jks -destkeystore server.p12 -deststoretype pkcs12
ldif -b "userPKCS12" < server.p12

After this, you will need to add the usercertificate, userSMIMECertificate, and userPKCS12 output from the above to your LDIF

Example LDIF

The following is an example LDIF from using the above commands, with usercertificate and userPKCS12 entries concatracted due to length:

dn: ou=Users,dc=jboss,dc=org
objectClass: organizationalUnit
objectClass: top
ou: Users

dn: cn=client,ou=Users,dc=jboss,dc=org
objectClass: top
objectClass: person
objectClass: inetOrgPerson
objectClass: krb5principal
objectClass: krb5kdcentry
cn: client
sn: Client
uid: client
userPassword: secret
krb5PrincipalName: client@JBOSS.ORG
krb5KeyVersionNumber: 0
usercertificate:: MIICNDCCAZ2gAwIBAgIEZdeKRzANBgkqhkiG9w0BAQsFADBNMRMwEQYKCZIm iZPyLGQBGRYDb3JnMRUwEwYKCZImiZPyLGQBGRYFamJvc3MxDjAMBgNVBAsTBVVzZXJzMQ8wDQYDV QQDEwZjbGllbnQwHhcNMTgwODA3MTQxOTM3WhcNMTkwODA3MTQxOTM3WjBNMRMwEQYKCZImiZPyLG QBGRYDb3JnMRUwEwYKCZImiZPyLGQBGRYFamJvc3MxDjAMBgNVBAsTBVVzZXJzMQ8wDQYDVQQDEwZ jbGllbnQwgZ8wDQYJKoZIhvcNAQEBBQAD...
userSMIMECertificate:: LS0tLS1CRUdJTiBQS0NTNy0tLS0tCk1DY0dDU3FHU0liM0RRRUhBcUF hTUJnQ0FRRXhBREFMQmdrcWhraUc5dzBCQndHZ0FLRUFNUUE9Ci0tLS0tRU5EIFBLQ1M3LS0tLS0K
userPKCS12:: MIIGiwIBAzCCBkQGCSqGSIb3DQEHAaCCBjUEggYxMIIGLTCCAyEGCSqGSIb3DQEHA aCCAxIEggMOMIIDCjCCAwYGCyqGSIb3DQEMCgECoIICszCCAq8wKQYKKoZIhvcNAQwBAzAbBBQo8M yMzHi8sOp+eFeT+Bl84CmVkQIDAMNQBII...

dn: cn=server,ou=Users,dc=jboss,dc=org
objectClass: top
objectClass: person
objectClass: inetOrgPerson
objectClass: krb5principal
objectClass: krb5kdcentry
cn: server
sn: Server
uid: server
userPassword: secret
krb5PrincipalName: server@JBOSS.ORG
krb5KeyVersionNumber: 0
usercertificate:: MIICNDCCAZ2gAwIBAgIEbrmWsDANBgkqhkiG9w0BAQsFADBNMRMwEQYKCZIm iZPyLGQBGRYDb3JnMRUwEwYKCZImiZPyLGQBGRYFamJvc3MxDjAMBgNVBAsTBVVzZXJzMQ8wDQYDV QQDEwZzZXJ2ZXIwHhcNMTgwODA3MTQxOTM3WhcNMTkwODA3MTQxOTM3WjBNMRMwEQYKCZImiZPyLG QBGRYDb3JnMRUwEwYKCZImiZPyLGQBGRYFamJvc3MxDjAMBgNVBAsTBVVzZXJzMQ8wDQYDVQQDEwZ zZXJ2ZXIwgZ8wDQYJKoZIhvcNAQEBBQAD...
userSMIMECertificate:: LS0tLS1CRUdJTiBQS0NTNy0tLS0tCk1DY0dDU3FHU0liM0RRRUhBcUF hTUJnQ0FRRXhBREFMQmdrcWhraUc5dzBCQndHZ0FLRUFNUUE9Ci0tLS0tRU5EIFBLQ1M3LS0tLS0K
userPKCS12:: MIIGiwIBAzCCBkQGCSqGSIb3DQEHAaCCBjUEggYxMIIGLTCCAyEGCSqGSIb3DQEHA aCCAxIEggMOMIIDCjCCAwYGCyqGSIb3DQEMCgECoIICszCCAq8wKQYKKoZIhvcNAQwBAzAbBBT/rz vd7yCpgRK6v9klTDGrv75EPAIDAMNQBII...

Creating the initial SSL Context

File Backed Keystores

First, create the key-store and trust-store:

[standalone@localhost:9990 /] /subsystem=elytron/key-store=twoWayKS:add(path=server.keystore.jks,relative-to=jboss.server.config.dir,credential-reference={clear-text=secret},type=JKS)
{"outcome" => "success"}
[standalone@localhost:9990 /] /subsystem=elytron/key-store=twoWayTS:add(path=server.truststore.jks,relative-to=jboss.server.config.dir,credential-reference={clear-text=secret},type=JKS)
{"outcome" => "success"}

Next, define the key-manager and trust-manager:

[standalone@localhost:9990 /] /subsystem=elytron/key-manager=twoWayKM:add(key-store=twoWayKS,credential-reference={clear-text=secret})
{"outcome" => "success"}
[standalone@localhost:9990 /] /subsystem=elytron/trust-manager=twoWayTM:add(key-store=twoWayTS)
{"outcome" => "success"}

Next, setup the SSL Context:

[standalone@localhost:9990 /] /subsystem=elytron/server-ssl-context=twoWaySSC:add(key-manager=twoWayKM,protocols=["TLSv1.2"],trust-manager=twoWayTM,need-client-auth=true)
{"outcome" => "success"}

Next, replace the legacy security domain with the new SSL context in the Undertow HTTPS listener:

[standalone@localhost:9990 /] batch
[standalone@localhost:9990 / #] /subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm)
[standalone@localhost:9990 / #] /subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context,value=twoWaySSC)
[standalone@localhost:9990 / #] run-batch
The batch executed successfully
process-state: reload-required

Finally, reload the server:

[standalone@localhost:9990 /] reload

LDAP Backed Keystores

First, set the Kerberos configuration file system property:

[standalone@localhost:9990 /] /system-property=java.security.krb5.conf:add(value=/YOUR/PATH/TO/kerberos-using-apacheds/krb5.conf)

After this, follow the steps in the previous section File Backed Keystores, but replace the steps for adding the file backed keystores with the following steps for each replacement LDAP keystore:

Add the LDAP dir-context to Elytron:

[standalone@localhost:9990 /] /subsystem=elytron/dir-context=ldap:add(url="ldap://localhost:10389", principal="cn=client,ou=Users,dc=jboss,dc=org", credential-reference={clear-text="secret"})

Create the LDAP keystore:

[standalone@localhost:9990 /] /subsystem=elytron/ldap-key-store=LKS1/:add(dir-context=ldap, search-path="ou=Users,dc=jboss,dc=org")

Reload the server:

[standalone@localhost:9990 /] reload

If you want to verify the aliases have been read in correctly, then perform the following:

Switch to the LDAP key store directory:

[standalone@localhost:9990 /] cd subsystem=elytron/ldap-key-store=LKS1

Read the aliases:

[standalone@localhost:9990 ldap-key-store=LKS1] :read-aliases()

Verifying the Initial Two-Way SSL Setup

To check that the Two-Way SSL is setup initially, a browser can be used with WildFly's default home page. The certificate must first be imported into the browser, then the SSL context is known to be successful by being able to navigate to the WildFly home page, with the browser showing an (untrusted by virtue of an unknown issuer) SSL connection.

Importing the Client Certificate

Firefox

In Firefox (version 59.0.2 as of this article):
Menu => Preferences => Privacy & Security => Security#Certificates => View Certificates => Import... => Select client.keystore.pkcs12 from standalone/configuration => Open => Enter secret => OK
New Private Window => Navigate to https://localhost:8443 => Select OK on the User Identification Request pop-up => Advanced => Add Exception... => Confirm Security Exception

Chrome

In Chrome (version 66.0.3359.181 as of this article):
Navigate to chrome://settings (or Menu => Settings) => Advanced => Privacy and security => Manage certificates => IMPORT => Select client.keystore.pkcs12 from standalone/configuration => Open => Enter secret => OK
New incognito window => Navigate to https://localhost:8443 => Select OK on the Select a certificate pop-up => Advanced => Proceed to localhost (unsafe)

Reinitializing the Trust-Manager (and Key-Manager)

First, change your keystores and truststores. In this case, rerun the commands in the section "Pre-requirements" but changing the following in the keytool commands:
-alias client => -alias clientnew
-alias server => -alias servernew
-dname cn=client,ou=Users,dc=jboss,dc=org => -dname cn=clientnew,ou=Users,dc=jboss,dc=org
-dname cn=server,ou=Users,dc=jboss,dc=org => -dname cn=servernew,ou=Users,dc=jboss,dc=org

Reloading the Keystores

If the keystores are file backed, then you will first have to load the changed keystores into Elytron:

[standalone@localhost:9990 /] /subsystem=elytron/key-store=twoWayKS:load()
{
    "outcome" => "success",
    "result" => undefined
}
[standalone@localhost:9990 /] /subsystem=elytron/key-store=twoWayTS:load()
{
    "outcome" => "success",
    "result" => undefined
}

Changes in any LDAP backed keystores do not require any WildFly CLI commands to be seen once the LDAP server is restarted

Reinitializing the Managers

[standalone@localhost:9990 /] /subsystem=elytron/key-manager=twoWayKM:init()
{"outcome" => "success"}
[standalone@localhost:9990 /] /subsystem=elytron/trust-manager=twoWayTM:init()
{"outcome" => "success"}

Verifying the SSL Context Uses the New Managers

To verify the managers have been successfully reinitialized to use the new keystores and that the SSL context sees the change, follow the steps in Verifying the Initial Two-Way SSL Setup. You can further check the new "clientnew" certificate is being used by investigating the issuer certificate in the browser.

Summary

This post provides information on how to use the new trust-manager init operation through the use of a Two-Way SSL connection. Without having to read the example, the new operation can simply be used by running the following commands:

[standalone@localhost:9990 /] /subsystem=elytron/key-store=twoWayTS:load()
[standalone@localhost:9990 /] /subsystem=elytron/trust-manager=twoWayTM:init()

Appendix

Setting up a test LDAP server

First, you can clone the following repository for the Kerberos server code:
https://github.com/hkalina/kerberos-using-apacheds

Next, import the results of Pre-requirements#LDAP Backed Keystores into test.ldif in the relevant spots (see previous mentioned section for example test.ldif)

Finally, follow the steps on the Github link to initialize the server

You can now use LDAP keystores defined in test.ldif within your Two-Way SSL setup

Comments

Popular posts from this blog

Converting Legacy Properties Files into a FileSystemRealm with Elytron Tool

Enhanced Audit Logging in WildFly Elytron - RFC Support and Reliabiliity/Speed Customization

Enhanced Audit Logging in WildFly Elytron - RFC Support and Reliabiliity/Speed Customization Update