Getting the z/OS standard image to work.

I had a lot of challenges getting the zD&T replacement (the standard image) to work. I do not know if this is the same image that every one else gets, or if mine was “a special” one. Some things did not work, somethings were not best practice.

I also wanted to use the data from my previous systems, my PDS, my Unix file systems, my keyrings etc. I also wanted to future proof migrating to the next code drop from IBM.

Summary of actions

Below is a list of the things I did to get the system up and working as I expected it to look.

I’ve grouped them by area. In the main body of the document, they are in the approximate order of execution

Problems

Customising

Before you start using it

Missing download and setting the IBMUSER password

The files on the IBM Passport Advantage site are incomplete. The documentation tells you do download the ZDTDPY volume, edit it to set the password, and boot the system. This download was not on the download site.

I had an old z/OS system I could use and so could reset the password. See Help, I cannot logon to my z/OS system

It is not difficult to write a C program to prompt for a password on the z/OS console – and have the value not displayed. See How do I enter a password on the z/OS console for my program?

I needed to configure my laptop

The IP address of z/OS is 172.26.1.2. I configured my startup script to have

#  define route from my laptop to my server
sudo ip route add 10.1.1.0/24 via 10.1.0.3

# define route from my laptop to z/OS on the server
sudo ip route add 172.26.1.0/24 via 10.1.0.3

# connect to the server
ssh -X colin@10.1.0.3

The sample devmap is wrong, it does not provide 3270’s

The system would not IPL with a console, the output came out printer like.

I edited the devmap file:

  • add the 3270port 3270. Without this you do not get any 3270’s defined, and you get a line printer like console.
  • Change the processors to match what your server has. My dongle has support for 3 CPUs – but I can define 3-1 ZIIPs
  • Check the memory to match you configuration
  • I removed the IPL and put it in my shell script.

The top of my devmap is

[system]
processors 5 cp cp cp ziip ziip # number of processors
memory 10G
system_name VS01

3270port 3270 # port number for TN3270 connections

First IPL

The IPL parameters are configured to start up lots of subsystems I didn’t want to use I used

ipl DE27 parm DE28AU

Logon with userid IBMUSER and the password you configured.

Configure parmlib

The sys0.iplparm points to loadxx members. You need a load member with USER.PARMLIB in it (such as LOADAU)

  • Copy LOADAU to LOADCP
  • In LOADCP change SYSPARM to SYSPARM AU,CP
  • In user.parmlib create IEASYSCP (CP matching the CP above)
  • add your parameters, such as OMVS=(CP) for IP(V6) support

You can IPL with this

ipl DE27 parm DE28CP

If this fails to IPL, to back to parm DE28AU

Add userids

The userid IBMUSER is all powerful. I prefer using a less powerful userid.

I wanted to save my userids from the previous system. I wrote code makeRACF. With this you run a program on your old system, and specify a userid or dataset prefix. The program then generates the RACF commands to recreate the userid or resource.

Because the TSO configuration is different from the previous zD&T systems I had to configure the definitions

TSO (ACCTNUM ('ACCT001') - 
COMMAND ('ex ''colin.zlogon.clist''') -
PROC (PROC001 ) -
SIZE (2096128) -
MAXSIZE (2096128) -
USERDATA (0000) -
UNIT (3390))

I created some definitions to my userid COLIN access to resources on the new system

ALTUSER COLIN SPECIAL AUDITOR OPERATIONS                             
ALTUSER COLIN DFLTGRP(SYS1)
ALTUSER COLIN tso( ACCTNUM('ACCT001') -
CoMMAND('ISPF') PROC(PROC001 ) -
SIZE(2096128) MAXSIZE(2096128) USERDATA(0000) UNIT(SYSDA))
permit ACCT001 class(ACCTNUM) id(COLIN ) access(READ )
permit ACCT# class(ACCTNUM) id(COLIN ) access(READ )
permit JCL class(TSOAUTH)id(COLIN) access(REAd)
permit CONSOLE class(TSOAUTH)id(COLIN) access(REAd)
permit PROC001 class(TSOPROC)id(COLIN) access(REAd)
permit ISPFPROC class(TSOPROC)id(COLIN) access(REAd)
setropts raclist(TSOAUTH) refresh
setropts raclist(ACCTNUM) refresh
setropts raclist(TSOPROC) refresh
PERMIT *.** CLASS(JESSPOOL) ID(COLIN) ACCESS(ALTER)
SETR RACLIST(JESSPOOL) REFRESH

I created JCL for these definitions, so for system refreshes, I just rerun the jobs.

I did not use the UNIX facility to allocate a (random) UID. I specified the UID I had before.

On the ZFS with my files, I needed the uid of the file owner to be the same as my users uid. If z/OS allocated me a uid, I would not be able to access my files. I would then have to go through and change the owner of them.

I recreated userids COLIN and START1.

You need to see what groups the userids belonged to, and you may need to recreate the groups, or just us what are already defined.

Import user catalogs

I have user catalogs for all of my data sets. These catalogs need to be imported into the master catalog

