Skip to content

WIP: Add Support for ECDSA Host- and Private-Keys #489

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII</DefineConstants>
<DefineConstants>TRACE;DEBUG;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII;FEATURE_ECDSA</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand All @@ -29,7 +29,7 @@
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII</DefineConstants>
<DefineConstants>TRACE;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII;FEATURE_ECDSA</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\Renci.SshNet.xml</DocumentationFile>
Expand Down Expand Up @@ -695,6 +695,12 @@
<Compile Include="..\Renci.SshNet\Security\Cryptography\Key.cs">
<Link>Security\Cryptography\Key.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet\Security\Cryptography\EcdsaDigitalSignature.cs">
<Link>Security\Cryptography\EcdsaDigitalSignature.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet\Security\Cryptography\EcdsaKey.cs">
<Link>Security\Cryptography\EcdsaKey.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet\Security\Cryptography\RsaDigitalSignature.cs">
<Link>Security\Cryptography\RsaDigitalSignature.cs</Link>
</Compile>
Expand Down
20 changes: 20 additions & 0 deletions src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -1737,6 +1737,26 @@
<Link>Data\Key.SSH2.RSA.txt</Link>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\Renci.SshNet.Tests\Data\Key.ECDSA.txt">
<Link>Data\Key.ECDSA.txt</Link>
</EmbeddedResource>
<EmbeddedResource Include="..\Renci.SshNet.Tests\Data\Key.ECDSA384.txt">
<Link>Data\Key.ECDSA384.txt</Link>
</EmbeddedResource>
<EmbeddedResource Include="..\Renci.SshNet.Tests\Data\Key.ECDSA521.txt">
<Link>Data\Key.ECDSA521.txt</Link>
</EmbeddedResource>
<EmbeddedResource Include="..\Renci.SshNet.Tests\Data\Key.ECDSA.Encrypted.txt">
<Link>Data\Key.ECDSA.Encrypted.txt</Link>
</EmbeddedResource>
<EmbeddedResource Include="..\Renci.SshNet.Tests\Data\Key.ECDSA384.Encrypted.txt">
<Link>Data\Key.ECDSA384.Encrypted.txt</Link>
</EmbeddedResource>
<EmbeddedResource Include="..\Renci.SshNet.Tests\Data\Key.ECDSA521.Encrypted.txt">
<Link>Data\Key.ECDSA521.Encrypted.txt</Link>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
Expand Down
66 changes: 66 additions & 0 deletions src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,72 @@ public void Test_PrivateKey_RSA_DES_EDE3_CFB()
}
}

[TestMethod]
[Owner("darinkes")]
[TestCategory("PrivateKey")]
public void Test_PrivateKey_ECDSA()
{
using (var stream = GetData("Key.ECDSA.txt"))
{
new PrivateKeyFile(stream);
}
}

[TestMethod]
[Owner("darinkes")]
[TestCategory("PrivateKey")]
public void Test_PrivateKey_ECDSA384()
{
using (var stream = GetData("Key.ECDSA384.txt"))
{
new PrivateKeyFile(stream);
}
}

[TestMethod]
[Owner("darinkes")]
[TestCategory("PrivateKey")]
public void Test_PrivateKey_ECDSA521()
{
using (var stream = GetData("Key.ECDSA521.txt"))
{
new PrivateKeyFile(stream);
}
}

[TestMethod]
[Owner("darinkes")]
[TestCategory("PrivateKey")]
public void Test_PrivateKey_ECDSA_Encrypted()
{
using (var stream = GetData("Key.ECDSA.Encrypted.txt"))
{
new PrivateKeyFile(stream, "12345");
}
}

[TestMethod]
[Owner("darinkes")]
[TestCategory("PrivateKey")]
public void Test_PrivateKey_ECDSA384_Encrypted()
{
using (var stream = GetData("Key.ECDSA384.Encrypted.txt"))
{
new PrivateKeyFile(stream, "12345");
}
}

[TestMethod]
[Owner("darinkes")]
[TestCategory("PrivateKey")]
public void Test_PrivateKey_ECDSA521_Encrypted()
{
using (var stream = GetData("Key.ECDSA521.Encrypted.txt"))
{
new PrivateKeyFile(stream, "12345");
}
}

/// <summary>
///A test for Dispose
///</summary>
Expand Down
8 changes: 8 additions & 0 deletions src/Renci.SshNet.Tests/Data/Key.ECDSA.Encrypted.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,54D46F498C989115AAE14FEA21E3AF11

