Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for RSA SHA-2 public key algorithms #1177

Merged
merged 10 commits into from
Sep 23, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ public static void Reset(this RemoteSshdConfig remoteSshdConfig)
.ClearCiphers()
.ClearKeyExchangeAlgorithms()
.ClearHostKeyAlgorithms()
.AddHostKeyAlgorithm(HostKeyAlgorithm.SshRsa)
.ClearPublicKeyAcceptedAlgorithms()
.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.SshRsa)
.WithUsePAM(true)
.Update()
.Restart();
Expand Down
1 change: 0 additions & 1 deletion src/Renci.SshNet.IntegrationTests/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ RUN apk update && apk upgrade --no-cache && \
chmod 400 /etc/ssh/ssh*key && \
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config && \
sed -i 's/#LogLevel\s*INFO/LogLevel DEBUG3/' /etc/ssh/sshd_config && \
echo 'PubkeyAcceptedAlgorithms ssh-rsa' >> /etc/ssh/sshd_config && \
chmod 646 /etc/ssh/sshd_config && \
# install and configure sudo
apk add --no-cache sudo && \
Expand Down
72 changes: 25 additions & 47 deletions src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,63 +22,46 @@ public void TearDown()
{
_remoteSshdConfig?.Reset();
}

[TestMethod]
[Ignore] // No longer supported in recent versions of OpenSSH
// TODO: We should be able to enable some legacy settings to make it work
// https://www.openssh.com/legacy.html e.g. PubkeyAcceptedKeyTypes / HostbasedAcceptedKeyTypes ?
public void SshDsa()
{
_remoteSshdConfig.ClearHostKeyAlgorithms()
.AddHostKeyAlgorithm(HostKeyAlgorithm.SshDsa)
.ClearHostKeyFiles()
.AddHostKeyFile(HostKeyFile.Dsa.FilePath)
.Update()
.Restart();

HostKeyEventArgs hostKeyEventsArgs = null;

using (var client = new SshClient(_connectionInfoFactory.Create()))
{
client.HostKeyReceived += (sender, e) => hostKeyEventsArgs = e;
client.Connect();
client.Disconnect();
}

Assert.IsNotNull(hostKeyEventsArgs);
Assert.AreEqual(HostKeyFile.Dsa.KeyName, hostKeyEventsArgs.HostKeyName);
Assert.AreEqual(1024, hostKeyEventsArgs.KeyLength);
Assert.IsTrue(hostKeyEventsArgs.FingerPrint.SequenceEqual(HostKeyFile.Dsa.FingerPrint));
DoTest(HostKeyAlgorithm.SshDsa, HostKeyFile.Dsa, 1024);
}

[TestMethod]
public void SshRsa()
{
_remoteSshdConfig.ClearHostKeyAlgorithms()
.AddHostKeyAlgorithm(HostKeyAlgorithm.SshRsa)
.Update()
.Restart();

HostKeyEventArgs hostKeyEventsArgs = null;
DoTest(HostKeyAlgorithm.SshRsa, HostKeyFile.Rsa, 3072);
}

using (var client = new SshClient(_connectionInfoFactory.Create()))
{
client.HostKeyReceived += (sender, e) => hostKeyEventsArgs = e;
client.Connect();
client.Disconnect();
}
[TestMethod]
public void SshRsaSha256()
{
DoTest(HostKeyAlgorithm.RsaSha2256, HostKeyFile.Rsa, 3072);
}

Assert.IsNotNull(hostKeyEventsArgs);
Assert.AreEqual(HostKeyFile.Rsa.KeyName, hostKeyEventsArgs.HostKeyName);
Assert.AreEqual(3072, hostKeyEventsArgs.KeyLength);
Assert.IsTrue(hostKeyEventsArgs.FingerPrint.SequenceEqual(HostKeyFile.Rsa.FingerPrint));
[TestMethod]
public void SshRsaSha512()
{
DoTest(HostKeyAlgorithm.RsaSha2512, HostKeyFile.Rsa, 3072);
}

[TestMethod]
public void SshEd25519()
{
DoTest(HostKeyAlgorithm.SshEd25519, HostKeyFile.Ed25519, 256);
}