//IBMUSERT JOB 1,MSGCLASS=H                                           
//S1 EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
IMPORT CONNECT -
OBJECTS -
(('A4USR1.ICFCAT' VOLUME(A4USR1) DEVICETYPE(3390) -
))
/*

How do you find out what user catalogs you have?

On the old system.

//IBMUSERT JOB 1,MSGCLASS=H                               
//S1 EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//DD1 DD DISP=SHR,VOL=SER=D5SYS1,UNIT=3390
//SYSIN DD *
LISTCAT CATALOG(CATALOG.Z31B.MASTER) USERCATALOG ALL FILE(DD1)
/*

or

//IBMUSERT JOB 1,MSGCLASS=H                               
//S1 EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
LISTCAT USERCATALOG ALL
/*

The ALL Parameter also lists the Aliases using the user catalog.

Define aliases to map high level qualifier to a user catalog.

Once you have imported the catalogs you can define the data set aliases

//IBMUSERT JOB 1,MSGCLASS=H                                     
//S1 EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DEFINE ALIAS (NAME(BACKUP) RELATE('A4USR1.ICFCAT') )
DEFINE ALIAS (NAME(COLIN ) RELATE('A4USR1.ICFCAT') )
/*

What aliases do I have?

//IBMUSERT JOB 1,MSGCLASS=H                                         
//S1 EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
LISTCAT ALIAS
/*

Define user directories

For each file system, and each user, they need a directory defined. The standard image uses automount to create a ZFS for each entry in /u. If my RACF profile says my home directory is /u/colin, it will create a ZFS for this. If /u/colin already existed, it will not be used.

I created entries in /usr. If you try to make a directory, it may fail because /usr is mounted read only.

From userid IBMUSER to into Unix ( TSO OMVS)

  • mkdir /usr/colin
  • If this fails use
    • chmount -w /usr … do your work … chmount -r /usr
  • mkdir /usr/tmp
  • mkdir /usr/tmp/zowet
  • mkdir /usr/tmp/zowet/colin Userid COLIN has HOME= /usr/tmp/zowet/colin
  • You may need to change the ownership of the directory
    • chown -R colin:sys1 mkdir /usr/tmp/zowet/colin
  • If you need to…
    • chmount -r /usr

Mount the ZFS

Once I had imported the catalogs, and defined the aliases I could try to mount my ZFS

I created USER.PARMLIB(BPXPRMUS) and added

MOUNT FILESYSTEM('COLIN.ZFS.ZOWE.TEMP') TYPE(ZFS) 
MOUNTPOINT('/usr/tmp/zowet') MODE(RDWR)
PARM('AGGRGROW') AUTOMOVE

MOUNT FILESYSTEM('COLIN.ZOPEN.ZFS') TYPE(ZFS)
MOUNTPOINT('/usr/zopen') MODE(RDWR)
PARM('AGGRGROW') AUTOMOVE

The activate using the operator command

T OMVS=(US)

I was then able to logon to my newly created userid COLIN, and go into z/OS Unix.

Configure VTAM to give you greater than 80 *24 screen size

VTAM configuration

  • Edit SYS1.VTAMLST(EXLOCAL). You have to edit this because NET does not have USER.VTAMLST configured.
  • Create EXLOCALO from it (for backup)
  • change DLOGMOD to have value D4B32XX3,
  • create an entry for CUADDR=061,

Clean up

  • Edit SYS1.VTAMLST(ATCCON00). Remove IVPLCLI,IVPLCLT because the devices they reference do not exist.

If your changes to EXLOCAL do not work, use

V NET,ACT,ID=EXLOCALO

TCPIP

The provided TCPIP procedure creates certificates etc and does other work. It creates a new CA certificate, I need to export it, and sent it to my machines which connect in, and to all my keyrings.

I want to use the set up I have, so my TCPIP V6 Procedure is

USER.PROCLIB(TCPIP)

//TCPIP    PROC PARMS='CTRACE(CTIEZB00)' 
//TCPIP EXEC PGM=EZBTCPIP,PARM='&PARMS',REGION=0M,TIME=1440
//SYSPRINT DD SYSOUT=*
//SYSERR DD SYSOUT=*
//SYSERROR DD SYSOUT=*
//ERRORFIL DD SYSOUT=*
//SYSDEBUG DD SYSOUT=*
//PROFILE DD DISP=SHR,DSN=USER.TCPPARMS(PROFILE)
//SYSTCPD DD DISP=SHR,DSN=TCPIP.TCPPARMS(TCPDATA)

Support TCPIP V6

The TCPIP as shipped does not support IP V6. You need to create a BPXPRMxx member and activate it

You need a BPXPRMv6 member in user.parmlib

FILESYSTYPE TYPE(CINET) 
ENTRYPOINT(BPXTCINT)
SUBFILESYSTYPE NAME(TCPIP)
TYPE(CINET)
ENTRYPOINT(EZBPFINI)
DEFAULT
NETWORK DOMAINNAME(AF_INET6)
DOMAINNUMBER(19)
MAXSOCKETS(50000)
TYPE(CINET)

In USER.PARMLIB(IEASYSXX) use BPX=(V6).

In USER.TCPPARMS(PROFILE) I have

...
DATASETPREFIX TCPIP

TCPCONFIG TTLS
INCLUDE USER.TCPPARMS(IPV6)

...

and the IPV6 member has

IPCONFIG6 MULTIPATH

TCPIP Resolver

See Why is the wrong TCPIP Resolver proc being used?

Create USER.PROCLIB(RESOLVER)

//* TCPIP RESOLVER - COLINS 
//*
//RESOLVER PROC PARMS=CTRACE(CTIRES00)
//*
//EZBREINI EXEC PGM=EZBREINI,REGION=0M,TIME=1440,
// PARM=('&PARMS',
// 'ENVAR("RESOLVER_TRACE=/var/log/resolver"/')
//SETUP DD DISP=SHR,DSN=COLIN.TCPPARMS(GBLRESOL),FREE=CLOSE
//SYSTCPT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSOUT DD SYSOUT=*
//*

Create COLIN.TCPPARMS(GBLRESOL) with

Copy

  DEFAULTTCPIPDATA('COLIN.TCPPARMS(GBLTDATA)') 
GLOBALTCPIPDATA('COLIN.TCPPARMS(RESOLVE)')
# GLOBALTCPIPDATA(/etc/resolv.conf)
;
# -----------------------------------------------------------------
# Default zPDT Linux Base to z/OS Tunnel (Stand-Alone)
# -----------------------------------------------------------------
;
# GLOBALIPNODES(/etc/hosts)
GLOBALIPNODES('COLIN.TCPPARMS(HOSTS)')
....

Change the operator console PFKeys (to add the shutdown command)

See How do I change the PFKeys on the console?

Copy SYS1.PARMLIB(PFKTAB00) to USER.PARMLIB

  • Change PF12 to be PFK(12) CMD(“%NETV SHUTSYS”) CON(Y)
  • Change any other keys you fancy.

Fix SMF

Message HSF0066W

I was getting

HSF0066W Required exit IEFU86 for SMF subsystem SYS not enabled. Some data may be missing in SDSF event log.

Copy SYS1.PARMLIB(SMFPRM00) to USER.PARMLIB(SMFPRM00) add IEFU86

SYS(EXITS(IEFACTRT,IEFUJI,IEFU83,IEFU84,IEFU85,IEFUJV,IEFU86)), 
SUBSYS(STC,EXITS(IEFU83,IEFU84,IEFU85,IEFU29,IEFU86),
INTERVAL(SMF,SYNC))

Message IEE391A

IEE391A SMF ENTER DUMP FOR DATA SET ON VOLSER OPEVS1 DSN=SYS1.VS01.MAN1

Create in USER.PROCLIUB(SMFCLEAR)

//SMFCLEAR PROC MAN='SYS1.VS01.MAN1' 
//*
//* CLEAR SMF DATASET -
//* SMF MAN DATASET DUMPED REQUIRED MESSAGE RECIEVED
//* OR ISSUE SWITCH, I SMF, THEN THAT FILE WILL BE CLEARED
//*
//*
//DUMP1 EXEC PGM=IFASMFDP,REGION=1M
//INDD1 DD DSN=&MAN,DISP=SHR
//DUMPOUT DD DUMMY
//SYSPRINT DD SYSOUT=D
//SYSIN DD *
INDD(INDD1,OPTIONS(CLEAR))

Then you can use either of

S SMFCLEAR
S SMFCLEAR,MAN='SYS1.VS01.MAN2'

SETSMF command not enabled

I could not issue

setsmf recording(logstream)
setsmf recording(dataset)

setsmf recording(logstream)

commands, to be able to change the SMF LOGSTREAM.

I created USER.PARMLIB(SMFPRM00) from SYS1.PARMLIB and added AUTHSETSMF – it defaults to NONE.

...
DEFAULTLSNAME(IFASMF.VS01.DATA)
AUTHSETSMF
NOPROMPT,
REC(PERM),
,,,

Configure SYSLOGD

Define the started task

//IBMUSERT JOB 1,MSGCLASS=H 
//S1 EXEC PGM=IKJEFT01,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
RDEFINE STARTED SYSLOGD.* STDATA(USER(IBMUSER))
SETR RACLIST(STARTED) REFRESH

SYSLOGD is used by many Unix processes for recording errors and other information.

Create USER.PROCLIB(SYSLOGD)

//SYSLOGD PROC 
//* Licensed Materials - Property of IBM *
//* "Restricted Materials of IBM" *
//* 5650-ZOS *
//* Copyright IBM Corp. 1992, 2013 *
//* Read parms from /etc/syslog.conf
//CONFHFS EXEC PGM=SYSLOGD,REGION=4096K,TIME=NOLIMIT,
// PARM='ENVAR(''CEE_ENVFILE_S=DD:STDENV'')/-c -i '
//STDENV DD DISP=SHR,DSN=USER.PROCLIB(SYSLOGDD)
//SYSPRINT DD SYSOUT=*
//SYSIN DD DUMMY
//SYSERR DD SYSOUT=*
//SYSOUT DD SYSOUT=*
//CEEDUMP DD SYSOUT=*

Create USER.PROCLIB(SYSLOGDD)

I have

*.INETD*.*.*       /var/log/inetd.log 
auth.* /var/log/auth.log
mail.* /var/log//mail -F 640 -D 770
local1.err /var/log/local1.log
*.err /var/log/errors.log
# *.CPAGENT.*.* /var/log/CPAGENT.log
*.CPATTLS.*.* /var/log/CPATTLS
*.TTLS*.*.* /var/log/TTLS.log
*.Pagent.*.* /var/log/Pagent.log
*.TCPIP.*.debug /var/log/TCPIPdebug.log
*.TCPIP.*.warning /var/log/TCPIP.log
*.TCPIP.*.err /var/log/TCPIPerr.log
*.TCPIP.*.info /var/log/TCPIPinfo.log
*.SYSLOGD*.*.* /var/log/syslogd.log
*.TN3270*.*.* /var/log/tn3270.log
*.SSHD*.*.* /var/log/SSHD.log
*.FTPD*.*.* /var/log/FTPD.log
daemon.debug /var/log/SSHDdebug.log
*.TCPIP.*.none;
*.err /var/log/errors
*.CPAGENT.*.* /var/log/CPAGENT.log
*.TRMD1.*.info /var/log/TRMD1I.log
*.DMD.*.* /var/log/DMD.log

You can use this as a basis and change it as needed.

Configure SSHD

The SSHD procedure in SYS1.PROCLIB, invokes a shell script which then spawns the SSHD code with a name like SSHD.

I use

//SSHD    PROC 
//SSHD EXEC PGM=BPXBATCH,REGION=0M,TIME=NOLIMIT,
// PARM='PGM /usr/sbin/sshd -f /etc/ssh/sshd_config '
//* PARM='PGM /bin/sh -c /etc/ssh/sshd.sh'
//* STDIN AND STDOUT ARE BOTH DEFAULTED TO /dev/null
//STDERR DD PATH='/tmp/sshd.stderr',PATHOPTS=(OWRONLY,OCREAT,OAPPEND),
// PATHMODE=(SIRWXU)
//STDOUT DD PATH='/tmp/sshd.stdout',PATHOPTS=(OWRONLY,OCREAT,OAPPEND),
// PATHMODE=(SIRWXU)

Note that SSHD uses the /etc/ssh/sshd_config directory. You should back this up regulary. When IBM replaces the image this would be replace

After thought, I could always use -f /usr/colin/ssh/

Edit the configuration file and add either userids or groups.

# Allow specific user IDs 
AllowUsers IBMUSER COLIN
AllowGroups SYS1 IZUADMIN

If you add groups and not userids, you need to connect the userid to a group.

RACF changes

You can issue some racf commands on the z/OS console for example

<RVARY

To change this character (<) copy SYS1.PARMLIB(IEFSSN00) to USER.PARMLIB(IEFSSN01) and change the entry for RACF.

Define IXGLOGR as a started task to eliminate security messages

//IBMIXL  JOB 1,MSGCLASS=H 
//STEPNAME EXEC PGM=IKJEFT01
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
* IXGLOGR EXISTS AS A GROUP - IT REALLY SHOULD BE A USERID
ADDUSER IXGLUSER
CONNECT IXGLUSER GROUP(IXGLOGR)
RDEFINE STARTED IXGLOGR.* STDATA(USER(IXGLUSER) +
PRIVILEGED(YES) TRUSTED(YES) GROUP(IXGLOGR ))
SETROPTS RACLIST(STARTED) REFRESH
/*

Add missing groups

To protect datasets such as SYS1.*, the high level qualifier should be defined as a group. I have JCL ADDGROUP

//IBMKEY2 JOB 1,MSGCLASS=H 
//STEPNAME EXEC PGM=IKJEFT01
//SYSTSIN DD *
ADDGROUP SYS1
ADDGROUP ADCD
ADDGROUP AOK
ADDGROUP AOP
ADDGROUP AZD
ADDGROUP BBL
ADDGROUP CATALOG
ADDGROUP CBC
ADDGROUP CEE
ADDGROUP CFZ
ADDGROUP CNJ
ADDGROUP COUPLE
ADDGROUP CSD
ADDGROUP CSF
ADDGROUP CSQARC1
ADDGROUP CSQARC2
ADDGROUP EUVF
ADDGROUP FEU
ADDGROUP FEU1
ADDGROUP FFST
ADDGROUP GDDM
ADDGROUP GIM
ADDGROUP GLD
ADDGROUP GSK
ADDGROUP GTFNO
ADDGROUP GTFRACF
ADDGROUP HAP
ADDGROUP HLA
*DDGROUP IBMUSER
ADDGROUP ICQ
ADDGROUP IOE
ADDGROUP ISF
ADDGROUP ISP
ADDGROUP IXGLOGR
ADDGROUP IZU
ADDGROUP IZUSVR
ADDGROUP NETVIEW
ADDGROUP NFS
ADDGROUP SMPE
ADDGROUP STCJMON
ADDGROUP SYT1
ADDGROUP TCPIP
ADDGROUP USER
ADDGROUP ZFS
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=* g

Protect system data sets

You should define profiles for all datasets. I had a a member ADDSD.

//IBMKEY2 JOB 1,MSGCLASS=H 
//STEPNAME EXEC PGM=IKJEFT01
//SYSTSIN DD *
ADDSD 'SYS1.**' GENERIC UACC(READ) WARNING
PERMIT 'SYS1.**' ACCESS(ALTER) ID(SYS1)
ADDSD 'ADCD.**' GENERIC UACC(READ) WARNING
ADDSD 'AOK.**' GENERIC UACC(READ) WARNING
ADDSD 'AOP.**' GENERIC UACC(READ) WARNING
ADDSD 'AZD.**' GENERIC UACC(READ) WARNING
ADDSD 'BBL.**' GENERIC UACC(READ) WARNING
ADDSD 'CATALOG.**' GENERIC UACC(READ) WARNING
ADDSD 'CBC.**' GENERIC UACC(READ) WARNING
ADDSD 'CEE.**' GENERIC UACC(READ) WARNING
ADDSD 'CFZ.**' GENERIC UACC(READ) WARNING
ADDSD 'CNJ.**' GENERIC UACC(READ) WARNING
ADDSD 'COUPLE.**' GENERIC UACC(READ) WARNING
ADDSD 'CSD.**' GENERIC UACC(READ) WARNING
ADDSD 'CSF.**' GENERIC UACC(READ) WARNING
ADDSD 'CSQARC1.**' GENERIC UACC(READ) WARNING
ADDSD 'CSQARC2.**' GENERIC UACC(READ) WARNING
ADDSD 'EUVF.**' GENERIC UACC(READ) WARNING
ADDSD 'FEU.**' GENERIC UACC(READ) WARNING
ADDSD 'FEU1.**' GENERIC UACC(READ) WARNING
ADDSD 'FFST.**' GENERIC UACC(READ) WARNING
ADDSD 'GDDM.**' GENERIC UACC(READ) WARNING
ADDSD 'GIM.**' GENERIC UACC(READ) WARNING
ADDSD 'GLD.**' GENERIC UACC(READ) WARNING
ADDSD 'GSK.**' GENERIC UACC(READ) WARNING
ADDSD 'GTFNO.**' GENERIC UACC(READ) WARNING
ADDSD 'GTFRACF.**' GENERIC UACC(READ) WARNING
ADDSD 'HAP.**' GENERIC UACC(READ) WARNING
ADDSD 'HLA.**' GENERIC UACC(READ) WARNING
ADDSD 'IBMUSER.**' GENERIC UACC(READ) WARNING
ADDSD 'ICQ.**' GENERIC UACC(READ) WARNING
ADDSD 'IOE.**' GENERIC UACC(READ) WARNING
ADDSD 'ISF.**' GENERIC UACC(READ) WARNING
ADDSD 'ISP.**' GENERIC UACC(READ) WARNING
ADDSD 'IXGLOGR.**' GENERIC UACC(READ) WARNING
ADDSD 'IZU.**' GENERIC UACC(READ) WARNING
ADDSD 'IZUSVR.**' GENERIC UACC(READ) WARNING
ADDSD 'NETVIEW.**' GENERIC UACC(READ) WARNING
ADDSD 'NFS.**' GENERIC UACC(READ) WARNING
ADDSD 'SMPE.**' GENERIC UACC(READ) WARNING
ADDSD 'STCJMON.**' GENERIC UACC(READ) WARNING
ADDSD 'SYT1.**' GENERIC UACC(READ) WARNING
ADDSD 'TCPIP.**' GENERIC UACC(READ) WARNING
ADDSD 'USER.**' GENERIC UACC(READ) WARNING
ADDSD 'ZFS.**' GENERIC UACC(READ) WARNING
PERMIT 'ADCD.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'AOK.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'AOP.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'AZD.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'BBL.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CATALOG.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CBC.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CEE.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CFZ.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CNJ.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'COUPLE.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CSD.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CSF.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CSQARC1.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CSQARC2.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'EUVF.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'FEU.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'FEU1.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'FFST.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'GDDM.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'GIM.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'GLD.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'GSK.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'GTFNO.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'GTFRACF.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'HAP.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'HLA.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'IBMUSER.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'ICQ.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'IOE.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'ISF.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'ISP.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'IXGLOGR.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'IZU.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'IZUSVR.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'NETVIEW.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'NFS.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'SMPE.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'STCJMON.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'SYT1.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'TCPIP.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'USER.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'ZFS.**' ACCESS(ALTER) ID(SYS1)
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*

You should have started tasks defined

Started tasks should be defined, so end users cannot just create a Started Task, and run it as an authorised task.

Define a default

//IBMKEY2 JOB 1,MSGCLASS=H 
//STEPNAME EXEC PGM=IKJEFT01
//SYSTSIN DD *
RDEFINE STARTED *.* OWNER(IBMUSER) +
DATA('GENERIC DEFINITION - COLIN') +
STDATA( USER(=MEMBER)
SETROPTS RACLIST(STARTED) REFRESH

Export certificates and keyrings

I have member EXPRING. this runs the LRING Rexx which creates a data set containing certificates used by the userid. They are stored in &USERID..CERTS.START1

//IBMKEYR JOB 1,MSGCLASS=H 
//STEPNAME EXEC PGM=IKJEFT01,PARM='LRING START1',REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSEXEC DD DISP=SHR,DSN=USER.Z31B.CLIST
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD DUMMY

Import certificates and keyrings

Use the Rexx program to export certificates from your old system, and import them into the new system.

Import

//IBMKEYR JOB 1,MSGCLASS=H
//STEPNAME EXEC PGM=IKJEFT01,PARM='IRING COLIN.CERTS.START1',
// REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSEXEC DD DISP=SHR,DSN=USER.Z31B.CLIST,UNIT=3390,VOL=SER=B3CFG1
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD DUMMY

RRS Error messages

At the start up of RRS I got

ATR132I RRS LOGSTREAM CONNECT HAS FAILED FOR
– OPTIONAL LOGSTREAM ATR.VS01.ARCHIVE.
– RC=00000008, RSN=0000080B

See here

Issue the operator command

SETRRS ARCHIVELOGGING,DISABLE 

ICSF

ICSF

I have my own (I)CSF data sets, containing my keys. My Started Task JCL is the same as the default, but with a different member

//CSF  PROC PRM=CP 
//CSF EXEC PGM=CSFINIT,PARM=&PRM,REGION=0M,TIME=1440,MEMLIMIT=NOLIMIT

You could use the provided JCL, then stop and restart CSF

P CSF
S CSF,PRM=CP

The PARM=CP points to a member CSFPRMCP in USER.PARMLIB. Mine has

CKDSN(COLIN.SCSFCKDS) 
PKDSN(COLIN.SCSFPKDS)
TKDSN(COLIN.SCSFTKDS) qq
DOMAIN(0)
SSM(YES)
KEYARCHMSG(YES)

If this member does not exist you get an abend

IEF764I CSF CSF IEFPARM CSFMIOPD HCR77F0 PARMLIB READ FAILED - MEMBER CSFPRMCP NOT FOUND.        
CSFO0016 ERROR OCCURRED OPENING OPTIONS FILE. MEMBER CSFPRMCP IN DDNAME IEFPARM RC=12 RS=1.
...
DUMP TITLE=COMPON=CSF...ABEND=S018F,REASON=0000001B

Logrec EREP

When LOGREC fills up, you get a retained message on the console.

You can print the contents of the EREP file using

//PRINTLOG JOB (ACCT),'PRINT LOGREC',CLASS=A,MSGCLASS=H           
//STEP EXEC PGM=IFCEREP1,PARM='CARD'
//SERLOG DD DISP=SHR,DSN=VSPROV.VS01.LOGREC
//DIRECTWK DD UNIT=SYSDA,SPACE=(CYL,10,,CONTIG)
//EREPPT DD SYSOUT=A,DCB=BLKSIZE=133
//TOURIST DD SYSOUT=A,DCB=BLKSIZE=133
//ZERLOG DD SYSOUT=A,DCB=BLKSIZE=133
//SYSIN DD *
PRINT=PS
ACC=N
ZERO=Y
ENDPARM
/*

and clear it using a procedure in USER.PROCLIB(CLLOGREC)

//CLLOGREC  PROC 
//STEP1 EXEC PGM=IFCDIP00
//SERERDS DD DISP=OLD,DSN=VSPROV.VS01.LOGREC,
// UNIT=3390,VOL=SER=OPEVS1

and the started task definition in STLOGREC

//IBMUSERT JOB 1,MSGCLASS=H 
//S1 EXEC PGM=IKJEFT01,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
RDEFINE STARTED CLLOGREC.* STDATA(USER(IBMUSER))
RDEFINE STARTED PRLOGREC.* STDATA(USER(IBMUSER))
SETR RACLIST(STARTED) REFRESH

JAVA message and SMFLIM

I was getting messages

JVMJ9VM015W Initialization error for library j9shr29(11): JVMJ9VM009E J9VMDllMain failed
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

See JVMJ9VM015W Initialization error for library j9shr29(11): JVMJ9VM009E J9VMDllMain failed

I created USER.PARMLIB(SMFLIM00) with

REGION JOBNAME(JCACHER) JOBMSG(ISSUE) MAXSHARE(80000) 

SMF logstream data sets are too small

Im getting message allocating data sets like IXGLOGR.IFASMF.VS01.DATA… every couple of minutes.

The log stream is define with

LOGSTREAM NAME(IFASMF.VS01.DATA) STRUCTNAME() LS_DATACLAS()
LS_MGMTCLAS() LS_STORCLAS() HLQ(IXGLOGR) MODEL(NO) LS_SIZE(500)
STG_MGMTCLAS() STG_STORCLAS() STG_DATACLAS() STG_SIZE(500)
LOWOFFLOAD(0) HIGHOFFLOAD(80) STG_DUPLEX(YES) DUPLEXMODE(UNCOND)
RMNAME() DESCRIPTION() RETPD(2) AUTODELETE(YES) OFFLOADRECALL(YES)
DASDONLY(YES) DIAG(NO) LOGGERDUPLEX() EHLQ(NO_EHLQ) GROUP()
MAXBUFSIZE(65532)

Where LS_SIZE(500) is 45 tracks.

I used JCL

//IBMLOG JOB 1,MSGCLASS=H                                   
//LOGDEF EXEC PGM=IXCMIAPU,REGION=4M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DATA TYPE(LOGR) REPORT(YES)
UPDATE LOGSTREAM NAME(IFASMF.VS01.DATA)
LS_SIZE(15000)
/*

I could not run this, because the log stream was in use.

I had to create an USER.PARMLIB(SMFPRMNO) with

ACTIVE, 
DSNAME(SYS1.VS01.MAN1,
SYS1.VS01.MAN2),
RECORDING(DATASET)
DEFAULTLSNAME(IFASMF.VS01.DATA)
...

Then use

T SMF=NO

The run the command to update the logstream

and then switch back

T SMF=00

What’s next?

That’s as far as I’ve got. As I do more I’ll update this document.

Testing multi system ICSF on a single system.

I only have a single z/OS image, and as part of testing ICSF in a multi system environment, I needed a second ICSF environment. I am the only user on my system, so I can stop and start ICSF as I please.

I set up a second set of ICSF datasets, and a second CSPRMxx parmlib member. I then used

P CSF
S CSF,PRM=C2
D ICSF,KDS

The D ICSF,KDS command, tells you what ICSF data sets are being used.

When using CSFKGUP I was careful to specify the correct dataset

//STEP10 EXEC PGM=CSFKGUP
// SET CKDS=COLIN.SCSFCKDS.NEW

To go back to my primary system.

P CSF
S CSF

What ICSF APIs do I need to use for AES CIPHER keys

I’ve done a lot of work using ICSF to generate keys programmatically for data set encryption, and I found it hard to remember what the different APIs are,and what options to specify. This blog post covers the main APIs.

AES keys are better than DES keys, because they are more secure (take longer to break) and use less CPU.

There are different key tokens formats within ICSF. AES uses a variable key format. Within AES keys you can have types

  • CIPHER used for encrypting data – such as data set encryption
  • EXPORTER and IMPORTER, these are used to encrypt keys for sending to remote systems. They are known as Key Encrypting Keys.
  • DATA – CIPHER keys are better than DATA because they have more granular control. You can say a CIPHER key can be used to encrypt an AES key – but not a DES key. With DATA it is all or nothing.
  • Others – I haven’t played with these

For many APIs you can give the name of a token in the CKDS data set. The names are 64 characters long. You can also use a copy of a token in memory, for example your program reads a token from the CKDS, or you have been sent a token from a remote systems. These will have a length typically shorter than 64 characters. ICSF uses the length you specified to determine what information is being passed in.

Generating a key token

You can use CSNBKGN2 (Key Generate2) to generate a key token.

You can specify type CIPHER. This generates a key token using some defaults. The defaults are not suitable for generating keys for data set encryption.

You can specify type TOKEN. You pass a skeleton token key with some of the options specified. You could generate this yourself, setting all of the bits you need, but it is easier to use the Key Token Build2 (CSNBKTB2) API to generate the key token. For example you specify rule options as character strings such as “CIPHER”,”XPRTCPAC”,”ANY-MODE”, which are needed for data set encryption.

You can specify the hex string to be used as the key value, by using the skeleton. You specify clear_key_bit_length and the clear_key_value. If clear_key_bit_length is zero in the skeleton, no key value is used and the system generates a random value. You will need to specify a valid value in the Key Generate2 field clear_key_bit_length. If you want to specify the hex value, set the two clear_key_bit_length fields to the same value in CSNBKTB2 and CSNBKGN2.

You can create a key token for use

  • on the current system. Once you have successfully generated your key token, you can use it to encrypt data, but you are more likely to store it in the local PKDS service using the PKDS Key Record Create (CSNDKRC) API. You might need to use the Key Record Delete (CSNDKRD) API if the key already exits in the PKDS. There is no write with replace service.
    • At a later date you can use the ICSF API to extract the key and encrypt with an EXPORTER or IMPORTER key to send to a remote site
  • and/or you can get a copy encrypted with a Key Exporting Key (EXPORTER or IMPORTER) so it can be securely sent to another site. You can
    • export it using an EXPORTER Key Encrypting Key to send to a remote site.
    • export it using an IMPORTER key, so it can be imported into the local system at a later date. I do not think this is a common scenario.

List the CKDS

You can search the CKDS passing various criteria using function Key Data Set List (CSFKDSL). It returns the label of each record matching the criteria. For each record you can use Key Data Set Metadata Read (CSFKDMR) which displays information such as create time, and if it is archived or not. You can read the record from the CKDS using CKDS Key Record Read2 (CSNBKRR2). The actual key value is encrypted, but there are many fields which are available, such as this is an AES CIPHER key.

You can get the size of the key value within the token using the Key Test2 (CSNBKYT2) API, with the KEY-LEN option.

Get the checksum of the token

There is an API to get the checksum of a token. (I do not think this checksum is stored in the token, as you can specify different algorithms.) If you send the token to a remote system, you can check the checksum is the same as the original, and that the token has not been changed. The Key Test2 (CSNBKYT2) API, with the GENERATE option, returns the checksum value. You can specify which algorithm to use, for example SHA-256 or ENC-ZERO. There is a VERIFY option which seems to compare the value you pass with the calculated value, and if they do not match gives reason code 9000.

Reading a key from the CKDS

You can use the CKDS Key Record Read2 (CSNBKRR2) API to read a record from the CKDS into memory. There is an API CKDS Key Record Read (CSNBKRC2) which reads old format records from the CKDS.

Using ICSF API function CSNBKGN2 to generate keys

The ICSF function CSNBKGN2 allows you to generate keys for encrypting data (such as data sets) where you can

  • specify the hex data for the key value
  • have ICSF generate the key value securely so that the key value is never exposed as clear text.

Once a key has been created the key value will either be encrypted with the hardware key of the cryptographic hardware the program is running on, or is encrypted with Key Encryption Key, so it can be securely sent to a remote system.

You can generate a key in two modes:

  1. For use on the local system. This is known as the OP mode, because the cipher key is OPerational immediately. You can use it immediately to encrypt data, or you can use another ICSF function to write the key data to the CKDS. Once it has been written to the CKDS, you can refer to and use it by its label. At a later date you can extract the key and encrypt with another key for sending to a remote system.
  2. Encrypted under a transport key, called a Key Encrypting Key (KEK) an EXporter or IMporter key). You can write the created key to a file, send the file to a remote system, and then use an ICSF function(CSNDSYI2) to (decrypt it and re-encrypt it with the hardware key) and then write it to that systems CKDS. This is mode EX or IM.

The documentation for CSNBKGN2 has information about all of the options, but it is not very clear on how to use it!

I found it easier to understand the concepts, and to use, if I used two steps; generate a cipher key and then export it from the CKDS using a KEK, rather than trying to generate a cipher key for local use and encrypt it with a KEK in a single API call (point 3. below).

The CSNBKGN2 function has several modes:

  1. Generate a cipher key which you can use to encrypt data. This is known as the OP mode, because the cipher key is OPerational immediately.
  2. Generate a cipher key which is encrypted with a Key Encrypting Key. This is mode EX or IM.
  3. Generate a key you can use to encrypt data – both in OP mode, and generate the same key encrypted with a KEK, so you can send it somewhere. This is a combination of 1. and 2. in one API request (You specify mode = OPEX or mode = OPIM).
  4. Generate an exporter/importer pair of keys for encrypting other keys.
    • One of the pair is (usually) created so it can be used immediately, or written to the CKDS. This is known as the OP mode.
    • The other is encrypted with an existing Key Exporting Key. This is mode EX or IM.
    • The combined mode is OPEX or OPIM.

CSNBKGN2 provides some defaults which are suitable for some keys, but not suitable for AES CIPHER keys used to encrypt data sets.

You can create a skeleton key using CSNBKTB2, to specify non default parameters, and get CSNBKGN2 to use the skeleton. If you want to restrict what a key can do, you will need to use the skeleton. For example you can say this exporter/importer key pair can be used to encrypt AES keys, but not DES keys. For more information see the documentation. You tell CSNBKGN2 to use a skeleton by using the TOKEN keyword instead of CIPHER, EXPORTER, or IMPORTER.

Guidance on using CSNBKGN2

Lengths of data

When using some values such as KEKs, you can specify a key name in the CKDS of length 64 bytes. You can also read the key token from CKDS yourself (or get the key token from somewhere else). In this case the length you specify of the KEK may be ignored and the length of the data in the key token is used.

If an ICSF function provides you a key token, it will check your buffer is big enough, and return the length it used.

The function complains if you give a length field more than the maximum value. So when the documentation says generated_key_identifier_2_length is the maximum value is
900 bytes.
You must provide an area of the specified size, because it will complain if a different size is used.

Terms

The documentation uses the term generator key identifier. I think of this as the skeleton input.

My basic use of CSNBKGN2

Because of many parameters, I’ll give an example of my “standard” usage. The documentation gives the syntax

CALL CSNBKGN2(
return_code,
reason_code,
exit_data_length,
exit_data,
rule_array_count,
rule_array,
clear_key_bit_length,
key_type_1,
key_type_2,
key_name_1_length,
key_name_1,
key_name_2_length,
key_name_2,
user_associated_data_1_length,
user_associated_data_1,
user_associated_data_2_length,
user_associated_data_2,
key_encrypting_key_identifier_1_length,
key_encrypting_key_identifier_1,
key_encrypting_key_identifier_2_length,
key_encrypting_key_identifier_2,
generated_key_identifier_1_length,
generated_key_identifier_1,
generated_key_identifier_2_length,
generated_key_identifier_2 )f

Some constants I frequently use.

int rule_count = 2;
char * pKeyType1 = "EXPORTER";
char * pKeyType2 = "IMPORTER";
int lKey1 = 64;
int lKey2 = 64;
char KeyName1[64] ...
char KeyName2[64] ...
int lKekName = 64;
char KekName[64] ....
int lData1 = 900;
char data1[lData1];
char * pData1 = &data1[0];
int lData2 = 900;
char data2[lData2];
char * pData2 = &data2[0];

I used the parameters to CSNBKGN2 to define an Exporter/Importer

  • Return code &rc,
  • Reason code &rs,
  • exit data length 0
  • exit data array 0. This is not used because the previous field gives the length as 0.
  • &rule_count, this had the value 2 because pRule below pointed to two parameters.
  • pRule this pointed to {AES, OPEX}. AES is the type of cipher; OPEX says generate the first one so it can be written to the local CKDS, EX says use the second Key Exporting Key – which has a type of EXPORTER.
  • &keyBitLength keyBitLength has the value 256. This specifies how secure to make the cipher.
  • pKeyType1 where KeyType1 was EXPORTER.
  • pKeyType2 where KeyType2 was IMPORTER.
  • &lKey1 value 64. This is the length of the string following – the value of the key name stored in the first key. Set this to zero if you do not want a name stored in the first generated key.
  • &KeyName1[0], the address of the 64 char name to be stored in the first key. You can specify 0 if the length value is 0. This name becomes part of the key data. It needs to be unique within the CKDS.
  • &lKey2 value 64. This is the length of the string following – the value of the key name stored in the second key. Set this to zero if you do not want a name stored in the second generated key
  • &KeyName2[0], the address of 64 char name to be stored in the second key. You can specify 0 if the length value is 0.
  • 0, user associated data length for the first key.
  • 0 not used if the length is zero.
  • 0, user associated data length for the second key.
  • 0 not used if the length is zero.
  • 0,
  • – length of the KEK for the first key. Because the rule was OPEX – the first key is to be stored in the local CKDS and so does not have a KEK.
  • 0 this KEK is not used.
  • &lKekName lKekName has the value 64.
  • &KEK[0] this is the address of the first character of the Key Encrypting Key. It must be padded with blanks to 64 characters.
  • &lData1 the value 900 which is the length of the storage pointed to by pData1 for the first generated key. This storage is 900 characters long. If a smaller value is used, I got rc 8 rs 11000 Invalid length for a key token, key, or text field even though the returned data was less than 120 bytes long.
  • pData1 pointer to the first skeleton, which is also the area where the first key is returned. This storage is 900 characters long.
  • &lData2 the value 900, which is the length of the storage pointed to by pData2 for the second generated key. This storage is 900 characters long. The length of the data is returned here. If a smaller value is used, I got rc 8 rs 11000 Invalid length for a key token, key, or text field even though the returned data was less than 120 bytes long.
  • pData2 pointer to the second skeleton, which is also the area area where the second key is returned. This storage is 900 characters long.

Generate a CIPHER key using Key Generate 2 (CSNBKGN2) directly

I used the following parameters in CSNBKGN2. (See below for all of the typical parameters I specify.) The character values have been formatted for display, they are 8 byte characters, padded on the left with blanks.

  1. rule = {“AES”,”OP” }
  2. KeyType1 = “CIPHER”
  3. keyBitLength 256
  4. kek lengths = 0; no KEK is used (because it will be used/stored on this system)

This created a key, but I could not use it because it defaults to Key Usage CBC, when ANY_MODE is required for data set encryption.

Generate a CIPHER key using a skeleton and Key Generate 2

You need to use Key Token Build CSNBKTB2 if you want to use any of the non default options. For example

Key Token Build CSNBKTB2 parameters

  1. rule_count = 5;
  2. rule = {“EXTERNAL”,”AES “,”CIPHER “, “XPRTCPAC”,”ANY-MODE” }

The “XPRTCPAC”,”ANY-MODE” parameters are required if data set encryption is used

CSNBKTB2 returns an internal format key, which can be used by CSNBKGN2.

CSNBKGN2 parameters

  1. rule_count = 2;
  2. rule = {“AES “,”OP “};
  3. keyType1 = “TOKEN”. This says use the skeleton value in the generated_key_identifier_1 field.
  4. kek lengths = 0; no KEK is used (because it will be used/stored on this system).
  5. generated_key_identifier_1_length 900 (in this case).
  6. generated_key_identifier_1 address of my skeleton data.
  7. generated_key_identifier_2_length 0 – we are not generating a second parameter.
  8. generated_key_identifier_2 0 – this value is ignored.

Generation two CIPHERs one for local, one for remote.

To generate the skeletons

  1. Rule_count = 5;
  2. Rule1 = {“INTERNAL”,”AES “,”CIPHER “, “XPRTCPAC”,”ANY-MODE” }
  3. Rule2 = {“EXTERNAL”,”AES “,”CIPHER “, “XPRTCPAC”,”ANY-MODE” }

CSNBKGN2 parameters

  1. pOPRule = {“AES”,”OPIM “};
  2. keyType1 = “TOKEN”. This says use the skeleton value in generated_key_identifier_1. Skeleton 1 was defined with CIPHER.
  3. keyType2 = “TOKEN”. This says use the skeleton value in generated_key_identifier_2. Skeleton 2 was defined with CIPHER.
  4. kek length1 = 0; no KEK is used (because it will be used/stored on this system).
  5. kek length2 = 64 ; A KEK is used. The name of an IMPORTER KEK.
  6. generated_key_identifier_1_length 900
  7. generated_key_identifier_1 address of my skeleton data, and where the data is returned.
  8. generated_key_identifier_2_length 900.
  9. generated_key_identifier_2 address of my skeleton data, and where the data is returned.

I created one OPerational copy which I wrote to the local PKDS, and an encrypted copy which I wrote to a data set using fwrite(). On the remote system I used fread() toread the file, and used the IMPORTER key to import it into the PKDS. This is the OPIM in the rules.

Generating an importer/exporter pair

In the examples above they just generated a CIPHER for the local system. You can use CSNBKGN2 to generate a key an IMPORTER/EXPORTER pair.

It creates one of the keys in a form that can be added directly to the CKDS, and creates the opposite key, encrypted by a KEK. This means you can write it to a dataset, send the data set to the remote system, and import it using the KEK’s importer key.

To generate the skeletons

  1. Rule_count = 3;
  2. Rule1 = {“INTERNAL”,”AES “,”IMPORTER” }
  3. Rule2 = {“EXTERNAL”,”AES “,”EXPORTER” }

CSNBKGN2 parameters

  1. pOPRule = {“AES”,”OPEX”};
  2. keyType1 = “TOKEN”. This says use the skeleton value. Skeleton 1 was defined with EXPORTER.
  3. keyType2 = “TOKEN”. This says use the skeleton value. Skeleton 2 was defined with IMPORTER
  4. kek length1 = 0; no KEK is used (because it will be used/stored on this system).
  5. kek length2 = 64 ; A KEK is used. The name of an EXPORTER KEK.
  6. generated_key_identifier_1_length 900
  7. generated_key_identifier_1 address of my skeleton data, and where the data is returned.
  8. generated_key_identifier_2_length 900.
  9. generated_key_identifier_2 address of my skeleton data, and where the data is returned.

I used the ICSF function CSNBKRC2 to write the first generated key to the CKDS.

I wrote the second generated key to a file using fwrite() . I could send this file to a remote site, then use CSNDSYI2 with the IMPORTER version of the KEK to process the data into a key for local use, then write it to the CKDS using CSNBKRC2.

Which options produce what output?

  • With EX in the rule OPEX, and an EXPORTER Key Exporting Key it worked.
  • With IM in the rule OPIM, and an EXPORTER key, I got Key not found, because it was searching for keyname of type IMPORTER, when only key name with type EXPORTER was present.
  • With IM in the rule OPIM, and an IMPORTER key, I got reason code 10040 Key identifiers contain a version number.
  • You can use OPIM for CIPHER keys, but not IMPORTER or EXPORTER. See the list of valid combinations.

Setting up ICSF on z/OS

ICSF provides many functions. One function is to manage keys encryption and decryption.

As well as providing encryption etc, it can provide tokens to access encryption keys.

  • ICSF public and private keys are stored in the Public Key Data Set (PKDS)
  • ICSF Cryptographic keys that are encrypted are stored in the Cryptographic Key Data Set(CKDS)
  • ICSF PKCS #11 tokens and objects are stored in Token Key Data Set

There is a batch interface for some command, and ISPF interface using @ICSF, and an API.

The instructions below are a “get you going”. You can protect you keys see Maintaining cryptographic keys.

Create the datasets

Create the CKDS

//IBMCKDS   JOB 1 
//DEFINE EXEC PGM=IDCAMS,REGION=4M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DELETE 'COLIN.SCSFCKDS'
DEFINE CLUSTER (NAME(COLIN.SCSFCKDS) -
VOLUMES(C4SYS1) -
RECORDS(200 100) -
RECORDSIZE(372,32756 ) -
KEYS(72 0) -
FREESPACE(10,10) -
SHAREOPTIONS(2,3)) -
DATA (NAME(COLIN.SCSFCKDS.DATA) -
BUFFERSPACE(100000) -
ERASE) -
INDEX (NAME(COLIN.SCSFCKDS.INDEX))
/*

Create the PKDS

//IBMPKDS   JOB 1 
//DEFINE EXEC PGM=IDCAMS,REGION=64M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DELETE 'COLIN.SCSFPKDS' PURGE
DEFINE CLUSTER (NAME(COLIN.SCSFPKDS) -
VOLUMES(C4SYS1) -
RECORDS(100 50) -
RECORDSIZE(800,32756) -
KEYS(72 0) -
FREESPACE(0,0) -
SHAREOPTIONS(2,3)) -
DATA (NAME(COLIN.SCSFPKDS.DATA) -
BUFFERSPACE(100000) -
ERASE -
CISZ(32768)) -
INDEX (NAME(COLIN.SCSFPKDS.INDEX))
/*

Set up the TKDS

This is described here.

The documentation describes 2 ways of creating the TKDS.

  • Define
  • Define and initialise it

I do not know what the difference is. The first seems to work OK

//IBMCKDS   JOB 1 
//DEFINE EXEC PGM=IDCAMS,REGION=4M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DELETE 'COLIN.SCSFTKDS'
DEFINE CLUSTER (NAME(COLIN.SCSFTKDS) -
VOLUMES(C4SYS1) -
RECORDS(100 50) -
RECORDSIZE(2200,32756) -
KEYS(72 0) -
FREESPACE(0,0) -
SPANNED -
SHAREOPTIONS(2,3)) -
DATA (NAME(COLIN.SCSFTKDS.DATA) -
BUFFERSPACE(100000) -
CONTROLINTERVALSIZE(32768) -
ERASE) -
INDEX (NAME(COLIN.SCSFTKDS.INDEX))
/*
/*

Update the parmlib member for ICSF

The ICSF job output has information like

IEE252I MEMBER CSFPRMCP FOUND IN USER.Z31A.PARMLIB

Either use this member, or create a new member.

My member has

CKDSN(COLIN.SCSFCKDS)                        
PKDSN(COLIN.SCSFPKDS)
TKDSN(COLIN.SCSFTKDS)
DOMAIN(0)

See Parameters in the installation options data set.

Running on zPDT and ADCD, I also had to specify SSM(YES) so I could specify KGUP parameter CLEAR.

Check your IKJTSOxx has

AUTHPGM NAMES(          /* AUTHORIZED PROGRAMS      */      
...
CSFDAUTH /* ICSF COMMAND */ +
CSFDPKDS /* ICSF Command */
...
)