IQdFnndcbzz10d7YQIgEE1TzuzJrm7uYJr4Hvdfz/FshVxMRqxqaqtEgo2vAHHik
BOcPkm+84ERlTNPslcJqLSkKzCdxb7Rz5hfwHuN3Y6Lf01qGakDlzAUEjEyDor+4
zQtAne+f+gRUJnBvLLoVhH4xdeQFC55GECNUFQpEmos=
-----END EC PRIVATE KEY-----
5 changes: 5 additions & 0 deletions src/Renci.SshNet.Tests/Data/Key.ECDSA.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIEdqaFKgJBIibVjyUh1v7Y35LwIQJrocdTaYFLwl7iB0oAoGCCqGSM49
AwEHoUQDQgAEQD5MO/n9yqSDTszwzVpApLx5SQFecE5ZfDkgxqVdHQecm1BAPozZ
4eKGNhKn72hT79mLlp9HXX+oNEcuVT83Hw==
-----END EC PRIVATE KEY-----
9 changes: 9 additions & 0 deletions src/Renci.SshNet.Tests/Data/Key.ECDSA384.Encrypted.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,1D64653C5E18C2AACB0B17E3FE43C219

lCtRmcvKSeIACwqTtsf/ei1brtCZ386rsk/j7bSXdkZBpvzcmzbeo6w6CYm206Km
hV9TMl2dIO/I1/ov5/2VIR3ZkaElyDOJD/+Be0e3aus4EZj1H1YM/Dv+4QJId+is
Cw4ycWjfudYPPejGdiyjzt5qjaIJwrrEvGtMg7sWVAqDpjcAjS9KuaCu5nOgdItL
s7oHuz+DTGdJQNfUHAlUnz1JaMRWzpP0MwtxdcaRY+w=
-----END EC PRIVATE KEY-----
6 changes: 6 additions & 0 deletions src/Renci.SshNet.Tests/Data/Key.ECDSA384.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDCQawHdHLR7NvKa2vPV0sVkbzOE8c0enp95iEysGcGV66RXE1EH//nh
gu5UzeTR4KigBwYFK4EEACKhZANiAAQUk4rVvoOPI1hQzWpNx09Uo6qG+srGcbvB
q15eFK0GnK/T0UBKxdbZ2+//KAYI6SeDHM9t3ORF1aX5EpjTEBI4d7ZY/lV9jX6M
nJ4XuGteJselM2iMmy+p9ZYw83BYB1Y=
-----END EC PRIVATE KEY-----
10 changes: 10 additions & 0 deletions src/Renci.SshNet.Tests/Data/Key.ECDSA521.Encrypted.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,F995028237EBD79C928530CC6C3E957F

wT+iajbte4MnpCipVy/7W9t2I8OgwbMjNBw9PB5xmXR1NQX+yWa81DXMTgjHi8++
6tp+Vlftkr7mY1yvZCVo1Sy4VgcvZeMhtpVKtvYdMCmHJC6gaDOTYX3yee8DJ4FL
fG+IQz0wFyZZ26NFrHiwbufW9z6pXhGNCQZK0KLbFxI9iKwVA0llc7uzTEcmBBpn
0/Snp0CVvX+i6AP9Xj0bBdrFCsvcoT+ZHzS8YWJUfu3m6cpAJksCAy0PXR3ifvus
edTfDpkMxd4/b+DtPB6SMekIAjnQyzbyaTwJCujm8iU=
-----END EC PRIVATE KEY-----
7 changes: 7 additions & 0 deletions src/Renci.SshNet.Tests/Data/Key.ECDSA521.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-----BEGIN EC PRIVATE KEY-----
MIHcAgEBBEIBn2DAme7AU8sCA+/sd6s3c2FNW26IiPvulGd3FC8k5q+fjBZ5LUWR
iJMGrsf2rJLO8hXMGJYoF9tjZEGaabQ8KVagBwYFK4EEACOhgYkDgYYABABrpVjs
ANqcvqMUo1wo0I1uVCXQ6xrauy4iU86FiOwFmkYRrle4w3oYdRJwniC3TwGMuBuM
PMIoCTXr0UtUzn1vkQESNR/J/jAxVseLlVe+KDfZHKvsvk2+O4XaSa1qMfLwN3sp
wlj08+ylKjlO6V3g0hbz4ZaSVwuiRS7Xsv8W2MV6rg==
-----END EC PRIVATE KEY-----
8 changes: 8 additions & 0 deletions src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,14 @@
<Name>Renci.SshNet</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Data\Key.ECDSA.txt" />
<EmbeddedResource Include="Data\Key.ECDSA384.txt" />
<EmbeddedResource Include="Data\Key.ECDSA521.txt" />
<EmbeddedResource Include="Data\Key.ECDSA.Encrypted.txt" />
<EmbeddedResource Include="Data\Key.ECDSA384.Encrypted.txt" />
<EmbeddedResource Include="Data\Key.ECDSA521.Encrypted.txt" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Expand Down
85 changes: 77 additions & 8 deletions src/Renci.SshNet/Common/DerData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class DerData

