From 6bc5412eee0e8db3692dcfee047cdcf0542ec175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Sat, 23 Sep 2023 08:04:14 +0200 Subject: [PATCH] Improvements after #1177 --- .../Ciphers/RsaCipherBenchmarks.cs | 3 +- .../ED25519DigitalSignatureBenchmarks.cs | 2 +- ...Test_Connect_OnConnectedThrowsException.cs | 3 +- .../Classes/Common/HostKeyEventArgsTest.cs | 2 +- ...st_Connect_NetConfSessionConnectFailure.cs | 3 +- .../Classes/PrivateKeyFileTest.cs | 21 ++++----- .../Cryptography/RsaDigitalSignatureTest.cs | 2 +- .../Classes/Security/KeyAlgorithmTest.cs | 4 +- ...tTest_Connect_SftpSessionConnectFailure.cs | 3 +- src/Renci.SshNet/IHostAlgorithmsProvider.cs | 21 --------- src/Renci.SshNet/IPrivateKeySource.cs | 21 ++++----- src/Renci.SshNet/NetConfClient.cs | 4 +- .../PrivateKeyAuthenticationMethod.cs | 8 ++-- src/Renci.SshNet/PrivateKeyConnectionInfo.cs | 18 ++++---- src/Renci.SshNet/PrivateKeyFile.cs | 45 +++++++------------ src/Renci.SshNet/ScpClient.cs | 4 +- src/Renci.SshNet/SftpClient.cs | 4 +- src/Renci.SshNet/SshClient.cs | 4 +- 18 files changed, 68 insertions(+), 104 deletions(-) delete mode 100644 src/Renci.SshNet/IHostAlgorithmsProvider.cs diff --git a/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs b/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs index f25e6db71..13c08edb1 100644 --- a/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs +++ b/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs @@ -21,7 +21,8 @@ public RsaCipherBenchmarks() using (var s = typeof(RsaCipherBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.RSA.txt")) { - _privateKey = (RsaKey)((KeyHostAlgorithm) new PrivateKeyFile(s).HostKey).Key; + + _privateKey = (RsaKey)new PrivateKeyFile(s).Key; // The implementations of RsaCipher.Encrypt/Decrypt differ based on whether the supplied RsaKey has private key information // or only public. So we extract out the public key information to a separate variable. diff --git a/src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs b/src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs index 2f07a2d3a..44b2da8a6 100644 --- a/src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs +++ b/src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs @@ -21,7 +21,7 @@ public ED25519DigitalSignatureBenchmarks() using (var s = typeof(ED25519DigitalSignatureBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.OPENSSH.ED25519.txt")) { - _key = (ED25519Key) ((KeyHostAlgorithm) new PrivateKeyFile(s).HostKey).Key; + _key = (ED25519Key) new PrivateKeyFile(s).Key; } _signature = new ED25519DigitalSignature(_key).Sign(_data); } diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs index f2a30bbe2..806f6c30a 100644 --- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Reflection; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -140,7 +141,7 @@ private static KeyHostAlgorithm GetKeyHostAlgorithm() using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) { var privateKey = new PrivateKeyFile(s); - return (KeyHostAlgorithm) privateKey.HostKey; + return (KeyHostAlgorithm) privateKey.HostKeyAlgorithms.First(); } } diff --git a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs index e7ee53b90..28001655a 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs @@ -89,7 +89,7 @@ private static KeyHostAlgorithm GetKeyHostAlgorithm() using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) { var privateKey = new PrivateKeyFile(s); - return (KeyHostAlgorithm)privateKey.HostKey; + return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First(); } } diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs index 88410acc1..41c285a84 100644 --- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs +++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Reflection; using System.Threading; @@ -113,7 +114,7 @@ private static KeyHostAlgorithm GetKeyHostAlgorithm() using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) { var privateKey = new PrivateKeyFile(s); - return (KeyHostAlgorithm)privateKey.HostKey; + return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First(); } } } diff --git a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index c684f0be7..879dfa840 100644 --- a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs @@ -1,9 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; -using Renci.SshNet.Security; using Renci.SshNet.Tests.Common; using System; -using System.Collections.Generic; using System.IO; using System.Linq; @@ -412,7 +410,7 @@ public void ConstructorWithStreamAndPassphrase() using (var stream = GetData("Key.RSA.Encrypted.Aes.128.CBC.12345.txt")) { var privateKeyFile = new PrivateKeyFile(stream, "12345"); - Assert.IsNotNull(privateKeyFile.HostKey); + TestRsaKeyFile(privateKeyFile); } } @@ -430,7 +428,7 @@ public void ConstructorWithFileNameAndPassphrase() using (var fs = File.Open(_temporaryFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { var privateKeyFile = new PrivateKeyFile(_temporaryFile, "12345"); - Assert.IsNotNull(privateKeyFile.HostKey); + TestRsaKeyFile(privateKeyFile); fs.Close(); } @@ -498,7 +496,7 @@ public void ConstructorWithFileName() } var privateKeyFile = new PrivateKeyFile(_temporaryFile, "12345"); - Assert.IsNotNull(privateKeyFile.HostKey); + TestRsaKeyFile(privateKeyFile); } /// @@ -510,7 +508,7 @@ public void ConstructorWithStream() using (var stream = GetData("Key.RSA.txt")) { var privateKeyFile = new PrivateKeyFile(stream); - Assert.IsNotNull(privateKeyFile.HostKey); + TestRsaKeyFile(privateKeyFile); } } @@ -526,7 +524,7 @@ public void ConstructorWithFileNameShouldBeAbleToReadFileThatIsSharedForReadAcce using (var fs = File.Open(_temporaryFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { var privateKeyFile = new PrivateKeyFile(_temporaryFile); - Assert.IsNotNull(privateKeyFile.HostKey); + TestRsaKeyFile(privateKeyFile); fs.Close(); } @@ -544,7 +542,7 @@ public void ConstructorWithFileNameAndPassPhraseShouldBeAbleToReadFileThatIsShar using (var fs = File.Open(_temporaryFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { var privateKeyFile = new PrivateKeyFile(_temporaryFile, "12345"); - Assert.IsNotNull(privateKeyFile.HostKey); + TestRsaKeyFile(privateKeyFile); fs.Close(); } @@ -684,15 +682,14 @@ private string GetTempFileName() private static void TestRsaKeyFile(PrivateKeyFile rsaPrivateKeyFile) { - Assert.AreEqual(3, rsaPrivateKeyFile.HostAlgorithms.Count); + Assert.IsNotNull(rsaPrivateKeyFile.HostKeyAlgorithms); + Assert.AreEqual(3, rsaPrivateKeyFile.HostKeyAlgorithms.Count); - List algorithms = rsaPrivateKeyFile.HostAlgorithms.Cast().ToList(); + var algorithms = rsaPrivateKeyFile.HostKeyAlgorithms.ToList(); Assert.AreEqual("rsa-sha2-512", algorithms[0].Name); Assert.AreEqual("rsa-sha2-256", algorithms[1].Name); Assert.AreEqual("ssh-rsa", algorithms[2].Name); - - Assert.AreSame(algorithms[0], rsaPrivateKeyFile.HostKey); } } } diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs index 0c5c7eb02..4691fef27 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs @@ -164,7 +164,7 @@ private static RsaKey GetRsaKey() { using (var stream = GetData("Key.RSA.txt")) { - return (RsaKey) ((KeyHostAlgorithm) new PrivateKeyFile(stream).HostKey).Key; + return (RsaKey) new PrivateKeyFile(stream).Key; } } diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs index 6f92362b4..d024c05a6 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs @@ -1,4 +1,4 @@ -using System.Security.Cryptography; +using System.Security.Cryptography; using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -176,7 +176,7 @@ private static RsaKey GetRsaKey() { using (var stream = GetData("Key.RSA.txt")) { - return (RsaKey) ((KeyHostAlgorithm) new PrivateKeyFile(stream).HostKey).Key; + return (RsaKey) new PrivateKeyFile(stream).Key; } } diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs index 6f9650487..80c050a82 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Reflection; using System.Threading; @@ -122,7 +123,7 @@ private static KeyHostAlgorithm GetKeyHostAlgorithm() using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) { var privateKey = new PrivateKeyFile(s); - return (KeyHostAlgorithm)privateKey.HostKey; + return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First(); } } } diff --git a/src/Renci.SshNet/IHostAlgorithmsProvider.cs b/src/Renci.SshNet/IHostAlgorithmsProvider.cs deleted file mode 100644 index 89ac27128..000000000 --- a/src/Renci.SshNet/IHostAlgorithmsProvider.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; - -using Renci.SshNet.Security; - -namespace Renci.SshNet -{ - /// - /// Represents a collection of host algorithms. - /// - public interface IHostAlgorithmsProvider - { - /// - /// The host algorithms provided by this . - /// - /// - /// In situations where there is a preferred order of usage of the host algorithms, - /// the collection should be ordered from most preferred to least. - /// - IReadOnlyCollection HostAlgorithms { get; } - } -} diff --git a/src/Renci.SshNet/IPrivateKeySource.cs b/src/Renci.SshNet/IPrivateKeySource.cs index 466a36d2a..96ab4574f 100644 --- a/src/Renci.SshNet/IPrivateKeySource.cs +++ b/src/Renci.SshNet/IPrivateKeySource.cs @@ -1,5 +1,4 @@ -using System; -using System.ComponentModel; +using System.Collections.Generic; using Renci.SshNet.Security; @@ -8,19 +7,15 @@ namespace Renci.SshNet /// /// Represents private key source interface. /// - /// - /// This interface has been replaced by - /// and is obsolete. - /// - [Obsolete($"Use {nameof(IHostAlgorithmsProvider)} instead. " + - $"{nameof(IPrivateKeySource)} may be removed in a future release. " + - $"See https://github.com/sshnet/SSH.NET/issues/1174 for details.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public interface IPrivateKeySource : IHostAlgorithmsProvider + public interface IPrivateKeySource { /// - /// Gets the host key. + /// Gets the host keys algorithms. /// - HostAlgorithm HostKey { get; } + /// + /// In situations where there is a preferred order of usage of the host algorithms, + /// the collection should be ordered from most preferred to least. + /// + IReadOnlyCollection HostKeyAlgorithms { get; } } } diff --git a/src/Renci.SshNet/NetConfClient.cs b/src/Renci.SshNet/NetConfClient.cs index 95cc99f7d..bbedca3c2 100644 --- a/src/Renci.SshNet/NetConfClient.cs +++ b/src/Renci.SshNet/NetConfClient.cs @@ -107,7 +107,7 @@ public NetConfClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public NetConfClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) + public NetConfClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -120,7 +120,7 @@ public NetConfClient(string host, int port, string username, params IHostAlgorit /// Authentication private key file(s) . /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public NetConfClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles) + public NetConfClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } diff --git a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs index cb82cd7ac..224f8d295 100644 --- a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs +++ b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs @@ -31,7 +31,7 @@ public override string Name /// /// Gets the key files used for authentication. /// - public ICollection KeyFiles { get; private set; } + public ICollection KeyFiles { get; private set; } /// /// Initializes a new instance of the class. @@ -39,7 +39,7 @@ public override string Name /// The username. /// The key files. /// is whitespace or null. - public PrivateKeyAuthenticationMethod(string username, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyAuthenticationMethod(string username, params IPrivateKeySource[] keyFiles) : base(username) { if (keyFiles is null) @@ -47,7 +47,7 @@ public PrivateKeyAuthenticationMethod(string username, params IHostAlgorithmsPro throw new ArgumentNullException(nameof(keyFiles)); } - KeyFiles = new Collection(keyFiles); + KeyFiles = new Collection(keyFiles); } /// @@ -65,7 +65,7 @@ public override AuthenticationResult Authenticate(Session session) session.RegisterMessage("SSH_MSG_USERAUTH_PK_OK"); - var hostAlgorithms = KeyFiles.SelectMany(x => x.HostAlgorithms).ToList(); + var hostAlgorithms = KeyFiles.SelectMany(x => x.HostKeyAlgorithms).ToList(); try { diff --git a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs index 5ea0dacfd..29b48ffaa 100644 --- a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs +++ b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs @@ -17,7 +17,7 @@ public class PrivateKeyConnectionInfo : ConnectionInfo, IDisposable /// /// Gets the key files used for authentication. /// - public ICollection KeyFiles { get; private set; } + public ICollection KeyFiles { get; private set; } /// /// Initializes a new instance of the class. @@ -41,7 +41,7 @@ public PrivateKeyConnectionInfo(string host, string username, params PrivateKeyF /// Connection port. /// Connection username. /// Connection key files. - public PrivateKeyConnectionInfo(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(host, port, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty, keyFiles) { } @@ -56,7 +56,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, params I /// The proxy host. /// The proxy port. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles) : this(host, port, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles) { } @@ -72,7 +72,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp /// The proxy port. /// The proxy username. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles) : this(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles) { } @@ -86,7 +86,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp /// The proxy host. /// The proxy port. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles) : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles) { } @@ -101,7 +101,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy port. /// The proxy username. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles) : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles) { } @@ -117,7 +117,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy username. /// The proxy password. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles) : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, keyFiles) { } @@ -134,10 +134,10 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy username. /// The proxy password. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles) : base(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, new PrivateKeyAuthenticationMethod(username, keyFiles)) { - KeyFiles = new Collection(keyFiles); + KeyFiles = new Collection(keyFiles); } /// diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index ebd50fa42..6dc8d4274 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -65,11 +65,7 @@ namespace Renci.SshNet /// /// /// - public class PrivateKeyFile : IHostAlgorithmsProvider, -#pragma warning disable CS0618 // Type or member is obsolete - IPrivateKeySource, -#pragma warning restore CS0618 // Type or member is obsolete - IDisposable + public class PrivateKeyFile : IPrivateKeySource, IDisposable { private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?[A-Z0-9-]+),(?[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?([a-zA-Z0-9/+=]{1,80}\r?\n)+)-+ *END \k PRIVATE KEY *-+", RegexOptions.Compiled | RegexOptions.Multiline); @@ -79,32 +75,24 @@ public class PrivateKeyFile : IHostAlgorithmsProvider, private bool _isDisposed; /// - /// Gets the host key. + /// The supported host algorithms for this key file. /// - /// - /// This property returns the first item in . - /// - public HostAlgorithm HostKey + public IReadOnlyCollection HostKeyAlgorithms { get { - return _hostAlgorithms[0]; - } - private set - { - Debug.Assert(_hostAlgorithms.Count == 0, $"Only expected to set {nameof(HostKey)} at most once."); - _hostAlgorithms.Add(value); + return _hostAlgorithms; } } /// - /// The supported host algorithms for this key file. + /// Gets the key. /// - public IReadOnlyCollection HostAlgorithms + public Key Key { get { - return _hostAlgorithms; + return _key; } } @@ -114,7 +102,8 @@ public IReadOnlyCollection HostAlgorithms /// The key. public PrivateKeyFile(Key key) { - HostKey = new KeyHostAlgorithm(key.ToString(), key); + _key = key; + _hostAlgorithms.Add(new KeyHostAlgorithm(key.ToString(), key)); } /// @@ -124,7 +113,7 @@ public PrivateKeyFile(Key key) public PrivateKeyFile(Stream privateKey) { Open(privateKey, passPhrase: null); - Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKey)} is not set."); + Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKeyAlgorithms)} is not set."); } /// @@ -161,7 +150,7 @@ public PrivateKeyFile(string fileName, string passPhrase) Open(keyFile, passPhrase); } - Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKey)} is not set."); + Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKeyAlgorithms)} is not set."); } /// @@ -173,7 +162,8 @@ public PrivateKeyFile(string fileName, string passPhrase) public PrivateKeyFile(Stream privateKey, string passPhrase) { Open(privateKey, passPhrase); - Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKey)} is not set."); + + Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKeyAlgorithms)} is not set."); } /// @@ -266,11 +256,11 @@ private void Open(Stream privateKey, string passPhrase) break; case "DSA": _key = new DsaKey(decryptedData); - HostKey = new KeyHostAlgorithm("ssh-dss", _key); + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key)); break; case "EC": _key = new EcdsaKey(decryptedData); - HostKey = new KeyHostAlgorithm(_key.ToString(), _key); + _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); break; case "OPENSSH": _key = ParseOpenSshV1Key(decryptedData, passPhrase); @@ -282,9 +272,8 @@ private void Open(Stream privateKey, string passPhrase) } else { - HostKey = new KeyHostAlgorithm(_key.ToString(), _key); + _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); } - break; case "SSH2 ENCRYPTED": var reader = new SshDataReader(decryptedData); @@ -358,7 +347,7 @@ private void Open(Stream privateKey, string passPhrase) var y = reader.ReadBigIntWithBits(); var x = reader.ReadBigIntWithBits(); _key = new DsaKey(p, q, g, y, x); - HostKey = new KeyHostAlgorithm("ssh-dss", _key); + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key)); } else { diff --git a/src/Renci.SshNet/ScpClient.cs b/src/Renci.SshNet/ScpClient.cs index fc12413de..177a83bb5 100644 --- a/src/Renci.SshNet/ScpClient.cs +++ b/src/Renci.SshNet/ScpClient.cs @@ -146,7 +146,7 @@ public ScpClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public ScpClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) + public ScpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -159,7 +159,7 @@ public ScpClient(string host, int port, string username, params IHostAlgorithmsP /// Authentication private key file(s) . /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public ScpClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles) + public ScpClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index b5f757b96..e6f9cb2d6 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -218,7 +218,7 @@ public SftpClient(string host, string username, string password) /// is invalid. -or- is nunullll or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public SftpClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) + public SftpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -231,7 +231,7 @@ public SftpClient(string host, int port, string username, params IHostAlgorithms /// Authentication private key file(s) . /// is null. /// is invalid. -or- is null or contains only whitespace characters. - public SftpClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles) + public SftpClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } diff --git a/src/Renci.SshNet/SshClient.cs b/src/Renci.SshNet/SshClient.cs index e596caaa0..fb8bb37f0 100644 --- a/src/Renci.SshNet/SshClient.cs +++ b/src/Renci.SshNet/SshClient.cs @@ -103,7 +103,7 @@ public SshClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public SshClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) + public SshClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -120,7 +120,7 @@ public SshClient(string host, int port, string username, params IHostAlgorithmsP /// /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public SshClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles) + public SshClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { }