Several times I have had to set up certificates between Linux and z/OS and struggled for a day to get them working. Once you are familiar with doing it – it is easy. As the last time I needed to do this was over a year ago, I’ve forgotten some of the details. This blog post is to help me remember what I need to do, and to help other who struggle with this.
I’m ignoring self signed.
Basic TLS
A certificate contains
- who it belongs to, such as CN=COLIN,O=SSS
- the date range the certificate is valid
- a public key
- meta data about the key: What algorithm does the public key use, what parameters were used in the key generation, for example, algorithm=RSA, Keysize=2048.
There is a private key.
- If you encrypt using the private key, you can use the public key to decrypt it.
- If you encrypt using the public key, you can use the private key to decrypt it.
- If you encrypt something with my public key, and then encrypt it with your private key. I know it came from you (or someone with your private key) and only I (or someone with my private key) can decrypt it.
Anyone can have the public key. You keep the private key secure.
Certificate Authority. This is used in validating the trust of certificates. You send your certificate to the CA, The CA does a checksum of your data, and encrypts this checksum with the CA private key. It returns your original data appended with the encrypted checksum, and information about the CA, and what was used to calculate the checksum. If someone else has the CA public key, they can do the opposite process. Do the checksum calculation, and decrypt the checksum value in the certificate, using the CA public key. If they match you know it was signed by the CA. This is known as signing the certificate.
To be able to validate a certificate sent to it, the client end needs the CA of the server end. The server needs the CA of the client end to be able to validate the client’s certificate.
During the handshake to establish the TLS connection there is a flow like
- Establish the cipher spec to use
- Server sends down its certificate, the client checks it
- Servers sends down “Certificate request”, and these are the certificate(CAs) I know about
- The client goes through it’s list of certificates (usually only one), to find the first certificate with a CA in the list sent from the server.
- sends the client certificate to the server
- The server checks the certificate. For example the server may be set up to accept a subset of valid algorithms, for example TLS 1.2, and Elliptic Curve. If a certificate is sent up using RSA, then this is not accepted
- The server checks the signature of the certificate, finds the CA name, checks in the trust store for this CA, and validates the signature. Depending on the application it may check all the CA’s in the CA chain.
What do you need for the handshake to work
- You need to have a Certificate Authority to sign certificates. In the CA certificate are some flags that say this is a CA.
- You need to send the public key of each CA to the other end. You normally need to do this just once, and keep using the same certificates for all your TLS work.
- You need to have a key store/trust store/keyring to hold certificates.
- On z/OS
- you may have a keyring for different projects, for example MQ, and TN3270.
- You need to connect the client CA into each keyring where it will be used.
- You need to check that the certificates are compatible with the remote end, such as Algorithm etc.
Openssl files
When using openssl, you can store common information in a configuration file. See here. This configuration file has some required options, and some optional options where you can specify common options you frequently use.
If you are using the openssl req command (for example), by default it will look for a section called [req]. This can in turn point to other sections. Using this file you can specify most of your fields in one place, and just override the specific ones.
Create a CA certificate on Linux
I have a bash file docca.sh file on Linux.
CA=”docca256″
casubj=” -subj /C=GB/O=DOC/OU=CA/CN=SSCA256″
days=”-days 1095″
rm $CA.pem $CA.key.pemopenssl ecparam -name prime256v1 -genkey -noout -out $CA.key.pem1
openssl req -x509 -sha384 -config caca.config -key $CA.key.pem2 -keyform pem -nodes $casubj -out $CA.pem3 -outform PEM $days
openssl x509 -in $CA.pem -text -noout|less4
This
- creates a private key (docca256.key.pem)
- self signs it. For any parameters not specified, it uses the configuration file caca.config and section “req” (signing request) within it.
- produces a public certificate in docca256.pem. This file will need to be sent to the backend servers. You can use cut and paste or FTP as ASCII.
- displays the x509 data
The caca.config file has
[ req ]
distinguished_name = ca_distinguished_name
x509_extensions = ca_extensionsprompt = no
authorityKeyIdentifier = keyid:always,issuer:always
[ca_distinguished_name ]
# C=GB
# O=DOC
# OU=Stromness
# CN=SSSCA4####################################
[ ca_extensions ]subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:TRUE, pathlen:0
keyUsage = keyCertSign, digitalSignature,cRLSign
The distinguished_name = ca_distinguished_name says go and look in the file for a section [ca_distinguished_name], and x509_extensions = ca_extensions says go and look for a section called [ca_extensions]. You can specify your own names, for example I could have used section1, and s2.
When prompt = yes, openssl takes as defaults the values in the distinguished_name section. When prompt = no, the distinguished_name is still required – but the contents of the section are ignored.
The values in the x509_extensions are defined here.
Creating an Elliptic Curve certificate on Linux
I used another bash script docecadad.sh, to document an ElliptiCal certificate for userid ADCD. It uses the CA defined above.
name="docecadcd" key="$name.key.pem" cert="$name.pem" subj="-subj /C=GB/O=Doc/CN="$name CA="docca256" cafiles="-cert $CA.pem -keyfile $CA.key.pem " enddate="-enddate 20240130164600Z" passin="-passin file:password.file" passout="-passout file:password.file" rm $name.key.pem rm $name.csr rm $name.pem #define a certificate with elliptic key with size 256 openssl ecparam -name prime256v1 -genkey -noout -out $name.key.pem #create a certificate request (ie hello CA please sign this) openssl req -config openssl.config -new -key $key -out $name.csr -outform PEM -$subj $passin $passout # sign it. caconfig="-config ca2.config" policy="-policy signing_policy" extensions="-extensions clientServer" md="-md sha384" openssl ca $caconfig $policy $md $cafiles -out $cert -in $name.csr $enddate $extensions # display it openssl x509 -in $name.pem -text -noout|less
Where the openssl.config file has
[ req ] default_bits = 2048 distinguished_name = server_distinguished_name req_extensions = server_req_extensions string_mask = utf8only subjectKeyIdentifier = hash #extendedKeyUsage = critical, codeSigning [ server_req_extensions ] subjectKeyIdentifier = hash # subjectAltName = DNS:localhost, IP:127.0.0.1, IP:127.0.0.6 # nsComment = "OpenSSL" keyUsage = critical, nonRepudiation, digitalSignature # extendedKeyUsage = critical, OCSPSigning, codeSigning subjectKeyIdentifier = hash [ server_distinguished_name ] #c=GB #o=SSS #cn=mqweb
- See above for the distinguished_name value.
- req_extensions says use the section [server_req_extensions]
The ca2.config file used to sign it has
HOME = . RANDFILE = $ENV::HOME/.rnd #################################################################### [ ca ] default_ca = CA_default # The default ca section #################################################################### [ CA_default ] default_days = 1000 # How long to certify for default_crl_days = 30 # How long before next CRL #default_md = sha1 # Use public key default MD default_md = sha256 # Use public key default MD preserve = no # Keep passed DN ordering x509_extensions = ca_extensions # The extensions to add to the cert email_in_dn = no # Don't concat the email in the DN copy_extensions = copy # Required to copy SANs from CSR to cert #defaults base_dir = . certificate = $base_dir/cacert.pem # The CA certifcate private_key = $base_dir/cakey.pem # The CA private key new_certs_dir = $base_dir # Location for new certs after signing database = $base_dir/index.txt # Database index file serial = $base_dir/serial.txt # The current serial number unique_subject = no # Set to 'no' to allow creation of # several certificates with same subject. #################################################################### [ ca_extensions ] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always, issuer:always basicConstraints = critical,CA:TRUE, pathlen:0 keyUsage = nonRepudiation #################################################################### [ signing_policy ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied [ clientServer ] keyUsage = digitalSignature, keyAgreement, digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment subjectAltName = DNS:localhost, IP:127.0.0.1, extendedKeyUsage = serverAuth,clientAuth subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always, issuer:always nsComment = "clientserver"
The policy (my [ signing_policy] ) must have entries in it to create a valid Subject Distinguished name. Without it, I got a strange RACF code (0x0be8044d).
Send the CA to z/OS and import it
You need to send the CA public certificate to z/OS. This file looks like
-----BEGIN CERTIFICATE----- MIIFbTCCA1WgAwIBAgIUJw+gLLSFxqCyTdIyEUWyQ/g9JnEwDQYJKoZIhvcNAQEL. ... -----END CERTIFICATE-----
You can FTP the file, or create the file and use cut and paste. The file needs to be a sequential dataset with format VB. My file is VB, lrecl=256,blksize=6233. For the FTP I used
put docca256.pem ‘colin.docca256.pem’
You need to import this into RACF, and connect it to the keyrings.
//IBMRACF JOB 1,MSGCLASS=H //S1 EXEC PGM=IKJEFT01,REGION=0M //SYSPRINT DD SYSOUT=* //SYSTSPRT DD SYSOUT=* //SYSTSIN DD * RACDCERT CHECKCERT('COLIN.DOCCA256.PEM') /*
The CHECKCERT gave me
Certificate 1: Start Date: 2022/10/09 11:45:43 End Date: 2025/10/08 11:45:43 Serial Number: >782A62948699FF3FB00238FB296E4A647B7DF07C< Issuer's Name: >CN=SSCA256.OU=CA.O=DOC.C=GB< Subject's Name: >CN=SSCA256.OU=CA.O=DOC.C=GB< Signing Algorithm: sha384ECDSA Key Usage: HANDSHAKE, CERTSIGN Key Type: NIST ECC Key Size: 256
Which matches what I expected, and gave me information about the certificate – ECC, 256, and signed with SHA 384 ECDSA, (from the -sha384 parameter above).
Define it to RACF and connect it to the user’s keyring
racdcert list (label('Linux-CA256')) CERTAUTh RACDCERT DELETE (LABEL('LINUXDOCCA256')) CERTAUTH RACDCERT ADD('COLIN.DOCCA256.PEM') - CERTAUTH WITHLABEL('LINUXDOCA256') TRUST RACDCERT ID(START1) CONNECT(RING(MQRING)- CERTAUTH - LABEL('LINUXDOCCA256'))
If you delete a certificate, then it is removed from all keyrings. Once you have re-added it you need to reconnect it to all the keyrings. If you list the label (racdcert list (label(‘Linux-CA256’)) certauth) it will display where it is used, so you can read it.
Download the z/OS CA certificate
I downloaded the z/OS exported certificate in .pem format. it looks like
-----BEGIN CERTIFICATE----- MIIDYDCCAkigAwIBAgIBADANBgkqhkiG9w0BAQsFADAwMQ4wDAYDVQQKEwVDT0xJ ... +9TRng== -----END CERTIFICATE-----
You can use ftp or cut and paste. I created doczosca.pem.
Use it!
Before I could use it, I had to set up the server’s certificate, and download the z/OS CA certificate
I set up a bash script scl2.sh
name=docecadcd host="-connect 10.1.1.2:4000" CA="--CAfile doczosca.pem " openssl s_client $host $CA -cert $name.pem -certform PEM -key $name.key.pem -keyform PEM