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;
}

An easy question: how do you print a long long nicely as hex?

I wanted to print a long long nicely, consistent with other lines of output. It took me a while to get working properly.

The code

printf("... %20.16llx\n",ll);
  • The x means print as hexadecimal
  • ll means treat the value as a long long
  • 20.16. The 20 is the the minimum number of characters printed. The second 16 specifies the number of characters to be output. In the past, I’ve used formatting to print numbers so they line up in a column.

Below is the formatting string, and the output

.%16.llx.    .              68.
.%16.16llx. .0000000000000068.
.%.llx. .68.
.%llx. .68.

My final formatting string is

printf("Serial Number in hex:%llx\n",ll);

Serial Number in hex:68

It is another of the “it is always easy when you know the answer”.

My original problem was “how do you nicely print a variable length string”.

I solved it

char longChar[8];
char * pData; // points to the data
int lData = ... ; // length of the data
memset(&longChar[0],0,sizeof(longChar); // clear it to 0
memcpy(&longChar[8-lData],
pdata,
lData
);
long long ll;
memcpy(&ll,&longChar,8);
printf("Serial number Hex %llx\n",ll);

There may be better ways of doing it (please suggest a better way of doing it), but it works.

Why is the size of my enum larger than yours?

I’ve been doing some coding with GSK, system SSL, and had problems getting the data to match.

There are some definitions and my code

typedef enum {
gskdb_rectype_unknown = 0,
gskdb_rectype_keyPair = 1, /* Request key pair */
gskdb_rectype_certificate = 2, /* Certificate */
gskdb_rectype_certKey = 3, /* Certificate with key */
gskdb_rectype_maximum = 32767
} gskdb_record_type;
typedef struct _gskdb_record {
gskdb_record_type recordType;
....
} gskdb_record;
...
gskdb_record ccp;
printf("Length %i\n",sizeof(ccp .recordType));

It prints out a length of 4.

If I display the data in the control block, the value of ccp.recordType is 0x0003C000.

This had me scratching my head. It needed a trip to the shops, and lunch before I spotted the problem

In the options section of the compiler list it had

 *ENUMSIZE(INT)

This says treat all enums as integer. The default is enums(SMALL).

The smallest size of gskdb_record_type is 2 bytes, but I had specified use 4 bytes. The true value of the field is 0x003 (Certificate with key) rather than an undefined 0003c000!

I removed the -qenum=int from my compiler switches.

When I recompiled, and reran the program – it all worked, giving the result 3 -> certificate with key!

How do I know it is you sending me secret information?

I was involved in a conference call about security, and one of the topics was how do you prove who someone is.
For example you want to send me some secret information, such as your passport number, bank account details or the magic codes of your identification key.

  • Sending me an email is not secure. Bad guys monitoring your email (or mine) could steal your information and substitute some other information.
  • A carrier pigeon could be captured and the data changed
  • A video of you showing the information can be faked these days – putting your face onto someone else’s body is easy.
  • Some people said that the only secure way was to meet in person and exchange information. It was mentioned that this could be done at conferences. This has couple of problems
    1. You may not have met people you work with – so you have no way of knowing that the person who says he is Colin Paice, looks like the Colin Paice you’ve been corresponding with.
    2. With the technology in the Missions Impossible films, the person you are meeting could be wearing a Latex mask, and have a voice changer, and so look and sound like me, but still be a bad guy.
  • Using PKI where we we have a certificate chain with a common certificate works, seems to be the only way which works.
    • Until we have working Quantum computers which can break the RSA keys used in PKI!

Various TLS return codes

When debugging TLS problems I got various return codes. I’m collecting them here, so I can find them next time I have a problem.

I’d be happy to add to any problems and solutions you find, please let me know.

TLS Handshake failure

Alert 40

Wireshark produced

  • Alert Message
    • Level: Fatal (2)
    • Description: Handshake Failure (40)

Looking in the CTRACE I got

No SSL V3 cipher specs enabled for TLS V1.3

See tls-1-3-everything-possibly-needed-know. This has

just five recommended cipher suites:

  • TLS_AES_256_GCM_SHA384
  • TLS_CHACHA20_POLY1305_SHA256
  • TLS_AES_128_GCM_SHA256
  • TLS_AES_128_CCM_8_SHA256
  • TLS_AES_128_CCM_SHA256

Alert 51

With TLS 1.3, A certificate like

SUBJECTSDN(CN('10.1.1.2') - 
O('NISTEC256') -
OU('SSS')) -
ALTNAME(IP(10.1.1.2))-
NISTECC -
KEYUSAGE( HANDSHAKE ) -
SIZE(256 ) -
SIGNWITH (CERTAUTH LABEL('DOCZOSCA')) -
WITHLABEL('NISTEC256')

Failed. But changing it to SIZE(512) worked. Strange, because size 512 is supposed to be supported.

Debug details

From the CTRACE

 ICSF service failure: CSFPPKS retCode = 0x8, rsnCode = 0x2b00                                            

S0W1 MESSAGE 00000004 10:25:45.006617 SSL_ERROR
Job TCPIP Process 0001003B Thread 00000003 crypto_sign_data
crypto_ec_sign_data() failed: Error 0x03353084

S0W1 MESSAGE 00000004 10:25:45.006883 SSL_ERROR
Job TCPIP Process 0001003B Thread 00000003 construct_tls13_certificate_verify_message
Unable to generate certificate verify message: Error 0x03353084

S0W1 MESSAGE 00000004 10:25:45.007124 SSL_ERROR
Job TCPIP Process 0001003B Thread 00000003 send_tls13_alert
Sent TLS 1.3 alert 51 to ::ffff:10.1.0.2.43416.

in z/OS Unix the command

grep 03353084 /usr/incl/gsk

gave

/usr/include/gskcms.h:#define CMSERR_ICSF_SERVICE_FAILURE         0x03353084          

The ICSF API points to return codes. 2B00 (11008) says

The public or private key values are not valid (for example, the modulus or an exponent is zero or the exponent is even) or the key could not have created the signature (for example, the modulus value is less than the signature value). In any case, the key cannot be used to verify the signature.

Changing to

Policy agent

...
ServerCertificateLabel NISTECC521
...
RACDCERT ID(START1) GENCERT -                             
SUBJECTSDN(CN('10.1.1.2') -
O('NISTECC256') -
OU('SSS')) -
ALTNAME(IP(10.1.1.2))-
NISTECC -
KEYUSAGE(HANDSHAKE ) -
SIZE(256) -
SIGNWITH (CERTAUTH LABEL('DOCZOSCA')) -
WITHLABEL('NISTECC256')

worked.

I needed to do F CPAGENT,REFRESH to pickup the change. I needed to refresh the policy agent, because I was using TN3270, which uses AT-TLS.

Session just ends with no alert

Looking at the CTRACE output I got

S0W1      MESSAGE   00000004  12:52:55.333904  SSL_ERROR                                  
Job TCPIP Process 0201001E Thread 00000001 crypto_chacha_encrypt_ctx
ICSF service failure: CSFPSKE retCode = 0x8, rsnCode = 0xbfe

S0W1 MESSAGE 00000004 12:52:55.334123 SSL_ERROR
Job TCPIP Process 0201001E Thread 00000001 crypto_chacha_encrypt_ctx
The algorithm or key size is not supported by ICSF FIPS

S0W1 MESSAGE 00000004 12:52:55.334355 SSL_ERROR
Job TCPIP Process 0201001E Thread 00000001 gsk_encrypt_tls13_record
ChaCha20 Encryption failed: Error 0x0335308f

The return code 0xbfe is

The PKCS #11 algorithm, mode, or keysize is not approved for ICSF FIPS 140-2. This reason code can be returned for PKCS #11 clear key requests when ICSF is in a FIPS 140-2 mode or 140-3,HYBRID mode. To see how 8/BFE(3070) can be returned when the ICSF FIPSMODE is 140-3,HYBRID, see ‘Requiring FIPS 140-2 algorithm checking from select z/OS PKCS #11 applications’ in z/OS Cryptographic Services ICSF Writing PKCS #11 Applications.

FIPS was incorrectly specified. For example FIPS-140 with TLS 1.3

How do you download and use a dataset from z/OS.

Transferring a dataset from z/OS to Windows or Linux and using it can be a challenge.

A record in a data set on z/OS has a 4 byte Record Descriptor Word on the front of the record. The first two bytes give the length of the record (and the other two bytes are typically 0)

FTP has two modes for transferring data ASCII and BIN.

ASCII

With ASCII mode, FTP reads the record,

  • Removes the RDW
  • Converts it from EBCDIC to ASCII
  • Adds a “New Line” character to the end of data
  • Sends the data
  • Writes the data to a file stream.

On Unix and Windows a text file is a long stream of data. When the file is read, a New Line character ends the logical record, and so you display the following data on a “New Line”.

Binary mode

Binary mode is used when the dataset has hexadecimal content, and not just printable characters. The New Line hex character could be part of a some hexadecimal data, so this character cannot be used to delineate records.

FTP has an option for RDW

quote site RDW

The default is RDW FALSE.

If RDW is FALSE then FTP removes the RDW from the data before sending it. At the remote end, the data is a stream of data, and you have no way of identifying where one logical record ends, and the next logical record starts.

If RDW is TRUE, then the 4 byte RDW is sent as part of the data. The application reading the file can read the information and calculate where the logical record starts and ends.

For example on z/OS the dataset has (in hex) where the bold data is displayed when you edit or browse the dataset. The italic data is not displayed.

00040000C1C2C3C4
00020000D1CD2
00050000E1E2E3E4E5

If the data was transmitted with RDW FALSE the data in the file would be

C1C2C3C4D1D2E1E2E3E4E5

If the data was transmitted with RDW TRUE the data in the file would be

00040000C1C2C3C400020000D1CD200050000E1E2E3E4E5

Conceptually you can process this file stream using C code:

short RDW;  // 2 byte integer
short dummy; // 2 byte integer

RDW = fread(2); // get the length
dummy = fread(2); // ignore the 0s
mydata = fread(RDW -4); // -4 for the RDW already read

...
RDW = fread(2); // get the length
dummy = fread(2); // ignore the 0s
mydata = fread(RDW -4); // -4 for the RDW already read

(Thanks to pjfarley3 who pointed out the RDW length includes the 4 byte RDW – so the application data length is RDW -4.)

In practice this will not work because z/OS has numbers which are Big Endian, and X86 and ARM machines are Little Endian. (With Big Endian – the left byte is most significant, with Little Endian, the right bit is most significant – the bytes are transposed.)

On z/OS 0x0004 is decimal 4. On X86 and ARM 0x0400 is 4.

In practice you need code on X86 and ARM, like the following, to get the value of a half word from a z/OS data set.

char RDW[2];  // 2 characters
RDW = fread(2); // get the length
length = 256 * RDW[0] + RDW[1]

and similarly for longer integers.

Python

If you are using the Python struct facility, you can pass a string of data types and get the processed values.

  • The string “>HH” says two half words, and the > says the numbers are Big Endian.
  • The string “<HH” says two half words and the < says they are Little Endian
  • The string “HH” says two half words – read in the default representation.

Conversion

You’ll need to do your own conversion from EBCDIC to ASCII to make things printable!

How do you trust a file?

I was asked this question by someone wanting to ensure their files have not been hacked. In the press there are articles where bad guys have replaced some code with code that steals credentials, or it allows an outsider access to your machine. One common solution to trusting a file uses cryptography.

There are several solutions that do not work

Checking the date of a file.

This does not work because there are programs that allow you to change the date and time of files.

Checking the number of bytes

You can list a file’s properties. One property is the size of the file. You could keep a list of file, and file size.

There are two problems

  1. You can change the contents of the file without changing the size of the file. I’ve done this. Programs used to have a patch area where skilled people could write some code to fix problems in the program.
  2. Someone changes the size of the file – but also changes your list to reflect the new size, and then changes the date on file and your list so they look as if they have not changed.

Hashing the file contents

Do a calculation on the contents of the file. A trivial function to implement and easy to exploit, is to treat each character as an unsigned integer, and add up all of the characters.

A better hashing function is to do a calculation cs = mod(c **N,M). For example when the current character is 3, n is 7 and m is 13; find the remainder of 3*3*3*3*3*3*3 when divided by 13, the answer is 3. N and M should be very large. Instead of using one character you take 8 or more. You then apply the algorithm on the file.

cs = 0
do 8 bytes of the file at a time
cs = mod((cs + the 8 bytes)** N,M)
end
display cs

Some numbers N and M are better that others. Knowing the value cs, you cannot go back and recreate the file.

If you just store the checksum value in a file, then the bad guys can change this file, and replace the old checksum with the new checksum of the file with their change. It appears that doing a checkum on the file does not help.

Cryptography to the rescue

To make things secure, there are several bits of technology that are required

  • Public and private keys
  • How do I trust what you’ve sent me

Public and private keys

Cryptography has been around for thousands of years. This typically had a key which was use to encrypt data, and the same key could be used to decrypt the data.

The big leap in cryptography was the discovery of asymmetric keys where you need two keys. One can be used for encryption, and you need another for decryption. You keep the one key very secure (and call it the private key) and make the other key publicly available (the public key). Either key can be used to encrypt, and you need the other key to decrypt.

The keys can be used as follows

  • You encrypt some data with my public key. It can only be decrypted by someone with my private key.
  • I can encrypt some data with my private key and sent it to you. Anyone with my public key can decrypt it. In addition, because they had to use my public key, then they know it came from me (or, to be more accurate, someone with my private key).

How do I trust what you’ve sent me

I would be very suspicious if I received an email saying

This is your freindly bank heree. Please send us your bank account details with this public key. Pubic keys are very safe and we are the only peoples who can decrypt what you send me.

Digital certificates and getting a new passport

A public certificate has

  • Your name
  • You address such as Country=GB, Org=Megabank.com,
  • Your public key
  • Expiry date
  • What the certificate can be used for

I hope the following analogy explains the concepts of digital certificates.

Below are the steps required to get a new passport

  • You turn up at the Passport Office with your birth certificate, a photograph of you, a gas bill, and your public certificate.
  • The person in the office checks
    • that the photo is of you.
    • your name is the same as the birth certificate
    • the name on the gas bill matches your birth certificate
    • the address of the gas bill is the same as you provided for your place of residence.
  • The office creates the passport, with information such as where you live (as evidenced by the gas bill)
  • The checksum of your passport is calculated.
  • The checksum is encrypted with the Passport Office’s PRIVATE key.
  • The encrypted checksum and the Passport Office’s PUBLIC key are printed, and stapled to the back of the passport
  • The passport is returned to you. It has been digitally signed by the Passport Office.

How do I check your identity?

At the back of MY passport is the printout of the Passport Offices’ public key. I compare this with the one attached yo your passport – they match!

I take the encrypted checksum from your passport, and decrypt it using the Passport Office’s public key (yours or mine – they are the same). I write this on a piece of paper.

I do the same checksum calculation on your passport. If the value matches what is on the piece of paper, then you can be confident that the passport has not been changed, since it was issued by the Passport Office. Because I trust the Passport Office, I trust they have seen your birth certificate, and checked where you live, and so I trust you are who you say you are.

But..

Your passport was issued by the London Passport Office, and my passport was issued by the Scottish Passport Office, and the two public certificates do not match.

This problem is solved by use of a Certificate Authority(CA)

Consider a UK wide Certificate Authority office. The Scottish Passport Office sent their certificate (containing, name address and public key) to the UKCA. The UKCA did a checksum of it, encrypts the checksum with the UKCA PRIVATE key, attached the encrypted checksum, and the UKCA public certificate to the certificate sent in – the same process as getting a passport.

Now when the Scottish Passport office process my passport, they do the checksum as before, and affix the Scottish Passport Offices’ public certificate as before… but this certificate has a copy of the UKCA’s certificate, and the encrypted checksum stuck to it. The passport now has two bits of paper stapled to it, the Scottish Passport Office’s public certificate, and the UKCA’s public certificate.

When I validate your passport I see that the London Passport office’s certificate does not match the Scottish Passport Offices certificate, but they have both been signed by the UKCA.

  • I compare the UKCA’s public certificates – they match!
  • I decrypt the checksum from the London office using the UKCA’s certificate and write it down
  • I do the same checksum calculation on the London offices’s certificate and compare with what is written down. They match – I am confident that the UKCA has checked the credentials of the London office
  • I can now trust the London certificate, and use it to check your passport as before.

What happens if I do not have the UKCA certificate

Many “root” certificates from corporations, are shipped on Windows, Linux, z/OS, Macs etc. The UKCA goes to one of these corporations, gets their certificate signed, and includes the corporations certificate attached to the UKCA certificate. Of course it costs money to get your certificate signed by one of these companies

You could email the UKCA certificate with the public key to every one you know. This has the risk that the bad guys who are intercepting your email, change the official UKCA certificate with their certificate. Plan b) would be to ship a memory stick with the certificate on it – but the same bad guys could be monitoring your mail, and replace the memory stick with one of theirs.