private void DoTest(HostKeyAlgorithm hostKeyAlgorithm, HostKeyFile hostKeyFile, int keyLength)
{
_remoteSshdConfig.ClearHostKeyAlgorithms()
.AddHostKeyAlgorithm(HostKeyAlgorithm.SshEd25519)
.AddHostKeyAlgorithm(hostKeyAlgorithm)
.ClearHostKeyFiles()
.AddHostKeyFile(HostKeyFile.Ed25519.FilePath)
.AddHostKeyFile(hostKeyFile.FilePath)
.Update()
.Restart();

Expand All @@ -92,14 +75,9 @@ public void SshEd25519()
}

Assert.IsNotNull(hostKeyEventsArgs);
Assert.AreEqual(HostKeyFile.Ed25519.KeyName, hostKeyEventsArgs.HostKeyName);
Assert.AreEqual(256, hostKeyEventsArgs.KeyLength);
Assert.IsTrue(hostKeyEventsArgs.FingerPrint.SequenceEqual(HostKeyFile.Ed25519.FingerPrint));
}

private void Client_HostKeyReceived(object sender, HostKeyEventArgs e)
{
throw new NotImplementedException();
Assert.AreEqual(hostKeyAlgorithm.Name, hostKeyEventsArgs.HostKeyName);
Assert.AreEqual(keyLength, hostKeyEventsArgs.KeyLength);
CollectionAssert.AreEqual(hostKeyFile.FingerPrint, hostKeyEventsArgs.FingerPrint);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Renci.SshNet.IntegrationTests
{
[TestClass]
public class PrivateKeyAuthenticationTests : TestBase
{
{
private IConnectionInfoFactory _connectionInfoFactory;
private RemoteSshdConfig _remoteSshdConfig;

Expand All @@ -23,43 +23,64 @@ public void TearDown()
}

[TestMethod]
public void Ecdsa256()
[Ignore] // No longer supported in recent versions of OpenSSH
// TODO: We should be able to enable some legacy settings to make it work
// https://www.openssh.com/legacy.html e.g. PubkeyAcceptedKeyTypes / HostbasedAcceptedKeyTypes ?
public void SshDsa()
{
_remoteSshdConfig.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.EcdsaSha2Nistp256)
.Update()
.Restart();
DoTest(PublicKeyAlgorithm.SshDss, "id_dsa");
}

var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod("key_ecdsa_256_openssh"));
[TestMethod]
public void SshRsa()
{
DoTest(PublicKeyAlgorithm.SshRsa, "id_rsa");
}

using (var client = new SshClient(connectionInfo))
{
client.Connect();
}
[TestMethod]
public void SshRsaSha256()
{
DoTest(PublicKeyAlgorithm.RsaSha2256, "id_rsa");
}

[TestMethod]
public void Ecdsa384()
public void SshRsaSha512()
{
_remoteSshdConfig.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.EcdsaSha2Nistp384)
.Update()
.Restart();
DoTest(PublicKeyAlgorithm.RsaSha2512, "id_rsa");
}

var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod("key_ecdsa_384_openssh"));
[TestMethod]
public void Ecdsa256()
{
DoTest(PublicKeyAlgorithm.EcdsaSha2Nistp256, "key_ecdsa_256_openssh");
}

using (var client = new SshClient(connectionInfo))
{
client.Connect();
}
[TestMethod]
public void Ecdsa384()
{
DoTest(PublicKeyAlgorithm.EcdsaSha2Nistp384, "key_ecdsa_384_openssh");
}

[TestMethod]
public void EcdsaA521()
public void Ecdsa521()
{
DoTest(PublicKeyAlgorithm.EcdsaSha2Nistp521, "key_ecdsa_521_openssh");
}

[TestMethod]
public void Ed25519()
{
DoTest(PublicKeyAlgorithm.SshEd25519, "key_ed25519_openssh");
}

private void DoTest(PublicKeyAlgorithm publicKeyAlgorithm, string keyResource)
{
_remoteSshdConfig.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.EcdsaSha2Nistp521)
_remoteSshdConfig.ClearPublicKeyAcceptedAlgorithms()
.AddPublicKeyAcceptedAlgorithms(publicKeyAlgorithm)
.Update()
.Restart();