Started task member CSF

In the ICSF documentation the started task is called CSF. Personally I would have called it ICSF.

//CSF  PROC PRM=CP 
//CSF EXEC PGM=CSFINIT,PARM=&PRM,REGION=0M,TIME=1440,MEMLIMIT=NOLIMIT

RACF Started definition

On my system it uses the default STARTED * (G) profile. This has

STDATA INFORMATION          
------------------
USER= START1
GROUP= SYS1
TRUSTED= NO
PRIVILEGED= NO
TRACE= YES

RACF user definitions

RDEFINE CSFSERV CSF* UACC(NONE) 
RDEFINE CSFSERV CSF1TRL UACC(NONE)
RDEFINE CSFSERV CSF1TRC UACC(NONE)
PERMIT CSF* CLASS(CSFSERV) ID(PKISRVD) ACCESS(READ)
PERMIT CSF1TRL CLASS(CSFSERV) ID(PKISRVD) ACCESS(READ)
PERMIT CSF1TRL CLASS(CSFSERV) ID(COLIN ) ACCESS(READ)
PERMIT CSF1TRL CLASS(CSFSERV) ID(IBMUSER) ACCESS(READ)
PERMIT CSF1TRC CLASS(CSFSERV) ID(IBMUSER) ACCESS(READ)
SETROPTS CLASSACT(CSFSERV) RACLIST(CSFSERV)
SETROPTS RACLIST(CSFSERV,CRYPTOZ) REFRESH

