Using code signing on z/OS

There is an IBM document Task roadmap for program signing and signature verification, this provides some of the information, and some of the information is wrong!

I’ve documented Signing load modules on z/OS.

I hit various problems. The return code from the program signing function are documented here.

Using signed modules on your system

You have been sent some modules which have been signed, and you want to user the signature verification on these modules.

One-of system wide setup

Define the system wide keyring

For the validation of signed modules there is one system wide key ring. It needs to have the signing certificates (or the CA certificates) for all of the modules being used.

RACDCERT ADDRING(VERIFY) ID(COLIN ) 

* now the profile
RDEFINE RDATALIB COLIN.VERIFY.LST UACC(NONE)
PERMIT COLIN.VERIFY.LST CLASS(RDATALIB) ID(COLIN ) ACCESS(UPDATE)
SETROPTS RACLIST(RDATALIB) REFRESH

Connect the IBM CA to the keyring

You need to connect the IBM Provided Certificate authority, to be able to verify the signature of IBM provided modules. See Listing of RACF supplied certificates.

RACDCERT ID(COLIN )CONNECT(RING(VERIFY) - 
CERTAUTH -
LABEL('STG Code Signing CA - G2')

RACDCERT LISTRING(VERIFY) ID(COLIN )

Note the lower case name.

Tell the certificate certificate facility which key ring to use.

 RDEFINE FACILITY IRR.PROGRAM.SIGNATURE.VERIFICATION  - 
APPLDATA('COLIN/VERIFY')

This ring has the certificates needed to verify.

Define the program that does the signature validation.

RDEFINE PROGRAM IRRPVERS ADDMEM('SYS1.SIEALNKE'//NOPADCHK) UACC(READ)- 
SIGVER(SIGREQUIRED(YES) FAILLOAD(ANYBAD) SIGAUDIT(ANYBAD))

Run the IRRVELD job

I had to run this when setting up for the first time. When I next IPLed, I did not need to run it. I think that RACF checks to see if the above RACF profile exists – if so – loads the code.

See here.

//IRRVERLD JOB                        
//IRRVERLD EXEC PGM=IRRVERLD

When successful, this starts and ends with return code 0 and

ICH448I RACF program signature verification function is loaded. Program signature verification is available on this system.

Define your programs that need validation

RDEFINE PROGRAM ZZZDATA  ADDMEM('COLIN.ZWIRESHA.LOAD'//NOPADCHK) - 
UACC(READ) -
SIGVER(SIGREQUIRED(YES) FAILLOAD(ANYBAD) SIGAUDIT(ANYBAD))

SETROPTS WHEN(PROGRAM) REFRESH

Where my program is called ZZZDATA and it is loaded from COLIN.ZWIRESHA.LOAD. The definition SIGVER(SIGREQUIRED(YES) FAILLOAD(ANYBAD) SIGAUDIT(ANYBAD)) says that signature is required, and if verification fails do not load the module, and write an audit record.

Each userid (or group) needs a RACF profile to specify which keyring to use to sign the programs

If you want to do IPL data signing for Validated Boot for z/OS you need the profile IRR.PROGRAM.V2.SIGNING…..

If you want to validate a general program you need the profile IRR.PROGRAM.SIGNING….

Where you can specif userid, group, or group and userid.

  • IRR.PROGRAM.SIGNING.userid
  • IRR.PROGRAM.SIGNING.goup
  • IRR.PROGRAM.SIGNING.group.user
                              
RDELETE FACILITY IRR.PROGRAM.SIGNING.COLIN
RDEFINE FACILITY IRR.PROGRAM.SIGNING.COLIN -
APPLDATA('SHA256 COLIN/SIGNING')
PERMIT IRR.PROGRAM.SIGNING.COLIN CLASS(FACILITY) -
ID(COLIN) ACCESS(CONTROL)
SETROPTS RACLIST(FACILITY) refresh

This says for userid COLIN use SHA256 and keyring COLIN/SIGNING. It will use the default key in the keyring.

You sign a module at bind time, by specifying the binder options SIGN=YES.

I added sign=yes to the binder JCL

Create a certificate to sign it

RACDCERT ID(COLIN) GENCERT -                                 
SUBJECTSDN(CN('10.1.1.2') -
O('SIGNER521') -
OU('SSS')) -
ALTNAME(IP(10.1.1.2))-
SIZE(2048) -
NOTAFTER( DATE(2026-04-22) TIME(15:22:00) ) -
KEYUSAGE(HANDSHAKE DOCSIGN) -
SIGNWITH (CERTAUTH LABEL('SIGNCA')) -
WITHLABEL('SIGNER521')

RACDCERT id(COLIN) ALTER(LABEL('SIGNER521'))TRUST

SETROPTS RACLIST(DIGTCERT) REFRESH
RACDCERT ID(COLIN )CONNECT(RING(SIGNING) -
ID(COLIN) -
DEFAULT -
LABEL('SIGNER521') )

It seems to need KEYUSAGE HANDSHAKE and DOCSIGN.

It needed the default RSA size 2048. It did not work with an ECC algorithm.

It needs to be the default in the keyring.

Execute the program

When you come to execute the signed program, the system uses the keyring defined in the

IRR.PROGRAM.SIGNATURE.VERIFICATION CLASS(FACILITY) profile. I believe this has the certificates needed to verify the programs signature.

I used keyring COLIN/VERIFY.

IEW2494E 9116 A PROBLEM WAS ENCOUNTERED WITH THE SETUP OF THE DIGITAL CERTIFICATES REQUIRED FOR PROGRAM SIGNING. RACF RETURNED SAF RETURN CODE 8 RACF RETURN CODE 8 RACF REASON CODE 00000070.

R_PgmSign 70 Ver Key ring or token does not exist or does not contain a default certificate.

xhttps://www.ibm.com/support/pages/apar/OA49085

Signing load modules on z/OS

There is an IBM document Task roadmap for program signing and signature verification, this provides some of the information, and some of the information is wrong!

This blog post describes how to set up your environment to sign load modules. I’ve documented Using code signing on z/OS

I hit various problems. The return code from the program signing function are documented here.

Create RACF profiles

Each userid (or group) needs a RACF profile to specify which keyring to use to sign the programs

If you want to do IPL data signing for Validated Boot for z/OS you need the profile IRR.PROGRAM.V2.SIGNING…..

If you want to validate a general program you need the profile IRR.PROGRAM.SIGNING….

Where you can specify userid, group, or group and userid.

  • IRR.PROGRAM.SIGNING.userid
  • IRR.PROGRAM.SIGNING.goup
  • IRR.PROGRAM.SIGNING.group.user
                              
RDELETE FACILITY IRR.PROGRAM.SIGNING.COLIN
RDEFINE FACILITY IRR.PROGRAM.SIGNING.COLIN -
APPLDATA('SHA256 COLIN/SIGNING')
PERMIT IRR.PROGRAM.SIGNING.COLIN CLASS(FACILITY) -
ID(COLIN) ACCESS(CONTROL)
SETROPTS RACLIST(FACILITY) refresh

This says for userid COLIN use SHA256 and keyring COLIN/SIGNING. It uses the default key in the keyring.

How to sign a load module

You sign a module at bind time, by specifying the binder options SIGN=YES.

I added SIGN=YES to the binder JCL

When it failed, there were messages like

IEW2494E 9116 A PROBLEM WAS ENCOUNTERED WITH THE SETUP OF THE DIGITAL CERTIFICATES REQUIRED FOR PROGRAM SIGNING. RACF RETURNED SAF RETURN CODE 8 RACF RETURN CODE 8 RACF REASON CODE 00000098.

These are from the R_PgmSignVer (IRRSPS00): Program Sign and Verify callable service. See the return codes. The return codes in the messages are in hex; in the documentation they are in decimal. 0x98 is decimal 152. 152 is CA or signing certificate is expired or not yet active. This was true – my signing certificate had expired.

Create a certificate to sign load modules.

RACDCERT ID(COLIN) GENCERT -                                 
SUBJECTSDN(CN('10.1.1.2') -
O('SIGNER521') -
OU('SSS')) -
ALTNAME(IP(10.1.1.2))-
SIZE(2048) -
NOTAFTER( DATE(2026-04-22) TIME(15:22:00) ) -
KEYUSAGE(HANDSHAKE DOCSIGN) -
SIGNWITH (CERTAUTH LABEL('SIGNCA')) -
WITHLABEL('SIGNER521')

RACDCERT id(COLIN) ALTER(LABEL('SIGNER521'))TRUST

SETROPTS RACLIST(DIGTCERT) REFRESH
RACDCERT ID(COLIN )CONNECT(RING(SIGNING) -
ID(COLIN) -
DEFAULT -
LABEL('SIGNER521') )

It seems to need KEYUSAGE HANDSHAKE and DOCSIGN.

It needed the default RSA size 2048. It did not work with an ECC algorithm.

It needs to be the default in the keyring.

Code signing – error messages

The messages I received were from R_PgmSignVer (IRRSPS00 or IRRSPS64): Program Sign and Verify

Return code hex 70, decimal 112

  • ICH440I Program signature error 0x10/0x00000070 for program IRRPVERS in library SYS1.SIEALNKE.
  • The program was not loaded.
  • ICH442I The digital signature appears to be valid but the root signer is not trusted.
  • ICH451I RACF encountered an error while attempting to load the program verification module. Operation code = X’06’.
  • Return code X’00000306′ and Reason code X’00000040′.
  • Supplemental diagnostic code 1 = X’00000000′.
  • Supplemental diagnostic code 2 = X’00000000′.
  • Supplemental diagnostic code 3 = X’00000000′.
  • Supplemental diagnostic code 4 = X’00000000′.
  • Supplemental diagnostic code 5 = X’00000000′.

The certificate CERTAUTH LABEL(‘STG Code Signing CA – G2’) was not trusted.

R_PgmSignVer return codes code 0x70 is 112. Key ring or token does not exist or does not contain a default certificate.

I had mis typed the certificate name.

Action:

The the name of the keyring, there is a default certificate, and the certificate has not expired.

Return code hex 64, decimal 100

At execution time I got.

ICH440I Program signature error 0x10/0x00000064 for program ZZZDATA in library COLIN.ZWIRESHA.LOAD. The program was not loaded. ICH442I The digital signature appears to be valid but the root signer is not trusted.

code 0x64 is decimal 100 which is

The program appears to be correctly signed but one of the following conditions exists:

  • The root CA certificate in the zOSSignatureInfo structure of the program object is not connected to the signature-verification key ring.
  • The root CA certificate is marked NOTRUST.

The CA of the signing code was not in the verify keyring at execution time.

Action:

Connect the certificate or its CA to the verify keyring.

Return code hex 88, decimal 136

IEW2494E 9116 A PROBLEM WAS ENCOUNTERED WITH THE SETUP OF THE DIGITAL CERTIFICATES REQUIRED FOR PROGRAM SIGNING. RACF RETURNED SAF RETURN CODE 8 RACF RETURN CODE 8 RACF REASON CODE 00000088.

The default certificate in the key ring or token does not have code signing capability.

  • When Num_parms = 10, the keyUsage extension is optional. If the extension is present, the digitalSignature bit must be set.
  • When Num_parms = 11, the keyUsage extension must be present and the digitalSignature bit must be set.

The real reason is “HANDSHAKE” or “DOCSIGN” was missing from the KEYUSAGE().

Action:

Fix the keyusage field.

Return code hex 90, decimal 144

IEW2494E 9116 A PROBLEM WAS ENCOUNTERED WITH THE SETUP OF THE DIGITAL CERTIFICATES REQUIRED FOR PROGRAM SIGNING. RACF RETURNED SAF RETURN CODE 8 RACF RETURN CODE 8 RACF REASON CODE 00000090.

The key type of one or more certificates in the key ring or token is not supported. This reason code is also issued for the following conditions:

  • When Num_parms = 11, the signing key can be stored in ICSF, but it must be a 521-bits NIST Elliptic Curve Cryptography (ECC) key. Also, the key size of any other certificates in the key ring or token must be at least 2048 bits for RSA keys, or 224 bits for NIST ECC and Brainpool ECC keys.
  • When Num_parms = 10 and an RSA CA certificate in the chain has a key size less than 2048 bits.

This was caused by using a key with

NISTECC -
SIZE(521 ) -

using the followin

RSA
SIZE(2048) -

Works.

Action:

Use RSA key with size 2048;