var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod("key_ecdsa_521_openssh"));
var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod(keyResource));

using (var client = new SshClient(connectionInfo))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<EmbeddedResource Include="resources\client\key_ecdsa_256_openssh" />
<EmbeddedResource Include="resources\client\key_ecdsa_384_openssh" />
<EmbeddedResource Include="resources\client\key_ecdsa_521_openssh" />
<EmbeddedResource Include="resources\client\key_ed25519_openssh" />
<EmbeddedResource Include="resources\issue #70.png" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4N0T6VopnwPSYQUw0waQNhBjz0DYFQwvkv4OwWYSf//fJF3M6bH42Tn2J+IlQ+4/fCFnE3m99seV5T1myEj7fsupNteY2sKFGXENLGtAD/76FM0iBmXx76xlSTyZSSmNDIRU4xUR23cfc+al84F5mO2lEk+5Zr3Qn5JUpucBfis4vtu0sMDgZ4w1d0tcuXkT/MEJn2iX2cnxbSy5qNAPHu7b+LEfXBv2OrMDqPrx/X6QREgi3w5RxL5kz7bvitWsIwIvb3ST2ARAArBwb8pEyp2A/w5p22rkQtL+3ibZ8fkmpgn33f31AZPgtM++iJPBmPKFjArcWEJ9fIVB/6DAj
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPzzrPpItEjNG7tU0DpJJ4pkI01E9d6K61OKTVPdFQSyGCdMj9XdP93lC6sJA+9/ahvf5F3gWEKxUJL2CKUiFWw=
ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBLSsu/HNKiaALhQ26UDv+N0AFdMb26fMVrOKe866CGu6ajSf9HUOhJFdjhseihB2rTalMPr8MrcXNLufii4mL8u4l9fUQXFgwnM/ZpiVPSs6C+8i4u/ZDg7Nx2NXybNIgQ==
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACB4WgRgGBRo6Uk+cRgg8tJPCbEtGURRWlUA7PDDerXR+P9O6mm3L99Etxsyh5XNYqXyaMNtH5c51ooMajrFwcayAHIhPPb8X3CsTwEfIUQ96aDyHQMotbRfnkn6uefeUTRrSNcqeAndUtVyAqBdqbsq2mgJYXHrz2NUKlPFYgauQi+WQ==
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACB4WgRgGBRo6Uk+cRgg8tJPCbEtGURRWlUA7PDDerXR+P9O6mm3L99Etxsyh5XNYqXyaMNtH5c51ooMajrFwcayAHIhPPb8X3CsTwEfIUQ96aDyHQMotbRfnkn6uefeUTRrSNcqeAndUtVyAqBdqbsq2mgJYXHrz2NUKlPFYgauQi+WQ==
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAkNGPVOTuzuKTgGfHcve2MRj57yXhmZgkUyi9RpmJrl
7 changes: 5 additions & 2 deletions src/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,11 @@ public void SaveTo(TextWriter writer)
writer.WriteLine("MACs " + string.Join(",", MessageAuthenticationCodeAlgorithms.Select(c => c.Name).ToArray()));
}

writer.WriteLine("PubkeyAcceptedAlgorithms " + string.Join(",", PublicKeyAcceptedAlgorithms.Select(c => c.Name).ToArray()));

if (PublicKeyAcceptedAlgorithms.Count > 0)
{
writer.WriteLine("PubkeyAcceptedAlgorithms " + string.Join(",", PublicKeyAcceptedAlgorithms.Select(c => c.Name).ToArray()));
}

foreach (var match in Matches)
{
_matchFormatter.Format(match, writer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void HostKeyEventArgsConstructorTest()
0xa0, 0x23, 0xaf, 0xff, 0x9c, 0x0f, 0x8c, 0x83, 0x7c, 0xf8, 0xe1, 0x8e, 0x32, 0x8e, 0x61, 0xfc,
0x5b, 0xbd, 0xd4, 0x46, 0xe1
}.SequenceEqual(target.HostKey));
Assert.AreEqual("ssh-rsa", target.HostKeyName);
Assert.AreEqual("rsa-sha2-512", target.HostKeyName);
Assert.AreEqual(2048, target.KeyLength);
}

