I have to renew my TLS certificate every 47 days. What?!

There has been some discussion about this, and what it means. With the help of Matt Hogstrom, I now understand this a bit more.

Background

Symmetric encryption is when you change A-> B->6 etc. You use the same mapping to decrypt as you used to encrypt. If you have the mapping to encode, you can decode it. If several people use the same mapping – you can read other people’s messages.

Most digital encryption is done these days using asymmetric encryption. With an asymmetric encryption there are two keys. You encrypt with one key, and need the other key to decrypt it.

You make one key public, so anyone can have access to it, and keep the other key private and secure.

  • When you encrypt with my public key, and I decrypt it with my private key.
  • When I encrypt with my private key, you decrypt with my public key, and you know it came from me, because you used my public key.

A certificate is a package of a public key, and other information such as who it belongs to, what the certificate can be used for, and validity dates. This is packaged up, sent to a certificate authority, who digitally signs it, and returns it.

TLS is a protocol for exchanging information between a client and a server. As part of the handshake the server sends down the server’s certificate. The client checks the digital signature, and if valid, can use the enclosed public certificate to encrypt data to be sent to the server.

The problem

Your organisation, (company or country) has been using the same certificate, and so the same public key for the last 10 years. Some bad guys have been monitoring the network traffic from your organisation during this time, and saving it on tape.

Somehow the private key has escaped. Perhaps the person who looks after the plants was bribed to come in and steal the private key, or you left your laptop on the train. The bad guys have 10 years worth of data, and your private key, and can now read all the traffic sent to and from you!

This scenario has been recognised as a problem.

One solution is to change the public/private keys more frequently.

This leads to a different problem,

How often do you change the public/private key?

A year is too long. Every day is too much of an overhead. Let’s aim for one month – 30 days.

It may be that the person whose job it is to renew certificates take annual leave (up to two weeks). It would be unfortunate for a certificate to expire because that person has just gone on holiday, so let’s allow two weeks for this (Friday to Monday, 16 days). We need to give them a day to go through their mail inbox – so let’s set an expiry interval of 30 days + 16 days +1 = 47 days.

What do you renew?

In the discussion people were talking about renewing the certificate. You can renew the certificate, but specify the old public key – this defeats the purpose of the change.

You need to renew your public/private key every 47 days, and as a consequence, renew your certificate. You do not just renew the certificate with the old key.

What’s the impact?

A certificate is about to expire, so you renew it. You have a program using the old certificate. Your program needs to read the new certificate. This may mean stopping and restarting your program. For those programs which are operational all day, every day, you need to factor restarting your program. This may mean restarting it every Sunday night between 0200 and 0400. If the certificate expires during normal operation you have an emergency set of changes; renew the certificate and restart your application.

This change is for certificates used in TLS, transfering information between client and server. The certificate has a flag saying this can be used as a server, or a client (but do not specify both).

A certificate with its public key can be used for other purposes besides TLS.

For example, signing data.

Signing data

When a file is signed, you calculate the checksum (a hash value) of the file, encrypt this checksum with your private key, and attach this encrypted checksum, and your certificate to the file.

When you receive the signed file. You extract the certificate, validate it, and use the public certificate to decrypt the encrypted checksum. You do the same checksum calculation on the data and compare the two checksums. If they match the data is as the originator provided.

In this case, the public/private key does not have the same problem as TLS. The originator could be recreating the public/private key every week, it would not affect you with the package.

Intermediate certificates

You may not want every user’s certificate to be sent to the commercial certificate authorities for digital signing. You could have your own Certificate Authority.

You send a certificate to the commercial Certificate Authority, and get it signed. You then use this certificate to sign all certificates in your organisation. In this case a user’s certificate has two CA certificates attached to it. When validating a certificate the code checks that the commercial CA matches what is stored in the computer. If that matches, it uses the public key in that certificate to validate the checksum from your CA. If that matches then the public key from your CA is used to validate the end certificate.

If any CA certificate has expired, the whole certificate chain will fail validation. In this case you need your intermediate CA to be long lasting. One of the commercial CA’s has a validity period of 17+ years!

Summary

Renewing a certificate used in Client to Server (TLS) communications should have the public/private keys renewed regularly. It is recommended to have no more than 47 days.

You may want other certificates, which have longer validity periods, such as intermediate certificates.

You may want certificates where you do not care how often the public/keys are refreshed – such as code signing.

