Getting HTTPD server to work with TLS on z/OS

This is one of a series of blog posts on HTTPD.

The HTTPD web server is the Apache web server ported to run on z/OS. It runs in Unix Services, and behaves like a proper z/OS program, for example it can use z/OS userids and keyrings.

One catch is that there is Apache SSL, and IBM SSL. For example SSLProtocolEnable is part of IBM SSL support, and does not exist in Apache SSL; and SSLVerifyClient exists in Apache SSL, and not in IBM SSL support.

You need to know which options you need to use. With the wrong options you will get a message like

AH00526: Syntax error on line .. of … Invalid command … , perhaps misspelled or defined by a module not included in the server configuration

This post describes how to get TLS to work with the HTTPD server.

You can use TLS to encrypt the session data, and you can use TLS to use the client certificate as authentication.

The IBM httpd TLS options are described here.

Before you start

  • You need a keyring with certificates. I won’t cover this, as it well documented. I had problems using elliptic keys with size other than 256 and 384. See here.
  • You need to select a port for the TLS sessions. The default for TLS is 443. You may wish to use another port for isolation, and ease of management and configuration.
  • I set up a self contained Virtual Host for the TLS stuff, you do not need to do this.
  • Consider putting your common TLS definitions in a file and including it where needed. For example the list of TLS Ciphers, and the keyring. If you want to change the parameters, you change it once, and restart the server.
  • You can define the SSL parameters in the main server section of the configuration, or within a virtual host. A definition within a virtual host overrides the main server definitions.

Establish a TLS session to encrypt the session data.

Set up permissions

The started task userid needs access to read the keyring. Because WEB2 is not the owner of the ring (START1 is the owner), WEB2 needs CONTROL to get access to the private key.

permit START1.MQRING.LST class(RDATALIB) ID(WEB2) ACCESS(CONTROL)
setropts raclist(RDATALIB) refresh

PERMIT CSFOWH CLASS(CSFSERV) ID(WEB2) ACCESS(READ)
SETROPTS RACLIST(CSFSERV) REFRESH

I was using keyring START1.MQRING,and the httpd server userid is WEB2.

Setup the configuration

For the z/OS SSL support you need

LoadModule ibm_ssl_module modules/mod_ibm_ssl.so

The Apache module mod_ssl.so does not exist on z/OS, so it, and the facilities it provides cannot be used.

I set up a configuration file tls.conf (and used Include conf/tls.conf in my colin.conf)

Listen 8832
<VirtualHost *:8832>
SSLEnable

# SSLTrace
<Location /xxxx.html>

</Location>

ErrorLog “/u/mqweb3/conf/tls.log”
ErrorLogFormat “[%{%X}t]![%l] %F: %E: [client %a] %M”

KeyFile /saf START1/MQRING#

# SSLVerifyClient None

SSLClientAuth optional

SSLProtocolEnable TLSv12
SSLServerCert SERVEREC
SSLCipherSpec TLS_AES_128_GCM_SHA256
SSLCipherSpec TLS_AES_256_GCM_SHA384

# TLS 1.3 cipher specs
# SSLCipherSpec TLS_CHACHA20_POLY1305_SHA256
# SSLCipherSpec TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
# SSLCipherSpec TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
SSLCipherSpec TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
SSLCipherSpec TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
SSLCipherSpec TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
SSLCipherSpec TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
SSLCipherSpec TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
SSLCipherSpec TLS_RSA_WITH_AES_128_GCM_SHA256
SSLCipherSpec TLS_RSA_WITH_AES_256_GCM_SHA384
SSLCipherSpec TLS_RSA_WITH_AES_128_CBC_SHA
SSLCipherSpec TLS_RSA_WITH_AES_256_CBC_SHA
SSLCipherSpec TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
SSLClientAuth none
TLS13Options ServerKeyRefresh=604800

</VirtualHost>

Debugging it

You can either have an SSL VirtualHost wide trace, or a server wide SSL trace (or both)

VirtualHost wide trace

You can use SSLTrace (see above) in your virtual host and it writes it to the error log for that virtual host.

Server wide trace

I changed the environment to create a GSK trace. I added

export GSK_TRACE=0x0f
export GSK_TRACE_FILE=/u/mqweb3/conf/httpd.gsktrace

to /usr/lpp/ihsa_zos/bin/envvars .

You use the gskit command gsktrace /u/mqweb3/conf/httpd.gsktrace > gsk_out to format it.

Testing it

If the httpd server starts, try connecting to it from a web browser. Don’t for get to use https:

https://10.1.1.2:8832

If you get

Internal Server Error

This means the TLS handshake worked, you just have not set up the backend application.

When I used

https://10.1.1.2:8832/xxxx.html

(matching the entry in my VirtualHost definition) I was prompted for userid and password.

Using a client certificate for authentication and identification.

You can use a certificate on a client to authenticate with the server, without having to enter a userid and password. The server needs the CA from the client to be able to authenticate the client certificate. I had problems using elliptic keys on the client with size other than 256 and 384. See here.
You need to set up the certificate in RACF to map from the certificate to a userid.

Map from certificate to userid

My certificate had DN CN=secp256r1,O=cpwebuser,C=GB.

I used the following to map it to userid ADCDA

RACDCERT LISTMAP ID(ADCDA)
RACDCERT DELMAP(LABEL(‘SECP256R1 )) ID(ADCDA)
RACDCERT MAP ID(ADCDA ) –
SDNFILTER(‘CN=secp256r1.O=cpwebuser.C=GB’) –
WITHLABEL(‘SECP256r1’)
RACDCERT LISTMAP ID(ADCDA)
SETROPTS RACLIST(DIGTNMAP, DIGTCRIT) REFRESH

Note: In the certificate the DN is CN=secp256r1,O=cpwebuser, in the RACF command, the comma is replace with a period CN=secp256r1.O… I get it wrong every time!

To force the client to send a certificate you need

SSLClientAuth Required

instead of SSLClientAuth none in your <VirtualHost>…</VirtualHost>.

You also need to specify SAFRunAs

<Location /xxxx.html>
AuthName colinvh
AuthType Basic
AuthBasicProvider saf
SAFRunAs %%CERTIF_REQ%%
Require saf-user ADCDA
Require saf-user COLIN
</Location

The documentation said SAFRunAs can be in “directory, virtual host, server config” , I could only get it to be accepted in the location or the directory statement.

My certificate mapped to ADCDA userid, and so with this certificate I can display page xxxx.html.

SAFAPPLID didn’t work at first.

You can use SAFAPPLID you can say that a user needs access to a profile in the APPL class, for example PAYROLL. The default is OMVSAPPL.

Initially I could not get SAFAPPLID to work. This was due to a set up error. See here for more information.

AuthName didn’t work

When HTTPD prompts you for a userid and password, it is meant to display the authname as the title of the popup window, so you know which userid and password to specify. It didn’t display it for me. I could tell from the network traffic that the AuthName was sent down to the Chromium Browser as WWW-Authenticate: Basic realm=”colinvh“. I believe this is for integrity reasons – someone could change the value, and get you to enter “the wrong” credentials.

Now you’ve go it to work

You should consider

  • How many ports do you need to support.
  • Moving your TLS definitions into one configuration file, and include this where needed.
  • Removing the weak SSL cipher specs.
  • Moving to TLS 1.2 or above.

Documentation

3 thoughts on “Getting HTTPD server to work with TLS on z/OS

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