Expand Down
36 changes: 26 additions & 10 deletions src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
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;

namespace Renci.SshNet.Tests.Classes
{
Expand Down Expand Up @@ -144,7 +147,7 @@ public void Test_PrivateKey_RSA()
{
using (var stream = GetData("Key.RSA.txt"))
{
_ = new PrivateKeyFile(stream);
TestRsaKeyFile(new PrivateKeyFile(stream));
}
}

Expand All @@ -166,7 +169,7 @@ public void Test_PrivateKey_SSH2_RSA()
{
using (var stream = GetData("Key.SSH2.RSA.txt"))
{
_ = new PrivateKeyFile(stream);
TestRsaKeyFile(new PrivateKeyFile(stream));
}
}

Expand All @@ -188,7 +191,7 @@ public void Test_PrivateKey_SSH2_Encrypted_RSA_DES_CBC()
{
using (var stream = GetData("Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt"))
{
_ = new PrivateKeyFile(stream, "12345");
TestRsaKeyFile(new PrivateKeyFile(stream, "12345"));
}
}

Expand Down Expand Up @@ -262,7 +265,7 @@ public void Test_PrivateKey_RSA_DES_CBC()
{
using (var stream = GetData("Key.RSA.Encrypted.Des.CBC.12345.txt"))
{
_ = new PrivateKeyFile(stream, "12345");
TestRsaKeyFile(new PrivateKeyFile(stream, "12345"));
}
}

Expand All @@ -284,7 +287,7 @@ public void Test_PrivateKey_RSA_AES_128_CBC()
{
using (var stream = GetData("Key.RSA.Encrypted.Aes.128.CBC.12345.txt"))
{
_ = new PrivateKeyFile(stream, "12345");
TestRsaKeyFile(new PrivateKeyFile(stream, "12345"));
}
}

Expand All @@ -295,7 +298,7 @@ public void Test_PrivateKey_RSA_AES_192_CBC()
{
using (var stream = GetData("Key.RSA.Encrypted.Aes.192.CBC.12345.txt"))
{
_ = new PrivateKeyFile(stream, "12345");
TestRsaKeyFile(new PrivateKeyFile(stream, "12345"));
}
}

Expand All @@ -306,7 +309,7 @@ public void Test_PrivateKey_RSA_AES_256_CBC()
{
using (var stream = GetData("Key.RSA.Encrypted.Aes.256.CBC.12345.txt"))
{
_ = new PrivateKeyFile(stream, "12345");
TestRsaKeyFile(new PrivateKeyFile(stream, "12345"));
}
}

Expand All @@ -317,7 +320,7 @@ public void Test_PrivateKey_RSA_DES_EDE3_CFB()
{
using (var stream = GetData("Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt"))
{
_ = new PrivateKeyFile(stream, "1234567890");
TestRsaKeyFile(new PrivateKeyFile(stream, "1234567890"));
}
}

Expand Down Expand Up @@ -576,7 +579,7 @@ public void Test_PrivateKey_OPENSSH_RSA()
{
using (var stream = GetData("Key.OPENSSH.RSA.txt"))
{
_ = new PrivateKeyFile(stream);
TestRsaKeyFile(new PrivateKeyFile(stream));
}
}

Expand All @@ -587,7 +590,7 @@ public void Test_PrivateKey_OPENSSH_RSA_ENCRYPTED()
{
using (var stream = GetData("Key.OPENSSH.RSA.Encrypted.txt"))
{
_ = new PrivateKeyFile(stream, "12345");
TestRsaKeyFile(new PrivateKeyFile(stream, "12345"));
}
}

Expand Down Expand Up @@ -678,5 +681,18 @@ private string GetTempFileName()
File.Delete(tempFile);
return tempFile;
}

private static void TestRsaKeyFile(PrivateKeyFile rsaPrivateKeyFile)
{
Assert.AreEqual(3, rsaPrivateKeyFile.HostAlgorithms.Count);

List<KeyHostAlgorithm> algorithms = rsaPrivateKeyFile.HostAlgorithms.Cast<KeyHostAlgorithm>().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);
}
}
}
Loading