One lesson from this is you should have a different public/private key/certificate for each area; TLS, CA, and signing. The areas have different requirements.

How do you validate files on z/OS, at install time and long term?

You’ve been asked to install some files. You are not sure of their provenance, or if they have been changed from what the author wrote, and what you have received. How can you check these files?

You have some systems which are meant to be identical how can you easily check this?

One way of doing these activities is to calculate a digital hash of the file, sign the hash value, and use it.

See background for information on public/private keys.

Digitally signing is to take value, encrypt it with your private key and send it out with your certificate. To verify the signature you use the public key from the certificate to decrypt the data. It should match your copy of the value. If it matches you know it came from the certificate owner.

On z/OS you can sign load modules. These are signed at bind time, and, if configured, are checked at execution time.

Packages like openssl, and GPG (Pretty Good Privacy) have the facilities to sign objects.

This blog post covers

Installing packages

On the author’s machine

You have the Certificate Authorities file ca256.pem. This is available to every one. This could have been provided by a commercial Certificate Authority.

You have a public certificate which you will send with your package.

You have a private key matching the public certificate.

On the recipient’s machine

You have the Certificate Authority file ca256.pem.

How you do it

Create the package

You want to package data.file and distribute it. Calculate the digest of the file, and digitaly sign it

openssl dgst -sign cert.key.pem -out data.file.signature  data.file

The signature is put into data.file.signature. The signature data is in binary.

Send the following to the recipient

  • data.file
  • data.file.signature
  • your public certificate matching the private key used to sign the data. (colins.cert.pem)

Validate the package

Validate the certificate against the CA.pem 

openssl verify -CAfile ca256.pem colins.cert.pem 

If this works, you can trust the certificate.

Extract the public key from the certificate

openssl x509 -pubkey -noout -in colins.cert.pem > colins.pubkey

Validate the checksum of the file

This uses the public key extracted above

openssl dgst -verify ./colins.pubkey  -signature data.file.signature  data.file

z/OS dataset

You can use z/OS dataset, for example

openssl dgst -sign z256.key.pem -out upa.signature "//'USER.Z31B.PARMLIB(AUTORCP)'"  

where you need the double quotes and the single quotes.

Package up a package

You could create a shell script to work on a directory. For example

