ICSF – background to writing my first ICSF application.

I was exploring data set encryption, and wanted to copy some data to an encrypted data set, and move to a new z/OS system (on a different USB). I used this as an exercise to learn about ICSF.

Overview

ICSF has lots of APIs to do wonderful things with encryption such as checking PIN numbers and encrypting packets of data. It also has some commands to define keys etc.

It was easy to set up data set encryption on one system. It was hard to set it up as a typical customer, where you had to set up two independent systems and send files between them.

The administration guide describes a scenario of two ICSF systems establishing initial transport keys. This was a bit clumsy. You have to edit a file, extract a string of hex digits and use a courier to send them to the remote system.

I set myself the challenge to use private and public keys to securely transfer the keys from one system to another. I could not find any commands to help me do this – so I had to write my own.

It took me much longer than expected, partly because I am not a good C programmer, but also because the path was not clear, and it took a while to understand what I needed to do. For example some APIs work with a key with type of DATA, and some do not. I ended up using a key type of CIPHER because that was the only one I could get to work. I’ve since got DATA to work.

Background ICSF information.

It took me a few days to understand the ICSF environments.

  • You have Symmetric keys – where a key is used for encryption, and the same key is used for decryption. These keys are stored in the Cryptographic Key Data Set (CKDS). These have two formats (and use different APIs) –
    • fixed length
    • variable length – this is a follow-on from fixed lengths and should be used instead of fixed lengths.
  • You have Asymmetric keys – for example private and public PKI keys. Everyone can have access to the public key. Only you have access to your private key. These are stored in the PKDS (Public Key Data Set). There are different flavours of PKI keys using different algorithm, and key sizes.
  • The ICSF API documentation refers to labels and tokens
    • Labels are a 64 character string used to identify the record in the +KDS.
    • Tokens represent the actual key, and is a structure (or blob of data). For example an AES token has information on the hash algorithm used, the encryption algorithm used, what sort of key it is (data, cipher, exporter). You can generate a token, use it, and not write it to the +KDS.
    • Sometimes a field in the API can be the label, or the token. If the length is 64 it is a label, otherwise it is a token.
  • Keys
    • Internal Keys in the +KDS are encrypted by a master level of encryption. If you you want to decrypt using a particular key. The (encrypted) key is extracted from the key store, and passed to the hardware encryption. The hardware decrypts the key, then uses it to decrypt the data. The unencrypted key does not leave the hardware.
    • External keys are keys that have not been encrypted, or are encrypted with a encrypted under a key-encrypting key (KEK) in the +KDS other than the master key. To use it you have to give the name/token of the KEK along with the name/token of external key.
  • You can say “extract the key, and encrypt it using another key before giving it to me”. You can then send the encrypted key to another system, which can decrypt the key and use it. The plain text of the key is never seen.
  • You can do things in the API which you are not authorised to do in the ISPF panels.
  • I was able to extract AES keys, encrypt them with Public/Private keys for transportation, and import them at the remote system. This is not considered good practice because the IBM cryptographic standards say you should keep keys used for encrypting data separate from those used to transmit keys. These are known as Key Transport Keys, and you have Exported and Importer keys. The documentation talks about Key Encryption Keys (KEKs) which is another name for the Key Transport Keys. You should have these for production, but I managed without them for my investigations. All these “keys” in a sentence made my head ache!

The hardest part

I found the hardest part about using ICSF was knowing which options to specify. For example you can use a public/private key to extract a key used for data set encryption, send it to the remote site, and decrypt it and add it to the system. How should you set it up? The answers are all in the documentation – somewhere, there is no getting started guide. The questions I had included:

What encryption technique and key strength should I use for data set encryption?

ICSF supports two techniques for symmetric encryption

  1. DES – Data Encryption Standard
  2. AES – Advanced Encryption Standard. This is often considered to be better than DES.

With each of these you can have different strength keys.

To encrypt data sets you need to use AES 256.

What sort of private/public key do I need

You can create a private/public pair of keys using

  1. RSA
    1. Modulus-exponent form (with a variety of different length modulus)
    2. Chinese Remainder Theorem(RCT) (with a variety of different length modulus)
  2. ECC (Elliptical curves)
    1. With a variety of curves: NIST, Prime, Brainpool
    2. And a variety of sizes
  3. CRYSTALS-Dilithium. Not having heard of this, I looked it up. It serves as a controlling agent in the faster than light warp drive in Star Trek, as well as being a technique for encryption.

Only RSA is supported to encrypt an AES key to send to a remote system using PKI.

What encryption technique should I use?

There are different ways of encrypting using an RSA key.

  1. PKCS–1.2 – RSA DSI PKCS #1 block type 02
  2. PKCSOAEP – RSA DSI PKCS #1V2 OAEP
  3. PKOAEP2 – RSA DSI PKCS #1 v2.1 RSAES-OAEP documentation (Not valid with DATA keys)

3. is better than 2. which is better than 1.

I use PKOAEP2 for CIPHER keys, and PKCSOAEP for DATA keys.

It would be very good if there was a documented decision tree giving the best advice on the options to use, along the lines of

  1. If you want to do data set encryption use AES256 and use CIPHER rather than DATA.
  2. If you want to encrypt a key to send to a remote system use RSA, with key size > … (eg 4096)
  3. …..

ICSF programming model

I had used the RACF callable services R_datalib (Certificate Data Library) to manage digital certificates. There is one module, and you pass parameters to define what to do, function_code = 0x01: get first, function code 0x0a: delete keyring. The parameters are similar.

