Example: ILE RPG program for certifying a public key token

Change this program example to suit your needs for certifying a public key token.

Note: Read the Code license and disclaimer information for important legal information.
     D*************************************************************
     D* CERTKEY
     D*
     D* Sample program to certify a CCA public key certificate to be
     D* used for master key cloning.
     D*
     D*
     D* COPYRIGHT 5769-SS1 (C) IBM CORP. 2000, 2000
     D*
     D* This material contains programming source code for your
     D* consideration.  These example has not been thoroughly
     D* tested under all conditions.  IBM, therefore, cannot
     D* guarantee or imply reliability, serviceability, or function
     D* of these programs.  All programs contained herein are
     D* provided to you "AS IS".  THE IMPLIED WARRANTIES OF
     D* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     D* ARE EXPRESSLY DISCLAIMED.  IBM provides no program services for
     D* these programs and files.
     D*
     D*
     D* Note: Input format is more fully described in Chapter 2 of
     D*       IBM  CCA Basic Services Reference and Guide
     D*       (SC31-8609) publication.
     D*
     D* Parameters: FILENAME          - File containing public key token
     D*             RETAINED_KEY_NAME - Name of key to certify token
     D*
     D* Example:
     D*   CALL PGM(CERTKEY) PARM(MYKEY.PUB  CERTKEY)
     D*
     D* Use these commands to compile this program on the system:
     D* CRTRPGMOD MODULE(CERTKEY) SRCFILE(SAMPLE)
     D* CRTPGM  PGM(CERTKEY) MODULE(CERTKEY)
     D*         BNDDIR(QCCA/QC6BNDDIR)
     D*
     D* Note: Authority to the CSNDDSG and CSNBOWH service programs
     D*       in the QCCA library is assumed.
     D*
     D* The Common Cryptographic Architecture (CCA) verbs used are
     D* Digital_Signature_Generate (CSNDDSG) and One_Way_Hash (CSNBOWH).
     D*
     D**************************************************************
     D*--------------------------------------------------------
     D* Declare variables used by CCA SAPI calls
     D*--------------------------------------------------------
     D*                **  Return code
     DRETURNCODE       S              9B 0
     D*                **  Reason code
     DREASONCODE       S              9B 0
     D*                **  Exit data length
     DEXITDATALEN      S              9B 0
     D*                **  Exit data
     DEXITDATA         S              4
     D*                **  Rule array count
     DRULEARRAYCNT     S              9B 0
     D*                **  Rule array
     DRULEARRAY        S             16
     D*                **  Token length
     DTOKENLEN         S              9B 0 INZ(2500)
     D*                **  Token and array for subscripting token
     DTOKEN            DS          2500
     DTOKENARRAY                      1    DIM(2500)
     D*                **  Chaining vector length
     DCHAINVCTLEN      S              9B 0 INZ(128)
     D*                **  Chaining vector
     DCHAINVCT         S            128
     D*                **  Hash length
     DHASHLEN          S              9B 0 INZ(20)
     D*                **  Hash
     DHASH             S             20
     D*                **  Text length
     DTXTLENGTH        S              9B 0
     D*                **  Signature length
     DSIGLENGTH        S              9B 0 INZ(256)
     D*                **  Signature length in bits
     DSIGBITLEN        S              9B 0
     D*--------------------------------------------------------
     D* Declare variables for working with tokens
     D*--------------------------------------------------------
     D*                **  NAMEPTR and NAME are used for copying
     D*                **  private key name
     DNAMEPTR          S               *
     DNAME             S             64    BASED(NAMEPTR)
     D*                **  Share administrator (certifying key) name length
     DSANAMELEN        S              9B 0
     D*                **  Share administrator (certifying key) name
     DSANAME           S             64
     D*                **  Share administrator name expressed in ASCII
     DSANAMEASC        S             64
     D*                **  Certificate section length
     DCRTSECLEN        S              9B 0
     D*                **  Public key section length
     DPUBSECLEN        S              9B 0
     D*                **  Index into PKA key token
     DTKNINDEX         S              9B 0
     D*                **  Index into PKA key token
     DTMPINDEX         S              9B 0
     D*                **  Structure used for aligning 2 bytes into a
     D*                **  2 byte integer.
     DLENSTRUCT        DS             2
     DMSB                      1      1
     DLSB                      2      2
     DLENGTH                   1      2B 0
     D*                **  File descriptor
     DFILED            S              9B 0
     D*                **  File path and path length
     DPATH             S             80    INZ(*ALLX'00')
     DPATHLEN          S              9B 0
     D*                ** Open flag - Create on open, open for writing,
     D*                **             and clear if exists
     DOFLAGW           S             10I 0 INZ(X'4A')
     D*                ** Open Flag - Open for Read only
     DOFLAGR           S             10I 0 INZ(1)
     D*                ** Declares for calling QDCXLATE API
     DXTABLE           S             10    INZ('QASCII    ')
     DLIB              S             10    INZ('QSYS      ')
     DXLATLEN          S              5  0 INZ(64)
     D
     D*
     D**********************************************************
     D* Prototype for Digital_Signature_Generate (CSNDDSG)
     D**********************************************************
     DCSNDDSG          PR
     DRETCOD                          9B 0
     DRSNCOD                          9B 0
     DEXTDTALN                        9B 0
     DEXTDT                           4
     DRARRYCT                         9B 0
     DRARRY                          16
     DKEYIDLEN                        9B 0
     DKEYID                        2500    OPTIONS(*VARSIZE)
     DHSHL                            9B 0
     DHSH                            20    OPTIONS(*VARSIZE)
     DSIGFLDL                         9B 0
     DSIGBTL                          9B 0
     DSIGFLD                        256    OPTIONS(*VARSIZE)
     D*
     D**********************************************************
     D* Prototype for One_Way_Hash (CSNBOWH)
     D**********************************************************
     DCSNBOWH          PR
     DRETCOD                          9B 0
     DRSNCOD                          9B 0
     DEXTDTALN                        9B 0
     DEXTDT                           4
     DRARRYCT                         9B 0
     DRARRY                          16
     DTXTLEN                          9B 0
     DTXT                           500    OPTIONS(*VARSIZE)
     DCHNVCTLEN                       9B 0
     DCHNVCT                        128
     DHSHLEN                          9B 0
     DHSH                            20
     D*
     D*
     D**********************************************************
     D* Prototype for open()
     D**********************************************************
     D*    value returned = file descriptor (OK), -1 (error)
     Dopen             PR             9B 0 EXTPROC('open')
     D*    path name of file to be opened.
     D                              128    OPTIONS(*VARSIZE)
     D*    Open flags
     D                                9B 0 VALUE
     D*    (OPTIONAL) mode - access rights
     D                               10U 0 VALUE OPTIONS(*NOPASS)
     D*    (OPTIONAL) codepage
     D                               10U 0 VALUE OPTIONS(*NOPASS)
     D*
     D*********************************************************************
     D* Prototype for read()
     D**********************************************************
     D*    value returned = number of bytes actually read, or -1
     Dread             PR             9B 0 EXTPROC('read')
     D*    File descriptor returned from open()
     D                                9B 0 VALUE
     D*    Input buffer
     D                             2500    OPTIONS(*VARSIZE)
     D*    Length of data to be read
     D                                9B 0 VALUE
     D*
     D*********************************************************************
     D* Prototype for write()
     D**********************************************************
     D*    value returned = number of bytes written, or -1
     Dwrite            PR             9B 0 EXTPROC('write')
     D*    File descriptor returned from open()
     D                                9B 0 VALUE
     D*    Output buffer
     D                             2500    OPTIONS(*VARSIZE)
     D*    Length of data to be written
     D                                9B 0 VALUE
     D*
     D*********************************************************************
     D* Prototype for close()
     D*********************************************************************
     D*    value returned = 0 (OK), or -1
     Dclose            PR             9B 0 EXTPROC('close')
     D*    File descriptor returned from open()
     D                                9B 0 VALUE
     D*
     D*-------------------------------------------------------------
     D*                **  Declares for sending messages to the
     D*                **  job log using the QMHSNDPM API
     D*-------------------------------------------------------------
     DMSG              S             75    DIM(7) CTDATA PERRCD(1)
     DMSGLENGTH        S              9B 0 INZ(75)
     D                 DS
     DMSGTEXT                  1     75
     DSAPI                     1      7
     DFAILRETC                41     44
     DFAILRSNC                46     49
     DMESSAGEID        S              7    INZ('       ')
     DMESSAGEFILE      S             21    INZ('                     ')
     DMSGKEY           S              4    INZ('    ')
     DMSGTYPE          S             10    INZ('*INFO     ')
     DSTACKENTRY       S             10    INZ('*         ')
     DSTACKCOUNTER     S              9B 0 INZ(2)
     DERRCODE          DS
     DBYTESIN                  1      4B 0 INZ(0)
     DBYTESOUT                 5      8B 0 INZ(0)
     C*
     C**************************************************************
     C* START OF PROGRAM                                           *
     C**************************************************************
     C     *ENTRY        PLIST
     C                   PARM                    FILEPARM         32
     C                   PARM                    CKEY             32
     C**************************************************************
     C* Open certificate file
     C**************************************************************
     C*   *---------------------*
     C*   ** Build path name    *
     C*   *---------------------*
     C                   EVAL      PATHLEN = %LEN(%TRIM(FILEPARM))
     C     PATHLEN       SUBST     FILEPARM:1    PATH
     C*   *---------------------*
     C*   * Open the file       *
     C*   *---------------------*
     C                   EVAL      FILED = open(PATH: OFLAGR)
     C*   *----------------------*
     C*   * Check if open worked *
     C*   *----------------------*
     C     FILED         IFEQ      -1
     C*     *------------------------------------*
     C*     * Open failed, send an error message *
     C*     *------------------------------------*
     C                   MOVEL     MSG(1)        MSGTEXT
     C                   EXSR      SNDMSG
     C                   RETURN
     C*
     C                   ENDIF
     C*    *--------------------------------------------------*
     C*    * Open worked, read certificate and close the file *
     C*    *--------------------------------------------------*
     C                   EVAL      TOKENLEN = read(FILED: TOKEN: TOKENLEN)
     C                   CALLP     close         (FILED)
     C*
     C*    *--------------------------------------*
     C*    * Check if read operation was OK       *
     C*    *--------------------------------------*
     C     TOKENLEN      IFEQ      -1
     C                   MOVEL     MSG(2)        MSGTEXT
     C                   EXSR      SNDMSG
     C                   ENDIF
     C*
     C*    *--------------------------------------*
     C*    * Check if certificate length is valid *
     C*    *--------------------------------------*
     C                   EVAL      MSB = TOKENARRAY(3)
     C                   EVAL      LSB = TOKENARRAY(4)
     C     LENGTH        IFLT      TOKENLEN
     C*        *-----------------------------------*
     C*        * Certificate length is not valid   *
     C*        *-----------------------------------*
     C                   MOVEL     MSG(3)        MSGTEXT
     C                   EXSR      SNDMSG
     C                   RETURN
     C                   ENDIF
     C*
     C**************************************************************
     C* Find the certificate in the token
     C*
     C* The layout of the token is
     C*
     C* - Token header - 8 bytes - including 2 length bytes
     C* - Public key section - length bytes at offset 2
     C* - Private key name - 68 bytes
     C* - Certificate section
     C*
     C**************************************************************
     C*    *--------------------------------------------------------*
     C*    * Certificate starts after the public key header section *
     C*    *--------------------------------------------------------*
     C                   EVAL      MSB = TOKENARRAY(11)
     C                   EVAL      LSB = TOKENARRAY(12)
     C                   EVAL      PUBSECLEN = LENGTH
     C                   EVAL      TKNINDEX = PUBSECLEN + 68 + 8 + 1
     C*
     C*    *-----------------------------------------*
     C*    * Determine length of certificate section *
     C*    *-----------------------------------------*
     C                   EVAL      MSB = TOKENARRAY(TKNINDEX + 2)
     C                   EVAL      LSB = TOKENARRAY(TKNINDEX + 3)
     C                   EVAL      CRTSECLEN = LENGTH
     C                   EVAL      TMPINDEX = TKNINDEX + 4
     C*
     C*    *-----------------------------------------------------*
     C*    * Parse each subsection of the certificate until the  *
     C*    * signature subsection is found or the end is reached.*
     C*    * (Identifier for signature subsection is Hex 45.)    *
     C*    *-----------------------------------------------------*
     C                   DOW       (TOKENARRAY(TMPINDEX) <> X'45') AND
     C                             (TMPINDEX < TKNINDEX + CRTSECLEN)
     C                   EVAL      MSB = TOKENARRAY(TMPINDEX + 2)
     C                   EVAL      LSB = TOKENARRAY(TMPINDEX + 3)
     C     TMPINDEX      ADD       LENGTH        TMPINDEX
     C                   ENDDO
     C*
     C*    *----------------------------------------------------*
     C*    * Check if no signature was found before the end of  *
     C*    * the certificate section.                           *
     C*    *----------------------------------------------------*
     C                   IF        TOKENARRAY(TMPINDEX) <> X'45'
     C                   MOVEL     MSG(4)        MSGTEXT
     C                   EXSR      SNDMSG
     C                   RETURN
     C                   ENDIF
     C*
     C**************************************************************
     C* Sign the Certificate
     C**************************************************************
     C*    *----------------------------------------------------*
     C*    * Convert the Certifying Keyname to ASCII            *
     C*    *----------------------------------------------------*
     C                   EVAL      SANAMELEN = %LEN(%TRIM(CKEY))
     C     SANAMELEN     SUBST     CKEY:1        SANAME
     C                   MOVEL     SANAME        SANAMEASC
     C                   CALL      'QDCXLATE'
     C                   PARM                    XLATLEN
     C                   PARM                    SANAMEASC
     C                   PARM                    XTABLE
     C                   PARM                    LIB
     C*    *----------------------------------------------------*
     C*    * Replace the private key name in the certificate    *
     C*    *----------------------------------------------------*
     C                   EVAL      NAMEPTR = %ADDR(TOKENARRAY(TMPINDEX + 6))
     C                   MOVEL     SANAMEASC     NAME
     C*    *----------------------------------------------------*
     C*    * Calculate length of data to hash                   *
     C*    * TKNINDEX is the start of the certificate,          *
     C*    * TMPINDEX is start of signature subsection,         *
     C*    * signature subsection header is 70 bytes long       *
     C*    *----------------------------------------------------*
     C                   EVAL      TXTLENGTH = TMPINDEX - TKNINDEX + 70
     C*    *------------------------------------------*
     C*    * Set the keywords in the rule array       *
     C*    *------------------------------------------*
     C                   MOVEL     'SHA-1   '    RULEARRAY
     C                   Z-ADD     1             RULEARRAYCNT
     C*    *-------------------------*
     C*    * Call One Way Hash SAPI  *
     C*    *-------------------------*
     C                   CALLP     CSNBOWH       (RETURNCODE:
     C                                            REASONCODE:
     C                                            EXITDATALEN:
     C                                            EXITDATA:
     C                                            RULEARRAYCNT:
     C                                            RULEARRAY:
     C                                            TXTLENGTH:
     C                                            TOKENARRAY(TKNINDEX):
     C                                            CHAINVCTLEN:
     C                                            CHAINVCT:
     C                                            HASHLEN:
     C                                            HASH)
     C*  *------------------------*
     C*  * Check the return code  *
     C*  *------------------------*
     C     RETURNCODE    IFGT      0
     C*     *-----------------------*
     C*     *  Send failure message *
     C*     *-----------------------*
     C                   MOVEL     MSG(5)        MSGTEXT
     C                   MOVE      RETURNCODE    FAILRETC
     C                   MOVE      REASONCODE    FAILRSNC
     C                   MOVEL     'CSNBOWH'     SAPI
     C                   EXSR      SNDMSG
     C                   RETURN
     C                   ENDIF
     C*    *------------------------------------------*
     C*    * Set the keywords in the rule array       *
     C*    *------------------------------------------*
     C                   MOVEL     'ISO-9796'    RULEARRAY
     C                   Z-ADD     1             RULEARRAYCNT
     C*    *------------------------------------------*
     C*    * Adjust TMPINDEX to where signature starts*
     C*    * in the certificate                       *
     C*    *------------------------------------------*
     C     TMPINDEX      ADD       70            TMPINDEX
     C*    *------------------------------------------*
     C*    * Set the Key name length                  *
     C*    *------------------------------------------*
     C                   Z-ADD     64            SANAMELEN
     C*    *---------------------------------------*
     C*    * Call Digital Signature Generate SAPI  *
     C*    *---------------------------------------*
     C                   CALLP     CSNDDSG       (RETURNCODE:
     C                                            REASONCODE:
     C                                            EXITDATALEN:
     C                                            EXITDATA:
     C                                            RULEARRAYCNT:
     C                                            RULEARRAY:
     C                                            SANAMELEN:
     C                                            SANAME:
     C                                            HASHLEN:
     C                                            HASH:
     C                                            SIGLENGTH:
     C                                            SIGBITLEN:
     C                                            TOKENARRAY(TMPINDEX))
     C*  *------------------------*
     C*  * Check the return code  *
     C*  *------------------------*
     C     RETURNCODE    IFGT      0
     C*     *-----------------------*
     C*     *  Send failure message *
     C*     *-----------------------*
     C                   MOVEL     MSG(5)        MSGTEXT
     C                   MOVE      RETURNCODE    FAILRETC
     C                   MOVE      REASONCODE    FAILRSNC
     C                   MOVEL     'CSNDDSG'     SAPI
     C                   EXSR      SNDMSG
     C                   RETURN
     C                   ENDIF
     C*
     C*  *-----------------------------------------------*
     C*  * Check if the new signature is longer than the *
     C*  * original signature                            *
     C*  *-----------------------------------------------*
     C*     ** Adjust TMPINDEX back the start of the subsection
     C     TMPINDEX      SUB       70            TMPINDEX
     C*     ** Get two byte length of subsection
     C                   EVAL      MSB = TOKENARRAY(TMPINDEX + 2)
     C                   EVAL      LSB = TOKENARRAY(TMPINDEX + 3)
     C*     ** Subtract length of subsection header
     C     LENGTH        SUB       70            LENGTH
     C*     ** Compare old length with new length
     C     LENGTH        IFNE      SIGLENGTH
     C*    *----------------------------------*
     C*    * Adjust certificate lengths       *
     C*    *----------------------------------*
     C*     ** Adjust signature length
     C                   EVAL      LENGTH = SIGLENGTH
     C                   EVAL      TOKENARRAY(TMPINDEX + 2) = MSB
     C                   EVAL      TOKENARRAY(TMPINDEX + 3) = LSB
     C*     ** Adjust certificate section length
     C                   EVAL      LENGTH = LENGTH + TXTLENGTH
     C                   EVAL      TOKENARRAY(TKNINDEX + 2) = MSB
     C                   EVAL      TOKENARRAY(TKNINDEX + 3) = LSB
     C*     ** Adjust length in token header section
     C                   EVAL      LENGTH = LENGTH + 8 + PUBSECLEN + 68
     C                   EVAL      TOKENARRAY(3) = MSB
     C                   EVAL      TOKENARRAY(4) = LSB
     C                   Z-ADD     LENGTH        TOKENLEN
     C                   ENDIF
     C*
     C**************************************************************
     C* Write certified public key out to a file
     C**************************************************************
     C*    ** Build path name
     C                   EVAL      %SUBST(PATH:PATHLEN+1:4) = '.CRT'
     C*
     C*    ** Open the file
     C*
     C                   EVAL      FILED = open(PATH: OFLAGW)
     C*
     C*    ** Check if open worked
     C*
     C     FILED         IFEQ      -1
     C*
     C*      ** Open failed, send an error message
     C*
     C                   MOVEL     MSG(6)        MSGTEXT
     C                   EXSR      SNDMSG
     C*
     C                   ELSE
     C*
     C*      ** Open worked, write certificate out to file and close file
     C*
     C                   CALLP     write         (FILED:
     C                                            TOKEN:
     C                                            TOKENLEN)
     C                   CALLP     close         (FILED)
     C*
     C*      ** Send completion message
     C*
     C                   MOVEL     MSG(7)        MSGTEXT
     C                   EVAL      %SUBST(MSGTEXT: 41: PATHLEN + 4) =
     C                                     %SUBST(PATH: 1: PATHLEN + 4)
     C                   EXSR      SNDMSG
     C                   ENDIF
     C*
     C                   SETON                                            LR
     C*
     C**************************************************************
     C* Subroutine to send a message
     C**************************************************************
     C     SNDMSG        BEGSR
     C                   CALL      'QMHSNDPM'
     C                   PARM                    MESSAGEID
     C                   PARM                    MESSAGEFILE
     C                   PARM                    MSGTEXT
     C                   PARM                    MSGLENGTH
     C                   PARM                    MSGTYPE
     C                   PARM                    STACKENTRY
     C                   PARM                    STACKCOUNTER
     C                   PARM                    MSGKEY
     C                   PARM                    ERRCODE
     C                   ENDSR
     C*
**
The input file could not be opened.
There was an error reading from the file.
The length of the certificate is not valid.
The certificate is not valid.
CSNBOWH failed with return/reason codes 9999/9999.
The output file could not be opened.
The certified token was written to file