Setting up Linux to z/OS certificates

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.pem

openssl 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

  1. creates a private key (docca256.key.pem)
  2. self signs it. For any parameters not specified, it uses the configuration file caca.config and section “req” (signing request) within it.
  3. 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.
  4. displays the x509 data

The caca.config file has

[ req ]
distinguished_name = ca_distinguished_name
x509_extensions = ca_extensions

prompt = 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
 

Using certificates to logon to z/OS.

I was testing out certificate access to logon to z/OS using pthread_secure_applid() services . It took a little while to get my program working, but once it was working I tried to be “customer like” rather than a simple Unit Test. The documentation is not very clear, but it does work.

You can create a RACF definition for the simple case

  • For a certificate where the Subject Distinguished Name(DN) matches the definition’s Subject DN, then use userid xyz.
  • For a certificate where part of the Subject DN matches the definitions Subject DN, then use userid ijklm.

These both default to using an APPLID OMVSAPPL

I wanted to say

  • for application id ZZZ, if a certificate with this subject DN, then use userid TESTZ
  • for application id YYY if a certificate with the same subject DN, then use userid TESTY

Topics covered n this post:

How to set up your enterprise certificates

If you want to control certificate to userid mapping, at an individual level

You can use the following, where SDN is the Subject Distinguished Name from the certificate,

RACDCERT MAP ID(....  ) SDN(...)

for each individual.

To remove access you just delete the profile (and refresh RACLIST).

You can also specify the Issuers Distinguished Name (IDN) so you refer to the correct certificate.

If you want to control certificate to userid mapping, at the group level

You can use a Subject DN filter. This may mean you need to define your Subject DN with Organisation Units(OU), as

  • CN=COLIN,OU=TEST,O=MYORG
  • CN=MARY,OU=SALES,O=MYORG

You can then have a filter SDN(‘OU=TEST,O=MYORG’) to allow just those in the OU=TEST group to logon, and sales people will not get access.

If you then want to prevent individuals from getting access you need to define a specific profile, and point it to a userid which can do nothing.

You could also have your certificates issued by different CA’s For example, have a certificate with an Issuer Distinguished Name(IDN) including the department name.

  • Subject DN(CN=COLIN,OU=TEST,O=MYORG) Issuer DN(OU=TEST,OU=CA,O=MYORG)

and specify IDN(OU=TEST,OU=CA,O=MYORG).

Note: with this, if someone changes department, and moved from Sales to Test, they will need a new certificate.

Some people may require more than one certificate. For example someone who has normal access for their day to day job, and super powers for emergencies.

Note: In addition to getting access with a certificate you may still want to use a password.

Define a certificate to user mapping (simple case)

Use a fully qualified Subject DN filter

For example, a certificate has SDN CN=docec256.O=Doc.C=GB .

//COLRACF  JOB 1,MSGCLASS=H 
//S1  EXEC PGM=IKJEFT01,REGION=0M 
//STEPLIB  DD  DISP=SHR,DSN=SYS1.MIGLIB 
//SYSPRINT DD SYSOUT=* 
//SYSTSPRT DD SYSOUT=* 
//SYSTSIN DD * 

RACDCERT DELMAP(LABEL('CP'))  ID(COLIN) 
RACDCERT MAP ID(COLIN  )  - 
   SDNFILTER('CN=docec256.O=Doc.C=GB')                  - 
   IDNFILTER('CN=SSCA256.OU=CA.O=DOC.C=GB')             - 
   WITHLABEL('CP') 