With ICSF there are many functions, and the parameters are different. Although I was expecting a function “create public key and store it in the database with this name”, there may be times when you want to create a public key, use it and not store it in the database.

When you consider the options, using just one API does not work.

Low level functions

ICSF provides functions for each logical function. for example:

  1. create key (several flavours)
  2. store key in *KDS (several flavours)
  3. extract key (several flavours)
  4. encrypt data using this public key token (big blob of data), or use this label of a public key in the PKDS.

Rules

You pass configuration through to routines using “rules”. For example

typedef char char8[8];

int rule_count = 4 ;

char8 rule[ 4] ={ “AES “, “INTERNAL”, “CIPHER “, “ANY-MODE” };

These are like passing parameters through a command interface. It was easy to do – and worked well.

These parameters mean

  1. Create an AES key (the choice is AES or HMAC)
  2. Create an INTERNAL format token which will be used on this machine.
  3. Create a key with type of CIPHER. There is a choice of 8 options.
  4. ANY-MODE: Specifies that this key can be used for any encryption mode. The default is CBC:Specifies that this key can be used for cipher block chaining.

Using the rules was easy – finding which rules to use was hard (as I mentioned above).

Return and reason codes

Each function provides a return code, and a reason code. There is no service to call which returns a short string describing the error from the reason code. I wrote my own.

Exit programs

You can pass information through to an exit program – this feels like a very advanced topic. I haven’t used it.

Using the functions

The ICSF functions call stub services (which jump into the ICSF address space). These services do not have much function in them. You should not have to recompile your programs, or rebind them if you use a different level of ICSF.

C coding

With C routines you might code

printf(“the number is %\n”,i);

and pass “i” in.

With the stub interface you have to pass in the address of the variables for example

int zero = 0;

rc= CSNDPKB (&rc, &rs, &zero…)…

I found it easiest to put each ICSF function into its own function and call that, so hiding a lot of the ICSF API, and using common C techniques.

Rexx coding

It is pretty easy to write in Rexx. The hardest part is knowing which options to use.

The disadvantage of using Rexx, is that people could turn trace on, and display sensitive information.

Writing my own helper interface

I created routines like rc= skeletonAES(char ** pData, int * lData) {} to do the work, and return storage with the data in it.

Memory management: Within this routine I did a malloc() request for the storage. It passed the storage to ICSF, and returned the address back to the caller. I could have passed in a block of storage, but this means the higher level function needs to know length of the storage required. I think having the lower level function allocate the storage is better, because the routine knows the length it needs and makes it self contained.

int skeletonAES(char ** pData, int * lData) {

int lStorage = 725;
char *pStorage = malloc(lStorage);
CSNBKTB2(&rc, &rs,
…
     &zero,         /* service data length     */ 
     0,             /* service data[] ignored  */ 
     &lKeyToken,    /* target key token length */ 
     pKeyToken   ); /* target key token[]      */ 

*pData = pStorage;
* lData = lStorage;  // return the  true length 
                     //  of data returned.
return rc 
}

Once I had finished with the storage I could use free(…) to release the block.

What helper routines did I create?

I found it useful to create some helper routines.

Read the *KDS

rc=read(“C”,pKey, pData, lData );

rc= read(“P”,pKey, pData, lData );

to read the record and return a pointer to the data.
Internally

  • If “C” then use CSNBKRR2.
  • If “P” then use CSNDKRR.

I wrote some Rexx helper functions: readCKDS(label) and readPKDS(label), returning the return code, reason code, and the data.

doExists

rc=doExists(“C”,pKey );

rc= doExists(“P”,pKey );

to read the record and return if the record was not found.
If “C” then use CSNBKRR2.

If “P” then use CSNDKRR.

This is actually a wrapper around read, passing back the return code.

Add

rc = doAdd2(“C”,pKey,pReplace,Token ,lToken );

If “C” then use CSNBKRC2.

If “P” then use CSNDKRC.

If the add got the return code “already exists”, and pReplace = “yes” , then delete the record and retry the add.

In rexx I wrote addCKDS(label,data) and addPKDS(label,data).

PrintHex(stdout,pData,lData)

To print a dump like format of a block of storage.

PrintAES(pData,lData))

to print a summary of the AES token.

WriteKey

rc = writekey(dd,pData,lData)

This writes the data to a file specified by dd. Where dd is a string used in fopen, such as “dd:cert”.

The dataset was a variable length, with just one on record in it.

ReadKey

rc = readkey(dd,&pData,&lData)

This reads one record from the file specified by dd. Where dd is a string used in fopen, such as “dd:cert”. It allocates storage, and passes it back to the caller.

Other helpers

  • Export PKI public certificate
  • Import PKI public certificate
  • Create AES Skeleton for CIPHER (Variable format key)
  • Create AES Skeleton for DATA(Fixed format key)
  • Generate symmetric key using Diffi-Hellman
  • Export AES CIPHER key (Variable format key)
  • Export AES DATA key(Fixed format key)
  • Import AES CIPHER key (Variable format key)
  • Import AES DATA key(Fixed format key)

_____________________________________________________

4 thoughts on “ICSF – background to writing my first ICSF application.

  1. Just a thought (we already discussed this), you can also use EC-DH to derive an AES transport key. Using AESKW, you can use that derived transport key to share a key with other systems.

    Like

Leave a comment