Skip to content

Commit 97c6ce7

Browse files
author
msvprogs
committed
Prioritizing of encryption algorithms (might be SECURITY HOLE)
Sending SSH certificate to client
1 parent 71a1c07 commit 97c6ce7

10 files changed

+179
-60
lines changed

src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,9 @@
569569
<Compile Include="..\Renci.SshNet\PasswordConnectionInfo.cs">
570570
<Link>PasswordConnectionInfo.cs</Link>
571571
</Compile>
572+
<Compile Include="..\Renci.SshNet\PriorityString.cs">
573+
<Link>PriorityString.cs</Link>
574+
</Compile>
572575
<Compile Include="..\Renci.SshNet\PrivateKeyAuthenticationMethod.cs">
573576
<Link>PrivateKeyAuthenticationMethod.cs</Link>
574577
</Compile>
@@ -605,6 +608,9 @@
605608
<Compile Include="..\Renci.SshNet\Security\CertificateHostAlgorithm.cs">
606609
<Link>Security\CertificateHostAlgorithm.cs</Link>
607610
</Compile>
611+
<Compile Include="..\Renci.SshNet\Security\CertificateKeyHostAlgorithm.cs">
612+
<Link>Security\CertificateKeyHostAlgorithm.cs</Link>
613+
</Compile>
608614
<Compile Include="..\Renci.SshNet\Security\Cryptography\AsymmetricCipher.cs">
609615
<Link>Security\Cryptography\AsymmetricCipher.cs</Link>
610616
</Compile>
@@ -974,7 +980,7 @@
974980
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
975981
<ProjectExtensions>
976982
<VisualStudio>
977-
<UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
983+
<UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
978984
</VisualStudio>
979985
</ProjectExtensions>
980986
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Globalization;
4+
using System.Linq;
45
using System.Net;
56
using System.Net.Sockets;
67
using System.Security.Cryptography;
@@ -152,7 +153,9 @@ private void SetupMocks()
152153
{
153154
_serviceFactoryMock.Setup(
154155
p =>
155-
p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, new[] { _keyExchangeAlgorithm })).Returns(_keyExchangeMock.Object);
156+
p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms
157+
.ToDictionary(x => x.Key.Value, x => x.Value),
158+
new[] { _keyExchangeAlgorithm })).Returns(_keyExchangeMock.Object);
156159
_keyExchangeMock.Setup(p => p.Name).Returns(_keyExchangeAlgorithm);
157160
_keyExchangeMock.Setup(p => p.Start(Session, It.IsAny<KeyExchangeInitMessage>()));
158161
_keyExchangeMock.Setup(p => p.ExchangeHash).Returns(SessionId);

src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Globalization;
4+
using System.Linq;
45
using System.Net;
56
using System.Net.Sockets;
67
using System.Security.Cryptography;
@@ -136,7 +137,8 @@ private void SetupMocks()
136137
{
137138
_serviceFactoryMock.Setup(
138139
p =>
139-
p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, new[] { _keyExchangeAlgorithm })).Returns(_keyExchangeMock.Object);
140+
p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms.ToDictionary(x => x.Key.Value, x => x.Value),
141+
new[] { _keyExchangeAlgorithm })).Returns(_keyExchangeMock.Object);
140142
_keyExchangeMock.Setup(p => p.Name).Returns(_keyExchangeAlgorithm);
141143
_keyExchangeMock.Setup(p => p.Start(Session, It.IsAny<KeyExchangeInitMessage>()));
142144
_keyExchangeMock.Setup(p => p.ExchangeHash).Returns(SessionId);

src/Renci.SshNet/ConnectionInfo.cs

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,22 @@ public class ConnectionInfo : IConnectionInfoInternal
4343
/// <summary>
4444
/// Gets supported key exchange algorithms for this connection.
4545
/// </summary>
46-
public IDictionary<string, Type> KeyExchangeAlgorithms { get; private set; }
46+
public IDictionary<PriorityString, Type> KeyExchangeAlgorithms { get; private set; }
4747

4848
/// <summary>
4949
/// Gets supported encryptions for this connection.
5050
/// </summary>
51-
public IDictionary<string, CipherInfo> Encryptions { get; private set; }
51+
public IDictionary<PriorityString, CipherInfo> Encryptions { get; private set; }
5252

5353
/// <summary>
5454
/// Gets supported hash algorithms for this connection.
5555
/// </summary>
56-
public IDictionary<string, HashInfo> HmacAlgorithms { get; private set; }
56+
public IDictionary<PriorityString, HashInfo> HmacAlgorithms { get; private set; }
5757

