Getting the SFTP Host Key Programmatically

Advertisement

InteXX
Joined:
Posts:
29
Location:
Fairbanks, Alaska

Getting the SFTP Host Key Programmatically

I'm not finding a way in the API to silently discover the Host Key at runtime. This doesn't mean that there's not a way to do it--just that if it's there I'm not finding it.

So I've come up with an alternate method, using WinSCP.com. I'm including my VB.NET code below for review and suggestion.

As far as I can tell, WinSCP.com doesn't use STDIN and STDOUT for its interactive Host Key prompts. The process emits several STDOUT calls and immediately exits, without waiting for STDIN to simulate user interaction. Because of this I've handled the output asynchronously, using the Process_OutputDataReceived event. The Process.WaitForExit() call is essential for the operation.

This is clunky to be sure, but I can see no other way presently. My plan is to present a form for entry of the key that the user has already obtained from the server administrator, so that I can compare that manually entered key against this one that I'm getting programmatically. Upon a successful match my app will persist the key and proceed.

If the ability to discover the Host Key doesn't already exist in the API, I'd like to enter it as a feature request. Thank you Martin, for all the hard work you do.

In the meantime, I'd be interested to know of any downsides to this approach--memory leaks, etc.

Thanks,
Jeff Bowman
Fairbanks, Alaska



Public Class Main
  Private HostKey As String

  Private Sub cmdTest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdTest.Click
    File.Delete("WinScp.ini")

    Using oProcess As New Process
      AddHandler oProcess.OutputDataReceived, AddressOf Process_OutputDataReceived

      oProcess.StartInfo.UseShellExecute = False
      oProcess.StartInfo.FileName = "WinScp.com"
      oProcess.StartInfo.Arguments = "/command ""open server.com"""
      oProcess.StartInfo.RedirectStandardInput = True
      oProcess.StartInfo.RedirectStandardOutput = True
      oProcess.StartInfo.CreateNoWindow = True
      oProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden

      oProcess.Start()
      oProcess.BeginOutputReadLine()
      oProcess.WaitForExit()

      RemoveHandler oProcess.OutputDataReceived, AddressOf oProcess_OutputDataReceived
    End Using

    File.Delete("WinScp.ini")
  End Sub

  Private Sub Process_OutputDataReceived(sender As Object, e As DataReceivedEventArgs)
    If Trim(e.Data).ToLower.StartsWith("ssh-rsa") Then
      Me.HostKey = e.Data
    End If
  End Sub
End Class

Reply with quote

Advertisement

InteXX
Joined:
Posts:
29
Location:
Fairbanks, Alaska

I've updated my code to remove the asynchronous design.

I had thought it necessary during my initial testing, where I noted that the output was being emitted one line at a time to the OutputDataReceived event. With a synchronous call, however, WinSCP.com emits the entire sequence in one STDOUT call (again, without pausing for STDIN). Thus we can simply loop through the output to extract the Host Key.

The simplified code is below.

This looks like just about as good as it's going to get without an explicit API call.

Thanks,
Jeff Bowman
Fairbanks, Alaska

Private Function GetHostKey(HostName As String) As String
  Dim aOutput As String()

  File.Delete("WinScp.ini")

  Using oProcess As New Process
    oProcess.StartInfo.UseShellExecute = False
    oProcess.StartInfo.FileName = "WinScp.com"
    oProcess.StartInfo.Arguments = String.Format("/command ""open {0}""", HostName)
    oProcess.StartInfo.RedirectStandardInput = True
    oProcess.StartInfo.RedirectStandardOutput = True
    oProcess.StartInfo.CreateNoWindow = True
    oProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden

    oProcess.Start()
    aOutput = oProcess.StandardOutput.ReadToEnd.Split(vbCrLf)
    oProcess.WaitForExit()

    GetHostKey = aOutput.Where(Function(Line)
                                 Return Line.Trim.ToLower.StartsWith("ssh-rsa")
                               End Function).SingleOrDefault.Trim
  End Using

  File.Delete("WinScp.ini")
End Function

Reply with quote

martin
Site Admin
martin avatar
Joined:
Posts:
41,518
Location:
Prague, Czechia

Re: Getting the SFTP Host Key Programmatically

If your application already has the fingerprint, why don't you provide it to open command using -hostkey switch?

Regarding the request: I do not see a use case. Either you know the host key, then you pass it to open command. Or you do not know it and you do not care about security, then you can use -hostkey=*.

Reply with quote

InteXX
Joined:
Posts:
29
Location:
Fairbanks, Alaska

Re: Getting the SFTP Host Key Programmatically

martin wrote:

Either you know the host key, then you pass it to open command.
Well that'll be it then. I'll just relay the user-entered key and trap for an exception. If the key doesn't match I'll handle the result and return an appropriate message to the UI. If so, then I'll store the key for later sessions.

Request withdrawn.



martin wrote:

Or you do not know it and you do not care about security, then you can use -hostkey=*.
Is this the equivalent of setting Connection.SshHostKeyFingerprint = "*"?

Thanks,
Jeff Bowman
Fairbanks, Alaska

Reply with quote

InteXX
Joined:
Posts:
29
Location:
Fairbanks, Alaska

Re: Getting the SFTP Host Key Programmatically

InteXX wrote:

Request withdrawn

Hm... I may have spoken too soon. I believe there is a use case.

In my situation at least, I want to collect the host name/key and compare those values to what comes from the server first. Only after a match will I prompt for credentials. This UX flow fits nicely with the SFTP security paradigm.

The only way to do this is to get the host key programmatically.

Thanks,
Jeff Bowman
Fairbanks, Alaska

Reply with quote

Advertisement

martin
Site Admin
martin avatar
Joined:
Posts:
41,518
Location:
Prague, Czechia

Re: Getting the SFTP Host Key Programmatically

While I understand your use case, note that:
The library is primarily intended for advanced automation tasks that require conditional processing, loops or other control structures for which the basic scripting interface is too limited. The library is not a general purpose file transfer library. It particularly lacks support for interactive processing and as such it is not well suited for use in GUI applications.
Quote from: https://winscp.net/eng/docs/library

Reply with quote

InteXX
Joined:
Posts:
29
Location:
Fairbanks, Alaska

Re: Getting the SFTP Host Key Programmatically

martin wrote:

While I understand your use case, note that:
The library is primarily intended for advanced automation tasks that require conditional processing, loops or other control structures for which the basic scripting interface is too limited. The library is not a general purpose file transfer library. It particularly lacks support for interactive processing and as such it is not well suited for use in GUI applications.
Quote from: https://winscp.net/eng/docs/library

Fair 'nuff.

I'll stick with my workaround and I'll be happy about it :-)

Thanks,
Jeff Bowman
Fairbanks, Alaska

Reply with quote

Advertisement

You can post new topics in this forum