Using z/OS LDAP with TLS 1.3

This blog post started as one line in the Using z/OS LDAP with TLS post. After it took two days to get working, I thought it deserved its own page.

Displaying the handshake

Using Wireshark to display TLS traffic is harder with TLS 1.3, as most of the handshake is now encrypted. See here on how to display it.

What supports LDAP and TLS 1.3?

I could not get Openldap on Ubuntu 18.04 to use TLS 1.3 – I do not think it has the support.

I could use the z/OS LDAPSEARCH with TLS 1.3, see below.

Java should work with the right set up.

Updating LDAP server on z/OS

Updates to enable TLS V1.3 protocol support for GSKIT has some good information.

You need to add the following to the configuration file

sslCipherSpecs GSK_V3_CIPHER_SPECS_EXPANDED

# TLS 1.3 only supports sslFipsState off
slFipsState off

Below are the environment variables I used for the LDAP server on z/OS

GSK_TRACE=0xff
GSK_TRACE_FILE=/tmp/gsktrace.ldap
GSK_PROTOCOL_TLSV1_1=off
GSK_PROTOCOL_TLSV1_2=off
GSK_PROTOCOL_TLSV1_3=on
GSK_SERVER_TLS_KEY_SHARES=00300029002500240023
GSK_V3_CIPHER_SPECS_EXPANDED=C02CC02BC030C02FC024C023130313011302
GSK_TLS_SIG_ALG_PAIRS=060105010401030108060805080405030403

I think this is the super set of data, and should be used as a starter list. You can remove unwanted cipher specs once you have it working. It is easier doing it this way compared to adding those you need (because it is hard to find what you need).

GSK_V3_CIPHER_SPECS_EXPANDED

You need to add the TLS 1.3 cipher specs to the GSK_V3_CIPHER_SPECS_EXPANDED in the environment file.

For example

GSK_V3_CIPHER_SPECS_EXPANDED=13011302C028C0271303

GSK_TLS_SIG_ALG_PAIRS

This variable needs to include 0806,0805,0804.

Key share

TLSv1.3 uses client and server key-shares to facilitate the encryption of TLSv1.3 handshake messages and to determine the key exchange algorithms.

You give a preference as to which elliptic curve to use.

You need to list the key shared values (from this list (table 5)), where  secp256r1 has the value 0023.

GSK_SERVER_TLS_KEY_SHARES is used by the server. The client has GSK_CLIENT_TLS_KEY_SHARES

GSK_SERVER_TLS_KEY_SHARES=00300029002500240023

or

GSK_CLIENT_TLS_KEY_SHARES=00300029002500240023

Remove any definitions in the keyshares which are not supported by TLS 1.3 (0019 and 0021) (even though you have GSK_PROTOCOL_TLSV1_2=on)

With these my LDAP started.

Once you have LDAP working, you can review the cipher specs, and remove the ones you no longer use. You should plan to remove the weaker cipher specs. If you remove a cipher spec and it is still needed, clients will fail to connect. You will need to replace the cipher specs and restart the server.

Using openssl s_client on Linux to establish a session to LDAP on z/OS.

Openssl s_client sends the TLS 1.3 supported cipher specs as part of the initial client hello handshake, so you can see the flows.

When I did this I got

s_client fails with SSL alert number 42.

From the z/OS GSK trace I can see

ERROR check_cert_extensions_3280_and_later(): authorityKeyIdentifier extension is missing
ERROR validate_certificate_basics(): Unable to verify certificate extensions: Error 0x0335306f
ERROR validate_certificate_mode(): Unable to validate certificate: Error 0x0335306f
ERROR cms_validate_certificate_mode_int(): Unable to validate certificate: Error 0x0335306f

ERROR read_tls13_certificate(): Unable to validate peer certificate: Error 0x0335306f

ERROR send_tls13_alert(): Sent TLS 1.3 alert 42 to 10.1.0.2[42514]

Where 0x0335306f (search for 0335306f) is

Explanation

A certificate extension that is mandatory for the certificate to be used for the required purpose has not been found.

User response

Ensure that the certificate chain is correct and complies with the validation mode defined for the connection. Collect a System SSL trace containing the error and then contact your service representative if the error persists.

A certificate authority can use multiple certificates to sign a certificate, for example you are refreshing or upgrading the certificate. Having the authorityKeyIdentifier says which certificate was used to sign it.
On the web there are documents which recommend its use, for example with openssl, the configuration file should have.

[ v3_ca ]
subjectKeyIdentifier=hash

authorityKeyIdentifier=keyid:always,issuer:always

On z/OS with RACF you get this attribute when using RACDCERT GENCERT … SIGNWITH() .

On my system I had misconfigured it

subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer


I had to

  • create a new CA with the above in the Openssl configuration file
  • reissue the end user certificate
  • update all my servers with the new CA
  • update my LDAP CRL server

Wow – what a lot of work for a user error.

When I had done the above work, I used the

openssl x509 -in rsaca256.pem -text -noout

to list the end user certificate, and there was additional information

X509v3 Authority Key Identifier:
keyid:B3:0C:14:E9:C4:7D:8D:C1:45:9D:57:CE:19:8C:6B:0A:6C:EF:00:78
DirName:/C=GB/O=SSS/OU=CA/CN=SSCARSA1024
serial:03:DB:6B:09:E5:38:41:7D:8C:F3:CB:62:CA:1A:DD:63:CE:7E:C6:24

Using openLDAP ldapsearch on Ubuntu 18.04

I had problems getting ldapsearch on Linux to work with TLS 1.3, because it was difficult to get TLS 1.3 support – it did not send the TLS 1.3 cipher specs as part of the Client Hello. The documentation describes TLS_CIPHER_SUITE option. The Openssl syntax did not work, and the GnuTLS Syntax did work but I could not get it working with TLS 1.3 – perhaps it is not supported.

Using ldapsearch from z/OS

This was easy to set up, and I could use the gsktrace from each end to observe the flows.

I set up a bash script

export GSK_TRACE=0xff
export GSK_TRACE_FILE=./colin.gsktrace
export GSK_PROTOCOL_TLSV1_1=”off”
export GSK_PROTOCOL_TLSV1_2=”off”
export GSK_PROTOCOL_TLSV1_3=”on”
export GSK_CLIENT_TLS_KEY_SHARES=”003000290025002400230021″
export GSK_TLS_SIG_ALG_PAIRS=”0601050104010301080608050804050304030603″
export LDAP_SSL_CIPHER_FORMAT=”CHAR4″
export GSK_CLIENT_ECURVE_LIST=”00230024002500290030″
export GSK_V3_CIPHER_SPECS_EXPANDED=”130213011303C02BC02CC030C028C02aC024C026C02E”
debug=”-d all”
debug=”-d error+conns”
tls=”-Z -K adcda/MQRING -N ADCDRSA -S EXTERNAL”
tls=”-Z -K adcda/MQRING -N ADCDEC -S EXTERNAL”
host=”-h 127.0.0.1 -p 1389″
host=”-h 10.1.0.2 -p 9443″
ldapsearch $host $tls $debug -b “o=Your Company” “(objectclass=*)” aclEntry

gsktrace colin.* > out
oedit out

I defined an environment variable more than once, so I just needed to move the line down to change what was used. For example by swapping over the “tls” lines I could quickly use a different certificate.

I added the commands to format the gsktrace and display it.

Output

Because I used the debug value “-d error+conns” I got

CONNS ldap_ssl_socket_init()1600: 4-byte ciphers format will be used
CONNS ldap_ssl_socket_init()1625: No 4-byte cipher specs specified in LDAP handle
CONNS ldap_ssl_socket_init()1689: SSL Protocol Version = 621
CONNS ldap_ssl_socket_init()1700: SSL Cipher Specs
Address: 1FA36946 Length: 4 (x’4′)
00000000: f1f3f0f3 *1303 *
ERROR ldap_parse_pwdpolicy_response_int()856: No server controls o=Your Company

I think these messages are OK, and do not show a problem.

You can see that cipher spec 1303 was used.

Other information

TLS 1.3 uses one of the following ciphers

  • TLS_AES_128_GCM_SHA256 -1301
  • TLS_AES_256_GCM_SHA384 – 1302
  • TLS_CHACHA20_POLY1305_SHA256 1303
  • TLS_AES_128_CCM_SHA256 -1304
  • TLS_AES_128_CCM_8_SHA256 -1305

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s