5858
/// <summary>
5959
/// Gets supported host key algorithms for this connection.
6060
/// </summary>
61-
public IDictionary<string, Func<byte[], KeyHostAlgorithm>> HostKeyAlgorithms { get; private set; }
61+
public IDictionary<PriorityString, Func<byte[], KeyHostAlgorithm>> HostKeyAlgorithms { get; private set; }
6262

6363
/// <summary>
6464
/// Gets supported authentication methods for this connection.
@@ -321,12 +321,12 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy
321321
MaxSessions = 10;
322322
Encoding = Encoding.UTF8;
323323

324-
KeyExchangeAlgorithms = new Dictionary<string, Type>
324+
KeyExchangeAlgorithms = new Dictionary<PriorityString, Type>
325325
{
326-
{"diffie-hellman-group-exchange-sha256", typeof (KeyExchangeDiffieHellmanGroupExchangeSha256)},
327-
{"diffie-hellman-group-exchange-sha1", typeof (KeyExchangeDiffieHellmanGroupExchangeSha1)},
328-
{"diffie-hellman-group14-sha1", typeof (KeyExchangeDiffieHellmanGroup14Sha1)},
329-
{"diffie-hellman-group1-sha1", typeof (KeyExchangeDiffieHellmanGroup1Sha1)},
326+
{new PriorityString("diffie-hellman-group-exchange-sha256", 10), typeof (KeyExchangeDiffieHellmanGroupExchangeSha256)},
327+
{new PriorityString("diffie-hellman-group-exchange-sha1", 5), typeof (KeyExchangeDiffieHellmanGroupExchangeSha1)},
328+
{new PriorityString("diffie-hellman-group14-sha1", 1), typeof (KeyExchangeDiffieHellmanGroup14Sha1)},
329+
{new PriorityString("diffie-hellman-group1-sha1", 1), typeof (KeyExchangeDiffieHellmanGroup1Sha1)},
330330
//{"ecdh-sha2-nistp256", typeof(KeyExchangeEllipticCurveDiffieHellman)},
331331
//{"ecdh-sha2-nistp256", typeof(...)},
332332
//{"ecdh-sha2-nistp384", typeof(...)},
@@ -335,52 +335,52 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy
335335
//"gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==" - WinSSHD
336336
};
337337

338-
Encryptions = new Dictionary<string, CipherInfo>
338+
Encryptions = new Dictionary<PriorityString, CipherInfo>
339339
{
340-
{"aes256-ctr", new CipherInfo(256, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), null))},
341-
{"3des-cbc", new CipherInfo(192, (key, iv) => new TripleDesCipher(key, new CbcCipherMode(iv), null))},
342-
{"aes128-cbc", new CipherInfo(128, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), null))},
343-
{"aes192-cbc", new CipherInfo(192, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), null))},
344-
{"aes256-cbc", new CipherInfo(256, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), null))},
345-
{"blowfish-cbc", new CipherInfo(128, (key, iv) => new BlowfishCipher(key, new CbcCipherMode(iv), null))},
346-
{"twofish-cbc", new CipherInfo(256, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), null))},
347-
{"twofish192-cbc", new CipherInfo(192, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), null))},
348-
{"twofish128-cbc", new CipherInfo(128, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), null))},
349-
{"twofish256-cbc", new CipherInfo(256, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), null))},
340+
{new PriorityString("aes256-ctr", 100), new CipherInfo(256, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), null))},
341+
{new PriorityString("3des-cbc", 10), new CipherInfo(192, (key, iv) => new TripleDesCipher(key, new CbcCipherMode(iv), null))},
342+
{new PriorityString("aes128-cbc", 90), new CipherInfo(128, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), null))},
343+
{new PriorityString("aes192-cbc", 91), new CipherInfo(192, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), null))},
344+
{new PriorityString("aes256-cbc", 92), new CipherInfo(256, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), null))},
345+
{new PriorityString("blowfish-cbc", 80), new CipherInfo(128, (key, iv) => new BlowfishCipher(key, new CbcCipherMode(iv), null))},
346+
{new PriorityString("twofish-cbc", 70), new CipherInfo(256, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), null))},
347+
{new PriorityString("twofish192-cbc", 71), new CipherInfo(192, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), null))},
348+
{new PriorityString("twofish128-cbc", 72), new CipherInfo(128, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), null))},
349+
{new PriorityString("twofish256-cbc", 73), new CipherInfo(256, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), null))},
350350
////{"serpent256-cbc", typeof(CipherSerpent256CBC)},
351351
////{"serpent192-cbc", typeof(...)},
352352
////{"serpent128-cbc", typeof(...)},
353-
{"arcfour", new CipherInfo(128, (key, iv) => new Arc4Cipher(key, false))},
354-
{"arcfour128", new CipherInfo(128, (key, iv) => new Arc4Cipher(key, true))},
355-
{"arcfour256", new CipherInfo(256, (key, iv) => new Arc4Cipher(key, true))},
353+
{new PriorityString("arcfour", 50), new CipherInfo(128, (key, iv) => new Arc4Cipher(key, false))},
354+
{new PriorityString("arcfour128", 51), new CipherInfo(128, (key, iv) => new Arc4Cipher(key, true))},
355+
{new PriorityString("arcfour256", 52), new CipherInfo(256, (key, iv) => new Arc4Cipher(key, true))},
356356
////{"idea-cbc", typeof(...)},
357-
{"cast128-cbc", new CipherInfo(128, (key, iv) => new CastCipher(key, new CbcCipherMode(iv), null))},
357+
{new PriorityString("cast128-cbc", 40), new CipherInfo(128, (key, iv) => new CastCipher(key, new CbcCipherMode(iv), null))},
358358
////{"rijndael-cbc@lysator.liu.se", typeof(...)},
359-
{"aes128-ctr", new CipherInfo(128, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), null))},
360-
{"aes192-ctr", new CipherInfo(192, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), null))},
359+
{new PriorityString("aes128-ctr", 98), new CipherInfo(128, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), null))},
360+
{new PriorityString("aes192-ctr", 99), new CipherInfo(192, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), null))},
361361
};
362362