Start ICSF

S  CSF

This gave me

CSFO0230 CKDSN(COLIN.SCSFCKDS)                                
CSFO0230 PKDSN(COLIN.SCSFPKDS)
CSFO0230 TKDSN(COLIN.SCSFTKDS)
CSFO0230 DOMAIN(0)
CSFO0166 DEFAULT CICS WAIT LIST WILL BE USED.
IEE252I MEMBER CTICSF00 FOUND IN SYS1.PARMLIB
CSFM607I A CKDS KEY STORE POLICY IS NOT DEFINED.
CSFM607I A PKDS KEY STORE POLICY IS NOT DEFINED.
CSFM610I GRANULAR KEYLABEL ACCESS CONTROL IS DISABLED.
CSFM611I XCSFKEY EXPORT CONTROL FOR AES IS DISABLED.
CSFM611I XCSFKEY EXPORT CONTROL FOR DES IS DISABLED.
CSFM612I PKA KEY EXTENSIONS CONTROL IS DISABLED.
CSFM654I KEY ARCHIVING USE CONTROL IS DISABLED.
CSFM723I ARCHIVED KEY USE DATA DECRYPTION CONTROL IS DISABLED.
CSFM732I MASTER KEY ENTRY UTILITY KEY OWNERSHIP CONTROL IS DISABLED.
CSFM653I CKDS LOADED 3 RECORDS WITH AVERAGE SIZE 254
CSFM653I TKDS LOADED 45 RECORDS WITH AVERAGE SIZE 2083
CSFM129I MASTER KEY DES ON CRYPTO EXPRESS8 COPROCESSOR 8C00, SERIAL
NUMBER 93AAC740, IS CORRECT.
CSFM129I MASTER KEY AES ON CRYPTO EXPRESS8 COPROCESSOR 8C00, SERIAL
NUMBER 93AAC740, IS CORRECT.
CSFM129I MASTER KEY RSA ON CRYPTO EXPRESS8 COPROCESSOR 8C00, SERIAL
NUMBER 93AAC740, IS CORRECT.
CSFM129I MASTER KEY ECC ON CRYPTO EXPRESS8 COPROCESSOR 8C00, SERIAL
NUMBER 93AAC740, IS CORRECT.
CSFM111I CRYPTOGRAPHIC FEATURE IS ACTIVE. CRYPTO EXPRESS8 COPROCESSOR
8C00, SERIAL NUMBER 93AAC740.
CSFM129I MASTER KEY DES ON CRYPTO EXPRESS8 COPROCESSOR 8C01, SERIAL
NUMBER 93AAC741, IS CORRECT.
CSFM129I MASTER KEY AES ON CRYPTO EXPRESS8 COPROCESSOR 8C01, SERIAL
NUMBER 93AAC741, IS CORRECT.
CSFM129I MASTER KEY RSA ON CRYPTO EXPRESS8 COPROCESSOR 8C01, SERIAL
NUMBER 93AAC741, IS CORRECT.
CSFM129I MASTER KEY ECC ON CRYPTO EXPRESS8 COPROCESSOR 8C01, SERIAL
NUMBER 93AAC741, IS CORRECT.
CSFM111I CRYPTOGRAPHIC FEATURE IS ACTIVE. CRYPTO EXPRESS8 COPROCESSOR
8C01, SERIAL NUMBER 93AAC741.
CSFM133I THERE ARE NO ACTIVE PKCS11 COPROCESSORS.
CSFM508I CRYPTOGRAPHY - THERE ARE NO CRYPTOGRAPHIC ACCELERATORS ONLINE.
CSFM698I DOMAIN IN USE: 0
CSFM015I FIPS 140 SELF CHECKS FOR PKCS11 SERVICES SUCCESSFUL.
CSFM400I CRYPTOGRAPHY - SERVICES ARE NOW AVAILABLE.
CSFM130I CRYPTOGRAPHY - DES SERVICES ARE AVAILABLE.
CSFM130I CRYPTOGRAPHY - RSA SERVICES ARE AVAILABLE.
CSFM130I CRYPTOGRAPHY - ECC SERVICES ARE AVAILABLE.
CSFM127I CRYPTOGRAPHY - AES SERVICES ARE AVAILABLE.
CSFM126I CRYPTOGRAPHY - FULL CPU-BASED SERVICES ARE AVAILABLE.
CSFM001I ICSF INITIALIZATION COMPLETE
CSFM640I ICSF RELEASE FMID=HCR77E0.
CSFM716I ICSF HAS BEEN INITIALIZED WITH SCSFMOD0 FROM LNKLST
CSFM716I ICSF HAS BEEN INITIALIZED WITH SIEALNKE FROM LNKLST

