PSNOSKEY ;BIR/SJA-PPS-N SSH Key Management ;09/16/2016
 ;;4.0;NATIONAL DRUG FILE;**513,563,575**; 30 Oct 98;Build 22
 ;
 ;SAC EXEMPTION 202402221226-01: Allows the use of the $ZF(-100) function
 ;
 ; taken mostly from: PSOSPMKY - State Prescription Monitoring Program - SSH Key Management
 ;
EN ; -- Entry point
 N X,Y,PSNOS,LOCALDIR,X1,DIR,ENCRBITS,PSNDSA
 ;
ACTION ; -- SSH Key Action
 K DIR S DIR("A")="Action"
 S DIR(0)="S^V:View Public SSH Key;C:Create New SSH Key Pair;D:Delete SSH Key Pair;H:Help with SSH Keys",DIR("B")="V"
 D ^DIR
 I $D(DUOUT)!($D(DIRUT)) G END
 I Y="C"!(Y="D"),'$D(^XUSEC("PSN PPS COORD",DUZ)) D  G ACTION
 .W !!,"The PSN PPS COORD security key is required for this action.",$C(7)
 K ^TMP("PSNPUBKY",$J) D RETRIEVE("PUB")
 I Y="V"!(Y="D"),'$D(^TMP("PSNPUBKY",$J)) D  G ACTION
 .W !!,"[No SSH Key Pair found]",$C(7) D PAUSE
 I Y="C"!(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" W ! D VIEW,PAUSE G ACTION
 ;
 ; -- Create New SSH Key Pair
 I Y="C" D  G ACTION
 .I '$$ASK() W !!,"No action taken!",$C(7) Q
 .S PSNOS=$$ENDOS()
 .S LOCALDIR=$$GET1^DIQ(57.23,1,$S(PSNOS["VMS":1,1:3))
 .I LOCALDIR="" D  Q
 ..W !!,"The ",$S(PSNOS["VMS":"OPEN VMS",1:"UNIX/LINUX")," LOCAL DIRECTORY parameter is missing. Please, update it in"
 ..W !,"the 'PPS-N Site Parameters (Enter/Edit)' option and try again.",$C(7) D PAUSE
 .K DIR S DIR("A")="SSH Key Encryption Type",DIR("?")="^D HELP1^PSNOSKEY"
 .;PSN*4*575 Add ECDSA
 .S PSNDSA=$$GET1^DIQ(57.23,1,11,"I")
 .I 'PSNDSA S DIR(0)="S^RSA:Rivest, Shamir & Adleman (RSA)"
 .I PSNDSA S DIR(0)="S^RSA:Rivest, Shamir & Adleman (RSA);ECDSA:Elliptic Curve Digital Signature Algorithm (ECDSA)"
 .S DIR("B")="RSA" D ^DIR I $D(DUOUT)!($D(DIRUT)) Q
 .S ENCRTYPE=Y
 . ;p575 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("PSNPUBKY",$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 Keys",DIR(0)="Y",DIR("B")="NO"
 .W ! D ^DIR I $D(DIRUT)!$D(DUOUT)!'Y Q
 .;
 .; -- Deleting Existing SSH Key
 .I $D(^TMP("PSNPUBKY",$J)) D DELETE
 .W !!,"Creating New SSH Keys, please wait..."
 . ;p575 removing the task off logic, unnecessary
 .;N ZTRTN,ZTIO,ZTDESC,ZTDTH,ZTSK
 .;S ZTRTN="NEWKEY^PSNOSKEY("""_ENCRTYPE_""")",ZTIO="",ZTDESC="SSH Key Generation",ZTDTH=$$NOW^XLFDT()
 .;D ^%ZTLOAD K ZTSK,^TMP("PSNPUBKY",$J)
 .;F I=1:1:30 D RETRIEVE("PUB") Q:$D(^TMP("PSNPUBKY",$J))  H 1
 .; -- If unable to create the key via Taskman after 30 seconds, creates them in the foreground
 .;I '$D(^TMP("PSNPUBKY",$J)) D
 .D NEWKEY(ENCRTYPE),RETRIEVE("PUB")
 .I '$D(^TMP("PSNPUBKY",$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
 .E  W "Done",$C(7)
 ;
 ; -- Delete SSH Key Pair
 I Y="D" D  G ACTION
 .D RETRIEVE("PUB")
 .I '$D(^TMP("PSNPUBKY",$J)) W !!,"[No SSH Key Pair found]",$C(7) Q
 .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 SSH Keys",DIR(0)="Y",DIR("B")="NO"
 .W ! D ^DIR I $D(DIRUT)!$D(DUOUT)!'Y Q
 .W !!,"Deleting SSH Keys..." D DELETE H 1 W "Done",$C(7)
 ; SSH Key Help
 I Y="H" D HELP G ACTION
 G ACTION
 ;
END ;
 Q
 ;
NEWKEY(ENCRTYPE) ; Generate and store a pair of SSH keys
 ; Input:  (o) ENCRTYPE - SSH Encryption Type (DSA/RSA) (Default: RSA)
 ;
 N LOCALDIR,DTE,PSNOS,KEYFILE,PV,FILE2DEL,LN,OVFLN,PSNSPC,KYTXT,SAVEKEY,DIE,DR,DA
 S PSNOS=$$OS^%ZOSV()
 S LOCALDIR=$$GET1^DIQ(57.23,1,$S(PSNOS["VMS":1,1:3)) I LOCALDIR="" Q  ;Error: Missing directory
 ;PSN*4*575 handle ECDSA
 ;I $G(ENCRTYPE)'="RSA" S ENCRTYPE="DSA"
 S ENCRTYPE=$S($G(ENCRTYPE)="ECDSA":"ECDSA",1:"RSA")
 ; -- LOCK to avoid OS files overwrite
 F  S DTE=+$$FMTHL7^XLFDT($$HTFM^XLFDT($H)) S KEYFILE="KY"_DTE L +@KEYFILE:0 Q:$T  H 2
 ; -- Deleting existing SSH Keys first
 D DELETE
 ;
 ; -- OpenVMS SSH Key Generation
 I PSNOS["VMS" D
 .N COMFILE S COMFILE="COM"_DTE_".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 PSNOS["UNIX" D
 .I '$$DIREXIST^PSNFTP2(LOCALDIR) D MAKEDIR^PSNFTP2(LOCALDIR)
 . S ENCRBITS=$S($G(ENCRBITS):ENCRBITS,1:"")
 . S ENCRTYPE=$$LOW^XLFSTR($G(ENCRTYPE))
 . I ($P($$VERSION^%ZOSV(1),"/",1)[("Cache")) D
 . . S:ENCRBITS ENCRBITS=" -b "_ENCRBITS
 . . X "S PV=$ZF(-1,""ssh-keygen -q -N '' -C '' -t "_$$LOW^XLFSTR($G(ENCRTYPE))_" -f "_LOCALDIR_KEYFILE_ENCRBITS_""")"
 . I $P($$VERSION^%ZOSV(1),"/",1)'[("Cache") D
 . . I ENCRBITS S PV=$ZF(-100,"","ssh-keygen","-q","-t",ENCRTYPE,"-b",ENCRBITS,"-f",LOCALDIR_KEYFILE,"-N","","-C","")
 . . I ENCRBITS="" S PV=$ZF(-100,"","ssh-keygen","-q","-t",ENCRTYPE,"-f",LOCALDIR_KEYFILE,"-N","","-C","")
 .S FILE2DEL(KEYFILE)="",FILE2DEL(KEYFILE_".pub")=""
 ;
 K ^TMP("PSNPRVKY",$J),^TMP("PSNPUBKY",$J)
 ; -- Retrieving SSH Private Key Content
 S X=$$FTG^%ZISH(LOCALDIR,KEYFILE_$S(PSNOS["VMS":".",1:""),$NAME(^TMP("PSNPRVKY",$J,1)),3)
 I '$D(^TMP("PSNPRVKY",$J,1)) Q
 ; -- Retrieving SSH Public Key Content
 S X=$$FTG^%ZISH(LOCALDIR,KEYFILE_$S(PSNOS["VMS":".PUB",1:".pub"),$NAME(^TMP("PSNPUBKY",$J,1)),3)
 I '$D(^TMP("PSNPUBKY",$J,1)) Q
 ;
 ; -- Deleting temporary files used to generate the keys
 D DEL^%ZISH(LOCALDIR,"FILE2DEL")
 ;
 ; -- Saving new SSH Keys content in the PPS-N UPDATE CONTROL file (#57.23)
 F PSNSPC="PSNPRVKY","PSNPUBKY" D
 .K KYTXT,SAVEKEY
 .F LN=1:1 Q:'$D(^TMP(PSNSPC,$J,LN))  D
 ..; Unix/Linux Public SSH Key has no line-feed
 ..I PSNOS["UNIX",PSNSPC="PSNPUBKY" D  Q
 ...S KYTXT(1)=^TMP(PSNSPC,$J,LN)
 ...F OVFLN=1:1 Q:'$D(^TMP(PSNSPC,$J,LN,"OVF",OVFLN))  D
 ....S KYTXT(1)=$G(KYTXT(1))_^TMP(PSNSPC,$J,LN,"OVF",OVFLN)
 ..S KYTXT(LN)=$$ENCRYP^XUSRB1(^TMP(PSNSPC,$J,LN))
 .I PSNOS["UNIX",PSNSPC="PSNPUBKY" S KYTXT(1)=$$ENCRYP^XUSRB1(KYTXT(1))
 .S SAVEKEY(57.23,"1,",$S(PSNSPC="PSNPRVKY":33,1:34))="KYTXT"
 .D UPDATE^DIE("","SAVEKEY")
 .K ^TMP(PSNSPC,$J)
 ;
 ; -- Saving SSH Key Format (SSH2/OpenSSH) and Encryption Type (DSA/RSA) fields
 K DIE S DIE="^PS(57.23,",DA=1
 S DR="39///"_$S(PSNOS["VMS":"SSH2",1:"OSSH")_";41///"_ENCRTYPE D ^DIE
 L -@KEYFILE
 Q
 ;
RETRIEVE(KTYPE) ; Retrieve the SSH Key into the ^TMP global
 ;        (o) KTYPE  - SSH Key Type (PUB - Public/PRV - PRivate) (Default: Public)
 ;Output: ^TMP("PSN[PUB/PRV]KY",$J,0)="SSH Key Format (SSH2/OpenSSH)^Encryption Type (DSA/RSA)"
 ;        ^TMP("PSN[PUB/PRV]KY",$J,1-N)=[SSH Key Content]
 ;
 N X,LN,KYTXT,PSNSPC
 I $G(KTYPE)'="PRV" S KTYPE="PUB"
 S X=$$GET1^DIQ(57.23,"1,",$S(KTYPE="PRV":33,1:34),,"KYTXT")
 S PSNSPC=$S(KTYPE="PRV":"PSNPRVKY",1:"PSNPUBKY")
 K ^TMP(PSNSPC,$J)
 F LN=1:1 Q:'$D(KYTXT(LN))  S ^TMP(PSNSPC,$J,LN)=$$DECRYP^XUSRB1(KYTXT(LN))
 I $D(^TMP(PSNSPC,$J)) D
 .S ^TMP(PSNSPC,$J,0)=$$GET1^DIQ(57.23,1,39,"I")_"^"_$$GET1^DIQ(57.23,1,41,"I")
 Q
 ;
VIEW ; Displays the SSH Public Key
 ;       ^TMP("PSNPUBKY",$J,0)="SSH Key Format (SSH2/OpenSSH)^Encryption Type (DSA/RSA)"
 ;       ^TMP("PSNPUBKY",$J,1-N)=[SSH Key Content]
 N SSHKEY,DASHLN
 S $P(DASHLN,"-",81)="",SSHKEY=$$OPENSSH()
 W !,"Public SSH Key (",$P($G(^TMP("PSNPUBKY",$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 ; Delete Both SSH Keys associated
 N DIE,DA,DR
 S DIE="^PS(57.23,",DA=1,DR="39///@;41///@;33///@;34///@" D ^DIE
 K ^TMP("PSNPRVKY",$J),^TMP("PSNPUBKY",$J)
 Q
 ;
OPENSSH() ; Returns the SSH Public Key in OpenSSH Format (Converts if necessary)
 ;Input: ^TMP("PSNPUBKY",$J,0)="SSH Key Format (SSH2/OpenSSH)^Encryption Type (DSA/RSA)"
 ;       ^TMP("PSNPUBKY",$J,1-N)=[SSH Key Content]
 ;
 N OPENSSH,ENCRTYPE,LN
 S OPENSSH=""
 I $P($G(^TMP("PSNPUBKY",$J,0)),"^")="SSH2" D
 .S ENCRTYPE=$P($G(^TMP("PSNPUBKY",$J,0)),"^",2),OPENSSH=""
 .F LN=5:1 Q:'$D(^TMP("PSNPUBKY",$J,LN))  D
 ..I $G(^TMP("PSNPUBKY",$J,LN))["---- END" Q
 ..S OPENSSH=OPENSSH_$G(^TMP("PSNPUBKY",$J,LN))
 .S OPENSSH=$S(ENCRTYPE="RSA":"ssh-rsa",1:"ssh-dss")_" "_OPENSSH
 E  D
 .F LN=1:1 Q:'$D(^TMP("PSNPUBKY",$J,LN))  D
 ..S OPENSSH=OPENSSH_$G(^TMP("PSNPUBKY",$J,LN))
 Q OPENSSH
 ;
ENDOS() ; Returns the Backend Server Operating System (OS)
 ;Output: Backend Operating System (e.,g., "VMS", "UNIX")
 ;
 N ENDOS,ZTRTN,ZTIO,ZTDESC,ZTDTH,ZTSK,I
 K ^XTMP("PSNKEY",$J,"OS")
 S ENDOS="",ZTRTN="SETOS^PSNOSKEY("_$J_")",ZTIO=""
 S ZTDESC="Backend Server OS Check"
 S ZTDTH=$$NOW^XLFDT() D ^%ZTLOAD
 F I=1:1:5 S ENDOS=$G(^XTMP("PSNKEY",$J,"OS")) Q:ENDOS'=""  H 1
 K ^XTMP("PSNKEY",$J,"OS")
 Q $S(ENDOS'="":ENDOS,1:$$OS^%ZOSV())
 ;
SETOS(JOB) ; Sets the Operating Systems in ^XTMP("PSNKEY",$J,"OS") (Called via Taskman)
 ;Input: JOB - $Job value from calling process
 S ^XTMP("PSNKEY",JOB,"OS")=$$OS^%ZOSV()
 Q
 ;
 ;PSN*4*575 UPDATE HELP TEXT WORDING FOR ECDSA
HELP ; Encryption Type Help
 W !!,"Secure SHell (SSH) Encryption Keys are used to allow data file download."
 W !,"Follow the steps below to successfully setup data file download from Austin "
 W !,"server to VistA sites:",!
 W !,"Step 1: Select the 'C' (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."
 W !,"        You can check whether you already have an existing SSH Key Pair"
 W !,"        through the 'V' (View Public SSH Key) Action."
 W !,""
 D HELP1,PAUSE
 W !!,"Step 2: Share the Public SSH Key content with the PPS-N SFTP server (Austin)."
 W !,"        In order to successfully establish the data download files, the SFTP  "
 W !,"        server at Austin needs to install/configure the new SSH Key created in"
 W !,"        step 1 for the user id they assigned to your site. Use the 'V' (View "
 W !,"        Public SSH Key) Action to retrieve the content of the Public SSH key."
 W !,"        The Public SSH Key should not contain line-feed characters, therefore "
 W !,"        after you copy & paste it from the terminal emulator into an email or "
 W !,"        text editor make sure it contains only one line of text (no wrapping)."
 Q
 ;
HELP1 ; Encryption Type Help
 W !,"        Encryption Type: RSA or ECDSA?"
 W !,"        -----------------------------------"
 W !,"        Rivest, Shamir & Adleman (RSA) has been one of the most common"
 W !,"        encryption algorithms used by the IT industry for securely sharing data."
 W !,""
 W !,"        Elliptic Curve Digital Signature Algorithm (ECDSA) is a more complex"
 W !,"        public key cryptography encryption algorithm that is now supported by"
 W !,"        the VA. If ECDSA is selected you will be prompted to enter the Bit size."
 W !,"        Valid selections are 256, 384 or 521."
 W !,""
 W !,"        You will need to contact the Austin SFTP server support to determine"
 W !,"        which type to select."
 Q
PAUSE ; Pauses screen until user hits Return
 W ! K DIR S DIR("A")="Press Return to continue",DIR(0)="E" D ^DIR
 Q
 ;
ASK() ; confirm creating new pair
 N Y S Y=0 Q:'$D(^TMP("PSNPUBKY",$J)) 1
 K DIRUT,DUOUT,DIR,X,Y S DIR(0)="Y",DIR("?")="Please enter Y or N."
 S DIR("A")="Do you want to delete existing key pair and create new pair" W !!
 S DIR("B")="NO" D ^DIR
 Q Y
 
--- Routine Detail   --- with STRUCTURED ROUTINE LISTING ---[H[J[2J[HPSNOSKEY   12146     printed  Sep 23, 2025@20:00:28                                                                                                                                                                                                   Page 2
PSNOSKEY  ;BIR/SJA-PPS-N SSH Key Management ;09/16/2016
 +1       ;;4.0;NATIONAL DRUG FILE;**513,563,575**; 30 Oct 98;Build 22
 +2       ;
 +3       ;SAC EXEMPTION 202402221226-01: Allows the use of the $ZF(-100) function
 +4       ;
 +5       ; taken mostly from: PSOSPMKY - State Prescription Monitoring Program - SSH Key Management
 +6       ;
EN        ; -- Entry point
 +1        NEW X,Y,PSNOS,LOCALDIR,X1,DIR,ENCRBITS,PSNDSA
 +2       ;
ACTION    ; -- SSH Key Action
 +1        KILL DIR
           SET DIR("A")="Action"
 +2        SET DIR(0)="S^V:View Public SSH Key;C:Create New SSH Key Pair;D:Delete SSH Key Pair;H:Help with SSH Keys"
           SET DIR("B")="V"
 +3        DO ^DIR
 +4        IF $DATA(DUOUT)!($DATA(DIRUT))
               GOTO END
 +5        IF Y="C"!(Y="D")
               IF '$DATA(^XUSEC("PSN PPS COORD",DUZ))
                   Begin DoDot:1
 +6                    WRITE !!,"The PSN PPS COORD security key is required for this action.",$CHAR(7)
                   End DoDot:1
                   GOTO ACTION
 +7        KILL ^TMP("PSNPUBKY",$JOB)
           DO RETRIEVE("PUB")
 +8        IF Y="V"!(Y="D")
               IF '$DATA(^TMP("PSNPUBKY",$JOB))
                   Begin DoDot:1
 +9                    WRITE !!,"[No SSH Key Pair found]",$CHAR(7)
                       DO PAUSE
                   End DoDot:1
                   GOTO ACTION
 +10       IF Y="C"!(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"
               WRITE !
               DO VIEW
               DO PAUSE
               GOTO ACTION
 +14      ;
 +15      ; -- Create New SSH Key Pair
 +16       IF Y="C"
               Begin DoDot:1
 +17               IF '$$ASK()
                       WRITE !!,"No action taken!",$CHAR(7)
                       QUIT 
 +18               SET PSNOS=$$ENDOS()
 +19               SET LOCALDIR=$$GET1^DIQ(57.23,1,$SELECT(PSNOS["VMS":1,1:3))
 +20               IF LOCALDIR=""
                       Begin DoDot:2
 +21                       WRITE !!,"The ",$SELECT(PSNOS["VMS":"OPEN VMS",1:"UNIX/LINUX")," LOCAL DIRECTORY parameter is missing. Please, update it in"
 +22                       WRITE !,"the 'PPS-N Site Parameters (Enter/Edit)' option and try again.",$CHAR(7)
                           DO PAUSE
                       End DoDot:2
                       QUIT 
 +23               KILL DIR
                   SET DIR("A")="SSH Key Encryption Type"
                   SET DIR("?")="^D HELP1^PSNOSKEY"
 +24      ;PSN*4*575 Add ECDSA
 +25               SET PSNDSA=$$GET1^DIQ(57.23,1,11,"I")
 +26               IF 'PSNDSA
                       SET DIR(0)="S^RSA:Rivest, Shamir & Adleman (RSA)"
 +27               IF PSNDSA
                       SET DIR(0)="S^RSA:Rivest, Shamir & Adleman (RSA);ECDSA:Elliptic Curve Digital Signature Algorithm (ECDSA)"
 +28               SET DIR("B")="RSA"
                   DO ^DIR
                   IF $DATA(DUOUT)!($DATA(DIRUT))
                       QUIT 
 +29               SET ENCRTYPE=Y
 +30      ;p575 prompt for bit size for ECDSA
 +31               IF ENCRTYPE="ECDSA"
                       Begin DoDot:2
 +32                       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."
 +33                       SET DIR(0)="S^256:256 bits;384:384 bits;521:521 bits"
 +34                       SET DIR("B")="256"
                           DO ^DIR
                       End DoDot:2
                       IF $DATA(DUOUT)!($DATA(DIRUT))
                           QUIT 
 +35               SET ENCRBITS=$SELECT(ENCRTYPE="ECDSA":Y,1:"")
 +36               IF $DATA(^TMP("PSNPUBKY",$JOB))
                       Begin DoDot:2
 +37                       WRITE !!,$GET(IOBON),"WARNING:",$GET(IOBOFF)," You may be overwriting SSH Keys that are currently in use.",$CHAR(7)
                       End DoDot:2
 +38               KILL DIR
                   SET DIR("A")="Confirm Creation of SSH Keys"
                   SET DIR(0)="Y"
                   SET DIR("B")="NO"
 +39               WRITE !
                   DO ^DIR
                   IF $DATA(DIRUT)!$DATA(DUOUT)!'Y
                       QUIT 
 +40      ;
 +41      ; -- Deleting Existing SSH Key
 +42               IF $DATA(^TMP("PSNPUBKY",$JOB))
                       DO DELETE
 +43               WRITE !!,"Creating New SSH Keys, please wait..."
 +44      ;p575 removing the task off logic, unnecessary
 +45      ;N ZTRTN,ZTIO,ZTDESC,ZTDTH,ZTSK
 +46      ;S ZTRTN="NEWKEY^PSNOSKEY("""_ENCRTYPE_""")",ZTIO="",ZTDESC="SSH Key Generation",ZTDTH=$$NOW^XLFDT()
 +47      ;D ^%ZTLOAD K ZTSK,^TMP("PSNPUBKY",$J)
 +48      ;F I=1:1:30 D RETRIEVE("PUB") Q:$D(^TMP("PSNPUBKY",$J))  H 1
 +49      ; -- If unable to create the key via Taskman after 30 seconds, creates them in the foreground
 +50      ;I '$D(^TMP("PSNPUBKY",$J)) D
 +51               DO NEWKEY(ENCRTYPE)
                   DO RETRIEVE("PUB")
 +52               IF '$DATA(^TMP("PSNPUBKY",$JOB))
                       Begin DoDot:2
 +53                       WRITE !!,"There was a problem with the generation of the new SSH Key Pair."
 +54                       WRITE !,"Please try again and if the problem persists contact IT Support.",$CHAR(7)
                           DO PAUSE
                       End DoDot:2
 +55              IF '$TEST
                       WRITE "Done",$CHAR(7)
               End DoDot:1
               GOTO ACTION
 +56      ;
 +57      ; -- Delete SSH Key Pair
 +58       IF Y="D"
               Begin DoDot:1
 +59               DO RETRIEVE("PUB")
 +60               IF '$DATA(^TMP("PSNPUBKY",$JOB))
                       WRITE !!,"[No SSH Key Pair found]",$CHAR(7)
                       QUIT 
 +61               WRITE !!,$GET(IOBON),"WARNING:",$GET(IOBOFF)," You may be deleting SSH Keys that are currently in use.",$CHAR(7)
 +62               KILL DIR
                   SET DIR("A")="Confirm Deletion of SSH Keys"
                   SET DIR(0)="Y"
                   SET DIR("B")="NO"
 +63               WRITE !
                   DO ^DIR
                   IF $DATA(DIRUT)!$DATA(DUOUT)!'Y
                       QUIT 
 +64               WRITE !!,"Deleting SSH Keys..."
                   DO DELETE
                   HANG 1
                   WRITE "Done",$CHAR(7)
               End DoDot:1
               GOTO ACTION
 +65      ; SSH Key Help
 +66       IF Y="H"
               DO HELP
               GOTO ACTION
 +67       GOTO ACTION
 +68      ;
END       ;
 +1        QUIT 
 +2       ;
NEWKEY(ENCRTYPE) ; Generate and store a pair of SSH keys
 +1       ; Input:  (o) ENCRTYPE - SSH Encryption Type (DSA/RSA) (Default: RSA)
 +2       ;
 +3        NEW LOCALDIR,DTE,PSNOS,KEYFILE,PV,FILE2DEL,LN,OVFLN,PSNSPC,KYTXT,SAVEKEY,DIE,DR,DA
 +4        SET PSNOS=$$OS^%ZOSV()
 +5       ;Error: Missing directory
           SET LOCALDIR=$$GET1^DIQ(57.23,1,$SELECT(PSNOS["VMS":1,1:3))
           IF LOCALDIR=""
               QUIT 
 +6       ;PSN*4*575 handle ECDSA
 +7       ;I $G(ENCRTYPE)'="RSA" S ENCRTYPE="DSA"
 +8        SET ENCRTYPE=$SELECT($GET(ENCRTYPE)="ECDSA":"ECDSA",1:"RSA")
 +9       ; -- LOCK to avoid OS files overwrite
 +10       FOR 
               SET DTE=+$$FMTHL7^XLFDT($$HTFM^XLFDT($HOROLOG))
               SET KEYFILE="KY"_DTE
               LOCK +@KEYFILE:0
               if $TEST
                   QUIT 
               HANG 2
 +11      ; -- Deleting existing SSH Keys first
 +12       DO DELETE
 +13      ;
 +14      ; -- OpenVMS SSH Key Generation
 +15       IF PSNOS["VMS"
               Begin DoDot:1
 +16               NEW COMFILE
                   SET COMFILE="COM"_DTE_".COM"
 +17               DO OPEN^%ZISH("COMFILE",LOCALDIR,COMFILE,"W")
 +18               DO USE^%ZISUTL("COMFILE")
 +19               WRITE "SSH_KEYGEN == ""$SYS$SYSTEM:TCPIP$SSH_SSH-KEYGEN2.EXE""",!
 +20               WRITE "SSH_KEYGEN -t "_$$LOW^XLFSTR($GET(ENCRTYPE))_" -""P"" "_LOCALDIR_KEYFILE,!
 +21               DO CLOSE^%ZISH("COMFILE")
 +22               XECUTE "S PV=$ZF(-1,""@"_LOCALDIR_COMFILE_""")"
 +23               SET FILE2DEL(COMFILE)=""
                   SET FILE2DEL(KEYFILE_".")=""
                   SET FILE2DEL(KEYFILE_".PUB")=""
               End DoDot:1
 +24      ;
 +25      ; -- Linux/Unix SSH Key Generation
 +26       IF PSNOS["UNIX"
               Begin DoDot:1
 +27               IF '$$DIREXIST^PSNFTP2(LOCALDIR)
                       DO MAKEDIR^PSNFTP2(LOCALDIR)
 +28               SET ENCRBITS=$SELECT($GET(ENCRBITS):ENCRBITS,1:"")
 +29               SET ENCRTYPE=$$LOW^XLFSTR($GET(ENCRTYPE))
 +30               IF ($PIECE($$VERSION^%ZOSV(1),"/",1)[("Cache"))
                       Begin DoDot:2
 +31                       if ENCRBITS
                               SET ENCRBITS=" -b "_ENCRBITS
 +32                       XECUTE "S PV=$ZF(-1,""ssh-keygen -q -N '' -C '' -t "_$$LOW^XLFSTR($GET(ENCRTYPE))_" -f "_LOCALDIR_KEYFILE_ENCRBITS_""")"
                       End DoDot:2
 +33               IF $PIECE($$VERSION^%ZOSV(1),"/",1)'[("Cache")
                       Begin DoDot:2
 +34                       IF ENCRBITS
                               SET PV=$ZF(-100,"","ssh-keygen","-q","-t",ENCRTYPE,"-b",ENCRBITS,"-f",LOCALDIR_KEYFILE,"-N","","-C","")
 +35                       IF ENCRBITS=""
                               SET PV=$ZF(-100,"","ssh-keygen","-q","-t",ENCRTYPE,"-f",LOCALDIR_KEYFILE,"-N","","-C","")
                       End DoDot:2
 +36               SET FILE2DEL(KEYFILE)=""
                   SET FILE2DEL(KEYFILE_".pub")=""
               End DoDot:1
 +37      ;
 +38       KILL ^TMP("PSNPRVKY",$JOB),^TMP("PSNPUBKY",$JOB)
 +39      ; -- Retrieving SSH Private Key Content
 +40       SET X=$$FTG^%ZISH(LOCALDIR,KEYFILE_$SELECT(PSNOS["VMS":".",1:""),$NAME(^TMP("PSNPRVKY",$JOB,1)),3)
 +41       IF '$DATA(^TMP("PSNPRVKY",$JOB,1))
               QUIT 
 +42      ; -- Retrieving SSH Public Key Content
 +43       SET X=$$FTG^%ZISH(LOCALDIR,KEYFILE_$SELECT(PSNOS["VMS":".PUB",1:".pub"),$NAME(^TMP("PSNPUBKY",$JOB,1)),3)
 +44       IF '$DATA(^TMP("PSNPUBKY",$JOB,1))
               QUIT 
 +45      ;
 +46      ; -- Deleting temporary files used to generate the keys
 +47       DO DEL^%ZISH(LOCALDIR,"FILE2DEL")
 +48      ;
 +49      ; -- Saving new SSH Keys content in the PPS-N UPDATE CONTROL file (#57.23)
 +50       FOR PSNSPC="PSNPRVKY","PSNPUBKY"
               Begin DoDot:1
 +51               KILL KYTXT,SAVEKEY
 +52               FOR LN=1:1
                       if '$DATA(^TMP(PSNSPC,$JOB,LN))
                           QUIT 
                       Begin DoDot:2
 +53      ; Unix/Linux Public SSH Key has no line-feed
 +54                       IF PSNOS["UNIX"
                               IF PSNSPC="PSNPUBKY"
                                   Begin DoDot:3
 +55                                   SET KYTXT(1)=^TMP(PSNSPC,$JOB,LN)
 +56                                   FOR OVFLN=1:1
                                           if '$DATA(^TMP(PSNSPC,$JOB,LN,"OVF",OVFLN))
                                               QUIT 
                                           Begin DoDot:4
 +57                                           SET KYTXT(1)=$GET(KYTXT(1))_^TMP(PSNSPC,$JOB,LN,"OVF",OVFLN)
                                           End DoDot:4
                                   End DoDot:3
                                   QUIT 
 +58                       SET KYTXT(LN)=$$ENCRYP^XUSRB1(^TMP(PSNSPC,$JOB,LN))
                       End DoDot:2
 +59               IF PSNOS["UNIX"
                       IF PSNSPC="PSNPUBKY"
                           SET KYTXT(1)=$$ENCRYP^XUSRB1(KYTXT(1))
 +60               SET SAVEKEY(57.23,"1,",$SELECT(PSNSPC="PSNPRVKY":33,1:34))="KYTXT"
 +61               DO UPDATE^DIE("","SAVEKEY")
 +62               KILL ^TMP(PSNSPC,$JOB)
               End DoDot:1
 +63      ;
 +64      ; -- Saving SSH Key Format (SSH2/OpenSSH) and Encryption Type (DSA/RSA) fields
 +65       KILL DIE
           SET DIE="^PS(57.23,"
           SET DA=1
 +66       SET DR="39///"_$SELECT(PSNOS["VMS":"SSH2",1:"OSSH")_";41///"_ENCRTYPE
           DO ^DIE
 +67       LOCK -@KEYFILE
 +68       QUIT 
 +69      ;
RETRIEVE(KTYPE) ; Retrieve the SSH Key into the ^TMP global
 +1       ;        (o) KTYPE  - SSH Key Type (PUB - Public/PRV - PRivate) (Default: Public)
 +2       ;Output: ^TMP("PSN[PUB/PRV]KY",$J,0)="SSH Key Format (SSH2/OpenSSH)^Encryption Type (DSA/RSA)"
 +3       ;        ^TMP("PSN[PUB/PRV]KY",$J,1-N)=[SSH Key Content]
 +4       ;
 +5        NEW X,LN,KYTXT,PSNSPC
 +6        IF $GET(KTYPE)'="PRV"
               SET KTYPE="PUB"
 +7        SET X=$$GET1^DIQ(57.23,"1,",$SELECT(KTYPE="PRV":33,1:34),,"KYTXT")
 +8        SET PSNSPC=$SELECT(KTYPE="PRV":"PSNPRVKY",1:"PSNPUBKY")
 +9        KILL ^TMP(PSNSPC,$JOB)
 +10       FOR LN=1:1
               if '$DATA(KYTXT(LN))
                   QUIT 
               SET ^TMP(PSNSPC,$JOB,LN)=$$DECRYP^XUSRB1(KYTXT(LN))
 +11       IF $DATA(^TMP(PSNSPC,$JOB))
               Begin DoDot:1
 +12               SET ^TMP(PSNSPC,$JOB,0)=$$GET1^DIQ(57.23,1,39,"I")_"^"_$$GET1^DIQ(57.23,1,41,"I")
               End DoDot:1
 +13       QUIT 
 +14      ;
VIEW      ; Displays the SSH Public Key
 +1       ;       ^TMP("PSNPUBKY",$J,0)="SSH Key Format (SSH2/OpenSSH)^Encryption Type (DSA/RSA)"
 +2       ;       ^TMP("PSNPUBKY",$J,1-N)=[SSH Key Content]
 +3        NEW SSHKEY,DASHLN
 +4        SET $PIECE(DASHLN,"-",81)=""
           SET SSHKEY=$$OPENSSH()
 +5        WRITE !,"Public SSH Key (",$PIECE($GET(^TMP("PSNPUBKY",$JOB,0)),"^",2),") content (does not include dash lines):"
 +6        WRITE !,DASHLN
 +7        FOR 
               if $LENGTH(SSHKEY)=0
                   QUIT 
               WRITE !,$EXTRACT(SSHKEY,1,80)
               SET SSHKEY=$EXTRACT(SSHKEY,81,9999)
 +8        WRITE !,DASHLN
 +9        QUIT 
 +10      ;
DELETE    ; Delete Both SSH Keys associated
 +1        NEW DIE,DA,DR
 +2        SET DIE="^PS(57.23,"
           SET DA=1
           SET DR="39///@;41///@;33///@;34///@"
           DO ^DIE
 +3        KILL ^TMP("PSNPRVKY",$JOB),^TMP("PSNPUBKY",$JOB)
 +4        QUIT 
 +5       ;
OPENSSH() ; Returns the SSH Public Key in OpenSSH Format (Converts if necessary)
 +1       ;Input: ^TMP("PSNPUBKY",$J,0)="SSH Key Format (SSH2/OpenSSH)^Encryption Type (DSA/RSA)"
 +2       ;       ^TMP("PSNPUBKY",$J,1-N)=[SSH Key Content]
 +3       ;
 +4        NEW OPENSSH,ENCRTYPE,LN
 +5        SET OPENSSH=""
 +6        IF $PIECE($GET(^TMP("PSNPUBKY",$JOB,0)),"^")="SSH2"
               Begin DoDot:1
 +7                SET ENCRTYPE=$PIECE($GET(^TMP("PSNPUBKY",$JOB,0)),"^",2)
                   SET OPENSSH=""
 +8                FOR LN=5:1
                       if '$DATA(^TMP("PSNPUBKY",$JOB,LN))
                           QUIT 
                       Begin DoDot:2
 +9                        IF $GET(^TMP("PSNPUBKY",$JOB,LN))["---- END"
                               QUIT 
 +10                       SET OPENSSH=OPENSSH_$GET(^TMP("PSNPUBKY",$JOB,LN))
                       End DoDot:2
 +11               SET OPENSSH=$SELECT(ENCRTYPE="RSA":"ssh-rsa",1:"ssh-dss")_" "_OPENSSH
               End DoDot:1
 +12      IF '$TEST
               Begin DoDot:1
 +13               FOR LN=1:1
                       if '$DATA(^TMP("PSNPUBKY",$JOB,LN))
                           QUIT 
                       Begin DoDot:2
 +14                       SET OPENSSH=OPENSSH_$GET(^TMP("PSNPUBKY",$JOB,LN))
                       End DoDot:2
               End DoDot:1
 +15       QUIT OPENSSH
 +16      ;
ENDOS()   ; Returns the Backend Server Operating System (OS)
 +1       ;Output: Backend Operating System (e.,g., "VMS", "UNIX")
 +2       ;
 +3        NEW ENDOS,ZTRTN,ZTIO,ZTDESC,ZTDTH,ZTSK,I
 +4        KILL ^XTMP("PSNKEY",$JOB,"OS")
 +5        SET ENDOS=""
           SET ZTRTN="SETOS^PSNOSKEY("_$JOB_")"
           SET ZTIO=""
 +6        SET ZTDESC="Backend Server OS Check"
 +7        SET ZTDTH=$$NOW^XLFDT()
           DO ^%ZTLOAD
 +8        FOR I=1:1:5
               SET ENDOS=$GET(^XTMP("PSNKEY",$JOB,"OS"))
               if ENDOS'=""
                   QUIT 
               HANG 1
 +9        KILL ^XTMP("PSNKEY",$JOB,"OS")
 +10       QUIT $SELECT(ENDOS'="":ENDOS,1:$$OS^%ZOSV())
 +11      ;
SETOS(JOB) ; Sets the Operating Systems in ^XTMP("PSNKEY",$J,"OS") (Called via Taskman)
 +1       ;Input: JOB - $Job value from calling process
 +2        SET ^XTMP("PSNKEY",JOB,"OS")=$$OS^%ZOSV()
 +3        QUIT 
 +4       ;
 +5       ;PSN*4*575 UPDATE HELP TEXT WORDING FOR ECDSA
HELP      ; Encryption Type Help
 +1        WRITE !!,"Secure SHell (SSH) Encryption Keys are used to allow data file download."
 +2        WRITE !,"Follow the steps below to successfully setup data file download from Austin "
 +3        WRITE !,"server to VistA sites:",!
 +4        WRITE !,"Step 1: Select the 'C' (Create New SSH Key Pair) Action and follow the prompts"
 +5        WRITE !,"        to create a new pair of SSH keys. If you already have an existing SSH"
 +6        WRITE !,"        Key Pair you can skip this step."
 +7        WRITE !,"        You can check whether you already have an existing SSH Key Pair"
 +8        WRITE !,"        through the 'V' (View Public SSH Key) Action."
 +9        WRITE !,""
 +10       DO HELP1
           DO PAUSE
 +11       WRITE !!,"Step 2: Share the Public SSH Key content with the PPS-N SFTP server (Austin)."
 +12       WRITE !,"        In order to successfully establish the data download files, the SFTP  "
 +13       WRITE !,"        server at Austin needs to install/configure the new SSH Key created in"
 +14       WRITE !,"        step 1 for the user id they assigned to your site. Use the 'V' (View "
 +15       WRITE !,"        Public SSH Key) Action to retrieve the content of the Public SSH key."
 +16       WRITE !,"        The Public SSH Key should not contain line-feed characters, therefore "
 +17       WRITE !,"        after you copy & paste it from the terminal emulator into an email or "
 +18       WRITE !,"        text editor make sure it contains only one line of text (no wrapping)."
 +19       QUIT 
 +20      ;
HELP1     ; Encryption Type Help
 +1        WRITE !,"        Encryption Type: RSA or ECDSA?"
 +2        WRITE !,"        -----------------------------------"
 +3        WRITE !,"        Rivest, Shamir & Adleman (RSA) has been one of the most common"
 +4        WRITE !,"        encryption algorithms used by the IT industry for securely sharing data."
 +5        WRITE !,""
 +6        WRITE !,"        Elliptic Curve Digital Signature Algorithm (ECDSA) is a more complex"
 +7        WRITE !,"        public key cryptography encryption algorithm that is now supported by"
 +8        WRITE !,"        the VA. If ECDSA is selected you will be prompted to enter the Bit size."
 +9        WRITE !,"        Valid selections are 256, 384 or 521."
 +10       WRITE !,""
 +11       WRITE !,"        You will need to contact the Austin SFTP server support to determine"
 +12       WRITE !,"        which type to select."
 +13       QUIT 
PAUSE     ; Pauses screen until user hits Return
 +1        WRITE !
           KILL DIR
           SET DIR("A")="Press Return to continue"
           SET DIR(0)="E"
           DO ^DIR
 +2        QUIT 
 +3       ;
ASK()     ; confirm creating new pair
 +1        NEW Y
           SET Y=0
           if '$DATA(^TMP("PSNPUBKY",$JOB))
               QUIT 1
 +2        KILL DIRUT,DUOUT,DIR,X,Y
           SET DIR(0)="Y"
           SET DIR("?")="Please enter Y or N."
 +3        SET DIR("A")="Do you want to delete existing key pair and create new pair"
           WRITE !!
 +4        SET DIR("B")="NO"
           DO ^DIR
 +5        QUIT Y