Debugging external smart cards and external pkcs11 keystores.

There is an open source package (opensc) which provides access to smart cards and external keystores. It provides some good tools for diagnosing problems.

There is a wiki with good information.

Opensc return codes are here, and the printable text is here

Monitor traffic to and from the device.

You can monitor the traffic to and from the device by using an intermediate “spy” module which displays the traffic.

In your configuration (for example a CCDT), where you specified the name of the module /usr/lib64/pkcs11/opensc-pkcs11.so, replace this with /usr/lib64/pkcs11/pkcs11-spy.so. Specify the environment variable

export PKCS11SPY=/usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so

The spy module is invoked, prints out the parameters, and then invokes the module specified in the environment variable.

The output is like

19: C_Login
2021-03-10 14:22:47.947
[in] hSession = 0x21fc030
[in] userType = CKU_USER
[in] pPin[ulPinLen] 00000000021fb2a0 / 8
00000000 5B C7 E7 BB E5 FC 6A BE […..j.
Returned: 160 CKR_PIN_INCORRECT

Detailed internal trace

You can specify the environment variable OPENSC_DEBUG to give a very detailed trace. The higher the number the more detailed the trac.

export OPENSC_DEBUG=9

and use unset OPENSC_DEBUG to reset it.

You can use OPENSC_CONF to specify a configuration file with more parameters, such as file name for the output.

The output from this trace (showing a logon with pin number 12345678) is like

0x7f96e2dca740 14:13:16.756 [opensc-pkcs11] framework-pkcs15.c:1494:pkcs15_login: pkcs15-login: userType 0x1, PIN length 8
0x7f96e2dca740 14:13:16.756 [opensc-pkcs11] pkcs15-pin.c:301:sc_pkcs15_verify_pin: called
….
0x7f96e2dca740 14:13:16.757 [opensc-pkcs11] reader-pcsc.c:283:pcsc_transmit: reader ‘Nitrokey Nitrokey HSM (DENK01051600000 ) 00 00’
0x7f96e2dca740 14:13:16.757 [opensc-pkcs11] reader-pcsc.c:284:pcsc_transmit:
Outgoing APDU (13 bytes):
00 20 00 81 08 31 32 33 34 35 36 37 38 . …12345678

GSKIT return codes

If you are using the MQ C Client interface, this uses GSKIT. There is documentation for the z/OS version, and the return codes are here.

Getting a Java program to use a TLS MQ channel, and use an external USB keystore.

This project started off trying to get a java program to use an HSM (external keystore on a USB). This was not well documented, so I have documented my path.

I had set up my keystore on the USB HSM device as described here. This post covers the MQ side of it.

MQ provides some JMS samples.

I could use JmsBrowser using local bindings with the jms.sh script.

. /opt/mqm/java/bin/setjmsenv64
java -Djava.library.path=/opt/mqm/java/lib64 JmsBrowser -m QMA -d CP0000

To use a client channel (QMACLIENT) was easy, the program is configured to allow a channel name to be passed as a parameter using the -l option.

. /opt/mqm/java/bin/setjmsenv64
java -Djava.library.path=/opt/mqm/java/lib64 JmsBrowser -m QMA -d CP0000 -h localhost -p 1414 -l QMACLIENT

To use a TLS channel (QMAQCLIENTTLS) proved harder

. /opt/mqm/java/bin/setjmsenv64
java -Djava.library.path=/opt/mqm/java/lib64 JmsBrowser -m QMA -d CP0000 -h localhost -p 1414 -l QMAQCLIENTTLS

This gave me

CC=2;RC=2397;AMQ9641: Remote CipherSpec error for channel ‘QMAQCLIENTTLS’ to host ”. [3=QMAQCLIENTTLS]

It was hard to find where to specify the CipherSpec. The documentation said “Using the environment variables MQCHLLIB to specify the directory where the table is located, and MQCHLTAB to specify the file name of the table.” I tried this and got the same error.

I collected a trace using the Java option -Dcom.ibm.msg.client.commonservices.trace.status=ON , but the trace showed the cipher spec was null.

I gave up with this program and used an enhanced version of the program. JMS programs can use JNDI as a file repository of configuration information and the program can extract the information. For example you can configure Connection Factories(cf) which are MQ connections, and Q objects – which are queues.

Use JNDI to store parameters

JMS programs can use a JNDI interface to access configuration parameters stored in an external file.
I used this article to get me started.

My JMSAdmin.config had

INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory
PROVIDER_URL=file:///home/colinpaice/mq/JNDI-Directory
SECURITY_AUTHENTICATION=none

I used the following commands to define a connection factory called CF1, using the channel, QMACLIENT, and a queue reference called MYQUEUE pointing to queue CP0000.

mkdir JNDI-Directory
/opt/mqm/java/bin/JMSAdmin -v -cfg JMSAdmin.config
define cf(CF1) transport(client) channel(QMACLIENT)
define q(MYQUEUE) queue(CP0000)
end

I used a bash script to run the program, using the JmsJndiBrowser sample (JmsBrowser with JNDI support).

. /opt/mqm/java/bin/setjmsenv64
java -Djava.library.path=/opt/mqm/java/lib64 JmsJndiBrowser -i file:///home/colinpaice/mq/JNDI-Directory -c CF1 -d MYQUEUE

This failed with

JMSCMQ0001: IBM MQ call failed with compcode ‘2’ (‘MQCC_FAILED’) reason ‘2400’ (‘MQRC_UNSUPPORTED_CIPHER_SUITE’).

Which was a surprise to me. I looked in the trace, and there was nothing obviously wrong. The channel was not configured for TLS.

I used the following command in the JMS Admin tool, to specify a TLS channel and configure the cipher suite

alter cf(CF1) channel(QMAQCLIENTTLS) SSLCIPHERSUITE(ANY_TLS12)

Note. If I displayed cf(CF1) it gave me SSLCIPHERSUITE(*TLS12).

This gave me unable to find valid certification path to requested target, which was good progress because it meant the cipher spec had been accepted.

I added in the Java parameters to identify the key store and trust store

. /opt/mqm/java/bin/setjmsenv64

kss=”-Djavax.net.ssl.keyStore=/home/colinpaice/ssl/ssl2/ecec.p12″
ksp=”-Djavax.net.ssl.keyStorePassword=password”
kst=”-Djavax.net.ssl.keyStoreType=pkcs12″
tss=”-Djavax.net.ssl.trustStore=/home/colinpaice/ssl/ssl2/dantrust.p12″
tsp=”-Djavax.net.ssl.trustStorePassword=password”
tst=”-Djavax.net.ssl.trustStoreType=pkcs12″
ks=”$kss $ksp $kst”
ts=”$tss $tsp $tst”

java $ks $ts -Djava.library.path=/opt/mqm/java/lib64 JmsJndiBrowser -i file:///home/colinpaice/mq/JNDI-Directory -c CF1 -d MYQUEUE

and it worked successfully.

Use the pkcs11 HSM external keystore.

I changed the file to specify the external keystore (with format pkcs11) on a USB device rather than a file on disk (format pkcs12).

kss=”-Djavax.net.ssl.keyStore=NONE”
kst=”-Djavax.net.ssl.keyStoreType=pkcs11″
ksp=”-Djavax.net.ssl.keyStorePassword=12345678″

but this gave

find /java.security.KeyStoreException: pkcs11 not found
java.security.NoSuchAlgorithmException: pkcs11 KeyStore not available

You have to tell Java where to find the pkcs11 code. This is configured in the java.security file. You can find it using find $JAVA_HOME/ -name java.security . This gave me the file name /usr/lib/jvm/java-8-oracle/jre/lib/security/java.security

It had the list of security providers,

security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=sun.security.ec.SunEC
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC

and is missing an entry for pkcs11.

You can edit this file, or override it. To override it, create a file like colin.java.properties with

security.provider.10=SunPKCS11 /home/colinpaice/mq/nitrokey.cfg

where

  • .10 is the next in sequence after the .9 in the java.security file
  • SunPKCS11 says use the Sun module.
  • /home/colinpaice/mq/nitrokey.cfg use this configuration file for the pkcs11 device.

Tell Java to use this override file, by using the Java option -Djava.security.properties=/home/colinpaice/mq/colin.java.properties.

The configuration file name for the pkcs11 is /home/colinpaice/mq/nitrokey.cfg with content

name = nitrokey
library = /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
slot=0

With these parameters the output from the JmsJndiBrowser command was

Initial context found!
Browse starts
No more messages
SUCCESS

Success – and it only took me half a day! The hardest part was known what to specify for the security.provider…… parameter.

Using the runmqakm commands and an HSM (but not strmqikm).

I tried to use strmqikm but it gave an exception.

You can use some of the runmqakm commands you know and love, to access a certificate with an HSM. For example

The command to list the database available to the runmqakm command,

runmqakm -keydb -list -crypto /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so

Gives

/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so : UserPIN (mytoken)

You can then use the token label UserPIN (mytoken) and password to use the key store, for example

runmqakm -cert -list all -crypto /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
-tokenlabel “UserPIN (mytoken)” -pw 12345678

gives

Certificates found
* default, - personal, ! trusted, # secret key
-	my_key3

and

runmqakm -cert -details -crypto /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
-tokenlabel “UserPIN (mytoken)” -pw 12345678
-label my_key3

displays the details of the certificate with label my_key3.

If the -tokenlabel was wrong or the -pw was wrong, I got the unhelpful messages

  • CTGSK3026W The key file “pkcs11” does not exist or cannot be read.
  • CTGSK2137W The label does not exist on the PKCS#11 device.

Create your certificate request

The following command create a new RSA private-public key pair and a PKCS10 certificate request. The documentation for runmqakm says it supports RSA. If you want to use an Elliptic Curve you will need to use an alternative method, for example openssl.

runmqakm -certreq -create -crypto /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
-tokenlabel “UserPIN (mytoken)” -pw 12345678
-dn “cn=colin,o=SSS” -file runmq.csr -label runmqlab -size 1024

Sign it

openssl ca -config openssl-ca-user.cnf -policy signing_policy -md sha256 -cert carsa1024.pem -keyfile carsa1024.key.pem -out runmq.pem -in runmq.csr

Store it back into the HSM keystore

I could not get the runmqakm command to receive the signed certificate and store it into the HSM keystore.

runmqakm -cert -receive -crypto /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so -tokenlabel “UserPIN (mytoken)” -file runmq.pem -pw 12345678

It failed with

CTGSK3034W The certificate request created for the certificate is not in the key database.

I could use

openssl x509 -inform pem -outform der -in runmq.pem -out runmq.der
pkcs11-tool –write-object runmq.der –type cert –label “runmqlab” -l –pin 12345678

The openssl command converts the file from .pem format, to .der format as .der format is required by pkcs11-tool.

Using strmqikm – the theory

If you want to use the strmqikm GUI, you have to configure the java.security file. For example edit /opt/mqm/java/jre64/jre/lib/security/java.security and add the next security.provider in the list.

security.provider.12=com.ibm.crypto.pkcs11impl.provider.IBMPKCS11Impl /home/colinpaice/mq/nitrokey.cfg

Where /home/colinpaice/mq/nitrokey.cfg is the configuration file, with

name = nitrokey
library = /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
slot=0

You can then use Ctrl+O, which brings up a pop up with “Key database type”. In this list should be PKCS11Config, if not check your java.security file. Select this, leave File Name and Location empty, and click “OK”. It pops up “Open Cryptographic Token” with the “Token Label” value taken from the configuration file name = nitrokey. This is strange as the runmqakm command uses a TokenLabel of “UserPIN (mytoken)”.

In practice…

I then got an exception java.lang.RuntimeException: PKCS11KeyStore.java: findSigner(): Failure while executing cobj.getX509Certificate(certFactory, session), and strmqikm ended.

Using a hardware security module USB as a keystore for a browser.

Background to certificates and keystores

When using TLS(SSL) you have two keystores

  • A keystore for holding the public part and private key of your certificate
  • A trust store which holds the public keys of certificate sent to you which you need to authenticate.

Your certificate has two parts

  • The private key which contains information needed to encrypt information you send. This needs to be kept private.
  • The public part,which has information that is needed to decrypt information you have encrypted, along with information such as your Distinguished Dame (DN) such as CN=ColinPaice C=GB,O=StromnessSoftware

The process of creating a signed certificate is

  • Create a private key and public key. This can be done using an external device Hardware Security Module (HSM), such as the Nitrogen HSM USB, or software, for example using OPENSSL. This produces a private key file, and a certificate request file containing the public information.
  • Send the public information to your certificate authority which signs it, and returns it
  • Import the signed public certificate into your keystore.

Creating a certificate using an HSM as the key repository

I used openssl to process my certificates, I’ve discussed the openssl setup here.

I use a bash script because it is easy to parametrize, and makes it easy to rerun until it works. I’ll give the script, then explain what it does

  • enddate=”-enddate 20240130164600Z”
  • name=”hw”
  • rm $name.key.pem
  • rm $name.csr
  • rm $name.pem
  • ca=”carsa1024″
  • pkcs11-tool –keypairgen –key-type rsa:2048 –login –pin 648219 –label “my_key3”
  • OPENSSL_CONF=eccert.config openssl req -new -engine pkcs11 -keyform engine -key label_my_key3 -out $name.csr -sha256 -subj “/C=GB/O=HW/CN=colinpaice” -nodes
  • openssl ca -config openssl-ca-user.cnf -policy signing_policy -md sha256 -cert $ca.pem -keyfile $ca.key.pem -out $name.pem -in $name.csr $enddate
  • openssl x509 -inform pem -outform der -in $name.pem -out $name.der
  • pkcs11-tool –write-object $name.der –type cert –label “my_key3” -l –pin 648219

What does the script do ?

enddate=”-enddate 20240130164600Z”

This sets the end date for the certificate – the end date is set when it is signed.

name=”hw”

This is used within the script to ensure the correct files are being used.

Remove old intermediate files
  • rm $name.key.pem
  • rm $name.csr
  • rm $name.pem
ca=”carsa1024″

Define the name of the CA files to use at signing time. The $ca.pem and $ca.key.pem are both needed.

pkcs11-tool –keypairgen –key-type rsa:2048 –login –pin 648219 –label “my_key3”
  • pkcs11-tool use this tool
  • –keypairgen to create a key pair (private and public pair)
  • –key-type rsa:2048 use this key type and key length
  • –login –pin 648219 login with the pin number
  • –label “my_key3” use this label to identify the key
OPENSSL_CONF=eccert.config openssl req -new -engine pkcs11 -keyform engine -key label_my_key3 -out $name.csr -sha256 -subj “/C=GB/O=HW/CN=colinpaice”
  • OPENSSL_CONF=eccert.config this sets up the openssl config file. Having -config eccert.config does not work. See here.
  • openssl
  • req this is to create a certificate requests – create a .csr.
  • -new it is a new request
  • -engine pkcs11 use the named engine, pkcs11, defined to the system
  • -keyform engine this says use the engine (HSM). Other choices are der and pem
  • -key label_my_key3 go to the engine and look for the my_key3 label
  • -out $name.csr create this request file with this name.
  • -sha256 using this signature
  • -subj “/C=GB/O=HW/CN=colinpaice” the name to go in the certificate. It uses colinpaice as the certificate will be used to authenticate with the mq web server, and this is the userid the mq web server should use.

Send the .csr file to the CA for signing (which is the same machine in my case).

openssl ca -config openssl-ca-user.cnf -policy signing_policy -md sha256 -cert $ca.pem -keyfile $ca.key.pem -out $name.pem -in $name.csr $enddate
  • openssl ca Use this command to sign the certificate
  • -config openssl-ca-user.cnf use this configuration file
  • -policy signing_policy use this policy within the config file
  • -md sha256 use this for the message digest
  • -cert $ca.pem use the public certificate of the CA
  • -keyfile $ca.key.pem use this private key of the CA to encrypt information about the csr request’s certificate
  • -out $name.pem whee to store the output
  • -in $name.csr the input .csr request
  • $enddate specify the certificate expiry date – set at the top of the script

Send the signed certificate back to the requester.b

openssl x509 -inform pem -outform der -in $name.pem -out $name.der

The pkcs11-tool uses .der files so convert the .pem file to .der format

  • openssl x509
  • -inform pem input format
  • -outform der output format
  • -in $name.pem hw.pem
  • -out $name.der hw.der
pkcs11-tool –write-object $name.der –type cert –label “my_key3” -l –pin 648219

Read the signed certificate and write it to the HSM

  • pkcs11-tool
  • –write-object $name.der write onto the HSM the file hw.der coverted above
  • –type cert import type (cert|pubkey|privkey)
  • –label “my_key3” use this name
  • -l –pin 648219 and logon with this pin number

Define the HSM to Chrome browser

Stop the browser because you need to update the keystore.
The command was issued in the home directory, because key store is in the home directory/.pki .

modutil -dbdir sql:.pki/nssdb/ -add “my_HSM” -libfile opensc-pkcs11.so

  • modutil use this command
  • -dbdir sql:.pki/nssdb/ to up date this keystore (in ~)
  • -add “my_HSM” give it this name
  • -libfile opensc-pkcs11.so and use this file to communicate to it

Display the contents of the browser’s keystore

modutil -dbdir sql:.pki/nssdb/ -list

This gave me

Listing of PKCS #11 Modules
 NSS Internal PKCS #11 Module
...
 Mozilla Root Certs
 library name: /usr/lib/x86_64-linux-gnu/nss/libnssckbi.so
...
my_HSM
 library name: opensc-pkcs11.so
    uri: pkcs11:library-manufacturer=OpenSC%20Project;library-description=OpenSC%20smartcard%20framework;library-version=0.17
  slots: 1 slot attached
 status: loaded
 slot: Nitrokey Nitrokey HSM (DENK01051600000         ) 00 00
 token: UserPIN (SmartCard-HSM)
   uri: pkcs11:token=UserPIN%20(SmartCard-HSM);manufacturer=www.CardContact.de;serial=DENK0105160;model=PKCS%2315%20emulated 

Restart the browser.

Use an URL which needs a certificate for authentication.

The browser prompts for the pin number (twice), and displays the list of valid certificate CNs. Pick one. When I connected to the mqweb server, I had 3 certificates displayed. I had to remember which one I wanted from the Issuer’s CN and serial number. For example

SubjectIssuerSerial
colinpaiceSSCARSA1024019c
ibmsys1SSCARSA1024019a
170594SSCARSA10240197
Select a certificate

(Having a CA just for HSM keys, such as SSSCAHSM would make it more obvious.)

Setting up digital certificates for identification in your enterprise.

You can use digital certificate for authentication, for example you can logon onto the MQ Web server using a certificate to identify you, and you do not have to enter a userid or password.

Many systems have Multi Factor Authentication (MFA) to logon which usually means you authenticate with something you have, and with something you know. Something you have is the private certificate, something you know is userid and password.

At the bottom I discuss having an external device for your keystore to make your keystore more secure.

General background and information

  • Your certificate has a private key (which should not leave your machine), and a public part, which anyone can have.
  • You can have a key store which has your private key in it. This is often just a file which could be copied to another machine. This is not a very secure way of keeping your certificates, as there is usually a stash file with the password in it, which could easily be copied along with the keystore.
  • You have a trust store which contains the public part of the certificates you want to validate (demonstrate trust) with. This is usually a set of Certificate Authority public keys, and any self signed certificates. The information in these certificates is commonly available and can be world read. You will want to protect this for write, so people cannot insert CAs from the bad guys.
  • You can use Hardware Security Module, a piece of hardware which can store your private keys, and does encryption for you. This is a secure way of keeping your certificates. You need physical access to the machine to be able to physically access the HSM hardware.
  • Certificates are based on trust. When I create a public certificate, I can get this signed by a Certificate Authority. When I send my public certificate to you, and you have the same Certificate Authority, you can check what I sent you using the Certificate Authority. My public certificate give information on how to decrypt stuff I send you.
  • When a connection is made between a client and a server. The server sends down its certificate for the client to validate and accept, and the client can then send up a certificate for the server to validate and accept. This is known as the handshake
  • A certificate has a Distinguished Name. This is like “CN=COLIN,OU=TEST,O=SSS.ORG” so my Common Name is COLIN, The Organizational Unit is TEST, and my Organization is SSS.ORG.
    • Some products like the mid-range MQ Web Server map the CN to a userid.
    • As part of the logon a client or server can check the certificate sent to it, for example allow any certificate with OU=TEST, and O=SSS.ORG.

Planning for TLS and certificate

Consider a simple scenario of two MQ Servers, and people from my.org and your.org want to work with MQ. Leaving aside the task of creating the certificate, you need to decide

  • What name hierarchy you want, for example CN=”COLIN PAICE”, OU=TEST, C=GB, O=SSS.ORG,
    • do you want to have a CN with a name in it, or a userid, or a personnel number. This is used by the MQWeb as a userid. You could have CN=MQPROD1, etc to give each server its own CN.
    • Do you want to have the country code in it C=GB? What happens if someone moves country. You might decide to have servers with CN=MQPROD1,OU=PROD… or OU=TEST… .
  • What CA hierarchy do you want. You could have a CA for OU=PROD, O=SSS.ORG at the PROD level, or CN=CA,O=SSS.ORG at the organisation level. Some servers can check the issuer is OU=PROD, O=SSS.ORG and so only allow certificates signed by that CA. Someone connecting with a certificate signed with OU=TEST,O=SSS.ORG would not be allowed access.
  • You could give each server the same DN, for example CN=MQSERVER,OU=PROD,O=SSS.ORG, or individual ones CN=MQSERVER1,OU=PROD,O=SSS.ORG
  • You can have a server check that a certificate is still valid by using Online Certificate Status Protocol (OCSP). After the handshake, a request goes to a remote server asking if the certificate is still valid. Ive written a blog post Are my digital certificates still valid and are they slowing down my channel start? z/OS does not support OCSP. MQ on z/OS supports a LDAP repository of Certificate Revocation Lists. If you intend to use OCSP you need to set up the OCSP infrastructure.
  • With the MQ mover, you can set up CHLAUTH records to allow or disallow DN’s or CA certificates.
  • The clients from my.org have a DN like CN=COLIN,OU=TEST,O=myorg.com. The clients from your.org have a DN like CN=170594,c=GB,o=your.org. You cannot have one string (SSLPEER) to allow both format certificates.
    • For connections to the chinit(mover) you can use CHLAUTH to give find grained control.
    • For the MQWeb on z/OS you can control which certificates (or Issuers) map to a userid.
    • For mid-range MQWEB you have no control beyond a successful handshake. CN=COLIN,o=MY.ORG, and CN=COLIN,o=YOUR.ORG would both map to userid COLIN even though they are from different organisations. The CN is used as a userid, and you map userids or groups to security profiles.

Setting up your certificates

As your private key should not leave your machine, the standard way of generating a certificate is

  • The client machine creates a certificate request. This has the public certificate, and the private key.
  • The public certificate is sent to the appropriate authority (a department in your organization) which signs the certificate. Signing the certificate consists of doing a check sum of the public certificate, encrypting the check sum value, and packaging the public certificate, the encrypted checksum, and the CA public certificate into one file. This file is sent back to the requester
  • The originator reads the package stores it in a keystore, and uses this as its public key.
  • Often this request for a certificate is allowed only when the machine is connected locally to the network, rather than over the internet. This means people need to bring their portable machines into the office to renew a certificate.

If you create the private certificate centrally and email it to the end user, someone who is snooping on the email will get a copy of it!

A machine can have more than one keystore and a keystore can have one or more certificates. With some servers you can configure the default certificate to use. If not they the “best” certificate is chosen. This could depend on the strength and selection of the cipher specs.

What if’s

Once you have set up your certificate strategy it is difficult to change it, so it is worth setting up a prototype to make sure the end to end solutions work, then throwing the prototype away and starting again.

You need to consider how to solve problems like

  • What if someone leaves my organisation, how do I inactivate the certificate
  • What happens of someone loses their laptop, how do I inactivate the certificate
  • Certificates have expiry dates. What do I need to do to renew the certificate before it expires – for example you could email the owner and tell them to bring the laptop to the office to renew the certificate
  • What happens if a CA expires?
  • Someone joins the department how do I update the access lists. Usually this is done using a repository like LDAP.
  • Are the CHLAUTH records restrictive enough to prevent the wrong people from getting access, but broad enough that you do not need to change them when someone joins the organisation.
  • What if you open up your business to a new organisation with a different standard of DN? What do you need to change to support it.

Use of physical keystores.

You can have a physical keystore to store your private key. This can range from a USB device up to integrated devices.
With these people cannot just copy the keystore and stash file, they need physical access to the device.

You need to plan how these will be used in your organisation for example you have two machines for HA reasons. Each has a USB store. Does each machine need its own private key? How do you handle disaster recovery when someone loses/breaks the keystore.

Physical keystores can have have a secure export and import capability. You configure a key onto the device, for example saying it needs 3 partial keys, needing three people to enter their portion of it. When you export the key, it comes out encrypted.

In this scenario the configuration process could be

  • Configure the first device. 3 people enter their password.
  • Create a private key
  • Export the private key and send it to the second machine. It is encrypted so can safely be sent.
  • Go to the second machine, and configure the second device.
  • As before, the three people have to configure the device.
  • Import the encrypted certificate to the device
  • Go the the next machine etc.
  • In some cases you can say that n out of m people are required to configure the device. So any 3 out of a team of 6 is enough.

Would you lock your front door and leave the key under the mat? So why do you do it with digital keys?

Where I live it is Island Mentality. Someone said to me that they do not lock their front door. Sometimes, when they come home, they find some eggs or tray-bakes on the kitchen table. They went on a celebration cruise, but could not find the key to the front door, and so left the house unlocked the two weeks they were away.

Digital certificates and keys are used for identification authentication. Often these are stored in a key store, just a file in Windows or Unix. You typically need a password to be able to read the file. If you got hold of a keystore, you could try “password” with an “o”, “passw0rd” with zero etc. There is no limit to the number of attempts you can have. Don’t worry, the password is stored in a stash file , which is just another file. If you have the key store and the stash file you can open the keystore using standard commands. Having both the keystore and the stash file is like finding the front door unlocked.

If someone is an administrator on the machine, they can access any file and so can get the keystore and the stash file. IBM says you need superuser access to install MQ – so the MQ administrator can access these files. I heard that one enterprise was doing backups from the user’s machines to a remote site. The files were encrypted at the remote site, but not the network link to the remote site – whoops! The files could have been stolen en route.

Use external security devices.

You can get round this problem by using an external Hardware Security Module. Instead of storing the keys in a file, they are stored on an external device. You can get USB like devices. Some HSM can store keys, other HSMs can encrypt data. For example my bank gives its user’s a small machine. You put in your debit card, enter your pin. It encrypts the data and generates a one time key which you enter into the bank’s web site.

To steal the keystore you now need access to the physical machine to be able to unplug the USB.

Built in devices that cannot be removed.

On some machines, such as z hardware, they have a tamper resistant “cryptographic chip” built in. If you remove it from the machine, it is useless. When you configure it you need three keys, so you have three people each with their own key. When you install the backup machine, the three people have to go on site, and re enter their keys. They have mechanisms like three wrong passwords and it self destructs (perhaps in a cloud of smoke, as it does in the movies).

“Cloud”

One of the selling points of cloud is flexibility. You can deploy an image anywhere; you can wheel in new machines, and wheel out old machines; and you can have different “tenants” on the same hardware. This makes it difficult to use an HSM device to store your keys, as each machine needs the same keys, and the HSM could have all the keys from all the tenants. So you have the problem, of having your key store as a file with its stash file, and even more people have access to these files.

Would you lock your front door and leave the key under the mat? So why do you do it with digital keys

It is all down to the management of risk. Digital certificates do not give absolute protection. Strong encryption just means it takes longer to crack!

Getting SSL/TLS to work on MQ on z/OS

After I succeeded in getting TLS 1.3 to run on MQ  midrange 9.2, I thought I would try it on z/OS.  I had not used TLS on z/OS for about 10 years, so it was almost like coming to the topic with very rusty knowledge.

I searched the Knowledge centre and found no relevant hits – lots of hits which were not relevant.  I eventually found an SSL related keyword, and this got me to the topic  Working with SSL/TLS on z/OS.   I think this is well documented.  It covered all the things I had to do.

The remained of this post covers the bits not covered by the documentation.

Define SSLTASKS.

You need to define SSLTASKS to be able to use TLS on z/OS.  See the comments here. I used

%CSQ9 ALTER QMGR SSLTASKS(5)

You need to restart the CHINIT if you change the value of SSLTASKS.

Set up the keyring for the queue manager. 

See here.  This post show how to create the keyring and import a CA from z/OS, and import a CA  from a Linux system.

If you alter the keyring or certlabl you just need a refresh security type(SSL) command to pick up the changes.

Defining the channel

I tried to define the channel, as this failed for security reasons, I’ve given the RACF setup I had to do.

In this section I defined the specific commands for example DEFINE.CHANNEL.   I could have defined DEFINE.* to allow all define commands.

I used a channel called TLS, and define the resource CSQ9.CHANNEL.TLS* to allow my ID to define TLS, TLS1 etc

The command %CSQ9 DEF CHL(TLS) CHLTYPE(SVRCONN) gave me

ICH408I USER(CSQOPR ) GROUP(SYS1 ) NAME(COLIN PAICE ) 167
CSQ9.DEFINE.CHANNEL CL(MQCMDS )
WARNING: INSUFFICIENT AUTHORITY – TEMPORARY ACCESS ALLOWED
ACCESS INTENT(ALTER ) ACCESS ALLOWED(NONE )

I used the RACF commands in a batch job.

 /* RDELETE MQCMDS CSQ9.DEFINE.CHANNEL
RDEF MQCMDS CSQ9.DEFINE.CHANNEL UACC(NONE)
PERMIT CSQ9.DEFINE.CHANNEL CLASS(MQCMDS ) –
        ID(COLIN,IBMUSER) ACCESS(ALTER )

I also set up CSQ9.DELETE.CHANNEL and CSQ9.ALTER.CHANNEL in a similar way, so my userid could maintain the channels.

I refreshed MQ security %CSQ9 refresh security to pick up the changes.

I reissued the command %CSQ9 DEF CHL(TLS ) CHLTYPE(SVRCONN) and got

ICH408I USER(COLIN ) GROUP(SYS1 ) NAME(COLIN PAICE )
CSQ9.CHANNEL.TLS CL(MQADMIN )
PROFILE NOT FOUND – REQUIRED FOR AUTHORITY CHECKING
ACCESS INTENT(ALTER ) ACCESS ALLOWED(NONE )

I used the RACF commands in a batch job.

  /* RDELETE MQADMIN CSQ9.CHANNEL.TLS*
RDEF MQADMIN CSQ9.CHANNEL.TLS* UACC(NONE) WARNING
PERMIT CSQ9.CHANNEL.TLS* CLASS(MQADMIN) –    
        ID(COLIN,IBMUSER) ACCESS(ALTER )
SETROPTS RACLIST(MQADMIN) REFRESH

I issued the commands

%CSQ9 refresh security
%CSQ9 DEF CHL(TLS ) CHLTYPE(SVRCONN)

And successfully defined the channel.

I changed the cipher spec.

I selected a cipher spec from the list.

%CSQ9 alter chl(TLS) chltype(SVRCONN) SSLCIPH(ECDHE_RSA_AES_128_CBC_SHA256)

When I started the channel I got

CSQX631E … CSQXRESP Cipher specifications differ,  channel TLS local=ECDHE_RSA_AES_128_CBC_SHA256 remote=TLS_RSA_WITH_AES_256_GCM_SHA384
connection 10.1.0.2 (10.1.0.2)

This was clear;  I love clear messages.

I decided to change the z/OS end

%CSQ9 alter chl(TLS) chltype(SVRCONN) SSLCIPH(TLS_RSA_WITH_AES_256_GCM_SHA384 )

and the client connected successfully.

With MQ 9.2 I could (and did) change this to

%CSQ9 alter chl(TLS) chltype(SVRCONN) SSLCIPH(ANY_TLS12)

and the client worked successfully.  The ANY_TLS12.  provides a wide list of supported cipher specifications, includes TLS_RSA_WITH_AES_256_GCM_SHA384  and ECDHE_RSA_AES_128_CBC_SHA256. 

When I am ready to support TLS 1.3 I will use ANY_TLS12_OR_HIGHER and ANY_TLS13_OR_HIGHER.

Connect a client to it!

I had had my client connect to a midrange queue manager, so I had working client environment.  See here for the journey.

I created a .json file for the CCDT connection to z/OS.  I specified

{ "channel":
  [{
    "name": "TLS",
    "clientConnection":
    {
      "connection":
      [{
        "host": "10.1.1.2",
        "port": 1414
       }],
      "queueManager": "CSQ9"
    },
    "transmissionSecurity":
    {
      "cipherSpecification": "ANY_TLS12",
      "certificateLabel": "rsaca256_client",
      "certificatePeerName": ""
    },
    "type": "clientConnection"
  }]
}

When it connected I got messages

+CSQX511I %CSQ9 CSQXRESP Channel TLS started connection 10.1.0.2
ICH408I USER(COLINPAI) GROUP( ) NAME(??? )
LOGON/JOB INITIATION – USER AT TERMINAL NOT RACF-DEFINED
IRR012I VERIFICATION FAILED. USER PROFILE NOT FOUND.
+CSQX512I %CSQ9 CSQXRESP Channel TLS no longer active connection 10.1.0.2

COLINPAI came from the userid on the Linux machine (colinpaice) upper cased and truncated. This id will be flowed and used as the MCAUSER if you don’t set it to anything else, using CHLAUTH for example  (Thanks to Morag for this information).

Enable chlauth

To be able to map from the DN in a certificate to a z/OS userid you have to use MQ CHLAUTH.  See  Mapping a client user ID to an MCAUSER user ID.

Check it is enabled at the queue manager level and enable it it needed.

%CSQ9 DIS QMGR CHLAUTH
%CSQ9 ALTER QMGR CHLAUTH(ENABLED)

Define a mapping from certificate to userid

I used

//S1 EXEC PGM=CSQUTIL,PARM='CSQ9' 
//STEPLIB  DD DSN=COLIN.MQ921.SCSQLOAD,DISP=SHR 
//         DD DSN=COLIN.MQ921.SCSQANLE,DISP=SHR 
//SYSPRINT DD SYSOUT=* 
//SYSIN   DD * 
 COMMAND DDNAME(COMMAND) 
//COMMAND DD * 
 SET CHLAUTH('TLS') + 
     TYPE(SSLPEERMAP) SSLPEER('O="cpwebuser"') + 
     ACTION(REPLACE)   + 
     MCAUSER(ADCDD ) CHCKCLNT(ASQMGR) 
/* 

This says for channel TLS,  take the Organisation(O=..)  from the certificate, and if it is cpwebuser then set the ID to ADCDD.

Check it works

Once the channel had started I used

%CSQ( DIS CHS(TLS)
it displayed the following, where I have removed lines which are not relevant to TLS and added some comments

  • CHSTATUS(TLS)
  • CHLTYPE(SVRCONN)
  • SECPROT(TLSV12) – this is the level of the protocol
  • SSLCERTI(CN=SSCARSA1024,OU=CA,O=SSS,C=GB)- this is the DN of the issuer of the SSLPEER certificate (below)
  • SSLCERTU(START1) – the IBM documentation says “The local user ID associated with the remote certificate.”  I dont know where this comes from.. how to change it, or where it is used.
  • SSLCIPH(TLS_RSA_WITH_AES_256_GCM_SHA384) – The negotiated cipher spec
  • SSLRKEYS(0) -The number of successful TLS key resets.
  • SSLKEYTI() -The time on which the previous successful TLS secret key was reset.  The secret key has not been reset
  • SSLKEYDA() -The date on which the previous successful TLS secret key was reset.  The secret key has not been reset
  • SSLPEER(SERIALNUMBER=01:90,CN=rsaca256,O=cpwebuser,C=GB, UNSTRUCTUREDNAME=openssl_ca_user_cnf.keyAgreement2, UNSTRUCTUREDNAME=localhost, UNSTRUCTUREDADDRESS=127.0.0.1) . This is information from the certificate at the remote end.
  • MCAUSER(ADCDD) – This is the userid (set by the CHLAUTH above) used by this channel.
  • LOCLADDR(10.1.1.2(1414)) – This is the address the connection came in from.  This value will be different it you have different IP stacks and different listener ports.

Setting up the MQ keyring on z/OS

I wanted to connect some clients to my z/OS queue manager over a TLS channel.  This post describes how I set up the z/OS keyring with the certificates.

Define the keyring.

The CSQ9 CHINIT runs with a userid of START1, so I defined a keyring belonging to that id.

I set up a dataset  called IBM.MQCSQ9.KEYRING to keep all of my JCL in for the CSQ9 queue manager.  This makes it easier to clone the definitions for another queue manager.

The definitions create the keyring, and add the z/OS CA certificate (CERTAUTH ADCD_CA) to it.

//IBMRACF JOB 1,MSGCLASS=H 
//* Use JCL for the RACF definitions
//S1 EXEC PGM=IKJEFT01,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
/*RACDCERT DELRING(MQRING) ID(START1)
RACDCERT ADDRING(MQRING) ID(START1)
RACDCERT ID(START1 ) -
   CONNECT(RING(MQRING) LABEL('ADCD-CA') CERTAUTH)
SETROPTS RACLIST(DIGTCERT,DIGTRING ) refresh

Define the queue manager’s certificate.   This uses an Elliptic curve with key size of 256.

 /*RACDCERT ID(START1) DELETE(LABEL('CSQ9CERT')) 
RACDCERT ID(START1) GENCERT - 
  SUBJECTSDN(CN('CSQ9CERT')  - 
             O('ADCD') - 
             OU('TEST')) - 
   SIZE(256) - 
   NISTECC - 
   SIGNWITH (CERTAUTH LABEL('ADCD-CA')) - 
ALTNAME(IP(10.1.1.9)) - NOTAFTER( DATE(2021-12-29))- WITHLABEL('CSQ9CERT')
RACDCERT id(START1) ALTER(LABEL('CSQ9CERT'))TRUST RACDCERT ID(START1) CONNECT(RING(MQRING) - LABEL('CSQ9CERT') USAGE(PERSONAL)) RACDCERT LISTRING(MQRING) ID(START1) RACDCERT LIST(LABEL('CSQ9CERT' )) ID(START1) SETROPTS RACLIST(DIGTCERT,DIGTRING ) refresh

It need ALTNAME(IP(10.1.1.2)) ( or similar) because some browsers check this name, with the IP address of the server.

 

Configure the queue manager

%CSQ9 ALTER QMGR SSLKEYR(START1/MQRING) CERTLABL(CSQ9CERT)

Note if you use mixed case keyring you need to put the value in quotes.

Export the CA certificate from z/OS and sent to the client machine

RACDCERT CERTAUTH EXPORT(LABEL('ADCD-CA'))- 
DSN('IBMUSER.CERT.ADCDCA.PEM') -
FORMAT(CERTB64) -
PASSWORD('password')

The data set  IBMUSER.CERT.ADCDCA.PEM  contained text, and the first line is —–BEGIN CERTIFICATE—– .   Send this file to the client machine, for example using FTP.  I sent it as zos.adcdca.pem.

Import this to the keystore

runmqakm -cert -add -file zos.adcdca.pem -type cms -stashed -db zzclient.kdb -label zosca

Upload  the certificates from Linux to z/OS.

On Linux, my CA certificiate was in a *.pem file where the first line was —–BEGIN CERTIFICATE—–.  Send this to z/OS.  I used FTP.

Import the CA into the keyring.

The command adds an existing certificate CARSA1024 for userid START1.  The CONNECT USAGE(CERTAUT) defines this as a CA certificate (without the need to have the certificate belong to CERTAUTH userid).

  /*RACDCERT DELETE  ( LABEL('CARSA1024')) ID(START1) 
 SETROPTS RACLIST(DIGTCERT,DIGTRING ) refresh 
                                                                   
 RACDCERT ADD('IBMUSER.CARS1024.PEM')  - 
   ID(START1)  WITHLABEL('CARSA1024') 
 RACDCERT ID(START1) CONNECT(RING(MQRING    ) - 
                             USAGE(CERTAUTH) - 
                             ID(START1)  - 
                             LABEL('CARSA1024') 
 racdcert listring(MQRING ) id(start1) 
 SETROPTS RACLIST(DIGTCERT,DIGTRING ) refresh 

Refresh the queue manager

%CSQ9 refresh security type(SSL)

I’m thinking of using MQ MinimumRSAKeySize. What do I need to plan for?

If you enable this option in the qm.ini or mqclient.ini, it can have problems which are hard to diagnose.

This option restricts

  1. the key size of certificates with a type of RSA
  2. the key size of any CA certificates  with a type of RSA, used to sign a certificate (whether the certificate is RSA or not).

For example with MinimumRSAKeySize=2048 you cannot use a certificate or CA generated with openssl genpkey -out $name.key.pem -algorithm RSA -pkeyopt rsa_keygen_bits:1024.

On the client machine in /var/mqm/errors/*01* I got AMQ9633E: Bad SSL certificate for channel ….

On z/OS I got CSQX620E … CSQXRESP System SSL error, channel … connection … function ‘gsk_secure_socket_init’ RC=541.  Code 451 means “bad certificate” was received from the remote end.

How do I check?

There is no easy way of displaying the details of all of the certificates in a key store.

Midrange.

You can use the following command to list the labels all of the certificates

runmqakm -cert -list all -db zzclient.kdb -type cms -stashed -v

Then use the following command to display the details of each label in turn (zosca in the example)

runmqakm -cert -details -db zzclient.kdb -type cms -stashed -label zosca

This displays information like the example below for a CA certificate of type RSA and key size 1024.

Label : zosca
Key Size : 1024
Version : X509 V3
Serial : 00
Issuer : "CN=z/OSCertification Authority,OU=TEST,O=ADCD"
Subject : "CN=z/OSCertification Authority,OU=TEST,O=ADCD"
Not Before : 7 July 2020 00:00:00 GMT+01:00
Not After : 7 July 2021 23:59:59 GMT+01:00
Public Key
    ...
Public Key Type : RSA (1.2.840.113549.1.1.1)
  

or for an Elliptic certificate with key size 256.

Label : ca256
Key Size : 256
Version : X509 V3
Serial : ...
Issuer : CN=SSCA256,OU=CA,O=SSS,C=GB
Subject : CN=SSCA256,OU=CA,O=SSS,C=GB
Not Before : 7 February 2021 11:24:56 GMT
Not After : 7 February 2024 11:24:56 GMT
Public Key
    ... 
Public Key Type :  EC_ecPublicKey 

You can only check the certificates that are in your key store, not certificates that are sent as part of the handshake. 

z/OS

The listring command displays the contents of the ring (owner and label).

RACDCERT LISTRING(MQRING) ID(START1)

The list command displays the details of a certificate.

RACDCERT certauth LIST(label(‘ADCD-CA’))

displays information like, for the RSA certificate with a small key size,

 Label: ADCD-CA                                                       
 Certificate ID: 2QiJmZmDhZmjgcHEw8Rgw8FA                             
 Status: TRUST                                                        
 Start Date: 2020/07/06 23:00:00                                      
 End Date:   2021/07/07 22:59:59                                      
 Serial Number: ...                                                
 Issuer's Name:                                                      
      >CN=z/OSCertification Authority.OU=TEST.O=ADCD<                 
 Subject's Name:                                                      
      >CN=z/OSCertification Authority.OU=TEST.O=ADCD<                 
 Signing Algorithm: sha1RSA                                           
 Key Usage: CERTSIGN                                                  
 Key Type: RSA                                                        
 Key Size: 1024                                                       

Certificates signed by this CA would not work if MinimumRSAKeySize=2048 was specified.

Colins updates to MQ messages

As I was trying to get TLS to work on midrange, I had many MQ error messages. Sometimes the messages were a bit vague “you’ve had a problem. Resolve it and restart the channel”.

Below is the list of messages I’ve added comments to. I’ve done it as a blog post as well-known search engines are not finding the pages.

Mid range

z/OS

Client