$!----------------------------------------------------------------------------- $! CREATE_CLIENT_CERT.COM $! $! Create our own client certificate! $! This procedure is very "quick-and-dirty", use with that in mind! $! $! P1 must specify the client certificate file name $! P2 optionally specified the configuration file (defaults to DEFAULT.CNF) $! $! WASD VMS Web Services, Copyright (C) 1996-2015 Mark G.Daniel. $! This program comes with ABSOLUTELY NO WARRANTY. $! This is free software, and you are welcome to redistribute it under the $! conditions of the GNU GENERAL PUBLIC LICENSE, version 3, or later version. $! http://www.gnu.org/licenses/gpl.txt $! $! 18-JAN-2015 MGD use sha256 when generating request $! 14-NOV-2014 MGD refine to better represent PKCS#12 $! 23-JUN-2012 MGD OPENSSL-1.0.1b (adapted from CREATE_SERVER_CERT.COM) $!----------------------------------------------------------------------------- $! $ if f$type(validDays) .eqs. "" then validDays = 1825 !(5*365 == five years!) $ if f$type(rsaKeySize) .eqs. "" then rsaKeySize = 2048 !(bits) $ if f$type(configFileName) .eqs. "" then configFileName = f$edit(P2,"lowercase") $! $ certDir = "[.CERT]" $ workDir = "[.CERT.WORK]" $ if configFileName .eqs. "" then configFileName = "default.cnf" $ configFileName = configFileName - ".cnf" + ".cnf" $! $ say = "write sys$output" $ tt = f$trnlnm("SYS$COMMAND","LNM$PROCESS",,"EXECUTIVE") $ say "" $! $ if P1 .eqs. "" $ then $ type sys$input ****************************** * CERTIFICATE NAME MISSING * ****************************** P1 must be the name of the certificate file (e.g. "MINE"). $ exit $ endif $ certFileName = f$edit(P1,"lowercase") - f$parse(P1,,,"type") $ if f$search("''certDir'''certFileName'.cer") .nes. "" .or. - f$search("''certDir'''certFileName'.pfx") .nes. "" $ then $ type sys$input ***************************** * CERTIFICATE FILE EXISTS * ***************************** A certificate file using this name already exists! Using the same name will create a new file with a higher version number. $ read sys$command response /prompt="Continue? [N]: " $ say "" $ if .not. response then exit $ endif $! $ on error then goto serverError $ procedure = f$environment("procedure") - "000000." $ newDefault = f$parse(procedure,,,"device") + f$parse(procedure,,,"directory") $ prevDefault = f$environment("default") $ set default 'newDefault' $! $ @FIND_SSL $! $ @CREATE_SUPPORT_FILES $! $ type sys$input ********************************* * GENERATE CLIENT CERTIFICATE * ********************************* A client certificate identifies a particular end-user. Its value as a guarantee of identity is founded in the authority of the organization that issues the certificate (the CA). It is the certificate is supplied by the browser if requested by the server. The client uses this certificate to establish its identity during SSL renegotiation. $ read sys$command response /prompt="Continue? [N]: " $ say "" $ if .not. response then exit $! $ type sys$input ****************** * GENERATE KEY * ****************** When prompted for: "Enter pass phrase for .key:" use "12345", or your own *secret* password. $ set noon $ define /user sys$input sys$command $!(^Y during password entry leaves the terminal kaput!) $ set nocontrol=y $ define /user openssl_conf 'configFileName' $ openssl genrsa -des3 -out 'workDir'_'certFileName'.key 2048 $ set control=y $ set on $! $ type sys$input ************************************* * GENERATE CLIENT SIGNING REQUEST * ************************************* When prompted for: "Enter pass phrase for .key:" supply the pass phrase used above. When prompted for each of "information that will be incorporated into your certificate request" modify the WASD defaults to suit purpose. Note: the pass phrase and all input is case-sensitive. $ set noon $ define /user sys$input sys$command $!(^Y during password entry leaves the terminal kaput!) $ set nocontrol=y $ define /user openssl_conf 'configFileName' $ openssl req -config 'configFileName' -new -sha256 - -key 'workDir'_'certFileName'.key - -out 'workDir'_'certFileName'.csr $ set control=y $ set on $! $ type sys$input ************************** * CA SIGNS CERTIFICATE * ************************** When prompted for: "Enter pass phrase for _cacert.pem:" supply the CA password, which should be "testing" if using the default WASD CA files. Note: the pass phrase is case-sensitive. $ set noon $ define /user sys$input sys$command $ set nocontrol=y $ define /user openssl_conf 'configFileName' $ openSSL ca -days 'validDays' -policy policy_anything - -config 'configFileName' - -outdir 'certDir' -out 'certDir''certFileName'.cer - -infiles 'workDir'_'certFileName'.csr $ set control=y $ set on $! $!(errors extrapolated from [.INCLUDE.OPENSSL]TXT_DB.H) $ type sys$input **************************************** * CHECK ABOVE FOR SUCCESSFUL SIGNING * **************************************** Indication of success: "Data Base Updated" These errors: "failed to update database TXT_DB error number 1" memory allocation failure number 2" index entry already exists number 3" index entry out-of-range number 4" no such index entry number 5" insert index entry clash (or other obvious error) Number 2 indicates this certificate's Distinguished Name (DN) is not unique. None of the fields is different to an existing certificate in the database. $ response = "" $ read sys$command response /prompt="Successful? [N]: " $ say "" $ if .not. response then goto clientCleanup $! $ type sys$input ********************************* * GENERATE PKCS#12/PFX FORMAT * ********************************* At this point, .cer is the public component of the client certificate, and .key is the private component. Some client software requires that these files be converted to a different format before they can be used by the client. This generates a .p12 which may need to be renamed to .pfx for use on Windows platforms. $ response = "Y" $ read sys$command line /prompt="Convert these two files into the single-file .p12 (.pfx) format? [Y]: " $ say "" $ if response .eqs. "" then response = "Y" $! $ if response $ then $! $ type sys$input When prompted for: "Enter PEM pass phrase:" use "12345", or your the original client password supplied. $ set noon $ define /user sys$input sys$command $ set nocontrol=y $ define /user openssl_conf 'configFileName' $ openssl pkcs12 -export -in 'certDir''certFileName'.cer - -inkey 'workDir'_'certFileName'.key - -out 'certDir''certFileName'.p12 $ set control=y $ set on $! $ endif $! $ define /user sys$output nl: $ define /user sys$error nl: $ set prot=w 'certDir''certFileName'.*;* $! $ type sys$input ********************* * C O M P L E T E * ********************* $ say "New client certificate is " + f$search("''certDir'''certFileName'.cer") $ if f$search("''certDir'''certFileName'.cer") .nes. "" then - say "And " + f$search("''certDir'''certFileName'.p12") $ say "" $! $ goto clientCleanup $! $serverError: $ type sys$input *************** * E R R O R * *************** $ define /user sys$output nl: $ define /user sys$error nl: $ delete 'certDir''certFileName'.*;* $! $ clientCleanup: $ define /user sys$output nl: $ define /user sys$error nl: $ delete 'workDir'_'certFileName'.*;* $ define /user sys$output nl: $ define /user sys$error nl: $ set prot=w 'certDir''certFileName'.*;* $ if f$type(RANDFILE) .nes. "" then delete/symbol/global RANDFILE $! $ set default 'prevDefault' $! $!-----------------------------------------------------------------------------