#!/bin/bash
for filename in ./*; do
[ -e "$filename" ] || continue
echo $filename
FILE="$(basename "${filename}")"
openssl dgst -sign z256.key.pem -out signatures/$FILE.signature $filename
done

When I ran this, the signatures directory contained the signatures of the files in the current directory.

Long term validation

You’ve validated that the files you have installed are the correct ones. Has anyone changed them since they’ve been installed?


You can issue the command to calculate the digest(hash) of a file.

openssl dgst index.txt >> dgst.txt

Which says calculate the digest – but do not sign it. The output is

SHA256(index.txt)= 1c6e0089a3ceebddf1f8e475c164162c06d7d58f29cc0b2d4c230e4e7a79cbce
SHA256(aa.txt)= d8b1fb09ac7649b61d13ca9cde72851037a83c0bca60a8545310645bb0b3da7d

You can now periodically reissue the commands, and check the value are the same as they were previously. If the values have changed – the files have changed. You can also extend this (with a small bit of Python or shell code) to include the system name

SYS1 2026/04/22 SHA256(index.txt)= 1c6e0089a3ceebddf1f8e475c...e7a79cbce
SYS2 2026/04/22 SHA256(index.txt)= d8b1fb09ac7649b61d13ca9cd...bb0b3da7d

If those files are meant to be the same on both of the systems, they clearly are not. If you run the digest command weekly you will be able to see approximately when the file was changed. It may be that maintenance was applied to one system, and the other system was overlooked.

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.

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;

First steps in using system ssl

System SSL also known as GS kit provides an API for doing

  • TLS handshakes
  • Keyring manipulation
  • Encryption and signing of data

This blog post covers background information for using GSKit. I wrote it because I could not find useful samples to get me started.

Introduction

It took me some time to understand how System SSL has been written. Now I understand it, I think it is a good API. They can be more than one way of doing something, so working out what you want to to can be hard.

Use of structures

It took me a while to understand the structures. I thought they were a little complex, and started designing my own equivalent, but I then found my “improved” definition were very similar to the original ones.

For example, I want to process some application data. It has an address and a length.
With my simplistic view I would define

  • char * pBuffer;
  • int lBuffer;

You could the use these in your application.

GSKIT provides the same files in a structure.

gsk_buffer mybuffer;
mybuffer.data = "ABCD"; // data is a void * pointing to the data
mybuffer.length = 4; //

I can then do

gsk_buffer in;
gsk_buffer out;
in.data = ...
in.length = ...
gsk_rc gsk_copy_buffer(*in,*out)

For gsk_buffers that are output from a GSKIT call you need to free the contents.

gsk_free_buffer(&in);

This will release any storage which had been allocated to the structure, and set the values to 0.

Do not use this for gsk_buffers you created, because it will free the storage the data is using.

Arrays of objects

Some API functions take one certificate, and others take an array of certificates.

You define one certificate-key

 pkcs_cert_key cert_key;

For an array of certificate keys you use

// Define the array (of 2)
pkcs_cert_key cert_key[2];
// Initialise it
cert_key[0].certificate = cert;
cert_key[0].privateKey = pRecord -> privateKey;
cert_key[1].certificate = cert1;
cert_key[1].privateKey = pRecord1 -> privateKey;
// Define the structure of array of keys
pkcs_cert_keys cert_keys;
cert_keys.count = 2;
cert_keys.certKeys = &cert_key[0];

Processing arrays of objects

void print_certs(pkcs_certificates * pcs)
{
// pkcs_certificate has a count and array of certs
// iterate over them all
int i;
pkcs_certificate * pc = & pcs-> certificates[0];
for (i = 1; i <= pcs-> count;i++)
{
printf("Certificate %i\n",i);
printf("==========\n");
print_cert(pc);
pc ++;
printf(" \n");
}
}

Where print_cert() is the program I wrote which prints information about one certificate.

Useful functions

Most gskit functions return a gsk_status. You can print the interpretation of this using

if ( gskrc != 0)
printf("Error return: %s\n" gsk_strerror(gskrc));

Definitions are in

  • /usr/include/gsktypes
  • /usr/include/gskcms.h

First steps in using system ssl: compiling a program

System SSL also known as GS kit provides an API for doing

  • TLS handshakes
  • Keyring manipulation
  • Encryption and signing of data

See First steps in using system ssl gives some introductions to gskit.

The blog post provides the script I used to compile my programs. Not everything may be relevant.

name=main
export _C89_CCMODE=1
p5="-I. -I/usr/include "
p7="-Wc,DLL "
p8="-Wc,LIST(c.lst),SOURCE,XREX,SHOWINC"
p8=" " # no listing
/bin/xlc $p5 $p7 $p8 -c $name.c -o $name.o
l1="-Wl,LIST=ALL,MAP,XREF "
bind=" /usr/lib/GSKCMS31.x /usr/lib/GSKSSL.x "
/bin/xlc $name.o ${bind} -o $name -v $l1 1>bind.lst

The output from the C compile goes into c.lst, and from the bind it goes into bind.lst

The gsk includes are in /usr/include.

For the bind you need /usr/lib/GSKCMS31.x /usr/lib/GSKSSL.x

Example of system ssl to display keyring information

System SSL also known as GS kit provides an API for doing

  • TLS handshakes
  • Keyring manipulation
  • Encryption and signing of data

This blog post covers how to access a keyring and use the information in it. I wrote it because I could not find useful samples to get me started.

Introduction

It took me some time to understand how System SSL has been written. Now I understand it, I think it is a good API. They can be more than one way of doing something, so working out what you want to to can be hard.

List the certificates in a keyring

// #include <gskssl.h> // only used for TLS and SSL
#include <gskcms.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <printhex.h>
int main(int argc, char * argv[]) {
int rc;
gsk_status gskrc;
gsk_handle hRing ;
int count = 0;// the number of certs is put here
char * ring = "START1/TN3270";
printf("Open keyring %s\n",ring);
gskrc= gsk_open_keyring (ring,
&hRing,
&count );
if (gskrc != 0)
{
printf("gsk_open_keyring %s\n", gsk_strerror(gskrc));
return 8;
}
printf("Number of certs in the ring %i\n",count);
//
// Get the default label (if it exists)
//
char * default_label;
gskrc = gsk_get_default_label(hRing,&default_label);
if (gskrc != 0)
{
else printf("gsk_get_default_label error %s\n",gsk_strerror(gskrc));
return 8;
}
printf("gsk_get_default_label %s\n",default_label);
//
// now get the record with this label (or by number)
//
gskdb_record * pRecord = 0;
gskrc = gsk_get_record_by_label(hRing,default_label,&pRecord);
//gskrc = gsk_get_record_by_id(hRing,4,&pRecord); // by number
if (gskrc != 0)
{
printf("gsk_get_record_by_label worked %s\n",gsk_strerror(gskrc));
return 8;
}
// The value is a half work enum
printf("Record Type %hi\n",pRecord ->recordType);
#include <readLabels.h>
#include <listall.>
gskrc = gsk_close_database(&hRing);
return 0 ;
}

ReadLabels

With gsk_get_record_labels you can request those with private keys (1) or those without private keys(0)

If you want all certificates on the ring use without private_keys(0).

gskrc = gsk_get_default_label ( hRing,&default_label);
if (gskrc == 0)
printf("gsk_get_default_label %s\n",default_label);
else printf("gsk_get_default_label error %s\n",gsk_strerror(gskrc));
char ** pl = 0;
int countL = 0;int whichRecords = 0;
printf("/nGet records with no private key (%i)\n",whichRecords);
gskrc = gsk_get_record_labels (hRing,
whichRecords, // those with public keys only
// 1 for this with private key
&countL, // How many returned
&pl); // char *** labels
if ( gskrc != 0)
{
printf("gsk_get_record_labels%s\n",gsk_strerror(gskrc));
return 8
}
for (int j = 0; j<countL ;j++)
{
printf("Label %i,%s\n",j,*pl);
pl++;
}
printf("============\n");

It took me some time to get the list of labels printed out. The value is a char ***;

  • If you had char * p; p is a pointer to a string so is a char *.
  • char * q[10]; pl = &q[0]
  • pl is a pointer to the elements in the array. pl is addr(a char * ) so char **;
  • the address of pl is passed to the function, so it is addr( a char **) so is a char ***
  • In the loop we get what pl points to (*pl). This is a pointer to a string. so we have printf(“…”,*pl);

Listall

printf("Number of records %i\n",count);
for (int j = 1 ; j<count+1 ;j++) // starts at 1
{
gskrc = gsk_get_record_by_index(hRing,j,&pRecord);
printf("Record %i:n",j);
printRecord(pRecord);
}
printf("============\n");

printRecord

void printRecord( gskdb_record * pRecord)
{
printf("Record Type %hi\n",pRecord ->recordType);
printf("Record Flags %2.2x\n",pRecord ->recordFlags);
printf("Record ID %i\n",pRecord ->recordId);
printf("Record Issuer ID %i\n",pRecord ->issuerRecordId );
printf("Record Label %s\n",pRecord ->recordLabel);
printf("============\n");
}

Output

The program printed out

Open keyring START1/TN3270
Number of certs in the ring 9
gsk_get_default_label NISTEC256
gsk_get_record_by_label worked
precrd 2 20a2e6e0
Sizeof gskdb_record_type 2
gsk_get_default_label NISTEC256

Get records with no private key (0)

Label 0,DOCZOSCA
Label 1,JUN24CA
Label 2,DocZosCADSA
Label 3,CA256

============
Number of records 9
Record 1:
Record Type 2
Record Flags 80
Record ID 1
Record Issuer ID 1
Record Label DOCZOSCA
...

Record 9:
Record Type 3
Record Flags c0
Record ID 9
Record Issuer ID 1
Record Label NISTEC256
============

  • The value of Record 1 type gskdb_rectype_certificate = 2, /* Certificate */
  • Flags is
    • GSKDB_RECFLAG_TRUSTED = The certificate is trusted ( 0x80);
    • GSKDB_RECFLAG_DEFAULT = This is the default key
  • ID 1 – record 1
  • Issuer ID 1 – it is self signed
  • Label DOCZOSCA
