/* Rexx */
/* PKCS#11 Unwrap Sample */
/*-------------------------------------------------------------------*/
/* Description: */
/* */
/* This REXX contains samples that show PKCS#11 Unwrap */
/* - Create a PKCS #11 token */
/* - Generate a clear 3072-bit RSA key pair to store in the TKDS */
/* - Extract the RSA public key from the RSA key pair */
/* - Generate a clear 128-bit AES key */
/* - Encrypt "Hello World" with the AES key */
/* - Wrap (encrypt) the AES key with the RSA public key */
/* - Unwrap (decrypt) the AES key with the RSA private key and */
/* store the unwrapped key in the TKDS */
/* - Decrypt "Hello World" with the unwrapped key */
/* */
/* How To Run: */
/* - Execute this script from TSO */
/* (e.g. EX 'HLQ.MLD.LLQ(P11UWK)') */
/*-------------------------------------------------------------------*/
SIGNAL ON NOVALUE;
/*-------------------------------------------------------------------*/
/* PKCS#11 Constants (subset) */
/*-------------------------------------------------------------------*/
/* Objects */
CKO_PUBLIC_KEY = '00000002'X
CKO_PRIVATE_KEY = '00000003'X
CKO_SECRET_KEY = '00000004'X
/* Key Types */
CKK_RSA = '00000000'X
CKK_AES = '0000001F'X
/* Miscellaneous */
CK_TRUE = '01'x
CK_FALSE = '00'x
CKA_CLASS = '00000000'X
CKA_TOKEN = '00000001'X
CKA_PRIVATE = '00000002'X
CKA_LABEL = '00000003'X
CKA_VALUE = '00000011'X
CKA_VALUE_LEN = '00000161'X
CKA_KEY_TYPE = '00000100'X
CKA_SENSITIVE = '00000103'X
CKA_SIGN = '00000108'X
CKA_VERIFY = '0000010A'X
CKA_MODULUS = '00000120'X
CKA_MODULUS_BITS = '00000121'X
CKA_PUBLIC_EXPONENT = '00000122'X
CKA_IBM_SECURE = '80000006'X
/* CLEANUP tokens in use for this sample */
Token_Handle = left('SAMPLE#P11UWK#TOKEN',44)
TRD_Handle = Token_Handle
Call CSFPTRD
/*********************************************************************/
/* Create a PKCS#11 token to contain PKCS #11 objects. */
/*********************************************************************/
TRC_rule_count = '00000001'x
TRC_rule_array = 'TOKEN '
TRC_attr_list = ,
'Manufacturer ' ||, /* 32 char Manuf ID */
'Model# _P11UWK ' ||, /* 16 char Model */
'Serial# _P11UWK ' ||, /* 16 char Serial# */
'00000000'x /* 4 char reserved */
TRC_attr_list_length = d2c(length(TRC_attr_list),4)
Call CSFPTRC
say "token handle: " trc_handle
/*********************************************************************/
/* Generate a 3072-bit RSA key pair. */
/*********************************************************************/
GKP_PubKey_Handle = copies(' ',44)
GKP_PrivKey_Handle = copies(' ',44)
GKP_PubKey_Attr_List = '0006'x ||, /* number attributes */
CKA_CLASS || '0004'x || CKO_PUBLIC_KEY ||,
CKA_KEY_TYPE || '0004'x || CKK_RSA ||,
CKA_TOKEN || '0001'x || CK_TRUE ||, /* TKDS */
CKA_MODULUS_BITS || '0004'x || '00000C00'x ||, /* 3072 */
CKA_LABEL || '0018'X || 'P11 Clear RSA Public Key' ||,
CKA_IBM_SECURE || '0001'X || CK_FALSE; /* clear */
GKP_PrivKey_Attr_List = '0005'x ||, /* number attributes */
CKA_CLASS || '0004'x || CKO_PRIVATE_KEY ||,
CKA_KEY_TYPE || '0004'x || CKK_RSA ||,
CKA_TOKEN || '0001'x || CK_TRUE ||, /* TKDS */
CKA_LABEL || '0019'X || 'P11 Clear RSA Private Key' ||,
CKA_IBM_SECURE || '0001'x || CK_FALSE; /* clear */
GKP_PubKey_Attr_List_Length = D2C(Length(GKP_PubKey_Attr_List),4)
GKP_PrivKey_Attr_List_Length = D2C(Length(GKP_PrivKey_Attr_List),4)
Call CSFPGKP;
/*-------------------------------------------------------------------*/
/* Find and extract the public key. */
/*-------------------------------------------------------------------*/
/* Lookup the public key handle */
TRL_handle = token_handle
TRL_rule_count = '00000001'x
TRL_rule_array = 'OBJECT '
TRL_srch_tmpl_length = '00000020'x
TRL_srch_tmpl = '0001'x ||, /* number attributes */
CKA_LABEL || '0018'X || 'P11 Clear RSA Public Key'
TRL_handle_count = '00000010'x /* expect one 44-byte handle */
TRL_list_length = '00000DAC'x
TRL_output_list = copies('00'x,3500)
CALL CSFPTRL
if c2d(TRL_handle_count) < 1 then
do
say "Public key not found. Check SAF authorization to the token."
exit
end
public_key_handle = TRL_output_list
/* Get the public key value */
GAV_handle = public_key_handle
GAV_attr_list_length = '00000DAC'x
GAV_attr_list = copies('00'x,3500)
CALL CSFPGAV
/*-------------------------------------------------------------------*/
/* Generate a 128-bit AES clear key */
/*-------------------------------------------------------------------*/
GSK_AttrList = '0006'x||, /* number attributes */
CKA_CLASS ||'0004'x|| CKO_SECRET_KEY ||,
CKA_KEY_TYPE ||'0004'x|| CKK_AES ||,
CKA_TOKEN ||'0001'x|| CK_TRUE ||, /* TKDS */
CKA_VALUE_LEN ||'0004'x|| '00000010'x ||, /* 16 byte */
CKA_LABEL ||'0011'X|| 'P11 Clear AES Key' ||,
CKA_IBM_SECURE ||'0001'X|| CK_FALSE; /* clear */
GSK_AttrListLength = D2C( Length( GSK_AttrList ),4);
Call CSFPGSK;
/* - Encrypt "Hello World" with the AES key */
SKE_rule_array_count = '00000002'X;
/* Using the CBC-PAD option defaults the chaining selection to ONLY */
SKE_rule_array = 'AES CBC-PAD ';
SKE_key_handle = GSK_Handle;
SKE_iv_length = '00000010'X;
SKE_iv = COPIES('00'X,C2D(SKE_iv_length));
SKE_chain_data_len = '00000080'X;
SKE_chain_data = COPIES('00'X,C2D(SKE_chain_data_len));
SKE_clear_text = 'Hello World';
Call CSFPSKE;
/* - Wrap (encrypt) the AES key with the RSA public key */
WPK_rule_array_count = '00000001'X;
WPK_rule_array = 'PKCS-1.2';
WPK_source_key_handle = GSK_Handle;
WPK_wrapping_key_handle = GKP_PubKey_Handle
Call CSFPWPK;
/* - Unwrap (decrypt) the AES key with the RSA private key and */
/* store the unwrapped key in the TKDS */
UWK_rule_array_count = '00000001'X;
UWK_rule_array = 'PKCS-1.2';
UWK_unwrapping_key_handle = GKP_PrivKey_Handle;
UWK_wrapped_key_length = D2C(LENGTH(WPK_wrapped_key),4);
UWK_wrapped_key = WPK_wrapped_key;
UWK_attribute_list = '0002'X ||,
CKA_TOKEN || '0001'X || CK_TRUE ||,
CKA_KEY_TYPE || '0004'X || CKK_AES ;
UWK_attribute_list_len = D2C(LENGTH(UWK_attribute_list),4);
Call CSFPUWK;
/* - Decrypt "Hello World" with the unwrapped key */
SKD_rule_array_count = '00000002'X;
/* Using the CBC-PAD option defaults the chaining selection to ONLY */
SKD_rule_array = 'AES CBC-PAD ';
SKD_key_handle = Left(UWK_target_key_handle,44) ;
SKD_iv_length = '00000010'X;
SKD_iv = '';
SKD_chain_data_len = '00000080'X;
SKD_chain_data = COPIES('00'X,C2D(SKD_chain_data_len));
SKD_clear_text = COPIES('00'X,C2D(SKE_cipher_text_len));
SKD_clear_text_len = SKE_cipher_text_len;
SKD_cipher_text_len = D2C(LENGTH(SKE_cipher_text),4);
SKD_cipher_text = SKE_cipher_text;
Call CSFPSKD;
say "-----------------------------------------------------------------"
say "End of Sample"
say "-----------------------------------------------------------------"
exit;
/* --------------------------------------------------------------- */
/* CSFPGKP - PKCS #11 Generate Key Pair */
/* */
/* Generates an asymmetric key pair. */
/* */
/* See the ICSF Application Programmer's Guide for more details. */
/* --------------------------------------------------------------- */
CSFPGKP:
GKP_RC = 'FFFFFFFF'x
GKP_RS = 'FFFFFFFF'x
GKP_Exit_Length = '00000000'x
GKP_Exit_Data = ''
GKP_Handle = Left(Token_Handle,44)
GKP_Rule_Count = '00000000'x
GKP_Rule_Array = ''
address linkpgm 'CSFPGKP' ,
'GKP_RC' 'GKP_RS' ,
'GKP_Exit_Length' 'GKP_Exit_Data' ,
'GKP_Handle' ,
'GKP_Rule_Count' 'GKP_Rule_Array' ,
'GKP_PubKey_Attr_List_Length' ,
'GKP_PubKey_Attr_List' ,
'GKP_PubKey_Handle' ,
'GKP_PrivKey_Attr_List_Length' ,
'GKP_PrivKey_Attr_List' ,
'GKP_PrivKey_Handle'
if (GKP_rc /= '00000000'x) Then
do
say "GKP Failed: RC =" c2x(GKP_rs) "RS =" c2x(GKP_rs)
exit
end
else
do
say ' Private key handle:' GKP_PrivKey_Handle
say ' Public key handle:' GKP_PubKey_Handle
end
return
/* --------------------------------------------------------------- */
/* CSFPGSK - PKCS #11 Generate Secret Key */
/* */
/* Generates a symmetric key. */
/* */
/* See the ICSF Application Programmer's Guide for more details. */
/* --------------------------------------------------------------- */
CSFPGSK:
GSK_RC = 'FFFFFFFF'x ;
GSK_RS = 'FFFFFFFF'x ;
GSK_Exit_Length = '00000000'x ;
GSK_Exit_Data = '' ;
GSK_Rule_Count = '00000001'x;
GSK_Rule_Array = 'KEY ';
GSK_Handle = Left(Token_Handle,44) ;
GSK_Parms_List = ''
GSK_Parms_List_Length = '00000000'x
address linkpgm 'CSFPGSK' ,
'GSK_RC' 'GSK_RS' ,
'GSK_Exit_Length' 'GSK_Exit_Data' ,
'GSK_Handle' ,
'GSK_Rule_Count' 'GSK_Rule_Array' ,
'GSK_AttrListLength' 'GSK_AttrList' ,
'GSK_Parms_List_Length' 'GSK_Parms_List' ;
if (GSK_rc /= '00000000'x) Then
do
say "GSK Failed: RC =" c2x(GSK_rs) "RS =" c2x(GSK_rs)
exit
end
else
do
say ' Secret key handle:' GSK_Handle
end
return
/* --------------------------------------------------------------- */
/* CSFPGAV - PKCS #11 Get Attribute Value */
/* */
/* Retrieves the attributes of an object. */
/* */
/* See the ICSF Application Programmer's Guide for more details. */
/* --------------------------------------------------------------- */
CSFPGAV:
gav_rc = 'FFFFFFFF'x
gav_rs = 'FFFFFFFF'x
gav_exit_length = '00000000'x
gav_exit_data = ''
gav_rule_count = '00000000'x
gav_rule_array = ''
ADDRESS LINKPGM 'CSFPGAV' ,
'gav_rc' 'gav_rs' ,
'gav_exit_length' 'gav_exit_data' ,
'gav_handle' ,
'gav_rule_count' 'gav_rule_array' ,
'gav_attr_list_length' 'gav_attr_list'
IF (gav_rc /= '00000000'x) THEN
DO
SAY 'GAV Failed (rc=' C2X(gav_rc)' rs='C2X(gav_rs)')'
EXIT
END
/* Parse the output */
num_attributes = c2d(substr(gav_attr_list,1,2))
index = 3
/* DO i = 1 TO num_attributes */
DO i = 1 TO num_attributes
tag = substr(gav_attr_list,index,4)
length = c2d(substr(gav_attr_list,index+4,2))
value = substr(gav_attr_list,index+6,length)
IF tag = CKA_MODULUS_BITS THEN
DO
say "modulus size:" c2d(value)
END
IF tag = CKA_MODULUS THEN
DO
say "modulus:" c2x(value)
END
IF tag = CKA_PUBLIC_EXPONENT THEN
DO
say "public exponent:" c2x(value)
END
index = index + 6 + length
END
RETURN
/* --------------------------------------------------------------- */
/* CSFPTRC - PKCS #11 Token Record Create */
/* */
/* Initializes a PKCS #11 token, creates or copies token or */
/* session objects. */
/* */
/* See the ICSF Application Programmer's Guide for more details. */
/* --------------------------------------------------------------- */
CSFPTRC:
TRC_rc = 'FFFFFFFF'x
TRC_rs = 'FFFFFFFF'x
TRC_exit_length = '00000000'x
TRC_exit_data = ''
TRC_handle = token_handle
ADDRESS linkpgm 'CSFPTRC' ,
'TRC_rc' 'TRC_rs' ,
'TRC_exit_length' 'TRC_exit_data' ,
'TRC_handle' ,
'TRC_rule_count' 'TRC_rule_array' ,
'TRC_attr_list_length' 'TRC_attr_list'
if (TRC_rc /= '00000000'x) then
do
say "TRC Failed: RC =" c2x(TRC_rc) "RS =" c2x(TRC_rs)
exit
end
return
/* --------------------------------------------------------------- */
/* CSFPTRL - PKCS #11 Token Record List */
/* */
/* Lists PKCS #11 tokens or objects. */
/* */
/* See the ICSF Application Programmer's Guide for more details. */
/* --------------------------------------------------------------- */
CSFPTRL:
TRL_RC = 'FFFFFFFF'x ;
TRL_RS = 'FFFFFFFF'x ;
TRL_Exit_Length = '00000000'x ;
TRL_Exit_Data = '' ;
address linkpgm 'CSFPTRL' ,
'TRL_RC' 'TRL_RS' ,
'TRL_Exit_Length' 'TRL_Exit_Data' ,
'TRL_Handle' ,
'TRL_Rule_Count' 'TRL_Rule_Array' ,
'TRL_srch_tmpl_Length' 'TRL_srch_tmpl' ,
'TRL_List_Length' 'TRL_Handle_Count' ,
'TRL_Output_List'
if (TRL_rc /= '00000000'x) then
do
say "TRL Failed: RC =" c2x(TRL_rc) "RS =" c2x(TRL_rs)
exit
end
return
/* --------------------------------------------------------------- */
/* CSFPTRD - PKCS #11 Token Record Delete */
/* */
/* Deletes a PKCS #11 token, token object, session object or state */
/* object. */
/* */
/* See the ICSF Application Programmer's Guide for more details. */
/* --------------------------------------------------------------- */
CSFPTRD:
TRD_rc = 'FFFFFFFF'x
TRD_rs = 'FFFFFFFF'x
TRD_exit_length = '00000000'x
TRD_exit_data = ''
TRD_rule_count = '00000001'x
TRD_rule_array = 'TOKEN '
ADDRESS linkpgm 'CSFPTRD' ,
'TRD_rc' 'TRD_rs' ,
'TRD_exit_length' 'TRD_exit_data' ,
'TRD_handle' ,
'TRD_rule_count' 'TRD_rule_array'
if (TRD_rc /= '00000000'x) & ,
^(TRD_rc = '00000008'x & TRD_rs = '00000BD3'x) then
say "TRD Failed: RC =" c2x(TRD_rc) "RS =" c2x(TRD_rs)
return
/*********************************************************************/
/* Encrypt using the AES-128 key */
/*********************************************************************/
/* --------------------------------------------------------------- */
/* CSFPSKE - PKCS #11 Secret Key Encrypt */
/* */
/* Encrypts plain text into cipher text using the AES 128 bit key */
/* generated earlier in the sample. */
/* */
/* See the ICSF Application Programmer's Guide for more details. */
/* --------------------------------------------------------------- */
CSFPSKE:
SKE_RC = 'FFFFFFFF'X;
SKE_RS = 'FFFFFFFF'X;
SKE_clear_text_len = D2C(LENGTH(SKE_clear_text),4);
SKE_clear_text_id = '00000000'X;
SKE_cipher_text_len = '00000010'X;;
SKE_cipher_text = COPIES('00'X,C2D(SKE_cipher_text_len));
SKE_cipher_text_id = '00000000'X;
SKE_exit_length = '00000000'x ;
SKE_exit_data = '' ;
say 'Text to Encrypt:' SKE_clear_text
ADDRESS LINKPGM 'CSFPSKE' ,
'SKE_RC' 'SKE_RS' ,
'SKE_exit_length' 'SKE_exit_data' ,
'SKE_rule_array_count' 'SKE_rule_array' ,
'SKE_key_handle' ,
'SKE_iv_length' 'SKE_iv' ,
'SKE_chain_data_len' 'SKE_chain_data' ,
'SKE_clear_text_len' 'SKE_clear_text' ,
'SKE_clear_text_id' ,
'SKE_cipher_text_len' 'SKE_cipher_text',
'SKE_cipher_text_id' ;
if (SKE_rc /= '00000000'x) then
say "SKE Failed: RC =" c2x(SKE_rc) "RS =" c2x(SKE_rs)
else
say "Cipher text:" c2x(SKE_cipher_text)
return
/*********************************************************************/
/* Wrap the 128 bit AES key with the RSA Public key */
/*********************************************************************/
/* --------------------------------------------------------------- */
/* CSFPWPK - PKCS #11 Wrap Key */
/* */
/* Wraps the generated AES 128 bit key with the RSA public key that*/
/* was previously created. */
/* */
/* See the ICSF Application Programmer's Guide for more details. */
/* --------------------------------------------------------------- */
CSFPWPK:
WPK_RC = 'FFFFFFFF'X;
WPK_RS = 'FFFFFFFF'X;;
WPK_init_vector_length = '00000000'x;
WPK_init_vector = '';
WPK_wrapped_key_length = '00000180'X;
WPK_wrapped_key = COPIES('00'X,C2D(WPK_wrapped_key_length));
WPK_Exit_Length = '00000000'x ;
WPK_Exit_Data = '' ;
ADDRESS LINKPGM 'CSFPWPK' ,
'WPK_RC' 'WPK_RS' ,
'WPK_exit_data_length' 'WPK_exit_data' ,
'WPK_rule_array_count' 'WPK_rule_array' ,
'WPK_source_key_handle' ,
'WPK_wrapping_key_handle' ,
'WPK_init_vector_length' 'WPK_init_vector' ,
'WPK_wrapped_key_length' 'WPK_wrapped_key' ;
if (WPK_rc /= '00000000'x) then
say "WPK Failed: RC =" c2x(WPK_rc) "RS =" c2x(WPK_rs)
say 'Wrapped key' c2x(WPK_wrapped_key)
return
/*********************************************************************/
/* Unwrap the 128 bit AES key with the RSA Private key */
/*********************************************************************/
/* --------------------------------------------------------------- */
/* CSFPUWK - PKCS #11 Unwrap Key */
/* */
/* Unwraps the AES 128 bit key using the RSA private key */
/* */
/* See the ICSF Application Programmer's Guide for more details. */
/* --------------------------------------------------------------- */
CSFPUWK:
UWK_RC = 'FFFFFFFF'X;
UWK_RS = 'FFFFFFFF'X;
UWK_init_vector_length = '000000000'x;
UWK_init_vector = '';
UWK_Exit_Length = '00000000'x ;
UWK_Exit_Data = '' ;
UWK_target_key_handle = Left('',44) ;
ADDRESS LINKPGM 'CSFPUWK' ,
'UWK_RC' 'UWK_RS' ,
'UWK_exit_data_length' 'UWK_exit_data' ,
'UWK_rule_array_count' 'UWK_rule_array' ,
'UWK_wrapped_key_length' 'UWK_wrapped_key' ,
'UWK_init_vector_length' 'UWK_init_vector' ,
'UWK_unwrapping_key_handle' ,
'UWK_attribute_list_len' 'UWK_attribute_list' ,
'UWK_target_key_handle' ;
if (UWK_rc /= '00000000'x) then
say "UWK Failed: RC =" c2x(UWK_rc) "RS =" c2x(UWK_rs)
return
/*********************************************************************/
/* Decrypt using the AES-128 key */
/*********************************************************************/
/* --------------------------------------------------------------- */
/* CSFPSKD - PKCS #11 Secret Key Decrypt */
/* */
/* Decrypts cipher text into plain text using the AES 128 bit key */
/* that was unwrapped earlier in the sample. */
/* */
/* See the ICSF Application Programmer's Guide for more details. */
/* --------------------------------------------------------------- */
CSFPSKD:
SKD_RC = 'FFFFFFFF'X;
SKD_RS = 'FFFFFFFF'X;
SKD_cipher_text_id = '00000000'X;
SKD_clear_text_id = '00000000'X;
SKD_Exit_Length = '00000000'x ;
SKD_Exit_Data = '' ;
ADDRESS LINKPGM 'CSFPSKD' ,
'SKD_RC' 'SKD_RS' ,
'SKD_exit_data_length' 'SKD_exit_data' ,
'SKD_rule_array_count' 'SKD_rule_array' ,
'SKD_key_handle' ,
'SKD_iv_length' 'SKD_iv' ,
'SKD_chain_data_len' 'SKD_chain_data' ,
'SKD_cipher_text_len' 'SKD_cipher_text',
'SKD_cipher_text_id' ,
'SKD_clear_text_len' 'SKD_clear_text' ,
'SKD_clear_text_id' ;
if (SKD_rc /= '00000000'x) then
say "SKD Failed: RC =" c2x(SKD_rc) "RS =" c2x(SKD_rs)
Else
say "Decrypted Text:" SKD_clear_text
return
NOVALUE:
SAY "Condition NOVALUE was raised."
SAY CONDITION("D") "variable was not initialized."
SAY SOURCELINE(sigl)
EXIT;