Message CSFM133I THERE ARE NO ACTIVE PKCS11 COPROCESSORS is because zPDT does not support this.

To stop ICSF use the operator command

p CSF

Initialise the environment

Get into the ICSF environment.

  • From ISPF option 6 (TSO)
  • @ICSF
  • panelid on to display the name of the panel in the top left corner of the screen
  • you should be in panel CSF@PRIM
  • option 6 PPINIT – Pass Phrase Master Key/KDS Initialization -> panelid CSFPMC40
  • Enter your pass phrase, tab down to _ Reinitialize system and select it using /
  • Enter your data set names for example CKDS ===> ‘COLIN.SCSFCKDS’ . Ensure the name is in quotes.
  • press enter. I got a panel with message ‘ARE YOU SURE YOU WISH TO PROCEED WITH PASS PHRASE INITIALIZATION?’
  • press enter to continue.
  • The message CSFM653I PKDS LOADED 6 RECORDS WITH AVERAGE SIZE 583 was displayed and INITIALIZATION COMPLETE was displayed in the top right corner.

Update your backup procedure to backup these datasets.

What can you do once it has started?

You can issue operator commands

d icsf,kds                                            
CSFM668I 14.33.27 ICSF KDS 319
CKDS COLIN.SCSFCKDS
FORMAT=KDSR SYSPLEX=N MKVPs=DES AES
DES MKVP date=2024-09-10 12:43:29
AES MKVP date=2024-09-10 12:43:29
PKDS COLIN.SCSFPKDS
FORMAT=KDSR SYSPLEX=N MKVPs=RSA ECC
RSA MKVP date=2024-09-10 12:43:30
ECC MKVP date=2024-09-10 12:43:30
TKDS COLIN.SCSFTKDS
FORMAT=KDSRL SYSPLEX=N MKVPs=None

You can use the @ICSF TSO command (see above)

  • To list the CKDS use 5 UTILITY; 5 CKDS KEYS;1 List all records
  • To list the PKDS use 5 UTILITY; 6 PKDS KEYS;1 List all records
  • To list the TKDS use 5 UTILITY; 7 tokens in TKDS ;4 List existing tokens

Note: Be careful when using the ISPF line commands as the D means delete, not display!

Batch programs

You can use The Key Generation Utility Program CSFKGUP. This uses definitions described here. See One minute MVS – Using individual data set encryption on z/OS for an example of defining a key.

Whoops

After I had used PKI Services to define certificates, I got the health checker message CSFH0054I Check for clear keys in the CKDS, PKDS, and TKDS.

The problems were

Active TKDS: COLIN.SCSFTKDS 
---------------------------------------------
PKISRVD.PKITOKEN 00000001T
PKISRVD.PKITOKEN 00000002T
PKISRVD.PKITOKEN 00000003T
PKISRVD.PKITOKEN 00000004T

Which came from PKISERVD

I fixed this changing the PKI Server pkiserv.conf file to have SecureKey=T, but zPDT does not support encrypted keys, so with zPDT you have to have SecureKey=F.
I got messages in the PKISERVD log

IKYC010I Error 791740530 returned from …: PKI Services can not generate certificates with secure keys.

Setting up ICSF security for commands and APIs

The documentation for ICSF and securing access to keys is hard to follow. There is a lot of it, but is not easily consumed.

There are two orthogonal aspects of ICSF security

  • Giving permission for a userid to use CSFKGUP utility, the ICSF ISPF panels, or the ICSF API. For example they can use list, but not define.
  • Give permissions to groups of keys. You can define keys with names like DSENCR* have more controls that ANYONE*

There are different levels of granularity for ICSF security.

  • The default is no security – you need to define profiles to protect ICSF resources
  • There is on|off security. If you have any security you can do anything
  • Then there is granular security. You can control down to the operation type.

This blog post is about setting up security for ICSF before you start defining keys.

ICSF security for commands and APIs

The approach to security for ICSF seems to be every one has access unless you take action to define security!

The CSFKGUP utility.

There is a master switch – if this profile exists then do more checks. If this profile does not exist any userid can use CSFKGUP commands to maintain keys. You need to set up Optional SAF checking for KGUP.

RDEFINE XFACILIT CSF.KGUP.VERB.AUTHORITY.CHECK UACC(NONE) 
SETR RACLIST(XFACILIT) REFRESH