Record 9:
Record Type 3
Record Flags c0
Record ID 9
Record Issuer ID 1
Record Label NISTEC256

  • The record type is 3 gskdb_rectype_certKey = 3, /* Certificate with key */
  • Flags is
    • GSKDB_RECFLAG_TRUSTED = The certificate is trusted.
    • GSKDB_RECFLAG_DEFAULT = This is the default key
  • ID 9 – it is record 9 in the keyring
  • Issuer ID 1- it was signed by the certificate with position 1 (DOCZOSCA)
  • Its label is NISTEC256

Example of using system ssl to print certificate information

The structure containing information about a certificate has a very deep nesting of structures and arrays. Fortunately for the most common information, gskit provides an interface.

There is a standards document giving the layout of the certificate, and what the fields mean.

The structures are in /usr/include/gskcms.h. Some of the data types are in /usr/include/gsktypes.h .

The certificate structure

  • The structure pkcs_certificate>s has an array of pkcs_certificate and a count of the elements.
  • The structure pkcs_certificate has a certificate type and an x509_certificate.
  • The structure x509_certificate has
    • a tbsCertificate
    • signature algorithm
  • The x509_tbs_certificate structure (tbs from To Be Signed) has
    • the certificate version
    • the certificate serial number
    • the signature algorithm of the certificate
    • the issuer
    • the validity period
    • the subject.

