-
-
Notifications
You must be signed in to change notification settings - Fork 955
Allow signed keys #595
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
Closed
Allow signed keys #595
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
using Renci.SshNet.Messages; | ||
using Renci.SshNet.Messages.Authentication; | ||
using System; | ||
|
||
namespace Renci.SshNet.Common | ||
{ | ||
internal class SshSignatureData : SshData | ||
{ | ||
private readonly RequestMessagePublicKey _message; | ||
|
||
private readonly byte[] _sessionId; | ||
private readonly byte[] _serviceName; | ||
private readonly byte[] _authenticationMethod; | ||
|
||
protected override int BufferCapacity | ||
{ | ||
get | ||
{ | ||
var capacity = base.BufferCapacity; | ||
capacity += 4; // SessionId length | ||
capacity += _sessionId.Length; // SessionId | ||
capacity += 1; // Authentication Message Code | ||
capacity += 4; // UserName length | ||
capacity += _message.Username.Length; // UserName | ||
capacity += 4; // ServiceName length | ||
capacity += _serviceName.Length; // ServiceName | ||
capacity += 4; // AuthenticationMethod length | ||
capacity += _authenticationMethod.Length; // AuthenticationMethod | ||
capacity += 1; // TRUE | ||
capacity += 4; // PublicKeyAlgorithmName length | ||
capacity += _message.PublicKeyAlgorithmName.Length; // PublicKeyAlgorithmName | ||
capacity += 4; // PublicKeyData length | ||
capacity += _message.PublicKeyData.Length; // PublicKeyData | ||
return capacity; | ||
} | ||
} | ||
|
||
public SshSignatureData(RequestMessagePublicKey message, byte[] sessionId) | ||
{ | ||
_message = message; | ||
_sessionId = sessionId; | ||
_serviceName = ServiceName.Connection.ToArray(); | ||
_authenticationMethod = Ascii.GetBytes("publickey"); | ||
} | ||
|
||
protected override void LoadData() | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
protected override void SaveData() | ||
{ | ||
WriteBinaryString(_sessionId); | ||
Write((byte)RequestMessage.AuthenticationMessageCode); | ||
WriteBinaryString(_message.Username); | ||
WriteBinaryString(_serviceName); | ||
WriteBinaryString(_authenticationMethod); | ||
Write((byte)1); // TRUE | ||
WriteBinaryString(_message.PublicKeyAlgorithmName); | ||
WriteBinaryString(_message.PublicKeyData); | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
using Renci.SshNet.Common; | ||
using Renci.SshNet.Messages; | ||
using Renci.SshNet.Messages.Authentication; | ||
using System; | ||
using System.Threading; | ||
|
||
|
||
namespace Renci.SshNet | ||
{ | ||
/// <summary> | ||
/// Provides functionality to perform private key authentication using a | ||
/// signed public key component (a certificate). | ||
/// </summary> | ||
public class PrivateKeyCertAuthenticationMethod : AuthenticationMethod, IDisposable | ||
{ | ||
private AuthenticationResult _authenticationResult = AuthenticationResult.Failure; | ||
private EventWaitHandle _authenticationCompleted = new ManualResetEvent(false); | ||
|
||
/// <summary> | ||
/// Gets authentication method name | ||
/// </summary> | ||
public override string Name | ||
{ | ||
get { return "publickey"; } | ||
} | ||
|
||
/// <summary> | ||
/// Gets the key files used for authentication. | ||
/// </summary> | ||
public PrivateKeyFile KeyFile { get; private set; } | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public PublicKeyCertFile CertificateFile { get; private set; } | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="PrivateKeyAuthenticationMethod"/> class. | ||
/// </summary> | ||
/// <param name="username">The username.</param> | ||
/// <param name="keyFile">The key files.</param> | ||
/// <exception cref="ArgumentException"><paramref name="username"/> is whitespace or <c>null</c>.</exception> | ||
public PrivateKeyCertAuthenticationMethod(string username, PrivateKeyFile keyFile) | ||
: base(username) | ||
{ | ||
if (keyFile == null) | ||
throw new ArgumentNullException("keyFiles"); | ||
|
||
KeyFile = keyFile; | ||
} | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="PrivateKeyAuthenticationMethod"/> class. | ||
/// </summary> | ||
/// <param name="username">The username.</param> | ||
/// <param name="keyFile">The key files.</param> | ||
/// <param name="certFile"></param> | ||
/// <exception cref="ArgumentException"><paramref name="username"/> is whitespace or <c>null</c>.</exception> | ||
public PrivateKeyCertAuthenticationMethod(string username, PrivateKeyFile keyFile, PublicKeyCertFile certFile) | ||
: base(username) | ||
{ | ||
if (keyFile == null) | ||
throw new ArgumentNullException("keyFile"); | ||
|
||
if (certFile == null) | ||
throw new ArgumentNullException("certFile"); | ||
|
||
KeyFile = keyFile; | ||
CertificateFile = certFile; | ||
} | ||
|
||
/// <summary> | ||
/// Authenticates the specified session. | ||
/// </summary> | ||
/// <param name="session">The session to authenticate.</param> | ||
/// <returns> | ||
/// Result of authentication process. | ||
/// </returns> | ||
public override AuthenticationResult Authenticate(Session session) | ||
{ | ||
session.UserAuthenticationSuccessReceived += Session_UserAuthenticationSuccessReceived; | ||
session.UserAuthenticationFailureReceived += Session_UserAuthenticationFailureReceived; | ||
session.UserAuthenticationPublicKeyReceived += Session_UserAuthenticationPublicKeyReceived; | ||
|
||
session.RegisterMessage("SSH_MSG_USERAUTH_PK_OK"); | ||
|
||
try | ||
{ | ||
_authenticationCompleted.Reset(); | ||
|
||
var message = new RequestMessagePublicKey(ServiceName.Connection, | ||
Username, | ||
CertificateFile.HostCertificate.Name, | ||
CertificateFile.HostCertificate.Data); | ||
|
||
// Send signature for very first request | ||
var signatureData = new SshSignatureData(message, session.SessionId).GetBytes(); | ||
message.Signature = KeyFile.HostKey.Sign(signatureData); | ||
|
||
// Send public key authentication request | ||
session.SendMessage(message); | ||
|
||
session.WaitOnHandle(_authenticationCompleted); | ||
|
||
return _authenticationResult; | ||
} | ||
finally | ||
{ | ||
session.UserAuthenticationSuccessReceived -= Session_UserAuthenticationSuccessReceived; | ||
session.UserAuthenticationFailureReceived -= Session_UserAuthenticationFailureReceived; | ||
session.UserAuthenticationPublicKeyReceived -= Session_UserAuthenticationPublicKeyReceived; | ||
session.UnRegisterMessage("SSH_MSG_USERAUTH_PK_OK"); | ||
} | ||
} | ||
|
||
private void Session_UserAuthenticationSuccessReceived(object sender, MessageEventArgs<SuccessMessage> e) | ||
{ | ||
_authenticationResult = AuthenticationResult.Success; | ||
|
||
_authenticationCompleted.Set(); | ||
} | ||
|
||
private void Session_UserAuthenticationFailureReceived(object sender, MessageEventArgs<FailureMessage> e) | ||
{ | ||
if (e.Message.PartialSuccess) | ||
_authenticationResult = AuthenticationResult.PartialSuccess; | ||
else | ||
_authenticationResult = AuthenticationResult.Failure; | ||
|
||
// Copy allowed authentication methods | ||
AllowedAuthentications = e.Message.AllowedAuthentications; | ||
|
||
_authenticationCompleted.Set(); | ||
} | ||
|
||
private void Session_UserAuthenticationPublicKeyReceived(object sender, MessageEventArgs<PublicKeyMessage> e) | ||
{ | ||
_authenticationCompleted.Set(); | ||
} | ||
|
||
#region IDisposable Members | ||
|
||
private bool _isDisposed; | ||
|
||
/// <summary> | ||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. | ||
/// </summary> | ||
public void Dispose() | ||
{ | ||
Dispose(true); | ||
GC.SuppressFinalize(this); | ||
} | ||
|
||
/// <summary> | ||
/// Releases unmanaged and - optionally - managed resources | ||
/// </summary> | ||
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> | ||
protected virtual void Dispose(bool disposing) | ||
{ | ||
if (_isDisposed) | ||
return; | ||
|
||
if (disposing) | ||
{ | ||
var authenticationCompleted = _authenticationCompleted; | ||
if (authenticationCompleted != null) | ||
{ | ||
_authenticationCompleted = null; | ||
authenticationCompleted.Dispose(); | ||
} | ||
|
||
_isDisposed = true; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Releases unmanaged resources and performs other cleanup operations before the | ||
/// <see cref="PasswordConnectionInfo"/> is reclaimed by garbage collection. | ||
/// </summary> | ||
~PrivateKeyCertAuthenticationMethod() | ||
{ | ||
Dispose(false); | ||
} | ||
|
||
#endregion | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove?