Topic "Getting the SFTP Host Key Programmatically"

Author Message
InteXX
[View user's profile]

Joined: 2009-05-17
Posts: 21
Location: Fairbanks, Alaska
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



Code:
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
Advertisements
InteXX
[View user's profile]

Joined: 2009-05-17
Posts: 21
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

Code:
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
martin
[View user's profile]
Site Admin
Joined: 2002-12-10
Posts: 25015
Location: Prague, Czechia
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=*.
InteXX
[View user's profile]

Joined: 2009-05-17
Posts: 21
Location: Fairbanks, Alaska
prikryl 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.



prikryl 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
InteXX
[View user's profile]

Joined: 2009-05-17
Posts: 21
Location: Fairbanks, Alaska
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
martin
[View user's profile]
Site Admin
Joined: 2002-12-10
Posts: 25015
Location: Prague, Czechia
While I understand your use case, note that:
Quote:
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
_________________
Martin Prikryl
InteXX
[View user's profile]

Joined: 2009-05-17
Posts: 21
Location: Fairbanks, Alaska
prikryl wrote:
While I understand your use case, note that:
Quote:
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 Smile

Thanks,
Jeff Bowman
Fairbanks, Alaska
Advertisements

You can post new topics in this forum






Search Site

What is WinSCP?

It is award-winning SFTP client, SCP client, FTPS client and FTP client integrated into one software program for file transfer to FTP server or secure SFTP server. [More]

And it's free!

Donate

About donations

$9   $19   $49   $99

About donations

Recommend

WinSCP Privacy Policy

WinSCP License