The fields

  • The certificate serial number. This a hexadecimal value. The definition has a pointer to the data, and a length of the data. The length is at least one.
  • The signature algorithm of the certificate. This includes
    • The signature type. This is a C enum, such as x509_alg_sha256WithRsaEncryption = 25
  • The issuer is a complex nest of structure. Fortunately gskit provide a function gsk_name_to_dn(structure,name). The output “name” is a printable EBCDIC string like CN=DocZosCA,OU=CA,O=COLIN
  • The validity period. This structure contains two time-value fields, not before, and not after.
    • You can format a time value field using
      • char dest[18];
      • strftime(dest,18,”%y/%m/%d %H:%M:%S”,timeval);
  • The subject is like the issuer. Use the function gsk_name_to_dn to convert it to printable EBCDIC. For example CN=10.1.1.2,OU=SSS,O=NISTECC521

Printing the structures

I have some functions like

void print_certs(pkcs_certificates * pcs)
{
// pkcs_certificate has a count and array of certs
// iterate over them all
int i;
pkcs_certificate * pc = & pcs-> certificates[0];
for (i = 1; i <= pcs-> count;i++)
{
printf("Certificate %i\n",i);
printf("==========\n");
print_cert(pc);
pc ++;
printf(" \n");
}
}

which invokes

