param ([Parameter(Position=0)][string]$stage, [string]$pubKeyFile="", [string]$instance="") # If there's an error in a call such as $cfg.keypairs.Lock(), it is important that the script stops. # Continuing while another application is also potentially modifying settings may corrupt them. # Alternately, your script can also handle errors in a Try/Catch block. $ErrorActionPreference = "Stop" # Check BssCfgManip.htm in your SSH Server installation directory for the correct COM object name for your installation. # The PowerShell instance executing this script needs to run elevated, as administrator, to access SSH Server settings. Write-Host "" Write-Host "Run this in an elevated, administrative PowerShell or Command Prompt window." Write-Host "Changes host keys to a new algorithm in Bitvise SSH Server versions 8.xx." Write-Host "" $newAlgName = "Ed25519" $newAlgId = 6 # $cfg.enums.hostKeyAlgId.ed25519 if (($stage -ne "generate") -and ($stage -ne "employ")) { Write-Host "Usage:" Write-Host "" Write-Host "Stage 1:" Write-Host "" Write-Host " generate -pubKeyFile [-instance ]" Write-Host "" Write-Host " Generates a new host key of type $newAlgName, but does not yet employ it." Write-Host " Displays generated host key fingerprint information." Write-Host " Writes the new public key into the file specified with -pubKeyFile." Write-Host "" Write-Host " After generating the new host key:" Write-Host "" Write-Host " - Clients that support host key synchronization, such as recent versions" Write-Host " of Bitvise SSH Client, will automatically trust the new host key when" Write-Host " they next connect." Write-Host "" Write-Host " - Clients that do NOT support host key synchronization need to be configured" Write-Host " to trust the new host key before it is employed." Write-Host "" Write-Host "Stage 2:" Write-Host "" Write-Host " employ [-instance ]" Write-Host "" Write-Host " Employs a previously generated host key of type $newAlgName." Write-Host " Dismisses host keys of all other algorithms, but does not remove them." Write-Host "" Write-Host " After employing the new host key, make sure all clients are able to" Write-Host " successfully connect." Write-Host "" Write-Host "The script can be trivially modified to generate and employ a new host key" Write-Host "for a different algorithm. $newAlgName is used simply as an example." Write-Host "" exit 2 } Write-Host "Instantiating BssCfg object..." $cfg = new-object -com "BssCfg815.BssCfg815" Write-Host "BssCfg object instantiated." Write-Host "" # If there are multiple SSH Server instances installed, select the desired instance by name. $cfg.SetInstance($instance) # Lock and load SSH Server host keys $cfg.keypairs.Lock() $cfg.keypairs.Load() $maxAlgId = 6 # $cfg.enums.hostKeyAlgId.ed25519 $newKey = $null $newKeyIndex = -1 for ($i=0; $i -le $cfg.keypairs.count; ++$i) { if ($cfg.keypairs.entries[$i].alg -eq $newAlgName) { $newKey = $cfg.keypairs.entries[$i] $newKeyIndex = $i break } } if ($stage -eq "generate") { if ($pubKeyFile -eq "") { $cfg.keypairs.Unlock() Write-Host "Missing -pubKeyFile parameter" exit 2 } if ($newKey -ne $null) { Write-Host "An existing host key of type $newAlgName was found" } else { Write-Host "A host key of type $newAlgName was not found, generating" $cfg.keypairs.GenerateNewKeypair($newAlgId, $false) for ($i=0; $i -le $cfg.keypairs.count; ++$i) { if ($cfg.keypairs.entries[$i].alg -eq $newAlgName) { $newKey = $cfg.keypairs.entries[$i] $newKeyIndex = $i break } } if ($newKey -eq $null) { $cfg.keypairs.Unlock() Write-Error "Could not find newly generated keypair" exit 1 } } Write-Host "Key algorithm: $($newKey.alg), bits: $($newKey.keyBits)" Write-Host "SHA-256 fingerprint: $($newKey.sha256)" $newKey.ExportPublicKeyToFile($cfg.enums.PublicKeyFormat.openSsh, $pubKeyFile) Write-Host "Public key saved to $pubKeyFile" } elseif ($stage -eq "employ") { if ($newKey -eq $null) { $cfg.keypairs.Unlock() Write-Error "Could not find previously generated keypair" exit 1 } $empKeyIndex = $cfg.keypairs.GetEmployedIndex($newAlgId) if (($empKeyIndex -ge 0) -and ($empKeyIndex -le 1000)) { Write-Host "A $newAlgName host key is already employed" } else { Write-Host "Non-employed $newAlgName host key found, employing" $cfg.keypairs.Employ($newKeyIndex) $empKeyIndex = $cfg.keypairs.GetEmployedIndex($newAlgId) if ($empKeyIndex -ne $newKeyIndex) { $cfg.keypairs.Unlock() Write-Error "Unexpected: host key not successfully employed" exit 1 } Write-Host "$newAlgName host key employed" } $nrDismissed = 0 for ($algId=0; $algId -le $maxAlgId; ++$algId) { if ($algId -ne $newAlgId) { $keyIndex = $cfg.keypairs.GetEmployedIndex($algId) if (($keyIndex -ge 0) -and ($keyIndex -le 1000)) { $key = $cfg.keypairs.GetEmployed($algId) Write-Host "Dismissing host key of type $($key.alg)" $cfg.keypairs.Dismiss($algId) ++$nrDismissed } } } if ($nrDismissed -eq 0) { Write-Host "No other host keys found to dismiss" } else { Write-Host "$nrDismissed host keys dismissed" } } else { $cfg.keypairs.Unlock() Write-Error "Unrecognized stage parameter value" exit 1 } # Save and unlock host keys $cfg.keypairs.Save($true) # $true to perform automatic backup, $false to not $cfg.keypairs.Unlock()