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

Agent auth and Keygen #794

Merged
merged 5 commits into from
Mar 5, 2022
Merged
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
15 changes: 15 additions & 0 deletions src/Renci.SshNet/IPrivateKeySource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Renci.SshNet.Security;

namespace Renci.SshNet
{
/// <summary>
/// Represents private key source interface.
/// </summary>
public interface IPrivateKeySource
{
/// <summary>
/// Gets the host key.
/// </summary>
HostAlgorithm HostKey { get; }
}
}
8 changes: 4 additions & 4 deletions src/Renci.SshNet/NetConfClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public NetConfClient(string host, string username, string password)
/// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="IPEndPoint.MinPort"/> and <see cref="IPEndPoint.MaxPort"/>.</exception>
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
public NetConfClient(string host, int port, string username, params PrivateKeyFile[] keyFiles)
public NetConfClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
: this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true)
{
}
Expand All @@ -116,7 +116,7 @@ public NetConfClient(string host, int port, string username, params PrivateKeyFi
/// <param name="keyFiles">Authentication private key file(s) .</param>
/// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
public NetConfClient(string host, string username, params PrivateKeyFile[] keyFiles)
public NetConfClient(string host, string username, params IPrivateKeySource[] keyFiles)
: this(host, ConnectionInfo.DefaultPort, username, keyFiles)
{
}
Expand Down Expand Up @@ -163,7 +163,7 @@ internal NetConfClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, I
/// <value>
/// The NetConf server capabilities.
/// </value>
public XmlDocument ServerCapabilities
public XmlDocument ServerCapabilities
{
get { return _netConfSession.ServerCapabilities; }
}
Expand Down Expand Up @@ -277,4 +277,4 @@ private INetConfSession CreateAndConnectNetConfSession()
}
}
}
}
}
8 changes: 4 additions & 4 deletions src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,21 @@ public override string Name
/// <summary>
/// Gets the key files used for authentication.
/// </summary>
public ICollection<PrivateKeyFile> KeyFiles { get; private set; }
public ICollection<IPrivateKeySource> KeyFiles { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="PrivateKeyAuthenticationMethod"/> class.
/// </summary>
/// <param name="username">The username.</param>
/// <param name="keyFiles">The key files.</param>
/// <exception cref="ArgumentException"><paramref name="username"/> is whitespace or <c>null</c>.</exception>
public PrivateKeyAuthenticationMethod(string username, params PrivateKeyFile[] keyFiles)
public PrivateKeyAuthenticationMethod(string username, params IPrivateKeySource[] keyFiles)
: base(username)
{
if (keyFiles == null)
throw new ArgumentNullException("keyFiles");

KeyFiles = new Collection<PrivateKeyFile>(keyFiles);
KeyFiles = new Collection<IPrivateKeySource>(keyFiles);
}

/// <summary>
Expand Down Expand Up @@ -250,4 +250,4 @@ protected override void SaveData()
}
}
}
}
}
20 changes: 10 additions & 10 deletions src/Renci.SshNet/PrivateKeyConnectionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class PrivateKeyConnectionInfo : ConnectionInfo, IDisposable
/// <summary>
/// Gets the key files used for authentication.
/// </summary>
public ICollection<PrivateKeyFile> KeyFiles { get; private set; }
public ICollection<IPrivateKeySource> KeyFiles { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="PrivateKeyConnectionInfo"/> class.
Expand All @@ -40,7 +40,7 @@ public PrivateKeyConnectionInfo(string host, string username, params PrivateKeyF
/// <param name="port">Connection port.</param>
/// <param name="username">Connection username.</param>
/// <param name="keyFiles">Connection key files.</param>
public PrivateKeyConnectionInfo(string host, int port, string username, params PrivateKeyFile[] 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)
{
}
Expand All @@ -55,7 +55,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, params P
/// <param name="proxyHost">The proxy host.</param>
/// <param name="proxyPort">The proxy port.</param>
/// <param name="keyFiles">The key files.</param>
public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params PrivateKeyFile[] 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)
{
}
Expand All @@ -71,7 +71,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp
/// <param name="proxyPort">The proxy port.</param>
/// <param name="proxyUsername">The proxy username.</param>
/// <param name="keyFiles">The key files.</param>
public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params PrivateKeyFile[] 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)
{
}
Expand All @@ -85,7 +85,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp
/// <param name="proxyHost">The proxy host.</param>
/// <param name="proxyPort">The proxy port.</param>
/// <param name="keyFiles">The key files.</param>
public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params PrivateKeyFile[] 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)
{
}
Expand All @@ -100,7 +100,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy
/// <param name="proxyPort">The proxy port.</param>
/// <param name="proxyUsername">The proxy username.</param>
/// <param name="keyFiles">The key files.</param>
public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params PrivateKeyFile[] 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)
{
}
Expand All @@ -116,7 +116,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy
/// <param name="proxyUsername">The proxy username.</param>
/// <param name="proxyPassword">The proxy password.</param>
/// <param name="keyFiles">The key files.</param>
public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params PrivateKeyFile[] 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)
{
}
Expand All @@ -133,10 +133,10 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy
/// <param name="proxyUsername">The proxy username.</param>
/// <param name="proxyPassword">The proxy password.</param>
/// <param name="keyFiles">The key files.</param>
public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params PrivateKeyFile[] 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<PrivateKeyFile>(keyFiles);
KeyFiles = new Collection<IPrivateKeySource>(keyFiles);
}