void print_cert(pkcs_certificate * pc )
{
print_x509_algorithm_type(pc ->u.certificate. signatureAlgorithm
.type,0);
// Serial number
char output[60]; // into here
// hexof is written by Colin Paice
printf("Serial number Hex :%s\n",hexof(
pc ->u.certificate.tbsCertificate.serialNumber.data,
pc ->u.certificate.tbsCertificate.serialNumber.length,
&output[0]) );
// get the subject and issuer names
gsk_status gskrc;
char * pName; // returned here - must free it
pName = "Unknown";
gskrc = gsk_name_to_dn(
& pc ->u.certificate.tbsCertificate.subject,
&pName);
if (gskrc != 0)
printf("Subject gsk_name_to_dn %s\n", gsk_strerror(gskrc));
printf("Subject name :%s\n",pName);
gsk_free_string(pName);
// extract the issuer,
pName = "Unknown";
gskrc = gsk_name_to_dn (
& pc ->u.certificate.tbsCertificate.issuer,
&pName);
if (gskrc != 0)
printf("Issuer gsk_name_to_dn %s\n, gsk_strerror(gskrc));
printf("Issuers name :%s\n",pName);
gsk_free_string(pName);
// extract the valid times.
char buffer[18];
printf("Not Before :%s\n",
ccpformattime (
& pc ->u.certificate.tbsCertificate.validity.notBefore,
&buffer[0] ) );
printf("Not After :%s\n",
ccpformattime (
& pc ->u.certificate.tbsCertificate.validity.notAfter,
&buffer[0] ));
print_x509_extensions(&pc ->
u.certificate.tbsCertificate.extensions);
}

Process DER ASN.1

Some data is encoded in ASN.1 format.

This is of format

  • 1 byte of type
  • 1 or more bytes of length
  • Value, where value can be
    • Integer data
    • ASCII string data
    • A sequence of things ..

For example

16304765 6E657261… is

  • Type 16 is an ASCII string
  • of length 0x30
  • with value 0x4765… which translates to EBCDIC Genera…

30068704 0A010102

  • Type 30 is a sequence (it happens to be a sequence of one element)
  • Of length 6
    • The value is a dotted decimal IP address of length 4
    • with value 0A010102 – which is 10.1.1.2.
Certificate 2
==========
Certificate algorithm :x509_alg_sha256WithRsaEncryption
Serial number Hex :68
Subject name :CN=10.1.1.2,OU=SSS,O=NISTEC256
Issuers name :CN=DocZosCA,OU=CA,O=COLIN
Not Before :26/04/05 00:00:00
Not After :27/04/05 23:59:59
Extension 1
============
Extension type:x509_ext_unknown
DER IA5String: Generated by the Security Server for z/OS (RACF)

Extension 2
============
Extension type:x509_ext_subjectAltName
DER Dotted address: 0x0A010102

Extension 3
============
Extension type:x509_ext_keyUsage
DER BitString: 0x0780
Sample output

Extension 4
============
Extension type:x509_ext_subjectKeyIdentifier
DER Octet: 0xF421DD55 F00BEE6E E81B97D2 1D5556AB A671EC59

Extension 5
============
Extension type:x509_ext_authorityKeyIdentifier
DER Context: 0xCAD12CE6 AACB598C 6E9595CD D812C90A C9C4C289

Example of using system ssl to sign some data

System SSL, also known as GS kit, provides an API for doing

  • TLS handshakes
  • Keyring manipulation
  • Encryption and signing of data

This blog post covers how to sign data. I wrote it because I could not find useful samples to get me started.

Signing data

To digitally sign data, you

  • perform a check sum calculation on the data,
  • encrypt the checksum with a private key,
  • package up make the data, the encrypted checkum, and the originator’s public certificate.

The recipient

  • checks the validity of the certificate
  • extracts the public key
  • decrypts the encrypted checksum
  • does a checksum of the enclosed data
  • compares the two checksums.

The checksums should match.

How the defining structures work together

Reference to fields

The definition of a record read from a keyring is

typedef struct _gskdb_record {
gskdb_record_type recordType;
gsk_octet recordFlags;
gsk_octet rsvd_1[1];
gsk_int32 recordId;
gsk_int32 issuerRecordId;
char * recordLabel;
union {
x509_certificate certificate;
pkcs_cert_request request;
} u;
pkcs_private_key_info privateKey;
gsk_octet rsvd_2[16];
} gskdb_record;

This has information about certificate, and the private key.

If you have a variable pRecord as a pointer to this structure, you can refer to the private key as pRecord->privateKey.

Because this structure can be used for both a certificate and a certificate request to refer to a certificate you have to use pRecord->u.certificate to locate the certificate.

Arrays of objects

Some API functions take one certificate, and others take an array of certificates. See Arrays of objects.

To sign some data

printf("....SIGN the data\n");
// pRecord points to the default record
gsk_buffer indata;
gsk_buffer outdata;
// Create the data to sign
indata.data = "ABCDEF";
indata.length = 6;
outdata.data ="OUTDATA "; // dummy data
outdata.length = 6 ;
// Define the certificate(s) to be used
pkcs_certificate cert;
cert.type = pkcs_certtype_certificate ;
cert.u. certificate = pRecord -> u.certificate;
pkcs_cert_key cert_key[1];
cert_key[0].certificate = cert;
cert_key[0].privateKey = pRecord -> privateKey;
// create our structure of an array of keys
// Note the structure is pkcs_cert_key>s< which contains
// one or more cert_key structures.
pkcs_cert_keys cert_keys;
cert_keys.count = 1;
cert_keys.certKeys = &cert_key[0];
// pkcs_certificates certs;
gsk_process_option po;
po.enforce_keyusage = 0;
po.enforce_content_length = 0;
po.enforce_keyparity = 0;
po.create_detached_signature = 0;
gskrc = gsk_make_signed_data_msg_extended
(po, // no options
0, // version
x509_alg_sha1Digest, // algoritm
1, // include certs in the output
&cert_keys, // the certs to use
0, // no ca certs
&indata,
0, // no attrib signers
&outdata);
if (gskrc == 0)
printf("gsk_make_signed_data_msg_extended worked\n");
else
{
printf("gsk_make_signed_data_msg_extended. %8.8x %s\n",
gskrc,gsk_strerror(gskrc));
return 8;
}
printf("Outdata length %i\n",outdata.length);
printHex(stdout,outdata.data,outdata.length);

This produced

00000000 : 3082048C 06092A86 4886F70D 010702A0  ................ .b.....f.f7..... 
00000010 : 82047D30 82047902 0100310B 30090605 ................ b.'.b.`.........
00000020 : 2B0E0302 1A050030 1506092A 864886F7 ................ ............f.f7
00000030 : 0D010701 A0080406 C1C2C3C4 C5C6A082 ................ ........ABCDEF.b
00000040 : 03023082 02FE3082 01E6A003 02010202 ................ ...b...b.W......
00000050 : 0168300D 06092A86 4886F70D 01010B05 ................ .......f.f7.....
00000060 : 00303031 0E300C06 0355040A 1305434F ................ ...............|
00000070 : 4C494E31 0B300906 0355040B 13024341 ................ <.+.............
...
00000460 : B6CBA3F3 48B5C9CD 76063F2D 007840A7 ................ ..t3..I....... x
00000470 : 0C8EF6FE 5442459E 47F6C1D0 12F1247E ................ ..6......6A}.1.=
00000480 : 0DC79B03 7723D129 078D1DB9 812F6EB9 ................ .G....J.....a.>.

