How do I get my client talking to the server with a signed certificate

Signed certificates are very common, but I was asked how I connected my laptop to my server, in the scenario “one up” from a trivial example.

Basic concepts

  • A private/public key pair are generated on a machine. The private stays on the machine (securely). The public key can be sent anywhere.
  • A certificate has ( amongst other stuff)
    • Your name
    • Address
    • Public key
    • Validity dates

Getting a signed certificate

When you create a certificate: it does a checksum of the contents of the certificate, encrypts the checksum with your private key, and attaches this encrypted value to the certificate.

Conceptually, you go to your favourite Certificate Authority (UKCA) building and they Sign it

  • They check your passport and gas bill with the details of your certificate.
  • They attach the UKCA public key to your certificate.
  • They do a checksum of the combined documents.
  • They encrypt the checksum with the the UKCA private key, and stick this on the combined document.

You now have a signed certificate, which you can send it to anyone who cares.

Using it

When I receive it, and use it

  • my system compares my copy of the UKCA public certificate with the one in your certificate – it matches!
  • Using (either) UKCA public certificate – decrypt the encrypted checksum
  • Do the same checksum calculation – and the two values should match.
  • If they match I know I can trust the information in the certificate.

This means the checking of the certificate requires the CA certificate that signed it.

To use a (Linux) certificate on z/OS you either need to

  • issue the RACF GENCERT command on the Linux .csr file, export it, then download it to Linux. The certificate will contain the z/OS CA’s certificate.
  • import the Linux CA certificate into RACF (This is the easy, do once solution.)

then

  • connect the CA certificate to your keyring, and usually restart your server.

Setting up my system

If the CA certificate is not on your system, you need to import it from a dataset.

You can use FTP, or use cut and paste to the dataset.

Once you have the CA certificate in your RACF database you can connect it to your keyring.

Create my Linux CA and copy it to z/OS

CA="docca256"
casubj=" -subj /C=GB/O=DOC/OU=CA/CN=LINUXDOCCA2564"
days="-days 1095"
rm $CA.pem $CA.key.pem

openssl ecparam -name prime256v1 -genkey -noout -out $CA.key.pem

openssl req -x509 -sha384 -config caca.config -key $CA.key.pem -keyform pem -nodes $casubj -out $CA.pem -outform PEM $days

openssl x509 -in $CA.pem -text -noout|less

Where my caca.config has

####################################################################
[ req ]
distinguished_name = ca_distinguished_name
x509_extensions = ca_extensions
prompt = no

authorityKeyIdentifier = keyid:always,issuer:always

[ca_distinguished_name ]
[ ca_extensions ]

subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:TRUE, pathlen:0
keyUsage = keyCertSign, digitalSignature,cRLSign

Running the command gave

Certificate:
Data:
...
Issuer: C = GB, O = DOC, OU = CA, CN = LINUXDOCCA256
...
Subject: C = GB, O = DOC, OU = CA, CN = LINUXDOCCA256
...
X509v3 extensions:
...
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Key Usage:
Digital Signature, Certificate Sign, CRL Sign
...

Where it has CA:TRUE and X509v3 Key Usage:Certificate Sign

Which allows this to be used to sign certificates.

Installing the CA certificate on z/OS

You need to copy the docca256.pem file from Linux to a z/OS dataset (Fixed block, lrecl 80, blksize 80) you can use FTP or cut and paste. I used dataset COLIN.DOCCA256.PEM.

Import it into z/OS, and connect it to the START1.MYRING keyring as a CERTAUTH.

//COLRACF  JOB 1,MSGCLASS=H 
//S1 EXEC PGM=IKJEFT01,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
RACDCERT CHECKCERT('COLIN.DOCCA256.PEM')

*RACDCERT DELETE (LABEL('LINUXDOCA256')) CERTAUTH
RACDCERT ADD('COLIN.DOCCA256.PEM') -
CERTAUTH WITHLABEL('LINUXDOCA256') TRUST

RACDCERT CONNECT(CERTAUTH LABEL('LINUXDOCA256') -
RING(MYRING) USAGE(CERTAUTH)) ID(START1)