RDEFINE CSFSERV CSFKGUP UACC(NONE) WARNING
PERMIT CSFKGUP CLASS(CSFSERV) id(IBMUSER) ACCESS(READ)
SETR RACLIST(CSFSERV ) REFRESH
/*

With the above security setup anyone with read access to the CSFKGUP in class(CSFSERV) gets access to all of the CSFKGUP commands (not just read operations).

This is another master switch, to check the keys security. Its presence or absence controls its use. I had security set up for a key, and with warning mode, which allows the request, and gives a warning message on the console.

RDEFINE XFACILIT CSF.KGUP.CSFKEYS.AUTHORITY.CHECK UACC(NONE)
SETR RACLIST(XFACILIT) REFRESH

Now when I try to delete key SECKEY2 I got

ICH408I USER(IBMUSER ) GROUP(SYS1 ) ...
SECKEY2 CL(CSFKEYS )
WARNING: INSUFFICIENT AUTHORITY - TEMPORARY ACCESS ALLOWED
FROM SEC* (G)
ACCESS INTENT(CONTROL) ACCESS ALLOWED(NONE )

and when I defined a key SECKEY2

ICH408I USER(COLIN   ) GROUP(SYS1    ) NAME(###################
SECKEY2 CL(CSFKEYS )
WARNING: INSUFFICIENT AUTHORITY - TEMPORARY ACCESS ALLOWED
ACCESS INTENT(CONTROL) ACCESS ALLOWED(NONE )

If there is no matching CSFKEYS profile, the userid will be allowed access. When I defined a key ZZZKEY, it worked because there was no matching security profile.

You should define a minimum of

RDEFINE CSFKEYS   C*      AUDIT(ALL) 
PERMIT * CLASS(CSFKEYS) ID(COLIN ) ACCESS(READ)
SETR RACLIST(CSFKEYS ) REFRESH

ISPF ICSF access

You can control which userids can manage ICSF using the ISPF interface. Behind the ISPF interface is code which issues ICSF APIs. You can protect the API calls.

You need to define a resource like

RDEFINE CSFSERV CSFKDSL .... 

and give the userid read access to it.

FunctionThe resources needed
List the contents of a PKDS or CKDSCSFKDSL – list
CSFKDMR – read meta data
CSFKRR2 – read record
Define an AES KeyCSFKRR2 – read record
CSFKGN – key generate
CSFKGN2 – key generate 2
CSFKRC2 -record create 2
CSFKRD – delete record
List the contents of a CKDS elementCSFBRCK
List the contents of a PKDS elementCSFBRPK
Delete a CKDS recordCSFBRCK – control access

The functions and the SAF resource names are defined here.

To define a symmetric cipher key, I needed CONTROL access to the CLASS(CSFKEYS) profile for the key.

Setting up ICSF security for access to keys.

The documentation for ICSF and securing access to keys is hard to follow. There is a lot of it, but is not easily consumed. The security model has evolved over time, and I found the definitions confusing.

There are two orthogonal aspects of ICSF security

  • Giving permission for a userid to use CSFKGUP utility, the ICSF ISPF panels, or the ICSF API. For example they can use list, but not define.
  • Give permissions to groups of keys. You can define keys with names like DSENCR* have more controls that ANYONE*.

There are different levels of granularity for ICSF security.

  • The default is no security – you need to define profiles to protect ICSF resources
  • There is on|off security. If you have any security you can do anything
  • Then there is granular security. You can control down to the operation type.

This blog post is about setting up security to protect keys.

“Required” definitions

You should define the profile below to give you granular controls.

RDEFINE XFACILIT CSF.CKDS.TOKEN.CHECK.LABEL.FAIL 
SETROPTS RACLIST(XFACILIT) REFRESH

If the profile CSF.CKDS.TOKEN.CHECK.LABEL.FAIL is defined, a userid needs the appropriate access to the CSFKEYS profile:

  • READ authority to read a label from the CKDS,
  • UPDATE authority if creating a label,
  • CONTROL authority if writing to or deleting a label.

A userid will also need access to the ICSF commands or APIs to be able to use the key.

If the CSF.CKDS.TOKEN.CHECK.LABEL.FAIL profile is not defined, and the userid has at least read access to a profile for the key, the userid can create, write or delete a label. If there is no profile for the key the userid has access to the key.

If you define the profile RDEFINE XFACILIT CSF.CKDS.TOKEN.CHECK.LABEL.WARN instead of CSF.CKDS.TOKEN.CHECK.LABEL.FAIL, and the userid has at least read access to a profile, the userid can create, write or delete a label. In addition it produces a warning message.

This feels like the same as RDEFINE XFACILIT CSF.CKDS.TOKEN.CHECK.LABEL.FAIL WARNING, so I do not see why RDEFINE XFACILIT CSF.CKDS.TOKEN.CHECK.LABEL.WARN is needed.

“Required” access control for exporting keys.

If you want to control who can export AES and DES keys you can enable this by defining a profile

RDEFINE XFACILIT CSF.XCSFKEY.ENABLE.AES
RDEFINE XFACILIT CSF.XCSFKEY.ENABLE.DES
SETROPTS RACLIST(XFACILIT) REFRESH

This turns on the checking system wide, you do not need to give any userid access to it.

To protect the export of all keys,

RDEFINE XCSFKEY * UACC(NONE)
PERMIT * CLASS(XCSFKEY) ID(SECADMN) ACCESS(UPDATE)
SETROPTS RACLIST(XFCSFKEY) REFRESH

You can generate individual or generic profiles for specific keys.

This security model feels broken, as I can read a key from the CKDS (encrypted with the hardware keys) write it to a file. Send the file to a remote system, and if they remote system has the same hardware keys, write the key to the CKDS. I still need access to read and write the key – but I do not use the XCSFKEY profile.

Defining profiles

The easy bits

You can define a standard security resource, such as

RDEFINE CSFKEY COLINSKEY ...
PERMIT  COLINSKEY CLASS(CSFKEY) ID(...) ACCESS(...)

Where COLINSKEY is the label of an entry in the CKDS or the PKDS. This can be a CIPHER key or a KEK key.

If there is no matching profile, there are no restrictions, so you may want to define a default

RDEFINE CSFKEY * UACC(NONE) AUDIT(ALL) warning

Where AUDIT(ALL) says report every time it is used, and WARNING reports if there is a security violation and gives access anyway. You can then use the information to create more specific profile. Once you have configured security you can remove the warning option, and protect your resources.

You need to specify access:

  • READ to be able to read the profile
  • UPDATE authority if creating a label,
  • CONTROL authority if writing to or deleting a label.

But see “Required” definitions and the CSF.CKDS.TOKEN.CHECK.LABEL.FAIL to enable the granular access. Without the CSF.CKDS.TOKEN.CHECK.LABEL.FAIL profile, if a userid has at least read access to the CSFKEY profile, it can do anything with it. If there is no profile for the key, any userid can do anything with the key.

Which profile is used?

There are different ways of using a key (especially with APIs)

  1. Use the label character string of a key in the CKDS. You can pass a label into an API request. The label name is used in the security checks.
  2. You can read the token from the CKDS using the label, and pass the token (a long string of internal format data) to an API request. ICSF compares the token with the CKDS and if it locates a record with the same key value – it uses the label of the record in the security checks.
  3. You can get the token from elsewhere, for example read a data set. The same checks are done as in 2. above.
  4. If a record with the same key value was not found in the CKDS, (so you are using a key which your CKDS does not know about)
    • If the profile CSF.CKDS.TOKEN.CHECK.LABEL.WARN or CSF.CKDS.TOKEN.CHECK.LABEL.FAIL in class(XFACILIT) is defined, and profile CSF.CKDS.TOKEN.CHECK.DEFAULT.LABEL in class(XFACILIT) is defined, then check the userid’s permission to profile CSF-CKDS-DEFAULT in class(CSFKEYS). See here.

What access do I need to the profile?

If you have CONTROL access to CSFBRCK CLASS(CSFSERV), and CONTROL access to the key’s profile SECKEY2 CL(CSFKEYS) you can delete the key SECKEY2.

If you have ALTER (more powerful than CONTROL) access to CSFBRCK CLASS(CSFSERV), the CSFKEYS profile is ignored you can delete any key.

You might want to give administrator only CONTROL access to the commands and APIs.

What are the ICSF bits?

I struggled for a while to understand the different parts of ICSF.

Definition of terms

You use a symmetric key for encrypting and decrypting data. You use the same key for encryption and decryption.

An asymmetric key has two parts. You encrypt with one, and decrypt with the other. If you encrypt with a key, you cannot use your key to decrypt it. You need the other part. You pick one part, and keep it secure – this is called the private key. The other part you can make this available to every one – the public key.

A certificate is a collecting of information. It contains a public key, and information about the owner of the certificate. I think of a certificate as a paper envelope in which you put the public key, they owner information, and other information, such as validity dates.

Hardware encryption. These days the calculations for encryption can be offloaded to special cryptographic hardware.

Cryptographic keys can be stored in hardware. The hardware can have a cryptographic key, which can be used to encrypt data before storing it in the hardware.

You can request the hardware to extract the data, and encrypt it with another key. This way the encryption key is never seen outside of the hardware.

ICSF provides an API to use z/OS hardware cryptographic functions, and some facilities to mange the keys.

ICSF

A symmetric key can have different algorithms. Typically RSA and AES. RSA came first, but AES is considered better as it takes more work to crack, and uses less resources when encrypting and decrypting data.

With ICSF, the symmetric keys are stored (encrypted) within the ICSF CKDS database. The keys are referenced to using tokens. You can have:

  • A null token – used as place holder.
  • A fixed length token, this is an old format token.
  • A variable length token. As cryptography developed over time, all the information could not be stored in a fixed length, and so variable length tokens were introduced.

With ICSF, Asymmetric keys are called PKA (Public Key algorithms).

An asymmetric key can have different algorithms. Typically RSA, Elliptic Curve (EC), and various Crystal methods (these are based on complex calculations based on crystal lattices).

The asymmetric keys are stored (encrypted) within the ICSF PKDS databases. The keys are referenced to using tokens.

As with symmetric keys, the early asymmetric tokens were a fixed length. As cryptography developed, variable length tokens were introduced.

Symmetric ciphers in more depth

ICSF has two forms of symmetric cipher for encrypting user data

  • DATA – I think of this as version 1. The key value can be extracted as cleartext – this is not very secure.
  • CIPHER – I think this as version 2. The key value is always encrypted – either within ICSF, encrypted on the hardware, or with a transmission key.

Best practice is to use CIPHER instead of DATA. There is an older API function for generating the DATA keys, and a newer API function (CSNBKTB2) for the CIPHER keys. The newer function has more capability. For example, you can specify options that allow/prohibit exporting the key, and which encryption modes can be used, such as cipher block chaining(CBC).

  • AES has one type of cipher: CIPHER. This can be used for data set encryption and in encrypt API (CSNBENC), and the decrypt API (CSNBDEC).
  • DES has three types of cipher
    • DATA which can be used to encrypt and decrypt. This can be used for data set encryption and in encrypt API (CSNBENC), and the decrypt API (CSNBDEC).
    • ENCIPHER. This can be used in the encrypt data API (CSNBENC).
    • DECIPHER. This can be used in the decrypt data API (CSNBDEC).

  • To use the ENCIPHER function you need a DATA, CIPHER or ENCIPHER key
  • To use the DECIPHER function you need a DATA, CIPHER or DECIPHER key
  • To use data set encryption you need DATA or CIPHER (because you need to do encryption and decryption).

Generating symmetric keys

You can use the ISPF panel interface.

For example, to create a symmetric key; from the ICSF main page select options:

  • 5 UTILITY
  • 5 CKDS KEYS – Manage keys in the CKDS
  • 8 Generate AES CIPHER keys

You specify the name of the key, the AES key bit length, which encryption mode and if it can be exported from the hardware (XPRTCPAC).

The ISPF panels provide defaults. You can see the values by using the ISPF interface to display entries in the CKDS. For example

Key usage:ENCRYPT and DECRYPT, and ANY-MODE

Key management: gives XPRTCPAC and other keys. For example XPRT-AES says the key can be exported and encrypted using an AES Key Exporting Key.

Use the CSFKGUP batch interface.

The ICSF administrators guide gives details of the utility. It uses data sets (which may not be the active ones). You need to tell ICSF to refresh the in-memory information after the data sets have been updated.

For example

//IBMICSF  JOB 1,MSGCLASS=H 
// SET CKDS=COLIN.SCSFCKDS
//KGUP EXEC PGM=CSFKGUP,PARM=('SSM')
//CSFCKDS DD DISP=OLD,DSN=&CKDS
//CSFIN DD *,LRECL=80
...
//CSFDIAG DD SYSOUT=*,LRECL=133
//CSFKEYS DD DSN=COLIN.CSFKEYS,DISP=SHR
//CSFSTMNT DD SYSOUT=*,LRECL=80
//* REFRESH THE IN MEMORY DATA
//REFRESH EXEC PGM=CSFEUTIL,PARM='&CKDS,REFRESH'
//

The statements in CSFIN are like

DELETE TYPE(CIPHER) LABEL(AESCIPHER) 
ADD TYPE(CIPHER ) ALGORITHM(AES) LENGTH(32),
LAB(AESCIPHER)

You can specify values for KEYUSAGE and KEYMGMT for example

KEYUSAGE(ANY-MODE) KEYMGMT(XPRTCPAC).

CSFKGUP seems to provide the same capability as the ISPF interface.

If you use CSFKGUP you need to issue a program to refresh the in memory information from the updated CKDS and TKDS data sets.

How is ICSF configured?

ICSF is started as a started task, so uses JCL in the SYS1.PROCLIB concatenation. I have member CSF in USER.Z31A.PROCLIB.

//CSF  PROC PRM=CP 
//CSF EXEC PGM=CSFINIT,PARM=&PRM,REGION=0M,TIME=1440,MEMLIMIT=NOLIMIT

The parameters are selected when the procedure is started. For example

S CSF,PRM=C2

The parameters come from member CSFPRMxx in the parmlib concatenation. My default parameters are in USER.Z31A.PARMLIB(CSFPRMCP)

CKDSN(COLIN.SCSFCKDS)                   
PKDSN(COLIN.SCSFPKDS)
TKDSN(COLIN.SCSFTKDS)
DOMAIN(0)
SSM(YES)
KEYARCHMSG(YES)

To use different data sets, you need to stop ICSF, and restart it with a different configuration member, specifying different data set names.

Using ICSF within a single image or sysplex

This blog post describes using ICSF within one system. This could be a sysplex if all systems use the same ICSF data sets. It gives some guidance on setting up your environment, and some implications of your decisions.

For some guidance on defining keys for Data Set Encryption see here(how many keys?). For a deep dive on key management which talks about changing the keys on the ICSF data sets (key rotation) see here.

Introduction

This section gives some general information about using ICSF, keys and data set encryption.

  • You set up a symmetric key for data set encryption.
  • You can specify which key a data set should use, when the data set is created.
    • You can configure a RACF profile to specify the key name in the DFP information.
      • When you allocate a data set which uses this RACF profile, the key is extracted from the DFP information and used.
    • The data set must be SMS-managed extended format. (You can configure this either in JCL, or with SMS options)
    • You can specify the keylabel in the JCL
    • You can specify in the SMS Data class. With SMS you configure ACS with statements like if the data set attributes are … then use data class xxxx, which in turn has a data set encryption key specified.
  • The key name is stored with in the catalog along with other SMS information.
  • If you change the label in the RACF profile, any new dataset which get created get the updated label, existing data sets are unchanged.
  • If you delete and recreate a key for a label, any data set which used the old label becomes unreadable.
  • You can unload and reload a key using my programs in EASYICSF on Github. ICSF does not provide this capability. When you define a key, you might unload it, and archive it away. Then, if the key gets deleted by accident, you can then recover by reloading it.
  • Keys stored by ICSF are encrypted before they are stored in the ICSF data set. The master encryption key for these data sets can be stored in the cryptographic hardware. If someone steals the ICSF data sets, they cannot use them, unless they have the master key as well.
  • You can get ICSF to use a new master password. It will take each entry in the ICSF data set, decrypt it with the old key, encrypt it with the new key, and store it back in (a new) data set. This is known as key rotation. (This is a strange use of the term rotation because there is no rotation, you just change the key.)
  • If you want to use a new key for a data set. You have to copy the contents of the data set to a new data set set up with the new key. You then rename the data set. You cannot just change the key.
  • You can specify a start and end date for a key. The start date can be today’s or any date in the future. The end date is after the value (this means you cannot specify an end date, so it can not be used today.)
  • If you want to stop a key from being used, you can set an archive flag on it. (If you delete it, any data sets using this key cannot be processed). By default the application using an archived key will fail. You can configure ICSF so that use of an archived key will work, and you get a message for the key on the ICSF joblog, and a record in SMF.
  • You can control who can use keys by a RACF profile in class CSFKEYS. If you use CSF.CSFKEYS.CONDITIONAL.ACCESS.CONTROL you can restrict what functions userids can execute – and so prevent most people from being able delete keys.
  • Copying data sets
    • If you use DFDSS backup, the encrypted data is backed up. When you restore it, it allocates a data set with the same encryption label. The intermediate file is not encrypted. You can still read the intermediate file and see the meta data – but the original file contents are still encrypted.
    • If you use IEBGENER to copy the data, if the output data set does not have an encryption label, the output data set is encrypted with the same key label as the input.
    • To specify a key label you can specify DSKEYLBL in JCL and in the TSO ALLOC command.
    • In an application
      • you can specify the key label using SVC 99 (dynamic allocation).
      • you cannot specify it using the C function fopen(). You will need to specify it in JCL and use DD:name to refer to the data set.
    • If you use other program, such as a ISPF edit or a C program, to read the file and write the contents out, by default the output file is not encrypted. The application sees the clear text, and the output is in clear text unless you have specified a key label for the output data set.

Planning

You need to consider how many keys you need. For example, one for all your data sets, or one per business function such as online banking, or stocks and shares.

Keys for some files, such as a database will be long lived – as long as the data base exists, or until you copy it with a new key. The data set may have been archived to tape, and could be recalled years later.

You need to plan who has access to the data set. For a DB2 data base data set, people will not normally need access to it, as the access is managed by DB2. The DB2 system userid will need access. Storage managers, responsible for backing up the data sets do not need access to the key, and access the encrypted data without decryption.

If someone has access to an encrypted data set, you need to ensure that any data set they create which may have sensitive information in it is also encrypted. This may mean reviewing userids and what they are used for. For example if you have a data set ENC.DATASET1 which userid COLIN can access, do you need to ensure that any data set that userid COLIN can create is encrypted?. This may mean data sets are encrypted which do not contain sensitive information. If userid COLIN can also create data sets beginning with SYS2 – you need to consider if all SYS2.* datasets need to be encrypted.

You might define a userid COLINE which can only access the encrypted data sets, and can only created data sets prefixed with COLINE – and these are all encrypted. Userid COLINE does not have access to general data sets, such as SYS1.PARMLIB.

For short lived data sets you could change the key every few months.

You need to consider backups and disaster recovery, and how your remote sites will use the datasets. The remote sites will need the same keys for the data sets, as the primary site.

Changing keys

As a general rule, you do not want to delete a key unless you are sure that is is not needed (including any data sets that may have been archived off the system). If you want to generate new keys periodically you may want to use a naming convention such as PAYROLL2024NOV, then generate a new key PAYROLL2025NOV, and update your definitions (or SMS).

Using keys

You can specify the encryption key to be used in

  1. The RACF profile used for the data set. The value is in the DFP segment.
  2. The JCL DSKEYLBL parameter on the DD statement.
  3. In the SMS data class used for the data set. This can be specified in the DATACLAS parameter on the DD statement, or selected via the ACS(Automatic Class Selection) routine.

The key is used when the data set is allocated(created).

If you change the RACF profile, the updated label will be used next time a data set is created.

If people specify the key either by application on JCL (the DSKEYLBL option on the DD statement), changing the key name will mean changing the applications and JCL to use the new key.

An ACS routine has logic like

if the data set names begins with … , and has properties …. then use the following volumes…, make it this size…, and use the Data Class … which has the Data Set Key Label…)

If you change the Data Set Key Label in the Data class, the next time the Data Class is used, it will use the updated key. This is much simpler than trying to change JCL.

It looks like it is easier to use the RACF profile or SMS if you will be changing the data set encryption key.

Creating keys

  • You can use the ICSF utility CSFKGUP to generate keys. The syntax is like ADD TYPE(CIPHER) LABEL(COLINKEY)…
  • You can use the ISPF interface to define keys. From the main panel, options 5 UTILITY -> 5 CKDS KEYS, option 7 or 8 to define a symmetric key.
  • You can use ISPF to generate statements for CSFKGUP. From the main panel option 8 KGUP – Key Generator Utility processes. This simplifies selecting the options. For example if you select the action to maintain (add) an entry, if you specify algorithm DES, it will display the valid key types for DES (eg CIPHER, DATA, ENCIPHER…). If you select algorithm AES, it will display the valid key types for AES ( eg CIPHER, DATA, EXPORTER…). If you use this method, you may still have to edit the statements manually, because not all the required parameters are specified, see below.

For some keys you need to have a RACF profile defined for the label name. For example

RDEFINE CSFKEYS DES5 UACC(NONE) –
ICSF(SYMCPACFWRAP(YES) SYMCPACFRET(YES))

This seems to be a strange way of storing this information.

Setting up data set encryption

Best practices.

Use definition like

ADD ALGORITHM(AES) TYPE(CIPHER) KEYUSAGE(ANY-MODE) LENGTH(32), 
KEYMGT(XPRTCPAC)LABEL(COLINCIPHER2 )

Where

  • ALGORITHM(AES) is better than ALGORITHM(DES). It is harder to crack, and uses less CPU.
  • TYPE(CIPHER) is better than TYPE(DATA).
  • KEYUSAGE(ANY-MODE) is needed for data set encryption with AES.
  • LENGTH(32) is the longest and strongest AES key size.
  • KEYMGT(XPRTCPAC) is needed for data set encryption.
  • LABEL(COLINCIPHER2 ) you specify your label.

If you use the ISPF panels to generate the key, you can specify all of the parameters. If you use the ISPF interface and 8 KGUP – Key Generator Utility processes. This does not specify create KEYUSAGE and KEYMGT values, which will have to be entered manually.

Afterthoughts

You need to backup the ICSF data sets.

If you need to use a (restored) data set with a different name, you will need to restart ICSF with a different parmlib member containing the different names.

ICSF does not provide a way of copying between ICSF data sets, but you can use UNLOAD and RELOAD programs in my EASYICSF on Github which allows you to copy a key from one ICSF data set to an intermediate data set, then reload it into a different,or the same, ICSF data set.

You should have a process, which you have tested, for replacing keys which may be been exposed. This may cause a long (hours) outage, so you need to have JCL and definitions written before you need them.

All I ever wanted to know about ICSF and data set encryption keys

z/OS systems have cryptographic processors, which can be used to offload expensive cryptographic operations. You can configure z/OS so if you generate a cryptographic key, you do not see the actual, clear text key (so it cannot easily be stolen). This is done by the cryptographic processors having a cryptographic key themselves, and any keys they emit, are encrypted with this hardware key. When you use your cryptographic key, it is passed to the cryptographic processors, which then decrypts the data using the hardware key, then uses your real cryptographic key.

ICSF provides an interface to do cryptography, use the cryptography processors and to mange cryptographic keys. Most z/OS user will ICSF capabilities without knowing about it.

ICSF works at the level of symmetric and asymmetric keys. You cannot use it to generate digital certificate, do TLS handshakes, nor do data set encryption (but data set encryption uses ICSF keys).

ICSF provides

  • An ISPF interface to mange keys. You can list, define, delete etc keys through the panels
  • A batch program CSFKGUP which can be used to so some of the key management. This acts on a data set. You need to tell ICSF to refresh the in-memory contents from the data set.
  • An extensive set of API’s if you want to write your own application, for example to generate a key, or to encrypt some data. It is relatively easy to write Rexx programs to use the APIS. These APIs work on the active ICSF data sets. To use different data sets you need to change the ICSF configuration.

Having spent a few weeks trying to use it I feel “how to” information is missing. I tried implementing data set encryption across disconnected system and found ICSF is missing some functions, for example batch program to export and import keys, and a batch program to securely generate shared keys on different systems.

In this blog post, I’ve tried to fill in the holes in the documentation, and provide the missing batch utility programs.

I’ve written blogs posts on

I’ve put my utilities and sample code on Github.