RACDCERT LISTMAP ID(COLIN) 
SETROPTS RACLIST(DIGTNMAP, DIGTCRIT) REFRESH 
/* 

This uses both Subject Distinguished Name, and Issuer Distinguished Name. You can use either or both filters.

With this definition when I used openssl s_client to talk to my server application running on z/OS. When I specified the client certificate with the specified Subject DN and signer, I could use:

  • AT-TLS, use BPX1IOC() and retrieve the userid. Internally this uses applid=OMVSAPPL
  • do it myself
    • retrieve the certificate with the BPX1IOC() TTLS_QUERY_ONLY call;
    • use rc = pthread_security_applid_np( __CREATE_SECURITY_ENV,…. “OMVSAPPL”) passing the certificate and the applid OMVSAPPL

The code checks my the extracted userid (COLIN) has read access to the profile OMVSAPPL in class(APPL)) and, if it has access, it returns the userid to the application.

See below if you do not want to use applid OMVSAPPL

Use a partially qualified Subject DN filter

Instead of a fully qualified Subject DN, CN=docec256.O=Doc.C=GB. You can use a partially qualified DN, for example CN=docec256.O=Doc.C=GB. Any certificate which has a DN including O=Doc.C=GB will be accepted

RACDCERT DELMAP(LABEL('CPGEN'))  ID(ADCDF) 
RACDCERT MAP ID(ADCDF  )  - 
   SDNFILTER('O=Doc.C=GB')                  - 
   WITHLABEL('CPGEN') 
RACDCERT LISTMAP ID(ADCDF) 
SETROPTS RACLIST(DIGTNMAP, DIGTCRIT) REFRESH 

With this definition when I used openssl s_client to talk to my server application running on z/OS. When I specified the client certificate with the specified Issuer CN, it worked the same way as the simple case above.

The code checks my the user extracted userid (ADCDF) has read access to the profile OMVSAPPL in class(APPL)) and, if it has access, it returns the userid to the application.

Define a certificate with mutliid mapping

A specific Subject DN gets a different userid depending on the application id.

As above you can specify an Issuer Distinguished Name or a Subject Distinguished Name.

Use an Issuer Distinguished Name

Use an Issuer certificate, so any certificate issued by DN this will be covered.

I defined the profile for my Issuer CA certificate. The definition below says – any certificate issued by this CA.

RACDCERT DELMAP(LABEL('CPMULTI')) MULTIID 

RACDCERT MULTIID MAP WITHLABEL('CPMULTI') TRUST - 
  IDNFILTER('CN=SSCA256.OU=CA.O=DOC.C=GB')      - 
  CRITERIA(ZZAPPLID=&APPLID) 

Define which userid to use based on the CRITeria

RDEFINE DIGTCRIT ZZAPPLID=ZZZ  APPLDATA('ADCDZ') 
RDEFINE DIGTCRIT ZZAPPLID=AAA  APPLDATA('ADCDF') 

In my program I had

struct __certificate  ct; 
ct.__cert_type = __CERT_X509; 
char * pData = (char *)  ioc.TTLSi_BufferPtr; 
       
ct.__cert_length = ...
ct.__cert_ptr    = ...;
rc = pthread_security_applid_np(__CREATE_SECURITY_ENV,
         __CERTIFICATE_IDENTITY, 
         sizeof(ct), 
         &ct, 
         "", 
         0,
        "AAA"); 

With this, the CRITERIA(ZZAPPLID=&APPLID) becomes CRITERIA(ZZAPPLID=AAA), which maps to CRITeria

RDEFINE DIGTCRIT ZZAPPLID=AAA  APPLDATA('ADCDF'), 

and so maps to userid ADCDF.

When applid ZZZ was used instead of AAA, then

RDEFINE DIGTCRIT ZZAPPLID=AAA  APPLDATA('ADCDF')

AT-TLS only seems to be able to use the APPL OMVSAPPL (the default). I could not find a way of getting it to use an APPLID, so I had to use pthead_security_appl_np to be able to use an applid different from the default.

Use a subject DN

You can use an explicit Subject DN

 RACDCERT MULTIID MAP WITHLABEL('CPMULTIU') TRUST - 
     SDNFILTER('CN=docecgen.O=Doc2.C=GB')            - 
   CRITERIA(UAPPLID=&APPLID) 

 RDEFINE DIGTCRIT UAPPLID=AAA  APPLDATA('ADCDA') 
 RDEFINE DIGTCRIT UAPPLID=BBB  APPLDATA('ADCDB') 

the userid used depending which APPLID was specified in my application.

I could use a subset of the the SDN

RACDCERT DELMAP(LABEL('CPMULTIU')) MULTIID 
RDELETE DIGTCRIT APPLID=OMVSAPPL 
RDELETE DIGTCRIT APPLID=ZZZ 
                                                                   
RACDCERT MULTIID MAP WITHLABEL('CPMULTIU') TRUST - 
    SDNFILTER('O=Doc2.C=GB')            - 
  CRITERIA(UAPPLID=&APPLID) 

RDEFINE DIGTCRIT UAPPLID=AAA  APPLDATA('ADCDD') 
RDEFINE DIGTCRIT UAPPLID=BBB  APPLDATA('ADCDE') 

Creating definitions

What the documentation does not say, is that you can have any keyword in the criteria, as long as the substitute value has a DIGTCRIT.

This means you can have

RACDCERT MULTIID MAP ...    CRITERIA(ZORK=&APPLID) 

and have statements like

RDEFINE DIGTCRIT ZORK=AAA  APPLDATA('IBMUSER')

Controlling access to the applid

If there is a profile for the applid in CLASS(APPL) the userid will need read access to the profile.

If the profile is not defined, then anyone can use the profile.

Problem I experienced

ESRCH: errno 143 EDC5143I No such process. errno2 0be8044c

I got messages

ESRCH:The user ID provided as input is not defined to the security product or does not have an OMVS segment defined
pthread_s… rc = -1 errno 143 EDC5143I No such process. errno2 0be8044c

Where TSO BPXMTEXT 0be8044c gives

BPXPTSEC 01/05/18
JRNoCertforUser: There is no userid defined for this certificate. Action: Ensure the userid is known to the SAF service.

Cause 1:

I used an APPLID which did not have a criteria

I also got this when I used pthread_security_applid_np(…) with an an applid which did not have a matching RDEFINE DIGTCRIT

For example the following worked

  • applid AAA and RDEFINE DIGTCRIT UAPPLID=AAA APPLDATA(‘ADCDA’)

when I used a different applid I got the “EDC5143I No such process. errno2 0be8044c” message, along with the following on the joblog.

ICH408I USER(COLIN ) GROUP(SYS1 ) NAME(COLIN PAICE )
DIGITAL CERTIFICATE IS NOT DEFINED. CERTIFICATE SERIAL NUMBER(027C)
SUBJECT(CN=docecgen.O=Doc2.C=GB) ISSUER(CN=SSCA256.OU=CA.O=DOC.C=GB).

Cause 2:

In the definitions I had the wrong case: c=GB and c=gb.

Cause 3:

NOTRUST was specified

RACDCERT MULTIID MAP WITHLABEL('CPMULTIU') noTRUST -
SDNFILTER('CN=docecgen.O=Doc2.C=GB') -
CRITERIA(UAPPLID=&APPLID)

This also had a message on the job log:

ICH408I USER(START1 ) GROUP(SYS1 ) NAME(####################)
DIGITAL CERTIFICATE DEFINED TO A RESERVED USER ID. CERTIFICATE SERIAL
NUMBER(027C) SUBJECT(CN=docecgen.O=Doc2.C=GB) ISSUER(CN=SSCA256.OU=C
A.O=DOC.C=GB).

Cause 4:

I had specified the certificate’s DN in Issuers DN. It should have been SDNFILTER(‘CN=rsarsa.O=cpwebuser.C=GB’)

EMVSSAFEXTRERR 163 EDC5163I SAF/RACF extract error. errno2 0be8081c

pthread_secuity_applid_np() rc = -1 errno 163 EDC5163I SAF/RACF extract error. errno2 0be8081c

TSO BPXMTEXT 0be8081c , just gives

BPXPTSEC 01/05/18

with no message description

Cause 1:

I got this when I used

RACDCERT MULTIID MAP WITHLABEL('CPMULTIU') TRUST - 
    SDNFILTER('CN=docecgen.O=Doc2.C=GB')            - 
  CRITERIA(UAPPLID=&APPLID) 

and the SDNFILTER value was in upper case. When I corrected it (to the above) it worked.

It looks like certificate filter not found.

Cause 2:

I had a lower case keyword such as SDNFILTER(‘CN=docecgen.O=Doc2.c=GB’)

EMVSSAFEXTRERR 163 EDC5163I SAF/RACF extract error. errno2 0be80820

TSO BPXMTEXT 0be8082 gave

BPXPTSEC 01/05/18

and no other information.

I had

RACDCERT MULTIID MAP WITHLABEL('CPMULTIU') TRUST - 
    SDNFILTER('CN=docecgen.O=Doc2.C=GB')            - 
  CRITERIA(UAPPLID=&APPLID) 

RDEFINE DIGTCRIT UAPPLID=ZZZ  APPLDATA('ADCDB') 

and userid ADCDB had no access to the RACF resource class(APPL) ZZZ.

EMVSERR 157 EDC5157I An internal error has occurred. errno2 0be800fc.

TSO BPXMTEXT 0be800fc gave

BPXPTSEC 01/05/18
JRSAFNoUID: The user ID has no UID

Action: Create an OMVS segment with a UID.

Cause:

If I display the userid LU ADCDG OMVS it gave UID= NONE.

I had created this situation using ALU ADCDG OMVS(NOUID). I reset it back using tso ALU ADCDG OMVS(UID(990098)).

How to import a certificate from openssl into z/OS

This question came up in an email exchange after someone had upgraded openssl from 1.1.1f to v3.

There are two format certificates – text, and binary.

Text certificate

The text certificate looks like

Certificate:                                        
    Data:                                           
        Version: 3 (0x2)                            
        Serial Number: 633 (0x279)                  
        Signature Algorithm: ecdsa-with-SHA384      
...
-----BEGIN CERTIFICATE-----                                      
MIICgTCCAiegAwIBAgICAnkwCgYIKoZIzj0EAwMwOjELMAkGA1UEBhMCR0IxDDAK 
BgNVBAoMA0RPQzELMAkGA1UECwwCQ0ExEDAOBgNVBAMMB1NTQ0EyNTYwHhcNMjMw 
MzE5MTIzODA1WhcNMjQwMTMwMTY0NjAwWjAuMQswCQYDVQQGEwJHQjEMMAoGA1UE 
CgwDRG9jMREwDwYDVQQDDAhkb2NlYzI1NjBZMBMGByqGSM49AgEGCCqGSM49AwEH 
...
-----END CERTIFICATE-----    

This has both a text version, and a base 64 encoded version within it.

On z/OS create a dataset with this file. Then use JCL like

//S1  EXEC PGM=IKJEFT01,REGION=0M 
//SYSPRINT DD SYSOUT=* 
//SYSTSPRT DD SYSOUT=* 
//SYSTSIN DD * 
RACDCERT CHECKCERT('COLIN.DOCEC256.NEW.PEM')           

This checks the file is usable, and you can check the contents before you install it on your system.

It produced output like

Certificate 1:                                               
                                                             
  Start Date: 2023/03/19 12:38:05                            
  End Date:   2024/01/30 16:46:00                            
  Serial Number:                                             
       >0279<                                                
  Issuer's Name:                                             
       >CN=SSCA256.OU=CA.O=DOC.C=GB<                         
  Subject's Name:                                            
       >CN=docec256.O=Doc.C=GB<                              
  Subject's AltNames:                                        
    IP: 127.0.0.1                                            
    Domain: localhost                                        
  Signing Algorithm: sha384ECDSA                             
  Key Usage: HANDSHAKE, DATAENCRYPT, DOCSIGN, KEYAGREE       
  Key Type: NIST ECC                                         
  Key Size: 256    
...                                         

It also gave me

Chain information:                                           
  Chain contains 1 certificate(s), chain is incomplete       

This message is because “A certificate chain is considered incomplete if RACF is unable to follow the chain back to a self-signed ‘root’ certificate”.

Which was true, RACF already had the CA in its database, and the CA certificate was not in the file.

When the file had already been imported I also got

Certificate 1:                                                     
Digital certificate information for CERTAUTH:
  Label: Linux-CARSA                                               

So I know it had already been imported into RACF.

I also got

Chain contains expired certificate(s)         

So I could tell I needed to get a newer certicate.

Add it to the RACF key store

There is no add-replace, so you have to delete it, then add it

RACDCERT DELETE - 
  (LABEL('DOCEC256')) ID(COLIN) 
RACDCERT ID(COLIN)    ADD('COLIN.DOCEC256.NEW.PEM') - 
  WITHLABEL('DOCEC256') 

SETROPTS RACLIST(DIGTNMAP, DIGTCRIT) REFRESH

The first time I ran this I got

RACDCERT DELETE   (LABEL('DOCEC256')) ID(COLIN)                                                           
IRRD107I No matching certificate was found for this user.                                                 
READY                                                                                                     
RACDCERT ID(COLIN)    ADD('COLIN.DOCEC256.NEW.PEM')   WITHLABEL('DOCEC256')                               
IRRD199I Certificate with label 'DOCEC256' is added for user COLIN.                                       
IRRD175I The new profile for DIGTCERT will not be in effect until a SETROPTS REFRESH has been issued.     

The second time I ran it I got

RACDCERT DELETE   (LABEL('DOCEC256')) ID(COLIN)                                                                   
IRRD176I RACLISTed profiles for DIGTCERT will not reflect the deletion(s) until a SETROPTS REFRESH is issued.     
READY                                                                                                             
RACDCERT ID(COLIN)    ADD('COLIN.DOCEC256.NEW.PEM')   WITHLABEL('DOCEC256')                                       
IRRD199I Certificate with label 'DOCEC256' is added for user COLIN.                                               
IRRD175I The new profile for DIGTCERT will not be in effect until a SETROPTS REFRESH has been issued.             

Refresh the RACLISTed data

If the classes are RACLISTed (cached in memory), you need

SETROPTS RACLIST(DIGTNMAP, DIGTCRIT) REFRESH

What happens if it is already in the key store under a different userid?

I tried adding it for a different userid and got

RACDCERT ID(ADCDA) ADD('COLIN.DOCEC256.NEW.PEM') WITHLABEL('DOCEC256')
IRRD109I The certificate cannot be added. Profile 0279.CN=SSCA256.OU=CA.O=DOC.C=GB is already defined.

Unfortunately it does not tell you the id it has already been defined for.

The only way I found of finding this information is

  • displaying all resources under class(DIGTCERT).
  • find the resource with the matching name.

For example

//COLRACF  JOB 1,MSGCLASS=H 
//S1  EXEC PGM=IKJEFT01,REGION=0M 
//SYSPRINT DD SYSOUT=* 
//SYSTSPRT DD SYSOUT=* 
//SYSTSIN DD * 
RLIST DIGTCERT  * 
/* 
// 

gave me output like

CLASS      NAME                                                  
-----      ----                                                  
DIGTCERT   0279.CN=SSCA256.OU=CA.O=DOC.C=GB                      
                                                                 
...                                                           
                                                                 
APPLICATION DATA                                                 
----------------                                                 
ADCDF                                                            

the current owner is ADCDF.

The serial number of the certificate is 0279, and the components are separated with periods ‘.’.

If the name has a blank in it you will get a value like

COLIN4Certification¢Authority.OU=TEST.O=COLIN

where the blank is replaced with the cent sign(¢).

Binary certificate, PKCS12, .P12

You should be able to upload the .p12 file to z/OS as a binary file and import it using the same JCL as above.

However in openssl V3 the packaging of the certificate has changed, and RACF does not yet support it.

The easiest way of getting a certificate into z/OS is to use the .pem file (grin)