private const byte Boolean = 0x01;
private const byte Integer = 0x02;
//private const byte BITSTRING = 0x03;
private const byte BITSTRING = 0x03;
private const byte Octetstring = 0x04;
private const byte Null = 0x05;
private const byte Objectidentifier = 0x06;
Expand Down Expand Up @@ -101,7 +101,7 @@ public BigInteger ReadBigInteger()
{
var type = ReadByte();
if (type != Integer)
throw new InvalidOperationException("Invalid data type, INTEGER(02) is expected.");
throw new InvalidOperationException(string.Format("Invalid data type, INTEGER(02) is expected, got {0}", type));

var length = ReadLength();

Expand All @@ -118,7 +118,7 @@ public int ReadInteger()
{
var type = ReadByte();
if (type != Integer)
throw new InvalidOperationException("Invalid data type, INTEGER(02) is expected.");
throw new InvalidOperationException(string.Format("Invalid data type, INTEGER(02) is expected, got {0}", type));

var length = ReadLength();

Expand All @@ -140,6 +140,36 @@ public int ReadInteger()
return result;
}

/// <summary>
/// Reads next octetstring data type from internal buffer.
/// </summary>
/// <returns>data read.</returns>
public byte[] ReadOctetString()
{
var type = ReadByte();
if (type != Octetstring)
throw new InvalidOperationException(string.Format("Invalid data type, OCTETSTRING(04) is expected, got {0}", type));

var length = ReadLength();
var data = ReadBytes(length);
return data;
}

/// <summary>
/// Reads next object data type from internal buffer.
/// </summary>
/// <returns>data read.</returns>
public byte[] ReadObject()
{
var type = ReadByte();
if (type != Objectidentifier)
throw new InvalidOperationException(string.Format("Invalid data type, OBJECT(06) is expected, got {0}", type));

var length = ReadLength();
var data = ReadBytes(length);
return data;
}

/// <summary>
/// Writes BOOLEAN data into internal buffer.
/// </summary>
Expand Down Expand Up @@ -189,6 +219,18 @@ public void Write(byte[] data)
WriteBytes(data);
}

/// <summary>
/// Writes BITSTRING data into internal buffer.
/// </summary>
/// <param name="data">The data.</param>
public void WriteBitstring(byte[] data)
{
_data.Add(BITSTRING);
var length = GetLength(data.Length);
WriteBytes(length);
WriteBytes(data);
}

/// <summary>
/// Writes OBJECTIDENTIFIER data into internal buffer.
/// </summary>
Expand Down Expand Up @@ -229,6 +271,18 @@ public void Write(ObjectIdentifier identifier)
WriteBytes(bytes);
}

/// <summary>
/// Writes OBJECTIDENTIFIER data into internal buffer.
/// </summary>
/// <param name="bytes">The bytes.</param>
public void WriteObjectIdentifier(byte[] bytes)
{
_data.Add(Objectidentifier);
var length = GetLength(bytes.Length);
WriteBytes(length);
WriteBytes(bytes);
}

/// <summary>
/// Writes NULL data into internal buffer.
/// </summary>
Expand Down Expand Up @@ -270,8 +324,11 @@ private static IEnumerable<byte> GetLength(int length)
}
return new[] {(byte) length};
}

private int ReadLength()
/// <summary>
/// Gets Data Length
/// </summary>
/// <returns>length</returns>
public int ReadLength()
{
int length = ReadByte();

Expand Down Expand Up @@ -306,20 +363,32 @@ private int ReadLength()
return length;
}

private void WriteBytes(IEnumerable<byte> data)
/// <summary>
/// Write Byte data into internal buffer.
/// </summary>
public void WriteBytes(IEnumerable<byte> data)
{
_data.AddRange(data);
}

private byte ReadByte()
/// <summary>
/// Reads Byte data into internal buffer.
/// </summary>
/// <returns>data read</returns>
public byte ReadByte()
{
if (_readerIndex > _data.Count)
throw new InvalidOperationException("Read out of boundaries.");

return _data[_readerIndex++];
}

private byte[] ReadBytes(int length)
/// <summary>
/// Reads lengths Bytes data into internal buffer.
/// </summary>
/// <returns>data read</returns>
/// <param name="length">amount of data to read.</param>
public byte[] ReadBytes(int length)
{
if (_readerIndex + length > _data.Count)
throw new InvalidOperationException("Read out of boundaries.");
Expand Down
6 changes: 5 additions & 1 deletion src/Renci.SshNet/ConnectionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,13 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy

HostKeyAlgorithms = new Dictionary<string, Func<byte[], KeyHostAlgorithm>>
{
#if FEATURE_ECDSA
{"ecdsa-sha2-nistp256", data => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(), data)},
{"ecdsa-sha2-nistp384", data => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(), data)},
{"ecdsa-sha2-nistp521", data => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(), data)},
#endif
{"ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data)},
{"ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(), data)},
//{"ecdsa-sha2-nistp256 "}
//{"x509v3-sign-rsa", () => { ... },
//{"x509v3-sign-dss", () => { ... },
//{"spki-sign-rsa", () => { ... },
Expand Down
Loading