#region IDisposable Members
Expand Down Expand Up @@ -194,4 +194,4 @@ protected virtual void Dispose(bool disposing)

#endregion
}
}
}
18 changes: 13 additions & 5 deletions src/Renci.SshNet/PrivateKeyFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ namespace Renci.SshNet
/// </list>
/// </para>
/// </remarks>
public class PrivateKeyFile : IDisposable
public class PrivateKeyFile : IPrivateKeySource, IDisposable
{
private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?<keyName>\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?<cipherName>[A-Z0-9-]+),(?<salt>[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?<data>([a-zA-Z0-9/+=]{1,80}\r?\n)+)-+ *END \k<keyName> PRIVATE KEY *-+",
#if FEATURE_REGEX_COMPILE
Expand All @@ -79,6 +79,15 @@ public class PrivateKeyFile : IDisposable
/// </summary>
public HostAlgorithm HostKey { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="PrivateKeyFile"/> class.
/// </summary>
/// <param name="key">The key.</param>
public PrivateKeyFile(Key key)
{
HostKey = new KeyHostAlgorithm(key.ToString(), key);
}

/// <summary>
/// Initializes a new instance of the <see cref="PrivateKeyFile"/> class.
/// </summary>
Expand Down Expand Up @@ -262,7 +271,7 @@ private void Open(Stream privateKey, string passPhrase)

if (decryptedLength > blobSize - 4)
throw new SshException("Invalid passphrase.");

if (keyType == "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}")
{
var exponent = reader.ReadBigIntWithBits();//e
Expand Down Expand Up @@ -515,8 +524,7 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase)
throw new SshException("OpenSSH key type '" + keyType + "' is not supported.");
}

//comment, we don't need this but we could log it, not sure if necessary
var comment = privateKeyReader.ReadString(Encoding.UTF8);
parsedKey.Comment = privateKeyReader.ReadString(Encoding.UTF8);

//The list of privatekey/comment pairs is padded with the bytes 1, 2, 3, ...
//until the total length is a multiple of the cipher block size.
Expand Down Expand Up @@ -642,4 +650,4 @@ protected override void SaveData()
}
}
}
}
}
6 changes: 3 additions & 3 deletions src/Renci.SshNet/ScpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public ScpClient(string host, string username, string password)
/// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="IPEndPoint.MinPort"/> and <see cref="IPEndPoint.MaxPort"/>.</exception>
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
public ScpClient(string host, int port, string username, params PrivateKeyFile[] keyFiles)
public ScpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
: this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true)
{
}
Expand All @@ -155,7 +155,7 @@ public ScpClient(string host, int port, string username, params PrivateKeyFile[]
/// <param name="keyFiles">Authentication private key file(s) .</param>
/// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is <c>null</c> or contains only whitespace characters.</exception>
public ScpClient(string host, string username, params PrivateKeyFile[] keyFiles)
public ScpClient(string host, string username, params IPrivateKeySource[] keyFiles)
: this(host, ConnectionInfo.DefaultPort, username, keyFiles)
{
}
Expand Down Expand Up @@ -466,4 +466,4 @@ private static SshException SecureExecutionRequestRejectedException()
throw new SshException("Secure copy execution request was rejected by the server. Please consult the server logs.");
}
}
}
}
9 changes: 9 additions & 0 deletions src/Renci.SshNet/Security/Cryptography/ED25519Key.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ public ED25519Key()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ED25519Key"/> class.
/// </summary>
/// <param name="pk">pk data.</param>
public ED25519Key(byte[] pk)
{
publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes);
}

/// <summary>
/// Initializes a new instance of the <see cref="ED25519Key"/> class.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ public override bool Verify(byte[] input, byte[] signature)
// for 521 sig_size is 132
var sig_size = _key.KeyLength == 521 ? 132 : _key.KeyLength / 4;
var ssh_data = new SshDataSignature(signature, sig_size);
#if NETSTANDARD2_0
return _key.Ecdsa.VerifyData(input, ssh_data.Signature, _key.HashAlgorithm);
#else
#if NETFRAMEWORK
var ecdsa = (ECDsaCng)_key.Ecdsa;
ecdsa.HashAlgorithm = _key.HashAlgorithm;
return ecdsa.VerifyData(input, ssh_data.Signature);
#else
return _key.Ecdsa.VerifyData(input, ssh_data.Signature, _key.HashAlgorithm);
#endif
}

Expand All @@ -57,12 +57,12 @@ public override bool Verify(byte[] input, byte[] signature)
/// </returns>
public override byte[] Sign(byte[] input)
{
#if NETSTANDARD2_0
var signed = _key.Ecdsa.SignData(input, _key.HashAlgorithm);
#else
#if NETFRAMEWORK
var ecdsa = (ECDsaCng)_key.Ecdsa;
ecdsa.HashAlgorithm = _key.HashAlgorithm;
var signed = ecdsa.SignData(input);
#else
var signed = _key.Ecdsa.SignData(input, _key.HashAlgorithm);
#endif
var ssh_data = new SshDataSignature(signed.Length);
ssh_data.Signature = signed;
Expand Down
Loading