SETROPTS RACLIST(DIGTCERT,DIGTRING ) refresh
/*

Once you have connected the CA to the keyring, you need to get the server to reread the keyring, or restart the server.

Getting my Linux certificate signed by z/OS

This works, but is a bit tedious for a large number of certificates.

I created a certificate request file using

timeout="--connect-timeout 10"
enddate="-enddate 20290130164600Z"

ext="-extensions end_user"

name="docec384Pass2"
key="$name.key.pem"
cert="$name.pem"
p12="$name.p12"
subj="-subj /C=GB/O=Doc3/CN="$name
rm $name.key.pem
rm $name.csr
rm $name.pem
passin="-passin file:password.file"
passout="-passout file:password.file"
md="-md sha384"
policy="-policy signing_policy"
caconfig="-config ca2.config"
caextensions="-extensions clientServer"


openssl ecparam -name secp384r1 -genkey -noout -out $name.key.pem
openssl req -config openssl.config -new -key $key -out $name.csr -outform PEM -$subj $passin $passout

The certificate request file docec384Pass2.csr looks like

-----BEGIN CERTIFICATE REQUEST----- 
MIIBpzCCAS0CAQAwNDELMAkGA1UEBhMCR0IxDTALBgNVBAoMBERvYzMxFjAUBgNV
...
Tmmvu/nqe0wTc/jJuC4c/QJt+BQ1SYMxz9LiYjBXZuOZkpDdUieZDbbEew==
-----END CERTIFICATE REQUEST-----

With words CERTIFICATE REQUEST in the header and trailer records.

Create a dataset(COLIN.DOCLCERT.CSR) with the contents. It needs to be a sequential FB, LRECL 80 dataset.

  • Delete the old one
  • Generate the certificate using the information in the .csr. Sign it with the z/OS CA certificate
  • Export it to a dataset.
//IBMRACF2 JOB 1,MSGCLASS=H 
//S1 EXEC PGM=IKJEFT01,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *

RACDCERT ID(COLIN ) DELETE(LABEL('LINUXCERT'))

RACDCERT ID(COLIN) GENCERT('COLIN.DOCLCERT.CSR') -
SIGNWITH (CERTAUTH LABEL('DOCZOSCA')) -
WITHLABEL('LINUXCERT')

RACDCERT ID(COLIN) LIST(label('LINUXCERT'))
RACDCERT EXPORT(label('LINUXCERT')) -
id(COLIN) -
format(CERTB64 ) -
password('password') -
DSN('COLIN.DOCLCERT.PEM' )

SETROPTS RACLIST(DIGTCERT,DIGTRING ) refresh

Then you can download COLIN.DOCLCERT.PEM to a file on Linux and use it. I used cut and paste to create a file docec384Pass2.zpem

I used it like

set -x 
name="colinpaice"
name="colinpaice"
name="docec384Pass2"
insecure=" "
insecure="--insecure"
timeout="--connect-timeout 100"
url="https://10.1.1.2:10443"
trace="--trace curl.trace.txt"

cert="--cert ./$name.zpem:password"
key="--key $name.key.pem"

curl -v $cert $key $url --verbose $timeout $insecure --tlsv1.2 $trace

Using wireshark I can see CA certificates being send from z/OS, and the docec384Pass2.lpem used; signed by a z/OS CA certificate.

Using the certificate in the Chrome browser.

  • In Chrome settings, search for cert.
  • Click security
  • Scroll down to Manage certificates, and select it
  • Select customised
  • Select import, and then select the file.
    • When I generated the file with the Linux CA it had a file type of .pem
    • When I signed it on z/OS, then downloaded it with a type of.zpem, I had to select all files (because the defaults are *.pem,*.csr,*.der..)

Using keyrings and certificates on z/OS with Liberty

This is a work in progress… but someone asked me for this information so I’ll publish as it is.

I had a lot of playing around with MQWEB on Linux, and I thought that z/OS would be just a small step more than Linux.  After many false steps, it is very similar to Linux – but because z/OS is more secure than Linux you have to do more work to get the right permissions.

Once you have set up the keyrings and got your web browser to talk to the Liberty at the back end, you can then

  • logon with userid and password
  • logon with digital certificate, so there is now set up to map your Linux  digital certificate to a z/OS userid

Once you have got the z/OS userids set up,  you need to set up the RACF groups which determine if you are allowed to use the server, and if you are a read only user, or a full function.

z/OS certificates background.

  • You use the RACF RACDCERT command to manage certificates
  • Certificates either stored in an (encrypted) RACF data base.
  • You provide similar information as with midrange machines to define certificates, such as Organisation, Common Name, Country etc.
  • On z/OS you cannot specify Extended Key Usage (EKU) attributes.
  • A certificate has two parts,
    • a private part, this allows you to encrypt data for that certificate.  It must be kept securely.
    • a public part  – anyone can have a copy of this – allows them to decrypt a message created using the private key.
  • Certificate ownership.  The RACF documentation says
    • User certificate A certificate that is associated with a RACF user ID and is used to authenticate the user’s identity. The RACF user ID can represent a traditional user or be assigned to a server or started procedure.  These are identified by ID(…).
    • Certificate-authority certificate. A certificate that is associated with a certificate authority and is used to verify signatures in other certificates.   These are identified by CERTAUTH.
    • Site certificate. A certificate that is associated with an off-platform server or other network entity, such as a peer VPNserver. This category of certificate can also be used to share a single certificate and its private key among multiple RACF user IDs. When used for sharing, a certificate might be referred to as a placeholder certificate.  These are identified by SITE.
  • A certificate has to have the TRUST attribute to be visible in a keyring.
  • Applications access certificate via a user’s keyring.
    • A userid can have many keyrings
    • A keyring can have many certificates.  They can belong to User, Certificate Authority, or Site.
    • You can control access at an individual keyring level.
  • Your web browser will likely have two keyrings (similar to midrange)
    • A Server key ring containing the private certificate to identify the server, and has the private key.   This keyring might only be used by a group of MQWEB servers and no other applications. A web server in CICS would have a its own keyring.
    • A Trust store.  This has the public certificates and allows people to communicate with the web server.  It typically has Certificate Authority certificates.   A CA certificate can validate all users who’s certificate was  signed by the CA. So one CA in the keyring could validate 1000 users.   If the end users are using self signed certificates, then the z/OS keyring has to have a copy of every self signed certificate.  If you add a new certificate then you may have to restart the server.
    • You might share this trust store with all web servers, either native or within CICS.

Steps for setting up the certificates and keyrings to connect the browser to the z/OS web server

  • Server keyring
    • Create a z/OS certificate authority
    • Create a server keyring
    • Create a certificate for the server
    • Add the certificate to the keying
    • Add the CA to the keyring
    • Give the mqweb userid access to the keyring.
    • Export the CA certificate, download it, distribute it to all users.  Import into their web browsers.
  • Trust keyring
    • Create a (shared) keyring
    • Get the CA from your users, upload to z/OS import them into the keyring
    • Give the server userids access to the keyring

Once you have been sucessfull with setting up the keyrings you will either be logged on on, or get a logon panel.

You now have to configure the environment to allow people to logon with the correct authorities.

Detailed steps.

I found it easiest to create JCL using batch TSO  with the various commands rather than use panels, or typing commands.  It means you can repeat the steps until they work.

//IBMRABB JOB 1,MSGCLASS=H 
//S1 EXEC PGM=IKJEFT01,REGION=0M 
//SYSPRINT DD SYSOUT=* 
//SYSTSPRT DD SYSOUT=* 
//SYSTSIN DD * 
  Put your commands here
  /* this (with a space in front) is ignored 
/* 

Configuration

  • The MQWEB server runs with userid START1
  • It will have a server key keyring called KEY
  • It will have a trust store keyring called TRUST
  • The IP address of the z/OS image is 10.1.1.2.   This is needed  when defining the server’s certificate because the clients compare this with web server’s location.  It can be IP(‘nn.nn.nn.nn’) or DOMAIN(‘ABC.COM’).

Create the CA

 /* Delete it in case it existed
RACDCERT CERTAUTH   DELETE(LABEL('TEMP-CA'))
 /* the CA needs size >= 2048 otherwise Chrome browser may ignore it
 /* The certificate shows up in browsers under org-TEST 
RACDCERT GENCERT  - 
  CERTAUTH - 
  SUBJECTSDN(CN('TEMPCertification Authority')- 
             O('TEMP') - 
             OU('TEST')) - 
  NOTAFTER(   DATE(2021-07-01  ) -   
  KEYUSAGE(HANDSHAKE,CERTSIGN,DOCSIGN,DATAENCRYPT          ) - 
  RSA SIZE(2048) - 
  WITHLABEL('TEMP-CA') 

RACDCERT CERTAUTH EXPORT(LABEL('TEMP-CA'))- 
       DSN('IBMUSER.CERT.TEMPCA.PEM') - 
       FORMAT(CERTB64) - 
       PASSWORD('password') 

You can now download the dataset IBMUSER.CERT.TEMPCA.PEM and import it into the browser’s keystore.

Create the server keyring

RACDCERT DELRING(KEY) ID(START1)
RACDCERT ADDRING(KEY) ID(START1)

Create the certificate to identify the server

This needs the ALTNAME so the browsers  accept the certificate

RACDCERT ID(START1) DELETE(LABEL('TEMP')) 
RACDCERT ID(START1) GENCERT - 
  SUBJECTSDN(CN('TEMP') - 
             O('TEMP') - 
             OU('TEST')) - 
   ALTNAME(IP(10.1.1.2)) - 
   SIGNWITH (CERTAUTH LABEL('TEMP-CA')) - 
   RSA SIZE(2048) 
   NOTAFTER(   DATE(2021-12-29))- 
   WITHLABEL('TEMP')
 /* KEYUSAGE is not needed 

RACDCERT ID(START1) ALTER(LABEL(‘TEMP’))TRUST

      
RACDCERT ID(START1) CONNECT(RING(KEY) LABEL('TEMP')) 
RACDCERT ID(START1) CONNECT(RING(KEY) - 
       LABEL('TEMP-CA') CERTAUTH) 
RACDCERT LIST(LABEL('TEMP-CA'             ))  CERTAUTH 
RACDCERT LIST(LABEL('TEMP'                ))  ID(START1) 
                                                                  
SETROPTS RACLIST(DIGTCERT,DIGTRING ) refresh                                                                

Give the servers userid access to the server’s keyring

See here.

RDEFINE RDATALIB START1.KEY.LST UACC(NONE)
 /* READ access enables retrieving one's own private key
 /* UPDATE access enables retrieving other's.
PERMIT START1.KEY.LST CLASS(RDATALIB) ID(START1 ) ACCESS(UPDATE)
PERMIT START1.KEY.LST CLASS(RDATALIB) ID(IBMUSER) ACCESS(UPDATE)

SETROPTS RACLIST(RDATALIB) REFRESH
RLIST FACILITY START1.KEY.LST

 

Upload the CA from the midrange machine and store in the key store.

The certificate ( .pem file) looks like

—–BEGIN CERTIFICATE—–

—–END CERTIFICATE—–

So should be uploaded as a source file.

RACDCERT CERTAUTH DELETE(LABEL('Linux-CA2')) 
RACDCERT SITE ADD('IBMUSER.CACERT.PEM') - 
    WITHLABEL('Linux-CA2') TRUST 
RACDCERT DELRING(TRUST) ID(START1) 
RACDCERT ADDRING(TRUST) ID(START1) 


RACDCERT ID(START1) CONNECT(RING(TRUST ) - 
       LABEL('Linux-CA2') SITE 

RACDCERT LISTRING(TRUST ) ID(START1) 
SETROPTS RACLIST(DIGTCERT,DIGTRING ) refresh

Of course you run this just once, and use the connect statement to add as many CAs as you have.

 

 

Using Elliptic Curves is better than RSA – but not as easy

I’ve spent a few days down some rabbit holes trying to solve a problem with an Elliptic Curve, and when I found the answer, I remember I had hit this problem before.

Using an Elliptic Curve generated with

RACDCERT ID( IZUSVR ) GENCERT + 
SUBJECTSDN(CN('CONN2') O('IBM') OU('C2PDFLT')) +
ALTNAME(IP(10.1.1.2))-
WITHLABEL('CONN2.IZUDFLT'), +
NISTECC +
SIZE(521) +

SIGNWITH(CERTAUTH LABEL('DOCZOSCAEC' )) NOTAFTER(DATE(2026/01/01))

I was getting in a Zowe trace

javax.net.ssl.SSLException: No supported CertificateVerify signature algorithm for EC key

This was with TLSv1.3.

In the TLS handshake from Chrome I could see

Supported Groups (5 groups)
Supported Group: Reserved (GREASE) (0x9a9a)
Supported Group: Unknown (0x11ec)
Supported Group: x25519 (0x001d)
Supported Group: secp256r1 (0x0017)
Supported Group: secp384r1 (0x0018)

I’m sure you spotted the problem immediately. The NISTECC SIZE(521) Elliptic Curve has a name of secp521r1, and this is not in the list. At the server, the logic checks that it’s certificate is supported by the groups sent from the client, and so reports

No supported CertificateVerify signature algorithm for EC key

I found Why is secp521r1 no longer supported in Chrome, others?. The article says that the keysize (256) is a strong as keysize(384) – so why bother with keysize(384).

I changed my certificate to keysize(256) and it worked.

Why didn’t my Elliptic Curve certificate work all the time?

I had created a certificate on z/OS, signed it with a CA, and it seemed that I could use in in some scenarios, but not when Java was involved. Sometimes when Java was involved, the Java program just hung!

The short answer.

After several weeks on and off, I found a reference saying an EC curve needs a CA which is also an EC. Having a EC certificate with an RSA certificate in the chain can cause problems!

I changed my CA, (and distributed it to all my clients) and it worked!

I also had to increase the length of the key…

The medium length answer

The definition which worked

RACDCERT ID( IZUSVR ) GENCERT + 
SUBJECTSDN(CN('CONN2') O('IBM') OU('C2PDFLT')) +
ALTNAME(IP(10.1.1.2))-
WITHLABEL('CONN2.IZUDFLT'), +
NISTECC SIZE(521) +
SIGNWITH(CERTAUTH LABEL('DOCZOSCAEC' )) NOTAFTER(DATE(2026/01/01))
RACDCERT ALTER(LABEL('CONN2.IZUDFLT')) ID(IZUSVR) TRUST

With a CA

RACDCERT GENCERT  -                                             
CERTAUTH -
SUBJECTSDN(CN('DocZosCAECC')-
O('ECC') -
OU('CA')) -
NOTAFTER( DATE(2027-07-02 ))-
KEYUSAGE( CERTSIGN ) -
NISTECC SIZE(521) -
WITHLABEL('DOCZOSCAEC')

The long and interesting answer

My debug trail was along the path of taking a System SSL trace, formatting it, and looking at the return code – to find a blog post I had written about the same return code.

With the chrome browser you can give a url chrome://net-export, and chrome will trace the flow.

You

  • start the trace
  • run the workload
  • stop the trace and save the file
  • use “The log file can be loaded using the netlog_viewer.” Click on the link.
  • drop your file onto the tools.
  • pick events
  • I found the last line of output to my server. It was like
  • Tick the box at the front of the line.

This gave me

2222: SOCKET
https://10.1.1.2:7557 <https://10.1.1.2 same_site>
Start Time: 2025-02-04 08:49:00.638

t=10890 [st= 0] +SOCKET_ALIVE [dt=128]
--> source_dependency = 2213 (SSL_CONNECT_JOB)
t=10890 [st= 0] +TCP_CONNECT [dt=8]
--> address_list = [
"10.1.1.2:7557"
]
--> aliases = []
t=10890 [st= 0] TCP_CONNECT_ATTEMPT [dt=8]
--> address = "10.1.1.2:7557"
t=10898 [st= 8] -TCP_CONNECT
--> local_address = "10.1.0.2:51284"
--> remote_address = "10.1.1.2:7557"
t=10898 [st= 8] +SSL_CONNECT [dt=119]
t=10900 [st= 10] SSL_HANDSHAKE_MESSAGE_SENT
...
t=11016 [st=126] SSL_HANDSHAKE_MESSAGE_RECEIVED
--> bytes =
... 1]T
--> type = 15
t=11016 [st=126] SSL_CERTIFICATES_RECEIVED
--> certificates =
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

t=11017 [st=127] SOCKET_BYTES_SENT
--> byte_count = 30
t=11017 [st=127] SSL_ALERT_SENT
--> bytes =
02 2F ./
t=11017 [st=127] SSL_HANDSHAKE_ERROR
--> error_lib = 16
--> error_reason = 245
--> file = "../../third_party/boringssl/src/ssl/extensions.cc"
--> line = 451
--> net_error = -107 (ERR_SSL_PROTOCOL_ERROR)
--> ssl_error = 1

This lead me to Feature: Deprecate TLS SHA-1 server signatures. This says Chrome is removing support for signature algorithms using SHA-1 for server signatures during the TLS handshake. This does not affect SHA-1 support in server certificates, which was already removed, or in client certificates, which continues to be supported.

This didn’t help me, but a link from a link from one hit mentioned the CA also needs to be an Elliptic Curve.

Setting up a JES2 output NJE TCPIP node as a client using AT-TLS

This is part of some work I did to configure AT-TLS for a JES2 TCPIP node to another system.

I didn’t have a remote system to connect to, but I had a Python TLS server which the NJE node could connect to (and then end), which demonstrated the TLS connection.

The JES2 definition

The address of the remote end, running the Python TLS server was 10.1.0.2.

$ADDSOCKET(LAPTOP),IPADDR=10.1.0.2,LINE=3,NETSRV=1,NODE=50,PORT=2175,SECURE=NO 

Starting the NJE node

$SN,SOCKET=LAPTOP

The AT-TLS definitions

This definition acts as a client to a remote server, so AT-TLS needs to be configured as a AT-TLS client.

TTLSRule CPJES2OUT 
{
RemoteAddr 10.1.0.2
RemotePortRange 2175
Direction Output
TTLSGroupAction
{
TTLSEnabled On
}
TTLSEnvironmentAction
{
HandshakeRole Client
TTLSEnvironmentAdvancedParms
{
# clientAuthType needs to be required or Passthru
ClientAuthType PassThru
TLSv1 Off
TLSv1.1 Off
TLSv1.2 On
# TLSv1.3 On
}
TTLSKeyringParms AZFKeyringParms
{
Keyring start1/TN3270
}

TTLSConnectionAction
{
TTLSCipherParmsRef AZFCipherParms
TTLSConnectionAdvancedParms
{
# ServerCertificateLabel is for a server connection
# ServerCertificateLabel RSA2048
CertificateLabel RSA2048
# ApplicationControlled OFF
}
}
}

AZFCipherParms

I put common definitions into their own section, for example

TTLSCipherParms AZFCipherParms 
{
V3CipherSuites TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
V3CipherSuites TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
V3CipherSuites TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
V3CipherSuites TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
V3CipherSuites TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
V3CipherSuites TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
V3CipherSuites TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
V3CipherSuites TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
# TLSv1.3
V3CipherSuites TLS_CHACHA20_POLY1305_SHA256
}

Using TLSv1.3

You need TTLSEnvironmentAdvancedParms to contain

TTLSEnvironmentAdvancedParms 
{
TLSv1.1 Off
TLSv1.2 On
TLSv1.3 On
}

and at least one TLSV1.3 cipher spec.

TTLSCipherParms AZFCipherParms 
{
# TLSv1.2
V3CipherSuites TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
V3CipherSuites TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
V3CipherSuites TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
V3CipherSuites TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
V3CipherSuites TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
V3CipherSuites TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
V3CipherSuites TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
# TLSv1.3
V3CipherSuites TLS_CHACHA20_POLY1305_SHA256
# TLSv1.2
V3CipherSuites4Char TLS_CHACHA20_POLY1305_SHA256
V3CipherSuites4Char TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
V3CipherSuites4Char TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
V3CipherSuites4Char TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 C02
}

such as TLS_CHACHA20_POLY1305_SHA256

See Cipher suite definitions and search for 1301 (TLS_AES_128_GCM_SHA256) ,1302 (TLS_AES_256_GCM_SHA384) ,1303(TLS_CHACHA20_POLY1305_SHA256).
There is a column called TLSv1.3 (but it is hard to find). There are two tables, you need to use the second table to find what version of TLS the cipher specs provide.

Python server

The code below acted as a remote TLS server for the handshake.

import socket
import ssl
import struct
import pprint

HOST= ''
PORT = 2175

cafile="/home/colinpaice/ssl/ssl2/jun24/docca256.pem"
certfile="/home/colinpaice/ssl/ssl2/jun24/docec521june.pem"
keyfile="/home/colinpaice/ssl/ssl2/jun24/docec521june.key.pem"
certpassword = None

context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.minimum_version = ssl.TLSVersion.TLSv1_2
context.maximum_version = ssl.TLSVersion.TLSv1_3
context.load_cert_chain(certfile, keyfile)
context.load_verify_locations(cafile=cafile)

context.verify_mode = ssl. CERT_REQUIRED
getciphers = context.get_ciphers()
#for gc in getciphers:
# print("get cipher",gc)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:
sock.bind((HOST, PORT))
sock.listen(1)
with context.wrap_socket(sock, server_side=True) as ssock:
conn, addr = ssock.accept()
cert = conn.getpeercert()
pprint.pprint(cert)
v = conn.version()
print("version",v)
c = conn.cipher()
print("ciphers",c)
sock.close

When this ran, and the z/OS NJE node connected to it ($SN,SOCKET=LAPTOP), the output was

{'issuer': ((('organizationName', 'COLIN'),),
(('organizationalUnitName', 'CA'),),
(('commonName', 'DocZosCA'),)),
'notAfter': 'Jun 17 23:59:59 2025 GMT',
'notBefore': 'Jun 17 00:00:00 2024 GMT',
'serialNumber': '07',
'subject': ((('organizationName', 'RSA2048'),),
(('organizationalUnitName', 'SSS'),),
(('commonName', '10.1.1.2'),)),
'subjectAltName': (('IP Address', '10.1.1.2'),),
'version': 3}
version TLSv1.3
ciphers ('TLS_CHACHA20_POLY1305_SHA256', 'TLSv1.3', 256)

Showing the certificate, the level of TLS and the cipher spec used.

The messages on the z/OS console were

$SN,SOCKET=LAPTOP                                                        
$HASP000 OK
IAZ0543I NETSRV1 TCP/IP connection with IP Addr: 10.1.0.2 Port: 2175
Initiated
IAZ0543I NETSRV1 TCP/IP connection with IP Addr: 10.1.0.2 Port: 2175
Successful
IAZ0543I NETSRV1 TCP/IP connection with IP Addr: ::ffff:10.1.0.2 Port:
2175 ended due to TCP/IP error, rc: 1121

Understanding a Wireshark TLS handshake trace

I’ve done a lot of work using TLS, and Wireshark is a great tool for displaying the flows of data. The problem is understanding what the output shows! This blog post shows what to look at.

Note: Flows with GREASE values should be ignored. This is designed to make sure the remote end can handle unexpected values, by sending up unsupported values.

Summary of the flows of the handshake

See here for an overview.

  • Client to Server: Client Hello
  • Server to Client: Server Hello, Certificate, Server Key Exchange, Certificate Request, Server Hello Done
  • Client to Server: Certificate, Client Key Exchange, Certificate Verify, Change Cipher Spec, Finished
  • Server to Client: Change Cipher Spec
  • Server to Client: Finished

Client to Server: Client Hello

This displays

Transport Layer Security
    TLSv1.2 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Version: TLS 1.2 (0x0303)
            Random: c5ec1cf320f2f77ba6f3f84e7fd7d1f946400484a56918a5e499b0e98be2a07f
            Session ID Length: 32
            Session ID: a839f3fcd1d7f4394c6e5bd0279da5c75458b8a81f35c5890107007cc921fa7b
            Cipher Suites Length: 32
            ▶Cipher Suites (16 suites)
            Compression Methods Length: 1
            ▶Compression Methods (1 method)j             
            Extensions Length: 429
            ▶Extension: signature_algorithms 
            Extension: Reserved (GREASE) (len=0)
            ▶Extension: supported_versions (len=7)
            ...

If you expand supported versions you get

 Extension: supported_versions (len=7)
       ...
       Supported Version: TLS 1.3 (0x0304)
       Supported Version: TLS 1.2 (0x0303)

Which shows you the TLS versions that the client supports.

If you expand Cipher Specs you get

Cipher Suites (16 suites)
   Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
   Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302)
   Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303)
   Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
   Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
   ...		        

This is the list of cipher specs in preference order, that the client supports.

The signature_algorithms defines which signature and hash algorithms are supported for the server’s digital certificate.

Server to Client: Server Hello, Certificate, Server Key Exchange, Certificate Request, Server Hello Done

The server sends down several blocks of data. These are logically distinct blocks of data – but tend to arrive in one block.

  • Server Hello, Here are some parameters for the handshake
  • Certificate, Here is my certificate(s)
  • Server Key Exchange,
  • Certificate Request, Please send me a certificate matching the enclosed parameters
  • Server Hello Done

Server to Client: Server Hello

Handshake Protocol: Server Hello
  Handshake Type: Server Hello (2)
  Version: TLS 1.2 (0x0303)
  Random: ...
  Session ID Length: 32
  Session ID: ...
  Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
  ...  

It shows which version of TLS has been picked.

The Cipher Suite is the value picked by the server.

Server to Client: Certificate

This is present if the server is configured to send down the server’s certificate.

Handshake Protocol: Certificate
  Handshake Type: Certificate (11)
     ...
     Certificates Length: 1608
       Certificates (1608 bytes)
          Certificate Length: 734
          ▼Certificate: .. (commonName=10.1.1.2,...organizationName=NISTECCTEST)
             ▶signedCertificate
                serialNumber: 0x7a
                ▶signature (sha256WithRSAEncryption)
                ▶issuer: ...
                ▶validity ...
                ▼subject: rdnSequence (0)
                   RDNSequence (organizationName=NISTECCTEST)
                   RDNSequence (organizationalUnitName=SSS)
                   RDNSequence (commonName=10.1.1.2)
                ▶subjectPublicKeyInfo
                ▶extensions: 5 items
                algorithmIdentifier (sha256WithRSAEncryption)
                    ...
          Certificate Length: 868
          ▶Certificate:  ...

From this we can see the certificates sent down from the server.

  • The certificate name is specified at many levels; including on the Certificate and subject.
  • The CA (issuer) which signed each certificate.
  • The validity dates of the certificate
  • The extensions, which include how the certificate can be used; key usage, Subject Alternative Name ( IP address) etc.

Check this is what you are expecting, and that the CA is in your trust store.

Server to Client: Server Key Exchange

I have never used the information in this area

Server to Client: Certificate Request

Handshake Protocol: Certificate Request
   Certificate types count: 3
      ▼Certificate types (3 types)
         Certificate type: RSA Sign (1)
         Certificate type: ECDSA Sign (64)
         Certificate type: DSS Sign (2)
      ▼Signature Hash Algorithms Length: 26
         Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
         Signature Algorithm: ecdsa_secp521r1_sha512 (0x0603)
         ... 
      ▼Distinguished Names Length: 246
         Distinguished Names (246 bytes)
             Distinguished Name: (commonName=COLIN4Certification Authority,...)
             Distinguished Name: (commonName=DocZosCA,...)
             Distinguished Name: (commonName=SSCA256...)

This is saying please send me a certificate:

  • The certificate must be one of certificate-type elements; RSA, ECDSA or DSS,
  • and signed by one of the algorithms listed,
  • and have a CA signer of COLIN4Certification Authority…, DocZosCA… or SSCA256… .

The CA signers are taken from the server’s trust store.

Server to Client: Server Hello Done

That’s the server side of the work done… almost

Client to Server: Certificate, Client Key Exchange, Certificate Verify, Change Cipher Spec, Finished

Client to Server: Certificate

The client needs to pick a certificate from those in its key store. Depending on the application

  • a browser may display a list of valid certificates for the end user to select
  • a program may use the information sent down in the handshake to pick the best certificate
  • a program may return what the configuration specified (such as default)
  • a program may just return the first certificate in the key file.
Handshake Protocol: Certificate
   Handshake Type: Certificate (11)
   Certificates Length: 683
   ▼Certificates (683 bytes)
     Certificate Length: 680
     ▼Certificate: … (commonName=docec384,...countryName=GB)
       ▼signedCertificate
          serialNumber: 0x029b
          ▶signature (ecdsa-with-SHA384)
          ▼issuer: rdnSequence (0)
          ▶rdnSequence: 4 items (commonName=SSCA256,OU=CA,iO=DOC,C=GB)
            ....
          ▶validity...
          ▼subject: rdnSequence (0)
              ▶RDNSequence item: 1 item (countryName=GB)
              ▶RDNSequence item: 1 item (organizationName=Doc2)
              ▶RDNSequence item: 1 item (commonName=docec384)
          ▶subjectPublicKeyInfo
          ▶extensions: 6 items...
          algorithmIdentifier (ecdsa-with-SHA384)
          ...

We can see

  • the algorithm identifier is ecdsa-with-SHA384 which is OK
  • the issuer is CN=SSA256,ou=CA,C=GB which is in the list of CAs passed from the server.
  • the signature is ecdsa – which is OK

Client to Server: Client Key Exchange

I haven’t used this. If the handshake gets this far, the set-up is good.

Client to Server: Certificate Verify

I have never used this. It is used to send up some data encrypted with the client’s private key, to check the server can decrypt it.

Client to Server: Change Cipher Spec

Response to the server. I have never used this. Business as usual, it periodically changes the Cipher Spec

Finished

Server to Client: Change Cipher Spec

Each direction has its own cipher spec. This is the server saying to the client … ok… I’m using the new cipher spec.

Server to Client: Finished

The final – final completion.

Problems

When an invalid CA was used at the client end, the server sent down

Transport Layer Security
    TLSv1.2 Record Layer: Alert (Level: Fatal, Description: Unknown CA)
        Content Type: Alert (21)
        Version: TLS 1.2 (0x0303)
        Alert Message
            Level: Fatal (2)
            Description: Unknown CA (48)

This has a list of the codes and their meaning.

Configuring RSEAPI on z/OS to use TLS

The RSEAPI server is the Apache Tomcat server plus RSEAPI specific stuff. If you know how to configure Tomcat, you know most of what you need. The Tomcat customising is documented here.

This post follows on from Getting REST to work into z/OS. I was unclear at first how to correctly specify overrides. I’ve blogged an article Passing parameters to Java program to show how some parameters are specified as RSEAPI_KEYSTORE_FILE=… and other parameters are specified as -Djava.protocol.handler.pkgs=…

See Java Parameters for how I configured RSEAPI to be able to flip configuration options.

Update your level of Java

I had various problems getting TLS to work with RSEAPI.

  • TLSv1.3 was not supported on the level of Java V8 I originally had.
  • I had to override the /etc/zexpl/java.security file so that it understood keyrings of the format safkeyring://START1/MQRING

When I refreshed the level of Java (to SR8 FP6 dated June 2023), things worked much better. I would recommend getting a level of Java shipped within the last year.

I tested this by changing rseapi.env to include

export JAVA_HOME="/usr/lpp/java/new/J8.0_64" 
export LIBPATH="$JAVA_HOME/bin:$JAVA_HOME/bin/classic:"$LIBPATH 
export PATH="$JAVA_HOME/bin:"$PATH 

Without this I got various Java problems, such as an unresolved dependency.

Getting RSE to work with TLS was not trivial

The original version of RSEAPI was v1.0.5 (see /usr/lpp/IBM/rseapi/tomcat.base/bin/current_version.txt) Another version is available in GITHUB with a version of v1.1.0 created 7 July 2022 which I worked with.

TLS configuration changes

RSEAPI supports only one port. To use TLS change the procedure to use SECURE=’true’, (or override it at startup).

The RESAPI proc has the location of the configuration files. Mine says /etc/zexpl.

The main file to edit is /etc/zexpl/rseapi.env . The sample has a lot of commented out statements. I added at the bottom

RSEAPI_KEYSTORE_FILE="safkeyring://START1/MQRING " 
RSEAPI_KEYSTORE_TYPE="JCERACFKS" 
RSEAPI_KEYSTORE_PASS="password" 
RSEAPI_USING_ATTLS=false 
RSEAPI_SSL_ENABLED_PROTOCOLS=TLSv1.2

Which server certificate to use?

By default, the first key read from the keystore will be used. See certificateKeyAlias in Apache Tomcat configuration.

To change this I edited /usr/lpp/IBM/rseapi/tomcat.base/conf/sserver.xml and added

 <Connector port="${port.http}" protocol="${http.protocol}" 
   certificateKeyAlias="${serverCert}" 
   ...
/> 

I then edited /etc/zexpl/rseapi.env and added

d3=" -DserverCert=NISTECCTEST" 
JAVA_OPTS="$d3 " 
CATALINA_OPTS=$JAVA_OPTS 
export JAVA_OPTS 
export CATALINA_OPTS 

Using TLSv1.3

I blogged configuring Java to support TLSV1.3 a separate post TLS 1.3, Java and z/OS.

The additional RSEAPI specific configuration was

RSEAPI_HTTP_PROTOCOL=HTTP/1.1 
RSEAPI_SSL_ENABLED_PROTOCOLS=TLSv1.3 
RSEAPI_SSL_CIPHERS=TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA_POLY1305_SHA256 
RSEAPI_KEYSTORE_FILE="safkeyring://START1/MQRING " 
RSEAPI_KEYSTORE_TYPE="JCERACFKS" 
RSEAPI_KEYSTORE_PASS="password" 
RSEAPI_USING_ATTLS=false 

You can use RSEAPI_SSL_ENABLED_PROTOCOLS=TLSv1.3,TLSV1.2 to get both TLS 1.2 and 1.3 support.

ClientAuth Support

The web browser (Tomcat) has support for requiring clients to specify a certificate as part of the TLS handshake.

I got this to work by editing /usr/lpp/IBM/rseapi/tomcat.base/conf/sserver.xml, and changing clientAuth=”false” to clientAuth=”{$clientAuth}”

<Connector port="${port.http}" protocol="${http.protocol}" 
     clientAuth="${clientAuth}" sslProtocol="TLS" 
...
>

and setting the value to “required” or specifying the value in the startup options:

d1="-DclientAuth=required"
t1=" -Djavax.net.ssl.trustStoreType=JCERACFKS" 
t2=" -Djavax.net.ssl.trustStore=safkeyring://START1/MQRING"
JAVA_OPTS=" $d1 $t1 $t2" 
CATALINA_OPTS=$JAVA_OPTS  
export JAVA_OPTS 
export CATALINA_OPTS 

The …trustStoreType and … trustStore provide the defaults if non are specified in the sserver.xml.

Use of keystore and trust store

The use of a trust store to store the CA certificates, and any self signed certificates is recommended. The keystore then contains just the private keys needed by the server. This means you can have one trust store per LPAR, which saves administratio.

If you use a combined trust key and trust store, and this is shared by applications, then applications may get access to private certificates used by other application, so is not as secure.

The tomcat documentation describes the truststore* parameters. These are in the in <Connector…. within file /usr/lpp/IBM/rseapi/tomcat.base/conf/sserver.xml .

For example

<SSLHostConfig 
       protocols="${ssl.enabled.protocols}"> 
       <Certificate type="EC" 
          certificateKeyAlias="NISTECCTEST" 
          certificateKeystoreFile="${keystoreFile}" 
          certificateKeystorePassword="${keystorePass}" 
          truststoreType="${trustStoreType}"                     
          truststoreFile="${trustStoreFile}"
          truststorePassword="${trustStorePass}"
      /> 
</SSLHostConfig>

and specify -Dxx where xx is the value in ${xx} such as -DtrustStoreType=”JCERACFKS” . You can hard code the values.

Setup problems

I had a variety of problems. Most were solved by going to a newer level of Java or RSEAPI. For example earlier versions did not support TLSv1.3

Authority issue

I got the message

Caused by: java.lang.IllegalArgumentException: The private key of NEWTECCTEST is not available or no authority to access the private key

This was caused by the certificate belonged to a userid START1, but I was running RSEAPI on userid STCRSE. For userid STCRSE to be able to access the private certificate part of the certificate of another userid’s certificate, the STCRSE userid need UPDATE access to the keyring profile.

My keyring was safkeyring://START1/MQRING. I needed

permit START1.MQRING.LST   class(RDATALIB) access(update) id(STCRSE)
setropts raclist(rdatalib) refresh

TLS 1.3, Java and z/OS

I was failing to get this working with Java 8 – despite it being supported in Java 8.

I eventually found a support statement which says

Enables TLS v1.3 protocol (defined by RFC 8446) in SR6 FP25

however java -version gave me

Java -version gives build 8.0.6.16 – pmz6480sr6fp16-20200902_01(SR6 FP16))

I had Fix Pack 16 and the support is in Fix Pack 25 (from 2020)

Download a more up to date version

The IBM Support page Java SDK Products on z/OS lists the supported version of Java. There is a link to IBM Semeru Runtime Certified Edition for z/OS (Semeru is free production-ready binaries built with the OpenJDK class libraries and the Eclipse OpenJ9 JVM).

When I tried to download V8 SR8, I got a window saying “You cannot download this due to export restrictions”. Next day, I tried again and it worked, the droids working in the background much have found I was a good guy.

Check your java.security file

When I used my own copy of the java.security file it did not work.

I had

security.provider.1=com.ibm.crypto.provider.IBMJCE 
security.provider.2=com.ibm.crypto.plus.provider.IBMJCEPlus 

The latest fix pack Java had

security.provider.1=com.ibm.jsse2.IBMJSSEProvider2 
security.provider.2=com.ibm.crypto.provider.IBMJCE 
security.provider.3=com.ibm.crypto.plus.provider.IBMJCEPlus 

The error messages I got were

SEVERE org.apache.catalina.util.LifecycleBase.handleSubClassException
Failed to initialize component Connector HTTP/1.1-6800

org.apache.catalina.LifecycleException: Protocol handler initialization failed Caused by: java.lang.IllegalArgumentException: None of the protocols specified are supported by the SSL engine : TLSv1.3

As the support for TLSv1.3 was in JSSE, it is clear (with hindsight) that I needed to specific the provider com.ibm.jsse2.IBMJSSEProvider2!

Some implementations of TLS are good, some are not so good.

Ive been struggling to get an application running on z/OS to use TLS with certificate authentication.

Now it is working, I despair at how the TLS has been implemented, and it feels that the development did not understand how the product would be used; or may be TLS has moved on since the product was initially written. Java on the other hand seems to have all the facilities for a good implementation, but they are not always used, resulting in a poor end user experience. It feels that the designers only expected one, or only a few users.

Experience shows…

The first time you do a journey, you are pleased if you get to the destination with no major problems. Once you have done the journey a couple of times you know the best options and what to avoid. For example when your plane arrives at an airport, and there is shuttle train to get you to the main terminal and immigration, if the escalator at the main terminal is near the front of the train – then get on at the front of the train, and you will be ahead of the hundreds of people from the train.

I learned when in a performance role, that it takes three attempts to write a performance report. After the first attempt you understand the real question you should be asking. The second attempt you get answers to these questions. The third attempt you try to add value and explanation. Many a time I’ve looked at someone else’s performance report and asked myself “what does this mean, how do I use this information?”. I spent a week doing some tests, and the outcome was a sentence “This performance tuning option has very little effect. Just leave it as the default”. This is so much more useful than a chart showing a flat line.

In the same way, a developer designing a program which uses TLS may be very happy having got one client to talk to the server using TLS. You need the experience to understand that there are different certificate types (Elliptic Curve, RSA), and different key sizes. It is easier to administer the CA certificates, if you have one enterprise wide keyring for them, and every one uses the same keyring; rather than one keyring for each server instance.

Where are certificate stored?

There can be two types of store for certificates:

  • Keystore – this contains the certificates each with its private key. Each group of servers may have its own keystore, with just the private keys it needs. So one key store for production CICS regions, one for test CICS regions, another key store for internal web servers.
  • Trust store. This contains the public keys of Certificate Authority certificate authorities, and any self-signed certificate from clients. The trust store is used to validate certificates which have been sent to the application. You could have one trust store for the whole LPAR, and every one uses it.

In many TLS implementations only one store is used, called the keystore, and has both the Key store and Trust store keys in it. This is easy to implement, but not a good design.

High level overview of the TLS handshake

The handshake

  • The client initiates the handshake, passing up information like I understand the following cipher specs…; I understand certificates created using Elliptic Curves (or RSA) (or both).
  • The server responds with ,
    • use this cipher spec…,
    • optionally (usually) here is my certificate which matches your criteria (Elliptic Curve or RSA)
    • optionally – please send your certificate which matches these criteria… here are the CA’s I know about
  • The client checks the server’s certificate is valid either because the certificate is in the trust store , or the certificate for the Certificate Authority is in the trust store, and can be used to validate the certificate.
  • If asked, the client picks a certificate from the key store and sends it. It should pick a certificate with a CA from the list which was sent down.
  • The server checks the client’s certificate is valid either because the certificate is in the trust store or the certificate for the Certificate Authority is in the trust store which validates the certificate.

Which certificate does the server send?

There are several implementations used in different products:

  • Take the first valid certificate in the ring. Easy to code, but causes problems. If I replace the certificate, by removing and readding it, then a different certificate may be used, as what was the second certificate in the keyring, will now be the first in the keyring, and this will be used instead. This may have a different type of certificate (Elliptic Curve or RSA), and clients may then fail to connect.
    • If the certificate has expired it will not be used, even though it looks the first.
  • Specify the default. There is one default. If you remove and add a certificate you can specify which certificate becomes the default. Not all clients may like the certificate type, so you may have to change the client certificate to match.
  • Pick the best option. Java has an function which says give me the list of certificate in the keyring which match the following, this might be EC or RSA or some other option. With this, different clients can get a different server certificate.

You could have one keystore for all your servers, or a keystore for CICS, and other for a Liberty web server, another for MQ web server.

I think that the keystore should contain only the keys for the certificates it needs to use. Do not have the CICS, Liberty, MQ certificate all in the same keystore if the certificates are all different. It would allow CICS to use the MQ certificate.

For added security certificates can have the name of the server, or the IP address of the server, and the client can check it matches the server’s host. You might not want to share a keyring between different z/OS images, because they may have a different IP address.

Client – picking the private certificate from the keystore

What should I use for my trust store?

The trust store has the certificates for all CAs you expect to use. If you start working with a different company you might need to add their CA to your trust store.
If you have one trust store for all users across the z/OS image, you add the certificate to it, and every one has access to it – easy.

If you have multiple trust stores, you’ll need to add the certificate to all the trust stores that need it. This may be a small number, for example, production and test.

If you use your keystore as a trust store then you will have to add the new CA to every trust store.

As certificate expire you will need to replace them. The amount of work depends on how many stores you have to update. Having one trust store makes this easier.

Why have I told you this?

I had a client server working using the DEFAULT certificate on z/OS. I wanted to use this keyring for a different application, which used the FIRST certificate in the keyring. This was a special-case certificate, and not to be used by most clients. I had to remove and re-add certificates in the keyring so the default certificate became the first certificate. It took over a day to identify the problem and fix it!

How to accept a certificate if I do not have their CA?

Someone contacted me saying that they had a z/OS application which was trying to access a remote server using TLS, but the connection was failing because the incoming certificate could not be validated.

Or or to put it another way, a certificate and its CA arrived at my system; how do I get the CA into my keyring to allow validation.

One way of getting the certificate is to use a browser. I used chrome.

  • enter the URL and press enter. It should display a page with a padlock at the front of the URL
  • click on this padlock
  • it should say “connection is secure”
  • click on “certificate is valid”, it displays certificate information
  • click on details. It should list the certificate and any CA certificates
  • click on the CA of interest
  • click Export and save the file (as base 64 encoded ASCII)
  • this will create a file containing —–BEGIN CERTIFICATE—– … —–END CERTIFICATE—–
  • check that this CA certificate is valid, and does not belong to a bad guy
  • upload this to a sequential file on z/OS
  • “check” it
//COLRACFI JOB 1,MSGCLASS=H 
//S1  EXEC PGM=IKJEFT01,REGION=0M 
//SYSPRINT DD SYSOUT=* 
//SYSTSPRT DD SYSOUT=* 
//SYSTSIN DD * 
RACDCERT CHECKCERT('COLIN.IMPORT.CA.PEM') 
  • Add it to RACF database
RACDCERT CERTAUTH     ADD(''COLIN.IMPORT.CA.PEM') - 
  WITHLABEL('MYBANK.CA') TRUST 
  • connect it to the keyring, CICSID/CICSRING
RACDCERT   CONNECT(CERTAUTH    LABEL('MYBANK.CA') - 
  RING(CICSRING) USAGE(CERTAUTH)) ID(CICSID)