363-
HmacAlgorithms = new Dictionary<string, HashInfo>
363+
HmacAlgorithms = new Dictionary<PriorityString, HashInfo>
364364
{
365-
{"hmac-md5", new HashInfo(16*8, CryptoAbstraction.CreateHMACMD5)},
366-
{"hmac-md5-96", new HashInfo(16*8, key => CryptoAbstraction.CreateHMACMD5(key, 96))},
367-
{"hmac-sha1", new HashInfo(20*8, CryptoAbstraction.CreateHMACSHA1)},
368-
{"hmac-sha1-96", new HashInfo(20*8, key => CryptoAbstraction.CreateHMACSHA1(key, 96))},
369-
{"hmac-sha2-256", new HashInfo(32*8, CryptoAbstraction.CreateHMACSHA256)},
370-
{"hmac-sha2-256-96", new HashInfo(32*8, key => CryptoAbstraction.CreateHMACSHA256(key, 96))},
371-
{"hmac-sha2-512", new HashInfo(64 * 8, CryptoAbstraction.CreateHMACSHA512)},
372-
{"hmac-sha2-512-96", new HashInfo(64 * 8, key => CryptoAbstraction.CreateHMACSHA512(key, 96))},
365+
{new PriorityString("hmac-md5", 1), new HashInfo(16*8, CryptoAbstraction.CreateHMACMD5)},
366+
{new PriorityString("hmac-md5-96", 0), new HashInfo(16*8, key => CryptoAbstraction.CreateHMACMD5(key, 96))},
367+
{new PriorityString("hmac-sha1", 50), new HashInfo(20*8, CryptoAbstraction.CreateHMACSHA1)},
368+
{new PriorityString("hmac-sha1-96", 49), new HashInfo(20*8, key => CryptoAbstraction.CreateHMACSHA1(key, 96))},
369+
{new PriorityString("hmac-sha2-256", 100), new HashInfo(32*8, CryptoAbstraction.CreateHMACSHA256)},
370+
{new PriorityString("hmac-sha2-256-96", 99), new HashInfo(32*8, key => CryptoAbstraction.CreateHMACSHA256(key, 96))},
371+
{new PriorityString("hmac-sha2-512", 100), new HashInfo(64 * 8, CryptoAbstraction.CreateHMACSHA512)},
372+
{new PriorityString("hmac-sha2-512-96", 99), new HashInfo(64 * 8, key => CryptoAbstraction.CreateHMACSHA512(key, 96))},
373373
//{"umac-64@openssh.com", typeof(HMacSha1)},
374-
{"hmac-ripemd160", new HashInfo(160, CryptoAbstraction.CreateHMACRIPEMD160)},
375-
{"hmac-ripemd160@openssh.com", new HashInfo(160, CryptoAbstraction.CreateHMACRIPEMD160)},
374+
{new PriorityString("hmac-ripemd160", 40), new HashInfo(160, CryptoAbstraction.CreateHMACRIPEMD160)},
375+
{new PriorityString("hmac-ripemd160@openssh.com", 40), new HashInfo(160, CryptoAbstraction.CreateHMACRIPEMD160)},
376376
//{"none", typeof(...)},
377377
};
378378

