PSOSPMKY ;BIRM/MFR - State Prescription Monitoring Program - SSH Key Management ;01/06/16
;;7.0;OUTPATIENT PHARMACY;**451,625,723**;DEC 1997;Build 13
;
EN ; Entry-point
N STATEIEN,DIC,X,Y,DUOUT,DTOUT,PSOOS,LOCALDIR,X1,DIR,DIRUT,LOCALDIR
W ! K DIC S DIC("A")="Select STATE: ",DIC="^PS(58.41,",DIC(0)="QOEAM"
I $O(^PS(58.41,0)) S DIC("B")=$O(^PS(58.41,0))
D ^DIC I X=""!(X="^")!$D(DUOUT)!$D(DTOUT) G END
K DIC("A") G:Y<0 EN S STATEIEN=+Y
;
ACTION ; SSH Key Action
K DIR S DIR("A")="Action"
S DIR(0)="S^V:View Public SSH Key;N:Create New SSH Key Pair;"
S DIR(0)=DIR(0)_"D:Delete SSH Key Pair;H:Help with SSH Keys"
S DIR("B")="V" D ^DIR I $D(DUOUT)!($D(DIRUT)) G END
I Y="N"!(Y="D"),'$D(^XUSEC("PSO SPMP ADMIN",DUZ)) D G ACTION
. W !!,"The PSO SPMP ADMIN security key is required for this action.",$C(7)
K ^TMP("PSOPUBKY",$J) D RETRIEVE(STATEIEN,"PUB")
I Y="V"!(Y="D"),'$D(^TMP("PSOPUBKY",$J)) D G ACTION
. W !!,"[No SSH Key Pair found for ",$$GET1^DIQ(5,STATEIEN,.01),"]",$C(7) D PAUSE^PSOSPMU1
I Y="N"!(Y="D") D SIG^XUSESIG I X="^"!($G(X1)="") W:$G(X1)="" " SIGNATURE NOT VERIFIED",$C(7) G ACTION
;
; View Public SSH Key
I Y="V" D G ACTION
. W ! D VIEW(STATEIEN),PAUSE^PSOSPMU1
;
; Create New SSH Key Pair
I Y="N" D G ACTION
. S PSOOS=$$BKENDOS()
. S LOCALDIR=$$GET1^DIQ(58.41,STATEIEN,$S(PSOOS["VMS":4,1:15))
. I LOCALDIR="" D Q
. . W !!,"The ",$S(PSOOS["VMS":"OPEN VMS",1:"UNIX/LINUX")," LOCAL DIRECTORY parameter is missing for ",$$GET1^DIQ(5,STATEIEN,.01),". Please,"
. . W !,"update it in the View/Edit SPMP State Parameters option and try again.",$C(7) D PAUSE^PSOSPMU1
. K DIR S DIR("A")="SSH Key Encryption Type",DIR("?")="^D ETHELP^PSOSPMKY"
. S DIR(0)="S^RSA:Rivest, Shamir & Adleman (RSA);DSA:Digital Signature Algorithm (DSA);ECDSA:Elliptic Curve Digital Signature Algorithm (ECDSA);EDDSA:Edward-curve Digital Signature Algorithm (ed25519)" ;p723
. S DIR("B")="RSA" D ^DIR I $D(DUOUT)!($D(DIRUT)) Q
. S ENCRTYPE=Y I Y="DSA" D Q
. . W !!,$G(IOBON),"WARNING:",$G(IOBOFF)," 'DSA' SSH keys are being phased out and are no longer supported.",$C(7)
. ;p723 prompt for bit size for ECDSA
. I ENCRTYPE="ECDSA" D I $D(DUOUT)!($D(DIRUT)) Q
. . K DIR S DIR("A")="ECDSA encryption key size (bit size)",DIR("?")="Available key sizes are 256 bits, 384 bits, or 521 bits. Also referred to as key length."
. . S DIR(0)="S^256:256 bits;384:384 bits;521:521 bits"
. . S DIR("B")="256" D ^DIR
. S ENCRBITS=$S(ENCRTYPE="ECDSA":Y,1:"")
. I $D(^TMP("PSOPUBKY",$J)) D
. . W !!,$G(IOBON),"WARNING:",$G(IOBOFF)," You may be overwriting SSH Keys that are currently in use.",$C(7)
. K DIR S DIR("A")="Confirm Creation of SSH "_ENCRTYPE_" Keys for "_$$GET1^DIQ(5,STATEIEN,.01),DIR(0)="Y",DIR("B")="NO"
. W ! D ^DIR I $D(DIRUT)!$D(DUOUT)!'Y Q
. ; Deleting Existing SSH Key
. I $D(^TMP("PSOPUBKY",$J)) D DELETE(STATEIEN)
. W !!,"Creating New SSH Keys, please wait..."
. ;p723 removing the task off logic, unnecessary
. ;N ZTRTN,ZTIO,ZTDESC,ZTDTH,ZTSK
. ;S ZTRTN="NEWKEY^PSOSPMKY("_STATEIEN_","""_ENCRTYPE_""")"
. ;S ZTDESC="State Prescription Monitoring Program (SPMP) SSH Key Generation"
. ;S ZTDTH=$$NOW^XLFDT() D ^%ZTLOAD K ZTSK
. ;K ^TMP("PSOPUBKY",$J)
. ;F I=1:1:30 D RETRIEVE(STATEIEN,"PUB") Q:$D(^TMP("PSOPUBKY",$J)) H 1
. ; If unable to create the key via Taskman after 30 seconds, creates them in the foreground
. ;I '$D(^TMP("PSOPUBKY",$J)) D
. D NEWKEY(STATEIEN,ENCRTYPE,ENCRBITS),RETRIEVE(STATEIEN,"PUB") ;p723 pass ENCRBITS
. I '$D(^TMP("PSOPUBKY",$J)) D
. . W !!,"There was a problem with the generation of the new SSH Key Pair."
. . W !,"Please try again and if the problem persists contact IT Support.",$C(7) D PAUSE^PSOSPMU1
. E W "Done",$C(7)
K ENCRBITS
;
; Delete SSH Key Pair
I Y="D" D G ACTION
. D RETRIEVE(STATEIEN,"PUB")
. I '$D(^TMP("PSOPUBKY",$J)) D Q
. . W !!,"[No SSH Key Pair found for ",$$GET1^DIQ(5,STATEIEN,.01),"]",$C(7)
. W !!,$G(IOBON),"WARNING:",$G(IOBOFF)," You may be deleting SSH Keys that are currently in use.",$C(7)
. K DIR S DIR("A")="Confirm Deletion of "_$$GET1^DIQ(5,STATEIEN,.01)_"'s SSH Keys",DIR(0)="Y",DIR("B")="NO"
. W ! D ^DIR I $D(DIRUT)!$D(DUOUT)!'Y Q
. W !!,"Deleting SSH Keys..." D DELETE(STATEIEN) H 1 W "Done",$C(7)
;
; SSH Key Help
I Y="H" D HELP G ACTION
;
G ACTION
;
END Q
;
NEWKEY(STATEIEN,ENCRTYPE,ENCRBITS) ; Generate and store a pair of SSH keys for a specific state
; Input: (r) STATEIEN - State that will be using the new key pair. Pointer to the STATE file (#5)
; (o) ENCRTYPE - SSH Encryption Type (DSA / RSA) (Default: RSA)
N LOCALDIR,DATETIME,PSOOS,KEYFILE,PV,FILE2DEL,LINE,OVFLINE,NMSPC,KEYTXT,SAVEKEY,DIE,DR,DA
;
I '$G(STATEIEN) Q ;Error: State missing
S PSOOS=$$OS^%ZOSV()
S LOCALDIR=$$GET1^DIQ(58.41,STATEIEN,$S(PSOOS["VMS":4,1:15)) I LOCALDIR="" Q ;Error: Missing directory
;I $G(ENCRTYPE)'="DSA",$G(ENCRTYPE)'="RSA" S ENCRTYPE="RSA"
S ENCRTYPE=$S($G(ENCRTYPE)="ECDSA":"ECDSA",$G(ENCRTYPE)="EDDSA":"ed25519",1:"RSA")
;
; LOCK to avoid OS files overwrite
F S DATETIME=$P($$FMTHL7^XLFDT($$HTFM^XLFDT($H)),"-") S KEYFILE="KEY"_DATETIME L +@KEYFILE:0 Q:$T H 2
;
; Deleting existing SSH Keys first
D DELETE(STATEIEN)
;
; OpenVMS SSH Key Generation
I PSOOS["VMS" D
. N COMFILE
. S COMFILE="COM"_DATETIME_".COM"
. D OPEN^%ZISH("COMFILE",LOCALDIR,COMFILE,"W")
. D USE^%ZISUTL("COMFILE")
. W "SSH_KEYGEN == ""$SYS$SYSTEM:TCPIP$SSH_SSH-KEYGEN2.EXE""",!
. W "SSH_KEYGEN -t "_$$LOW^XLFSTR($G(ENCRTYPE))_" -""P"" "_LOCALDIR_KEYFILE,!
. D CLOSE^%ZISH("COMFILE")
. X "S PV=$ZF(-1,""@"_LOCALDIR_COMFILE_""")"
. S FILE2DEL(COMFILE)="",FILE2DEL(KEYFILE_".")="",FILE2DEL(KEYFILE_".PUB")=""
;
; Linux/Unix SSH Key Generation
I PSOOS["UNIX" D
. I '$$DIREXIST^PSOSPMU1(LOCALDIR) D MAKEDIR^PSOSPMU1(LOCALDIR)
. S ENCRBITS=$S($G(ENCRBITS):" -b "_ENCRBITS,1:"")
. X "S PV=$ZF(-1,""ssh-keygen -q -N '' -C '' -t "_$$LOW^XLFSTR($G(ENCRTYPE))_" -f "_LOCALDIR_KEYFILE_ENCRBITS_""")"
. S FILE2DEL(KEYFILE)="",FILE2DEL(KEYFILE_".pub")=""
;
K ^TMP("PSOPRVKY",$J),^TMP("PSOPUBKY",$J)
; Retrieving SSH Private Key Content
S X=$$FTG^%ZISH(LOCALDIR,KEYFILE_$S(PSOOS["VMS":".",1:""),$NAME(^TMP("PSOPRVKY",$J,1)),3)
I '$D(^TMP("PSOPRVKY",$J,1)) Q
; Retrieving SSH Public Key Content
S X=$$FTG^%ZISH(LOCALDIR,KEYFILE_$S(PSOOS["VMS":".PUB",1:".pub"),$NAME(^TMP("PSOPUBKY",$J,1)),3)
I '$D(^TMP("PSOPUBKY",$J,1)) Q
;
; Deleting temporary files used to generate the keys
D DEL^%ZISH(LOCALDIR,"FILE2DEL")
;
; Saving new SSH Keys content in the SPMP STATE PARAMETERS file (#58.41)
F NMSPC="PSOPRVKY","PSOPUBKY" D
. K KEYTXT,SAVEKEY
. F LINE=1:1 Q:'$D(^TMP(NMSPC,$J,LINE)) D
. . ; Unix/Linux Public SSH Key has no line-feed (one long line)
. . I PSOOS["UNIX",NMSPC="PSOPUBKY" D Q
. . . S KEYTXT(1)=^TMP(NMSPC,$J,LINE)
. . . F OVFLINE=1:1 Q:'$D(^TMP(NMSPC,$J,LINE,"OVF",OVFLINE)) D
. . . . S KEYTXT(1)=$G(KEYTXT(1))_^TMP(NMSPC,$J,LINE,"OVF",OVFLINE)
. . S KEYTXT(LINE)=$$ENCRYP^XUSRB1(^TMP(NMSPC,$J,LINE))
. I PSOOS["UNIX",NMSPC="PSOPUBKY" S KEYTXT(1)=$$ENCRYP^XUSRB1(KEYTXT(1))
. S SAVEKEY(58.41,STATEIEN_",",$S(NMSPC="PSOPRVKY":100,1:200))="KEYTXT"
. D UPDATE^DIE("","SAVEKEY")
. K ^TMP(NMSPC,$J)
;
; Saving SSH Key Format (SSH2/OpenSSH) and Encryption Type (DSA/RSA) fields
K DIE S DIE="^PS(58.41,",DA=STATEIEN
S DR="18///"_$S(PSOOS["VMS":"SSH2",1:"OSSH")_";19////"_ENCRTYPE D ^DIE
;
L -@KEYFILE
Q
;
RETRIEVE(STATEIEN,KEYTYPE) ; Retrieve the SSH Key into the ^TMP global
; Input: (r) STATEIEN - State to retrieve the SSH Key from
; (o) KEYTYPE - SSH Key Type (PUB - Public / PRV - PRivate) (Default: Public)
;Output: ^TMP("PSO[PUB/PRV]KY",$J,0)="SSH Key Format (SSH2 / OpenSSH)^Encryption Type (DSA / RSA)"
; ^TMP("PSO[PUB/PRV]KY",$J,1-N)=[SSH Key Content]
N X,LINE,KEYTXT,NMSPC
I $G(KEYTYPE)'="PUB",$G(KEYTYPE)'="PRV" S KEYTYPE="PUB"
S X=$$GET1^DIQ(58.41,STATEIEN_",",$S(KEYTYPE="PRV":100,1:200),,"KEYTXT")
S NMSPC=$S(KEYTYPE="PRV":"PSOPRVKY",1:"PSOPUBKY")
K ^TMP(NMSPC,$J)
F LINE=1:1 Q:'$D(KEYTXT(LINE)) D
. S ^TMP(NMSPC,$J,LINE)=$$DECRYP^XUSRB1(KEYTXT(LINE))
I $D(^TMP(NMSPC,$J)) D
. S ^TMP(NMSPC,$J,0)=$$GET1^DIQ(58.41,STATEIEN,18,"I")_"^"_$$GET1^DIQ(58.41,STATEIEN,19,"I")
Q
;
VIEW(STATEIEN) ; Displays the SSH Public Key
;Input: (r) STATEIEN - State to display the Public SSH Key for
; ^TMP("PSOPUBKY",$J,0)="SSH Key Format (SSH2 / OpenSSH)^Encryption Type (DSA / RSA)"
; ^TMP("PSOPUBKY",$J,1-N)=[SSH Key Content]
N SSHKEY,DASHLN
I '$G(STATEIEN) Q
S SSHKEY=$$OPENSSH(),$P(DASHLN,"-",81)=""
W !,$$GET1^DIQ(5,STATEIEN,.01),"'s Public SSH Key (",$P($G(^TMP("PSOPUBKY",$J,0)),"^",2),") content (does not include dash lines):"
W !,DASHLN
F Q:$L(SSHKEY)=0 W !,$E(SSHKEY,1,80) S SSHKEY=$E(SSHKEY,81,9999)
W !,DASHLN
Q
;
DELETE(STATEIEN) ; Delete Both SSH Keys associated with the State
;Input: (r) STATEIEN - State from what the key should be deleted from in the SPMP STATE PARAMETERS file (#58.41)
N DIE,DA,DR
S DIE="^PS(58.41,",DA=+$G(STATEIEN),DR="18///@;19///@;100///@;200///@" D ^DIE
K ^TMP("PSOPRVKY",$J),^TMP("PSOPUBKY",$J)
Q
;
OPENSSH() ; Returns the SSH Public Key in OpenSSH Format (Converts if necessary)
;Input: ^TMP("PSOPUBKY",$J,0)="SSH Key Format (SSH2 / OpenSSH)^Encryption Type (DSA / RSA)"
; ^TMP("PSOPUBKY",$J,1-N)=[SSH Key Content]
N OPENSSH,ENCRTYPE,LINE
S OPENSSH=""
I $P($G(^TMP("PSOPUBKY",$J,0)),"^",1)="SSH2" D
. S ENCRTYPE=$P($G(^TMP("PSOPUBKY",$J,0)),"^",2),OPENSSH=""
. F LINE=5:1 Q:'$D(^TMP("PSOPUBKY",$J,LINE)) D
. . I $G(^TMP("PSOPUBKY",$J,LINE))["---- END" Q
. . S OPENSSH=OPENSSH_$G(^TMP("PSOPUBKY",$J,LINE))
. S OPENSSH=$S(ENCRTYPE="RSA":"ssh-rsa",1:"ssh-dss")_" "_OPENSSH
E D
. F LINE=1:1 Q:'$D(^TMP("PSOPUBKY",$J,LINE)) D
. . S OPENSSH=OPENSSH_$G(^TMP("PSOPUBKY",$J,LINE))
Q OPENSSH
;
BKENDOS() ; Returns the Backend Server Operating System (OS)
;Output: Backend Operating System (e.,g., "VMS", "UNIX")
N BKENDOS,ZTRTN,ZTIO,ZTDESC,ZTDTH,ZTSK,I
K ^XTMP("PSOSPMKY",$J,"OS")
S BKENDOS="",ZTRTN="SETOS^PSOSPMKY("_$J_")",ZTIO=""
S ZTDESC="State Prescription Monitoring Program (SPMP) Backend Server OS Check"
S ZTDTH=$$NOW^XLFDT() D ^%ZTLOAD
F I=1:1:5 S BKENDOS=$G(^XTMP("PSOSPMKY",$J,"OS")) Q:BKENDOS'="" H 1
K ^XTMP("PSOSPMKY",$J,"OS")
Q $S(BKENDOS'="":BKENDOS,1:$$OS^%ZOSV())
;
SETOS(JOB) ; Sets the Operating Systems in ^XTMP("PSOSPMKY",$J,"OS") (Called via Taskman)
;Input: JOB - $Job value from calling process
S ^XTMP("PSOSPMKY",JOB,"OS")=$$OS^%ZOSV()
Q
;
HELP ; SSH Key Help Text
W !!,"Secure SHell (SSH) Encryption Keys are used to automate the data transmission"
W !,"to the State Prescription Monitoring Programs (SPMPs). Follow the steps below"
W !,"to successfully setup SPMP transmissions from VistA to the state/vendor server:"
W !,""
W !,"Step 1: Select the 'N' (Create New SSH Key Pair) Action and follow the prompts"
W !," to create a new pair of SSH keys. If you already have an existing SSH"
W !," Key Pair you can skip this step. You can check whether you already"
W !," have an existing SSH Key Pair through the 'V' (View Public SSH Key)"
W !," Action."
W !,""
;PSO*7*723 add ECDSA
W !," Encryption Type: DSA, RSA, ECDSA or EDDSA?"
W !," -----------------------------------"
D ETHELP,PAUSE^PSOSPMU1
W !!,"Step 2: Share the Public SSH Key content with the state/vendor. In order to"
W !," successfully establish SPMP transmissions the state/vendor will have"
W !," to install/configure the new SSH Key created in step 1 for the"
W !," user id they assigned to your site. Use the 'V' (View Public SSH Key)"
W !," Action to retrieve the content of the Public SSH key. The Public SSH"
W !," Key should not contain line-feed characters, therefore after you copy"
W !," & paste it from the terminal emulator into an email or text editor"
W !," make sure it contains only one line of text (no wrapping)."
Q
ETHELP ; Encryption Type Help
W !," Digital Signature Algorithm (DSA) (No longer supported) and Rivest,"
w !," Shamir & Adleman (RSA) have been two of the most common encryption"
W !," algorithms used by the IT industry for securely sharing data. "
;PSO*7*723 add ECDSA/EDDSA
W !," Elliptic Curve Digital Signature Algorithm (ECDSA) and Edward-curve"
W !," Digital Signature Algorithm (EDDSA) are more complex public key"
W !," cryptography encryption algorithms that are now supported by the VA."
W !," Many of SPMP servers can handle all types; however there are vendors"
W !," that accept only one specific type. You will need to contact the SPMP"
W !," vendor support to determine which type to select. If ECDSA is selected"
W !," you will be prompted to enter the Bit size. Valid selections are 256,"
W !," 384 or 521."
Q
--- Routine Detail --- with STRUCTURED ROUTINE LISTING ---[H[J[2J[HPSOSPMKY 13132 printed Sep 02, 2024@19:20:08 Page 2
PSOSPMKY ;BIRM/MFR - State Prescription Monitoring Program - SSH Key Management ;01/06/16
+1 ;;7.0;OUTPATIENT PHARMACY;**451,625,723**;DEC 1997;Build 13
+2 ;
EN ; Entry-point
+1 NEW STATEIEN,DIC,X,Y,DUOUT,DTOUT,PSOOS,LOCALDIR,X1,DIR,DIRUT,LOCALDIR
+2 WRITE !
KILL DIC
SET DIC("A")="Select STATE: "
SET DIC="^PS(58.41,"
SET DIC(0)="QOEAM"
+3 IF $ORDER(^PS(58.41,0))
SET DIC("B")=$ORDER(^PS(58.41,0))
+4 DO ^DIC
IF X=""!(X="^")!$DATA(DUOUT)!$DATA(DTOUT)
GOTO END
+5 KILL DIC("A")
if Y<0
GOTO EN
SET STATEIEN=+Y
+6 ;
ACTION ; SSH Key Action
+1 KILL DIR
SET DIR("A")="Action"
+2 SET DIR(0)="S^V:View Public SSH Key;N:Create New SSH Key Pair;"
+3 SET DIR(0)=DIR(0)_"D:Delete SSH Key Pair;H:Help with SSH Keys"
+4 SET DIR("B")="V"
DO ^DIR
IF $DATA(DUOUT)!($DATA(DIRUT))
GOTO END
+5 IF Y="N"!(Y="D")
IF '$DATA(^XUSEC("PSO SPMP ADMIN",DUZ))
Begin DoDot:1
+6 WRITE !!,"The PSO SPMP ADMIN security key is required for this action.",$CHAR(7)
End DoDot:1
GOTO ACTION
+7 KILL ^TMP("PSOPUBKY",$JOB)
DO RETRIEVE(STATEIEN,"PUB")
+8 IF Y="V"!(Y="D")
IF '$DATA(^TMP("PSOPUBKY",$JOB))
Begin DoDot:1
+9 WRITE !!,"[No SSH Key Pair found for ",$$GET1^DIQ(5,STATEIEN,.01),"]",$CHAR(7)
DO PAUSE^PSOSPMU1
End DoDot:1
GOTO ACTION
+10 IF Y="N"!(Y="D")
DO SIG^XUSESIG
IF X="^"!($GET(X1)="")
if $GET(X1)=""
WRITE " SIGNATURE NOT VERIFIED",$CHAR(7)
GOTO ACTION
+11 ;
+12 ; View Public SSH Key
+13 IF Y="V"
Begin DoDot:1
+14 WRITE !
DO VIEW(STATEIEN)
DO PAUSE^PSOSPMU1
End DoDot:1
GOTO ACTION
+15 ;
+16 ; Create New SSH Key Pair
+17 IF Y="N"
Begin DoDot:1
+18 SET PSOOS=$$BKENDOS()
+19 SET LOCALDIR=$$GET1^DIQ(58.41,STATEIEN,$SELECT(PSOOS["VMS":4,1:15))
+20 IF LOCALDIR=""
Begin DoDot:2
+21 WRITE !!,"The ",$SELECT(PSOOS["VMS":"OPEN VMS",1:"UNIX/LINUX")," LOCAL DIRECTORY parameter is missing for ",$$GET1^DIQ(5,STATEIEN,.01),". Please,"
+22 WRITE !,"update it in the View/Edit SPMP State Parameters option and try again.",$CHAR(7)
DO PAUSE^PSOSPMU1
End DoDot:2
QUIT
+23 KILL DIR
SET DIR("A")="SSH Key Encryption Type"
SET DIR("?")="^D ETHELP^PSOSPMKY"
+24 ;p723
SET DIR(0)="S^RSA:Rivest, Shamir & Adleman (RSA);DSA:Digital Signature Algorithm (DSA);ECDSA:Elliptic Curve Digital Signature Algorithm (ECDSA);EDDSA:Edward-curve Digital Signature Algorithm (ed25519)"
+25 SET DIR("B")="RSA"
DO ^DIR
IF $DATA(DUOUT)!($DATA(DIRUT))
QUIT
+26 SET ENCRTYPE=Y
IF Y="DSA"
Begin DoDot:2
+27 WRITE !!,$GET(IOBON),"WARNING:",$GET(IOBOFF)," 'DSA' SSH keys are being phased out and are no longer supported.",$CHAR(7)
End DoDot:2
QUIT
+28 ;p723 prompt for bit size for ECDSA
+29 IF ENCRTYPE="ECDSA"
Begin DoDot:2
+30 KILL DIR
SET DIR("A")="ECDSA encryption key size (bit size)"
SET DIR("?")="Available key sizes are 256 bits, 384 bits, or 521 bits. Also referred to as key length."
+31 SET DIR(0)="S^256:256 bits;384:384 bits;521:521 bits"
+32 SET DIR("B")="256"
DO ^DIR
End DoDot:2
IF $DATA(DUOUT)!($DATA(DIRUT))
QUIT
+33 SET ENCRBITS=$SELECT(ENCRTYPE="ECDSA":Y,1:"")
+34 IF $DATA(^TMP("PSOPUBKY",$JOB))
Begin DoDot:2
+35 WRITE !!,$GET(IOBON),"WARNING:",$GET(IOBOFF)," You may be overwriting SSH Keys that are currently in use.",$CHAR(7)
End DoDot:2
+36 KILL DIR
SET DIR("A")="Confirm Creation of SSH "_ENCRTYPE_" Keys for "_$$GET1^DIQ(5,STATEIEN,.01)
SET DIR(0)="Y"
SET DIR("B")="NO"
+37 WRITE !
DO ^DIR
IF $DATA(DIRUT)!$DATA(DUOUT)!'Y
QUIT
+38 ; Deleting Existing SSH Key
+39 IF $DATA(^TMP("PSOPUBKY",$JOB))
DO DELETE(STATEIEN)
+40 WRITE !!,"Creating New SSH Keys, please wait..."
+41 ;p723 removing the task off logic, unnecessary
+42 ;N ZTRTN,ZTIO,ZTDESC,ZTDTH,ZTSK
+43 ;S ZTRTN="NEWKEY^PSOSPMKY("_STATEIEN_","""_ENCRTYPE_""")"
+44 ;S ZTDESC="State Prescription Monitoring Program (SPMP) SSH Key Generation"
+45 ;S ZTDTH=$$NOW^XLFDT() D ^%ZTLOAD K ZTSK
+46 ;K ^TMP("PSOPUBKY",$J)
+47 ;F I=1:1:30 D RETRIEVE(STATEIEN,"PUB") Q:$D(^TMP("PSOPUBKY",$J)) H 1
+48 ; If unable to create the key via Taskman after 30 seconds, creates them in the foreground
+49 ;I '$D(^TMP("PSOPUBKY",$J)) D
+50 ;p723 pass ENCRBITS
DO NEWKEY(STATEIEN,ENCRTYPE,ENCRBITS)
DO RETRIEVE(STATEIEN,"PUB")
+51 IF '$DATA(^TMP("PSOPUBKY",$JOB))
Begin DoDot:2
+52 WRITE !!,"There was a problem with the generation of the new SSH Key Pair."
+53 WRITE !,"Please try again and if the problem persists contact IT Support.",$CHAR(7)
DO PAUSE^PSOSPMU1
End DoDot:2
+54 IF '$TEST
WRITE "Done",$CHAR(7)
End DoDot:1
GOTO ACTION
+55 KILL ENCRBITS
+56 ;
+57 ; Delete SSH Key Pair
+58 IF Y="D"
Begin DoDot:1
+59 DO RETRIEVE(STATEIEN,"PUB")
+60 IF '$DATA(^TMP("PSOPUBKY",$JOB))
Begin DoDot:2
+61 WRITE !!,"[No SSH Key Pair found for ",$$GET1^DIQ(5,STATEIEN,.01),"]",$CHAR(7)
End DoDot:2
QUIT
+62 WRITE !!,$GET(IOBON),"WARNING:",$GET(IOBOFF)," You may be deleting SSH Keys that are currently in use.",$CHAR(7)
+63 KILL DIR
SET DIR("A")="Confirm Deletion of "_$$GET1^DIQ(5,STATEIEN,.01)_"'s SSH Keys"
SET DIR(0)="Y"
SET DIR("B")="NO"
+64 WRITE !
DO ^DIR
IF $DATA(DIRUT)!$DATA(DUOUT)!'Y
QUIT
+65 WRITE !!,"Deleting SSH Keys..."
DO DELETE(STATEIEN)
HANG 1
WRITE "Done",$CHAR(7)
End DoDot:1
GOTO ACTION
+66 ;
+67 ; SSH Key Help
+68 IF Y="H"
DO HELP
GOTO ACTION
+69 ;
+70 GOTO ACTION
+71 ;
END QUIT
+1 ;
NEWKEY(STATEIEN,ENCRTYPE,ENCRBITS) ; Generate and store a pair of SSH keys for a specific state
+1 ; Input: (r) STATEIEN - State that will be using the new key pair. Pointer to the STATE file (#5)
+2 ; (o) ENCRTYPE - SSH Encryption Type (DSA / RSA) (Default: RSA)
+3 NEW LOCALDIR,DATETIME,PSOOS,KEYFILE,PV,FILE2DEL,LINE,OVFLINE,NMSPC,KEYTXT,SAVEKEY,DIE,DR,DA
+4 ;
+5 ;Error: State missing
IF '$GET(STATEIEN)
QUIT
+6 SET PSOOS=$$OS^%ZOSV()
+7 ;Error: Missing directory
SET LOCALDIR=$$GET1^DIQ(58.41,STATEIEN,$SELECT(PSOOS["VMS":4,1:15))
IF LOCALDIR=""
QUIT
+8 ;I $G(ENCRTYPE)'="DSA",$G(ENCRTYPE)'="RSA" S ENCRTYPE="RSA"
+9 SET ENCRTYPE=$SELECT($GET(ENCRTYPE)="ECDSA":"ECDSA",$GET(ENCRTYPE)="EDDSA":"ed25519",1:"RSA")
+10 ;
+11 ; LOCK to avoid OS files overwrite
+12 FOR
SET DATETIME=$PIECE($$FMTHL7^XLFDT($$HTFM^XLFDT($HOROLOG)),"-")
SET KEYFILE="KEY"_DATETIME
LOCK +@KEYFILE:0
if $TEST
QUIT
HANG 2
+13 ;
+14 ; Deleting existing SSH Keys first
+15 DO DELETE(STATEIEN)
+16 ;
+17 ; OpenVMS SSH Key Generation
+18 IF PSOOS["VMS"
Begin DoDot:1
+19 NEW COMFILE
+20 SET COMFILE="COM"_DATETIME_".COM"
+21 DO OPEN^%ZISH("COMFILE",LOCALDIR,COMFILE,"W")
+22 DO USE^%ZISUTL("COMFILE")
+23 WRITE "SSH_KEYGEN == ""$SYS$SYSTEM:TCPIP$SSH_SSH-KEYGEN2.EXE""",!
+24 WRITE "SSH_KEYGEN -t "_$$LOW^XLFSTR($GET(ENCRTYPE))_" -""P"" "_LOCALDIR_KEYFILE,!
+25 DO CLOSE^%ZISH("COMFILE")
+26 XECUTE "S PV=$ZF(-1,""@"_LOCALDIR_COMFILE_""")"
+27 SET FILE2DEL(COMFILE)=""
SET FILE2DEL(KEYFILE_".")=""
SET FILE2DEL(KEYFILE_".PUB")=""
End DoDot:1
+28 ;
+29 ; Linux/Unix SSH Key Generation
+30 IF PSOOS["UNIX"
Begin DoDot:1
+31 IF '$$DIREXIST^PSOSPMU1(LOCALDIR)
DO MAKEDIR^PSOSPMU1(LOCALDIR)
+32 SET ENCRBITS=$SELECT($GET(ENCRBITS):" -b "_ENCRBITS,1:"")
+33 XECUTE "S PV=$ZF(-1,""ssh-keygen -q -N '' -C '' -t "_$$LOW^XLFSTR($GET(ENCRTYPE))_" -f "_LOCALDIR_KEYFILE_ENCRBITS_""")"
+34 SET FILE2DEL(KEYFILE)=""
SET FILE2DEL(KEYFILE_".pub")=""
End DoDot:1
+35 ;
+36 KILL ^TMP("PSOPRVKY",$JOB),^TMP("PSOPUBKY",$JOB)
+37 ; Retrieving SSH Private Key Content
+38 SET X=$$FTG^%ZISH(LOCALDIR,KEYFILE_$SELECT(PSOOS["VMS":".",1:""),$NAME(^TMP("PSOPRVKY",$JOB,1)),3)
+39 IF '$DATA(^TMP("PSOPRVKY",$JOB,1))
QUIT
+40 ; Retrieving SSH Public Key Content
+41 SET X=$$FTG^%ZISH(LOCALDIR,KEYFILE_$SELECT(PSOOS["VMS":".PUB",1:".pub"),$NAME(^TMP("PSOPUBKY",$JOB,1)),3)
+42 IF '$DATA(^TMP("PSOPUBKY",$JOB,1))
QUIT
+43 ;
+44 ; Deleting temporary files used to generate the keys
+45 DO DEL^%ZISH(LOCALDIR,"FILE2DEL")
+46 ;
+47 ; Saving new SSH Keys content in the SPMP STATE PARAMETERS file (#58.41)
+48 FOR NMSPC="PSOPRVKY","PSOPUBKY"
Begin DoDot:1
+49 KILL KEYTXT,SAVEKEY
+50 FOR LINE=1:1
if '$DATA(^TMP(NMSPC,$JOB,LINE))
QUIT
Begin DoDot:2
+51 ; Unix/Linux Public SSH Key has no line-feed (one long line)
+52 IF PSOOS["UNIX"
IF NMSPC="PSOPUBKY"
Begin DoDot:3
+53 SET KEYTXT(1)=^TMP(NMSPC,$JOB,LINE)
+54 FOR OVFLINE=1:1
if '$DATA(^TMP(NMSPC,$JOB,LINE,"OVF",OVFLINE))
QUIT
Begin DoDot:4
+55 SET KEYTXT(1)=$GET(KEYTXT(1))_^TMP(NMSPC,$JOB,LINE,"OVF",OVFLINE)
End DoDot:4
End DoDot:3
QUIT
+56 SET KEYTXT(LINE)=$$ENCRYP^XUSRB1(^TMP(NMSPC,$JOB,LINE))
End DoDot:2
+57 IF PSOOS["UNIX"
IF NMSPC="PSOPUBKY"
SET KEYTXT(1)=$$ENCRYP^XUSRB1(KEYTXT(1))
+58 SET SAVEKEY(58.41,STATEIEN_",",$SELECT(NMSPC="PSOPRVKY":100,1:200))="KEYTXT"
+59 DO UPDATE^DIE("","SAVEKEY")
+60 KILL ^TMP(NMSPC,$JOB)
End DoDot:1
+61 ;
+62 ; Saving SSH Key Format (SSH2/OpenSSH) and Encryption Type (DSA/RSA) fields
+63 KILL DIE
SET DIE="^PS(58.41,"
SET DA=STATEIEN
+64 SET DR="18///"_$SELECT(PSOOS["VMS":"SSH2",1:"OSSH")_";19////"_ENCRTYPE
DO ^DIE
+65 ;
+66 LOCK -@KEYFILE
+67 QUIT
+68 ;
RETRIEVE(STATEIEN,KEYTYPE) ; Retrieve the SSH Key into the ^TMP global
+1 ; Input: (r) STATEIEN - State to retrieve the SSH Key from
+2 ; (o) KEYTYPE - SSH Key Type (PUB - Public / PRV - PRivate) (Default: Public)
+3 ;Output: ^TMP("PSO[PUB/PRV]KY",$J,0)="SSH Key Format (SSH2 / OpenSSH)^Encryption Type (DSA / RSA)"
+4 ; ^TMP("PSO[PUB/PRV]KY",$J,1-N)=[SSH Key Content]
+5 NEW X,LINE,KEYTXT,NMSPC
+6 IF $GET(KEYTYPE)'="PUB"
IF $GET(KEYTYPE)'="PRV"
SET KEYTYPE="PUB"
+7 SET X=$$GET1^DIQ(58.41,STATEIEN_",",$SELECT(KEYTYPE="PRV":100,1:200),,"KEYTXT")
+8 SET NMSPC=$SELECT(KEYTYPE="PRV":"PSOPRVKY",1:"PSOPUBKY")
+9 KILL ^TMP(NMSPC,$JOB)
+10 FOR LINE=1:1
if '$DATA(KEYTXT(LINE))
QUIT
Begin DoDot:1
+11 SET ^TMP(NMSPC,$JOB,LINE)=$$DECRYP^XUSRB1(KEYTXT(LINE))
End DoDot:1
+12 IF $DATA(^TMP(NMSPC,$JOB))
Begin DoDot:1
+13 SET ^TMP(NMSPC,$JOB,0)=$$GET1^DIQ(58.41,STATEIEN,18,"I")_"^"_$$GET1^DIQ(58.41,STATEIEN,19,"I")
End DoDot:1
+14 QUIT
+15 ;
VIEW(STATEIEN) ; Displays the SSH Public Key
+1 ;Input: (r) STATEIEN - State to display the Public SSH Key for
+2 ; ^TMP("PSOPUBKY",$J,0)="SSH Key Format (SSH2 / OpenSSH)^Encryption Type (DSA / RSA)"
+3 ; ^TMP("PSOPUBKY",$J,1-N)=[SSH Key Content]
+4 NEW SSHKEY,DASHLN
+5 IF '$GET(STATEIEN)
QUIT
+6 SET SSHKEY=$$OPENSSH()
SET $PIECE(DASHLN,"-",81)=""
+7 WRITE !,$$GET1^DIQ(5,STATEIEN,.01),"'s Public SSH Key (",$PIECE($GET(^TMP("PSOPUBKY",$JOB,0)),"^",2),") content (does not include dash lines):"
+8 WRITE !,DASHLN
+9 FOR
if $LENGTH(SSHKEY)=0
QUIT
WRITE !,$EXTRACT(SSHKEY,1,80)
SET SSHKEY=$EXTRACT(SSHKEY,81,9999)
+10 WRITE !,DASHLN
+11 QUIT
+12 ;
DELETE(STATEIEN) ; Delete Both SSH Keys associated with the State
+1 ;Input: (r) STATEIEN - State from what the key should be deleted from in the SPMP STATE PARAMETERS file (#58.41)
+2 NEW DIE,DA,DR
+3 SET DIE="^PS(58.41,"
SET DA=+$GET(STATEIEN)
SET DR="18///@;19///@;100///@;200///@"
DO ^DIE
+4 KILL ^TMP("PSOPRVKY",$JOB),^TMP("PSOPUBKY",$JOB)
+5 QUIT
+6 ;
OPENSSH() ; Returns the SSH Public Key in OpenSSH Format (Converts if necessary)
+1 ;Input: ^TMP("PSOPUBKY",$J,0)="SSH Key Format (SSH2 / OpenSSH)^Encryption Type (DSA / RSA)"
+2 ; ^TMP("PSOPUBKY",$J,1-N)=[SSH Key Content]
+3 NEW OPENSSH,ENCRTYPE,LINE
+4 SET OPENSSH=""
+5 IF $PIECE($GET(^TMP("PSOPUBKY",$JOB,0)),"^",1)="SSH2"
Begin DoDot:1
+6 SET ENCRTYPE=$PIECE($GET(^TMP("PSOPUBKY",$JOB,0)),"^",2)
SET OPENSSH=""
+7 FOR LINE=5:1
if '$DATA(^TMP("PSOPUBKY",$JOB,LINE))
QUIT
Begin DoDot:2
+8 IF $GET(^TMP("PSOPUBKY",$JOB,LINE))["---- END"
QUIT
+9 SET OPENSSH=OPENSSH_$GET(^TMP("PSOPUBKY",$JOB,LINE))
End DoDot:2
+10 SET OPENSSH=$SELECT(ENCRTYPE="RSA":"ssh-rsa",1:"ssh-dss")_" "_OPENSSH
End DoDot:1
+11 IF '$TEST
Begin DoDot:1
+12 FOR LINE=1:1
if '$DATA(^TMP("PSOPUBKY",$JOB,LINE))
QUIT
Begin DoDot:2
+13 SET OPENSSH=OPENSSH_$GET(^TMP("PSOPUBKY",$JOB,LINE))
End DoDot:2
End DoDot:1
+14 QUIT OPENSSH
+15 ;
BKENDOS() ; Returns the Backend Server Operating System (OS)
+1 ;Output: Backend Operating System (e.,g., "VMS", "UNIX")
+2 NEW BKENDOS,ZTRTN,ZTIO,ZTDESC,ZTDTH,ZTSK,I
+3 KILL ^XTMP("PSOSPMKY",$JOB,"OS")
+4 SET BKENDOS=""
SET ZTRTN="SETOS^PSOSPMKY("_$JOB_")"
SET ZTIO=""
+5 SET ZTDESC="State Prescription Monitoring Program (SPMP) Backend Server OS Check"
+6 SET ZTDTH=$$NOW^XLFDT()
DO ^%ZTLOAD
+7 FOR I=1:1:5
SET BKENDOS=$GET(^XTMP("PSOSPMKY",$JOB,"OS"))
if BKENDOS'=""
QUIT
HANG 1
+8 KILL ^XTMP("PSOSPMKY",$JOB,"OS")
+9 QUIT $SELECT(BKENDOS'="":BKENDOS,1:$$OS^%ZOSV())
+10 ;
SETOS(JOB) ; Sets the Operating Systems in ^XTMP("PSOSPMKY",$J,"OS") (Called via Taskman)
+1 ;Input: JOB - $Job value from calling process
+2 SET ^XTMP("PSOSPMKY",JOB,"OS")=$$OS^%ZOSV()
+3 QUIT
+4 ;
HELP ; SSH Key Help Text
+1 WRITE !!,"Secure SHell (SSH) Encryption Keys are used to automate the data transmission"
+2 WRITE !,"to the State Prescription Monitoring Programs (SPMPs). Follow the steps below"
+3 WRITE !,"to successfully setup SPMP transmissions from VistA to the state/vendor server:"
+4 WRITE !,""
+5 WRITE !,"Step 1: Select the 'N' (Create New SSH Key Pair) Action and follow the prompts"
+6 WRITE !," to create a new pair of SSH keys. If you already have an existing SSH"
+7 WRITE !," Key Pair you can skip this step. You can check whether you already"
+8 WRITE !," have an existing SSH Key Pair through the 'V' (View Public SSH Key)"
+9 WRITE !," Action."
+10 WRITE !,""
+11 ;PSO*7*723 add ECDSA
+12 WRITE !," Encryption Type: DSA, RSA, ECDSA or EDDSA?"
+13 WRITE !," -----------------------------------"
+14 DO ETHELP
DO PAUSE^PSOSPMU1
+15 WRITE !!,"Step 2: Share the Public SSH Key content with the state/vendor. In order to"
+16 WRITE !," successfully establish SPMP transmissions the state/vendor will have"
+17 WRITE !," to install/configure the new SSH Key created in step 1 for the"
+18 WRITE !," user id they assigned to your site. Use the 'V' (View Public SSH Key)"
+19 WRITE !," Action to retrieve the content of the Public SSH key. The Public SSH"
+20 WRITE !," Key should not contain line-feed characters, therefore after you copy"
+21 WRITE !," & paste it from the terminal emulator into an email or text editor"
+22 WRITE !," make sure it contains only one line of text (no wrapping)."
+23 QUIT
ETHELP ; Encryption Type Help
+1 WRITE !," Digital Signature Algorithm (DSA) (No longer supported) and Rivest,"
+2 WRITE !," Shamir & Adleman (RSA) have been two of the most common encryption"
+3 WRITE !," algorithms used by the IT industry for securely sharing data. "
+4 ;PSO*7*723 add ECDSA/EDDSA
+5 WRITE !," Elliptic Curve Digital Signature Algorithm (ECDSA) and Edward-curve"
+6 WRITE !," Digital Signature Algorithm (EDDSA) are more complex public key"
+7 WRITE !," cryptography encryption algorithms that are now supported by the VA."
+8 WRITE !," Many of SPMP servers can handle all types; however there are vendors"
+9 WRITE !," that accept only one specific type. You will need to contact the SPMP"
+10 WRITE !," vendor support to determine which type to select. If ECDSA is selected"
+11 WRITE !," you will be prompted to enter the Bit size. Valid selections are 256,"
+12 WRITE !," 384 or 521."
+13 QUIT