In the data is

  • ABCDE – the original data
  • 3082048c – I recognise this as ANS-1 encoding. (ASN.1) is a standard interface description language (IDL) for defining data structures that can be serialized and deserialized in a cross-platform way. It is broadly used in telecommunications and computer networking, and especially in cryptography.
    • For example 048c is the length of data following

Once the signature has been obtained, it can be externalised (such as writing to a file) and sent to a remote site.

Because the data is in hexadecimal you may wish to convert it to EBCDIC for transport. You can use the

gsk_encode_base64 (gsk_buffer input_data,gsk_buffer_output_data);

to encode the data and use the gsk_decode_base64() to decode it.

Validate the data

The recipient can check that the signature and certificates are valid.

// Process the validation of the signature
// The list of input signatures
pkcs_certificates certs;
certs.count = 1;
certs.certificates = &cert;
gsk_attributes_signers as;
gsk_buffer temp; // process the data into temp.
printf("============READSIGNED======\n");
gsk_boolean ul; // were local certificates used?
gskrc = gsk_read_signed_data_msg_extended(
po, // no option
NULL, // no local certificates provided / local_certificates,
&outdata, // the signed data
&ul, // Set if certs were set locally or not
NULL, // returned cert not needed // msg_certificates
NULL, // signer_certificates
&as, // attrbute signers
&temp);
if (gskrc == 0)
{
printf("gsk_read_signed_data_msg_extended worked\n");
printf("Use local certificates %i\n",ul);
printHex(stdout,temp.data,temp.length);
}
else
{
printf("gsk_read_signed_data_msg_extended. %8.8x %s\n",
gskrc,gsk_strerror(gskrc));
return 8;
}

When this executed it produced

gsk_read_signed_data_msg_extended worked
Use local certificates 0
00000000 : C1C2C3C4 C5C6 ...... ABCDEF

which matches the original input data.

With

gskrc = gsk_read_signed_data_msg_extended(
po, // no option
NULL, // no local certificates provided / local_certificates,
...

Only certificates in the data were used. “Use local certificates” was 0.

When

gskrc = gsk_read_signed_data_msg_extended(
po, // no option
&certs, // use local certificates provided
...

it used the certificate(s) from my keyring. “Use local certificates” was 1.

My final code was

pkcs_certificates msgcerts;
pkcs_certificates signercerts;
gsk_attributes_signers as;
gskrc = gsk_read_signed_data_msg_extended(
po, // no option
&certs, // local_certificates,
&outdata, // stread output
&ul, // Set if certs were set locally or not
&msgcerts, // returned msg_certificates
&signercerts, // signer_certificates
&as, // attrbute signers
&temp);
if (gskrc == 0)
{
printf("gsk_read_signed_data_msg_extended worked\n");
printf("Use local certificates %i\n",ul);
printHex(stdout,temp.data,temp.length);
printf("====MSGCERTS+++\n");
// print_pkcs_certificates(&msgcerts);
print_certs(&msgcerts);
printf("====Signers++\n");
print_certs(&signercerts);
// print_pkcs_certificates(&signercerts);
}
else
{
printf("gsk_read_signed_data_msg_extended. %8.8x %s\n",
gskrc,gsk_strerror(gskrc));
return 8;
}