How does this help me trust a file?

The process is similar to that of getting a passport.

My “package” has two files abx.txt and xyz.txt

At build time

  • Create the files abc.txt and xyz.txt
  • Calculate the checksum of each file, and encrypt the value – this produces a binary file for each abc.txt.signature
  • Create a directory with
    • Your public certificate/public key
    • A directory containing all of the signature files
    • A list of all of the files in the signature directory
    • A checksum of the directory listing. directory.list.signature

You ship this file as part of your product.

When you install the package

  • Validate the certificate in the package against the CA stored in your system.
  • Decrypt the list of files in the directory (directory.list.signature). Check the list of files is valid
  • For each line in the directory list, go through the same validations process with the file and it’s signature.

For the paranoid

Every week calculate the checksum of each file in the package and sent it to a remote site.

At the remote site compare the filename, checksum combination against last week’s values.

If they do not match, the files have been changed.

Of course if your system has been hacked, the bad guys may be intercepting this traffic and changing it.

How do I do it?

I have a certificate mycert.pem, and my private key mycert.private.pem. It was signed by ca256.

Build

Run the command against the first file

openssl dgst -sign mycert.key.pem abc.txt   > abc.txt.signature

Move the abc.txt.signature to the package’s directory,

Create the trust package

/
.. /mycert.pem
.. /directory.list.txt
.. /directory.list.txt.signature
.. /signatures/
.. .. /abc.txt.signature
.. .. /xyz.txt.signature

Validate the package

Validate the certificate in the package.

openssl verify -CAfile ca256.pem mycert.pem 

extract the public key from the certificate.

openssl x509 -pubkey -noout -in mycert.pem > mycert.pubkey

validate the checksum of the abc file using the public key.

openssl dgst -verify ./mycert.pubkey  -signature abc.txt.signature  abc.txt

Does it work with data sets ?

On z/OS I created a signature file with

openssl dgst -sign tempcert.key.pem  "//'COLIN.JCL(ALIAS)'"  > jcl.alias.signature

and validated it with

openssl dgst -verify tempcert.pubkey -signature jcl.alias.signature  "//'COLIN.JCL(ALIAS)'"