379-
HostKeyAlgorithms = new Dictionary<string, Func<byte[], KeyHostAlgorithm>>
379+
HostKeyAlgorithms = new Dictionary<PriorityString, Func<byte[], KeyHostAlgorithm>>
380380
{
381-
{"ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data, 2)},
382-
{"ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(), data, int.MaxValue)},
383-
{"ssh-rsa-cert-v01@openssh.com", data => new KeyHostAlgorithm("ssh-rsa-cert-v01@openssh.com", new RsaCertV01Key(), data, 3)}
381+
{new PriorityString("ssh-rsa", 50), data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data, 2)},
382+
{new PriorityString("ssh-dss", 49), data => new KeyHostAlgorithm("ssh-dss", new DsaKey(), data, int.MaxValue)},
383+
{new PriorityString("ssh-rsa-cert-v01@openssh.com", 100), data => new CertificateKeyHostAlgorithm("ssh-rsa-cert-v01@openssh.com", new RsaCertV01Key(), data, 3)}
384384
//{"ecdsa-sha2-nistp256 "}
385385
//{"x509v3-sign-rsa", () => { ... },
386386
//{"x509v3-sign-dss", () => { ... },

src/Renci.SshNet/PriorityString.cs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System;
2+
3+
namespace Renci.SshNet
4+
{
5+
/// <summary>
6+
///
7+
/// </summary>
8+
public sealed class PriorityString : IEquatable<PriorityString>
9+
{
10+
/// <summary>
11+
///
12+
/// </summary>
13+
public string Value { get; private set; }
14+
15+
/// <summary>
16+
///
17+
/// </summary>
18+
public int Priority { get; private set; }
19+
20+
/// <summary>
21+
///
22+
/// </summary>
23+
/// <param name="value"></param>
24+
/// <param name="priority"></param>
25+
public PriorityString(string value, int priority)
26+
{
27+
Value = value;
28+
Priority = priority;
29+
}
30+
31+
/// <summary>
32+
///
33+
/// </summary>
34+
/// <param name="other"></param>
35+
/// <returns></returns>
36+
public bool Equals(PriorityString other)
37+
{
38+
if (ReferenceEquals(null, other)) return false;
39+
if (ReferenceEquals(this, other)) return true;
40+
return string.Equals(Value, other.Value) && Priority == other.Priority;
41+
}
42+
43+
/// <summary>
44+
///
45+
/// </summary>
46+
/// <param name="obj"></param>
47+
/// <returns></returns>
48+
public override bool Equals(object obj)
49+
{
50+
if (ReferenceEquals(null, obj)) return false;
51+
if (ReferenceEquals(this, obj)) return true;
52+
return obj is PriorityString && Equals((PriorityString) obj);
53+
}
54+
55+
/// <summary>
56+
///
57+
/// </summary>
58+
/// <returns></returns>
59+
public override int GetHashCode()
60+
{
61+
unchecked
62+
{
63+
return ((Value != null ? Value.GetHashCode() : 0) * 397) ^ Priority;
64+
}
65+
}
66+
67+
/// <summary>
68+
///
69+
/// </summary>
70+
/// <param name="src"></param>
71+
/// <returns></returns>
72+
public static implicit operator PriorityString(string src)
73+
{
74+
return new PriorityString(src, 0);
75+
}
76+
}
77+
}

src/Renci.SshNet/Renci.SshNet.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,12 @@
164164
<Compile Include="Messages\Transport\KeyExchangeEcdhInitMessage.cs" />
165165
<Compile Include="Messages\Transport\KeyExchangeEcdhReplyMessage.cs" />
166166
<Compile Include="Netconf\INetConfSession.cs" />
167+
<Compile Include="PriorityString.cs" />
167168
<Compile Include="RemotePathDoubleQuoteTransformation.cs" />
168169
<Compile Include="RemotePathNoneTransformation.cs" />
169170
<Compile Include="RemotePathShellQuoteTransformation.cs" />
170171
<Compile Include="RemotePathTransformation.cs" />
172+
<Compile Include="Security\CertificateKeyHostAlgorithm.cs" />
171173
<Compile Include="Security\Cryptography\HMACMD5.cs" />
172174
<Compile Include="Security\Cryptography\HMACSHA1.cs" />
173175
<Compile Include="Security\Cryptography\HMACSHA256.cs" />
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
namespace Renci.SshNet.Security
2+
{
3+
/// <inheritdoc />
4+
public class CertificateKeyHostAlgorithm : KeyHostAlgorithm
5+
{
6+
private readonly byte[] _data;
7+
8+
/// <inheritdoc />
9+
public override byte[] Data
10+
{
11+
get { return _data; }
12+
}
13+
14+
/// <inheritdoc />
15+
public CertificateKeyHostAlgorithm(string name, Key key)
16+
: base(name, key)
17+
{
18+
}
19+
20+
/// <inheritdoc />
21+
public CertificateKeyHostAlgorithm(string name, Key key, byte[] data, int maxKeyFields)
22+
: base(name, key, data, maxKeyFields)
23+
{
24+
_data = data;
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)