From e4301ce8272ab94ec73da5ab976fd92f37ff3298 Mon Sep 17 00:00:00 2001 From: Kai Scheddin Date: Mon, 3 Jul 2023 00:47:43 +0200 Subject: [PATCH] [#32][#61] added vsdbg to launch.json, added rsa-sha2-256 for ssh.net, added ssh.exe adapter,.. working version --- src/UpgradeLog.htm | Bin 0 -> 39044 bytes src/VsLinuxDebugger/Commands.Impl.cs | 3 +- src/VsLinuxDebugger/Core/LaunchBuilder.cs | 57 +++- src/VsLinuxDebugger/Core/RemoteDebugger.cs | 9 +- src/VsLinuxDebugger/Core/RsaSha256Util.cs | 151 +++++++++ src/VsLinuxDebugger/Core/SshTool.cs | 56 +++- src/VsLinuxDebugger/Core/UserOptions.cs | 6 +- .../OptionsPages/OptionsPage.DotNet.cs | 4 +- .../OptionsPages/OptionsPage.Ssh.cs | 22 +- .../Properties/AssemblyInfo.cs | 4 +- src/VsLinuxDebugger/VsLinuxDebugger.csproj | 303 +++++++++--------- .../source.extension.vsixmanifest | 61 ++-- 12 files changed, 451 insertions(+), 225 deletions(-) create mode 100644 src/UpgradeLog.htm create mode 100644 src/VsLinuxDebugger/Core/RsaSha256Util.cs diff --git a/src/UpgradeLog.htm b/src/UpgradeLog.htm new file mode 100644 index 0000000000000000000000000000000000000000..917922d00d1c6038395b34b9690243d9f723ca31 GIT binary patch literal 39044 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 AG5`Po literal 0 HcmV?d00001 diff --git a/src/VsLinuxDebugger/Commands.Impl.cs b/src/VsLinuxDebugger/Commands.Impl.cs index da29180..e7bb7b2 100644 --- a/src/VsLinuxDebugger/Commands.Impl.cs +++ b/src/VsLinuxDebugger/Commands.Impl.cs @@ -183,7 +183,8 @@ private UserOptions ToUserOptions() UserPrivateKeyPassword = VsixPackage.VsixOptions.UserPrivateKeyPassword, UserName = VsixPackage.VsixOptions.UserName, UserPass = VsixPackage.VsixOptions.UserPass, - UserGroupName = VsixPackage.VsixOptions.UserGroupName, + UserGroupName = VsixPackage.VsixOptions.UserGroupName, + UseSSHExeEnabled = VsixPackage.VsixOptions.UseSSHExeEnabled }; } } diff --git a/src/VsLinuxDebugger/Core/LaunchBuilder.cs b/src/VsLinuxDebugger/Core/LaunchBuilder.cs index eb2c6b9..cac762e 100644 --- a/src/VsLinuxDebugger/Core/LaunchBuilder.cs +++ b/src/VsLinuxDebugger/Core/LaunchBuilder.cs @@ -136,18 +136,24 @@ public string GenerateLaunchJson(bool vsdbgLogging = false) ////{ string plinkPath = string.Empty; - - // Adapter Path: - // PLink.exe - Use manual path or embedded - if (!string.IsNullOrEmpty(_opts.LocalPLinkPath) && File.Exists(_opts.LocalPLinkPath)) - { - plinkPath = _opts.LocalPLinkPath; - } - else - { - plinkPath = Path.Combine(GetExtensionDirectory(), "plink.exe").Trim('"'); + + if (_opts.UseSSHExeEnabled) + { + plinkPath = "ssh.exe"; + } + else + { + // Adapter Path: + // PLink.exe - Use manual path or embedded + if (!string.IsNullOrEmpty(_opts.LocalPLinkPath) && File.Exists(_opts.LocalPLinkPath)) + { + plinkPath = _opts.LocalPLinkPath; + } + else + { + plinkPath = Path.Combine(GetExtensionDirectory(), "plink.exe").Trim('"'); + } } - // Adapter Arguments: // NOTE: // 1. SSH Private Key ("-i PPK") fails with PLINK. Must use manual password until this is resolved. @@ -161,16 +167,33 @@ public string GenerateLaunchJson(bool vsdbgLogging = false) ////var sshPassword = !_opts.UserPrivateKeyEnabled //// ? $"-pw {RemoteUserPass}" //// : $"-i \"{_opts.UserPrivateKeyPath}{strictKeyChecking}\""; - // - var sshPassword = $"-pw {RemoteUserPass}"; + string sshPassword = ""; + + if(_opts.UseSSHExeEnabled) + { + sshPassword = ""; //nothing to do, we assume that c:\users\[user]\.ssh\id_rsa exists + } + else + { + sshPassword = $"-pw {RemoteUserPass}"; + } // TODO: Figure out why "-i " isn't working. if (string.IsNullOrEmpty(RemoteUserPass)) Logger.Output("You must provide a User Password to debug."); - - var adapter = plinkPath; - var adapterArgs = $"-ssh {sshPassword} {sshEndpoint} -batch -T {_opts.RemoteVsDbgFullPath} {vsdbgLogPath}"; - //// adapterArgs = $"-ssh {sshPassword} {sshEndpoint} -batch -T {RemoteVsDbgFullPath} --interpreter=vscode {vsdbgLogPath}"; + + string adapter = plinkPath; + string adapterArgs = ""; + + if (_opts.UseSSHExeEnabled) + { + adapterArgs = $"{sshPassword} {sshEndpoint} -T {_opts.RemoteVsDbgFullPath} {vsdbgLogPath}"; + //// adapterArgs = $"-ssh {sshPassword} {sshEndpoint} -batch -T {RemoteVsDbgFullPath} --interpreter=vscode {vsdbgLogPath}"; + } + else + { + adapterArgs= $"-ssh {sshPassword} {sshEndpoint} -T {_opts.RemoteVsDbgFullPath} {vsdbgLogPath}"; + } return (adapter, adapterArgs); } diff --git a/src/VsLinuxDebugger/Core/RemoteDebugger.cs b/src/VsLinuxDebugger/Core/RemoteDebugger.cs index 560122f..4f119a2 100644 --- a/src/VsLinuxDebugger/Core/RemoteDebugger.cs +++ b/src/VsLinuxDebugger/Core/RemoteDebugger.cs @@ -12,7 +12,9 @@ namespace VsLinuxDebugger.Core { public class RemoteDebugger : IDisposable { - private const string DebugAdapterHost = "DebugAdapterHost.Launch"; + private const string DebugAdapterHost = "DebugAdapterHost.Launch"; + private const string DebugAdapterHostLogging = "DebugAdapterHost.Logging"; + private const string DebugAdapterHostLoggingOnOutputWindow = "/On /OutputWindow"; private const string DebugAdapterLaunchJson = "/LaunchJson:"; private bool _buildSuccessful; @@ -192,7 +194,10 @@ private void BuildDebugAttacher() Logger.Output($"- launch.json path: '{_launchJsonPath}'"); Logger.Output($"- DebugAdapterHost.Launch /LaunchJson:\"{_launchJsonPath}\""); - DTE2 dte2 = (DTE2)Package.GetGlobalService(typeof(SDTE)); + DTE2 dte2 = (DTE2)Package.GetGlobalService(typeof(SDTE)); + //Enable Logging for the Debugger output + dte2.ExecuteCommand(DebugAdapterHostLogging, $"{DebugAdapterHostLoggingOnOutputWindow}"); + dte2.ExecuteCommand(DebugAdapterHost, $"{DebugAdapterLaunchJson}\"{_launchJsonPath}\""); // launchConfigName = "Debug on Linux"; diff --git a/src/VsLinuxDebugger/Core/RsaSha256Util.cs b/src/VsLinuxDebugger/Core/RsaSha256Util.cs new file mode 100644 index 0000000..4174069 --- /dev/null +++ b/src/VsLinuxDebugger/Core/RsaSha256Util.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Renci; +using Renci.SshNet; +using Renci.SshNet.Sftp; +using Renci.SshNet.Security; +using Renci.SshNet.Common; +using Renci.SshNet.Security.Cryptography.Ciphers; +using Renci.SshNet.Security.Cryptography; + +using System.Security.Cryptography; +using System.Reflection; +namespace VsLinuxDebugger.Core +{ + /// + /// Based on https://github.com/sshnet/SSH.NET/blob/1d5d58e17c68a2f319c51e7f938ce6e964498bcc/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs#L12 + /// + /// With following changes: + /// + /// - OID changed to sha2-256 + /// - hash changed from sha1 to sha2-256 + /// + public class RsaSha256DigitalSignature : CipherDigitalSignature, IDisposable + { + private HashAlgorithm _hash; + + public RsaSha256DigitalSignature(RsaWithSha256SignatureKey rsaKey) + // custom OID + : base(new ObjectIdentifier(2, 16, 840, 1, 101, 3, 4, 2, 1), new RsaCipher(rsaKey)) + { + // custom + _hash = SHA256.Create(); + } + + protected override byte[] Hash(byte[] input) + { + return _hash.ComputeHash(input); + } + + private bool _isDisposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_isDisposed) + return; + + if (disposing) + { + var hash = _hash; + if (hash != null) + { + hash.Dispose(); + _hash = null; + } + + _isDisposed = true; + } + } + + ~RsaSha256DigitalSignature() + { + Dispose(false); + } + } + + /// + /// Utility class which allows ssh.net to connect to servers using ras-sha2-256 + /// + public static class RsaSha256Util + { + public static void SetupConnection(ConnectionInfo connection) + { + connection.HostKeyAlgorithms["rsa-sha2-256"] = data => new KeyHostAlgorithm("rsa-sha2-256", new RsaKey(), data); + } + + /// + /// Converts key file to rsa key with sha2-256 signature + /// Due to lack of constructor: https://github.com/sshnet/SSH.NET/blob/bc99ada7da3f05f50d9379f2644941d91d5bf05a/src/Renci.SshNet/PrivateKeyFile.cs#L86 + /// We do that in place + /// + /// + /// + public static void ConvertToKeyWithSha256Signature(PrivateKeyFile keyFile) + { + var oldKeyHostAlgorithm = keyFile.HostKey as KeyHostAlgorithm; + if (oldKeyHostAlgorithm == null) + { + throw new ArgumentNullException(nameof(oldKeyHostAlgorithm)); + } + + var oldRsaKey = oldKeyHostAlgorithm.Key as RsaKey; + if (oldRsaKey == null) + { + throw new ArgumentNullException(nameof(oldRsaKey)); + } + + var newRsaKey = new RsaWithSha256SignatureKey(oldRsaKey.Modulus, oldRsaKey.Exponent, oldRsaKey.D, oldRsaKey.P, oldRsaKey.Q, + oldRsaKey.InverseQ); + + UpdatePrivateKeyFile(keyFile, newRsaKey); + } + + private static void UpdatePrivateKeyFile(PrivateKeyFile keyFile, RsaWithSha256SignatureKey key) + { + var keyHostAlgorithm = new KeyHostAlgorithm(key.ToString(), key); + + var hostKeyProperty = typeof(PrivateKeyFile).GetProperty(nameof(PrivateKeyFile.HostKey)); + hostKeyProperty.SetValue(keyFile, keyHostAlgorithm); + + var keyField = typeof(PrivateKeyFile).GetField("_key", BindingFlags.NonPublic | BindingFlags.Instance); + keyField.SetValue(keyFile, key); + } + } + + public class RsaWithSha256SignatureKey : RsaKey + { + public RsaWithSha256SignatureKey(BigInteger modulus, BigInteger exponent, BigInteger d, BigInteger p, BigInteger q, + BigInteger inverseQ) : base(modulus, exponent, d, p, q, inverseQ) + { + } + + private RsaSha256DigitalSignature _digitalSignature; + + protected override DigitalSignature DigitalSignature + { + get + { + if (_digitalSignature == null) + { + _digitalSignature = new RsaSha256DigitalSignature(this); + } + + return _digitalSignature; + } + } + + public override string ToString() + { + return "rsa-sha2-256"; + } + } +} diff --git a/src/VsLinuxDebugger/Core/SshTool.cs b/src/VsLinuxDebugger/Core/SshTool.cs index 662c765..a6414d3 100644 --- a/src/VsLinuxDebugger/Core/SshTool.cs +++ b/src/VsLinuxDebugger/Core/SshTool.cs @@ -156,7 +156,7 @@ public async Task CleanFolderAsync(string path) public async Task ConnectAsync() { PrivateKeyFile keyFile = null; - + ConnectionInfo conn = null; try { if (_info.PrivateKeyEnabled) @@ -164,7 +164,14 @@ public async Task ConnectAsync() if (string.IsNullOrEmpty(_info.PrivateKeyPassword)) keyFile = new PrivateKeyFile(_info.PrivateKeyPath); else - keyFile = new PrivateKeyFile(_info.PrivateKeyPath, _info.PrivateKeyPassword); + keyFile = new PrivateKeyFile(_info.PrivateKeyPath, _info.PrivateKeyPassword); + + // adds rsa-sha2-256 + RsaSha256Util.ConvertToKeyWithSha256Signature(keyFile); + var authenticationMethodRsa = new PrivateKeyAuthenticationMethod(_info.UserName, keyFile); + conn = new ConnectionInfo(_info.Host, _info.Port, _info.UserName, authenticationMethodRsa); + RsaSha256Util.SetupConnection(conn); + } } catch (Exception ex) @@ -175,10 +182,15 @@ public async Task ConnectAsync() } try - { - _ssh = (_info.PrivateKeyEnabled && File.Exists(_info.PrivateKeyPath)) - ? new SshClient(_info.Host, _info.Port, _info.UserName, keyFile) - : new SshClient(_info.Host, _info.Port, _info.UserName, _info.UserPass); + { + if (_info.PrivateKeyEnabled && File.Exists(_info.PrivateKeyPath)) + { + _ssh = new SshClient(conn); + } + else + { + _ssh = new SshClient(_info.Host, _info.Port, _info.UserName, _info.UserPass); + } await Task.Run(() => _ssh.Connect()); } @@ -189,19 +201,29 @@ public async Task ConnectAsync() } try - { - var sftpClient = (keyFile == null) - ? new SftpClient(_info.Host, _info.Port, _info.UserName, _info.UserPass) - : new SftpClient(_info.Host, _info.Port, _info.UserName, keyFile); - - sftpClient.Connect(); - _sftp = sftpClient; + { + if (_info.PrivateKeyEnabled && File.Exists(_info.PrivateKeyPath)) + { + _sftp = new SftpClient(conn); + } + else + { + _sftp = new SftpClient(_info.Host, _info.Port, _info.UserName, _info.UserPass); + } + + _sftp.Connect(); + } catch (Exception) - { - _scp = (keyFile == null) - ? new ScpClient(_info.Host, _info.Port, _info.UserName, _info.UserPass) - : new ScpClient(_info.Host, _info.Port, _info.UserName, keyFile); + { + if (_info.PrivateKeyEnabled && File.Exists(_info.PrivateKeyPath)) + { + _scp = new ScpClient(conn); + } + else + { + _scp = new ScpClient(_info.Host, _info.Port, _info.UserName, _info.UserPass); + } _scp.Connect(); } diff --git a/src/VsLinuxDebugger/Core/UserOptions.cs b/src/VsLinuxDebugger/Core/UserOptions.cs index 0e622b3..5826c9c 100644 --- a/src/VsLinuxDebugger/Core/UserOptions.cs +++ b/src/VsLinuxDebugger/Core/UserOptions.cs @@ -18,7 +18,7 @@ public class UserOptions /// Base path to VSDBG (i.e. `~/.vsdbg`). public string RemoteVsDbgBasePath { get; set; } /// Full path to VS Debugger. - public string RemoteVsDbgFullPath => LinuxPath.Combine(RemoteVsDbgBasePath, Constants.VS2022); + public string RemoteVsDbgFullPath => LinuxPath.Combine(RemoteVsDbgBasePath, Constants.VS2022, Constants.AppVSDbg); public bool UseCommandLineArgs { get; set; } public bool UsePublish { get; set; } @@ -28,6 +28,8 @@ public class UserOptions public string UserPass { get; set; } public bool UserPrivateKeyEnabled { get; set; } public string UserPrivateKeyPath { get; set; } - public string UserPrivateKeyPassword { get; set; } + public string UserPrivateKeyPassword { get; set; } + + public bool UseSSHExeEnabled { get; set; } = false; } } diff --git a/src/VsLinuxDebugger/OptionsPages/OptionsPage.DotNet.cs b/src/VsLinuxDebugger/OptionsPages/OptionsPage.DotNet.cs index 66f0e06..685ed5e 100644 --- a/src/VsLinuxDebugger/OptionsPages/OptionsPage.DotNet.cs +++ b/src/VsLinuxDebugger/OptionsPages/OptionsPage.DotNet.cs @@ -22,8 +22,8 @@ public partial class OptionsPage : DialogPage public string RemoteDeployBasePath { get; set; } = $"./VSLinuxDbg"; // "LinuxDbg" [Category(RemoteDebugger)] - [DisplayName(".NET Path")] - [Description("Path of .NET on remote machine. (Samples: `dotnet`, `~/.dotnet/dotnet`)")] + [DisplayName(".NET executable")] + [Description("Path of the .NET executable on remote machine. (Samples: `dotnet`, `~/.dotnet/dotnet`)")] public string RemoteDotNetPath { get; set; } = Constants.DefaultDotNetPath; [Category(RemoteDebugger)] diff --git a/src/VsLinuxDebugger/OptionsPages/OptionsPage.Ssh.cs b/src/VsLinuxDebugger/OptionsPages/OptionsPage.Ssh.cs index 2d40730..6adb682 100644 --- a/src/VsLinuxDebugger/OptionsPages/OptionsPage.Ssh.cs +++ b/src/VsLinuxDebugger/OptionsPages/OptionsPage.Ssh.cs @@ -44,11 +44,29 @@ public partial class OptionsPage : DialogPage [Description("Private key file.")] public string UserPrivateKeyPath { get; set; } = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), - ".ssh\\id_rsa"); + ".ssh\\id_rsa"); [Category(Credientials)] [DisplayName("SSH Private Key Password (optional)")] [Description("Private key password (only if it was set).")] - public string UserPrivateKeyPassword { get; set; } = ""; + public string UserPrivateKeyPassword { get; set; } = ""; + + [Category(Credientials)] + [DisplayName("Use SSH.exe with integrated user/[..]/.ssh/id_rsa instead of PLINK")] + [Description("Use SSH.exe with integrated user/[..]/.ssh/id_rsa instead of PLINK")] + public bool UseSSHExeEnabled { get; set; } = false; + + /*[Category(Credientials)] + [DisplayName("PLINK PPK Key File Enabled")] + [Description("Use SSH Key for connecting to remote machine.")] + public bool UserPlinkPrivateKeyEnabled { get; set; } = false; + + [Category(Credientials)] + [DisplayName("SSH Private Key File (optional)")] + [Description("Private key file.")] + public string UserPlinkPrivateKeyPath { get; set; } = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + ".ssh\\id_rsa"); + */ } } diff --git a/src/VsLinuxDebugger/Properties/AssemblyInfo.cs b/src/VsLinuxDebugger/Properties/AssemblyInfo.cs index dd85dda..b9ab1db 100644 --- a/src/VsLinuxDebugger/Properties/AssemblyInfo.cs +++ b/src/VsLinuxDebugger/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.0.1.0")] -[assembly: AssemblyFileVersion("2.0.1.0")] +[assembly: AssemblyVersion("2.0.3.1")] +[assembly: AssemblyFileVersion("2.0.3.1")] diff --git a/src/VsLinuxDebugger/VsLinuxDebugger.csproj b/src/VsLinuxDebugger/VsLinuxDebugger.csproj index f09925a..11788be 100644 --- a/src/VsLinuxDebugger/VsLinuxDebugger.csproj +++ b/src/VsLinuxDebugger/VsLinuxDebugger.csproj @@ -1,157 +1,160 @@ - - - - 17.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - Debug - AnyCPU - 2.0 - {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {C204143E-FDE0-4F29-976B-A0C8AC798BAD} - Library - Properties - VsLinuxDebugger - VsLinuxDebugger - v4.7.2 - true - true - true - false - false - true - true - Program - $(DevEnvDir)devenv.exe - /rootsuffix Exp - - - true - full - false - ..\..\output\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - ..\..\output\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - - Component - - - Component - - - Component - - - - - - - - Always - true - - - Designer - - - - - - - - - - - - - - - - 0.30.1 - - - 2020.0.2 - - - 6.0.2 - - - - - Menus.ctmenu - - - - - Always - true - - - true - - - true - - - true - - - Always - true - - - - - + + + + 17.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + Debug + AnyCPU + 2.0 + {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {C204143E-FDE0-4F29-976B-A0C8AC798BAD} + Library + Properties + VsLinuxDebugger + VsLinuxDebugger + v4.7.2 + 8.0 + true + true + true + false + false + true + true + Program + $(DevEnvDir)devenv.exe + /rootsuffix Exp + + + true + full + false + ..\..\output\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\output\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + Component + + + Component + + + Component + + + + + + + + Always + true + + + Designer + + + + + + + + + + + + + + + + 0.30.1 + + + 2020.0.2 + + + 6.0.2 + + + + + Menus.ctmenu + + + + + Always + true + + + true + + + true + + + true + + + Always + true + + + + + - - - https://the.earth.li/~sgtatham/putty/latest/w64/plink.exe - - - - - - - - - true - Always - - + --> + + + https://the.earth.li/~sgtatham/putty/latest/w64/plink.exe + + + + + + + + + true + Always + + \ No newline at end of file diff --git a/src/VsLinuxDebugger/source.extension.vsixmanifest b/src/VsLinuxDebugger/source.extension.vsixmanifest index 1cdc942..1d25718 100644 --- a/src/VsLinuxDebugger/source.extension.vsixmanifest +++ b/src/VsLinuxDebugger/source.extension.vsixmanifest @@ -2,34 +2,35 @@ - - - VS Linux Debugger - Remotely deploy and debug your .NET apps visa SSH on your Linux device using Visual Studio 2022. Works with popular Linux distrobutions such as Ubuntu, Raspberry Pi, and more! - https://github.com/SuessLabs/VsLinuxDebug - LICENSE.txt - ..\..\readme.md - ..\..\release-notes.md - Resources\TuxDebug.png - debug; build; remote debug; vsdbg; linux; xamarin; rpi; rpi4; remotedebug; remote; debugger; linux debug; net6; dotnet; raspberry pi; ubuntu; - - - - amd64 - - - - - - - - - - - + + + VS Linux Debugger + Remotely deploy and debug your .NET apps visa SSH on your Linux device using Visual Studio 2022. Works with popular Linux distrobutions such as Ubuntu, Raspberry Pi, and more! + https://github.com/SuessLabs/VsLinuxDebug + LICENSE.txt + ..\..\readme.md + ..\..\release-notes.md + Resources\TuxDebug.png + debug; build; remote debug; vsdbg; linux; xamarin; rpi; rpi4; remotedebug; remote; debugger; linux debug; net6; dotnet; raspberry pi; ubuntu; + true + + + + amd64 + + + + + + + + + + +