-
-
Notifications
You must be signed in to change notification settings - Fork 939
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
RSA SHA-2 implementation proposal #1174
Comments
Despite my initial preference for solution 1 (the factory delegate) as a targeted, non-breaking change, it feels somewhat unsatisfying and fudge-y. I have been thinking of a variant combining solutions 2 and 3: Like in solution 3, we do change Then, like in solution 2, we add constructors to public class KeyHostAlgorithm : HostAlgorithm
{
+ public KeyHostAlgorithm(string name, Key key, DigitalSignature digitalSignature);
+ public KeyHostAlgorithm(string name, Key key, byte[] data, DigitalSignature digitalSignature);
+ public DigitalSignature DigitalSignature { get; }
} This property will be used for signing. The existing constructors will set the property by accessing This feels like less fudge than solution 1, less aggressive than solution 3, and slightly less confusing than solution 2 by no longer forcing an implementation of As for problem 2, I am warming to solution 3 and just taking the break before +[Obsolete("Use IHostAlgorithmsProvider instead. See https://github.com/sshnet/SSH.NET/issues/1174 for details.",
+ error: true)]
+[EditorBrowsable(EditorBrowsableState.Never)]
public interface IPrivateKeySource
{
HostAlgorithm HostKey { get; }
}
+public interface IHostAlgorithmsProvider
+{
+ IReadOnlyList<HostAlgorithm> HostAlgorithms { get; }
+}
-public class PrivateKeyFile : IPrivateKeySource, IDisposable
+public class PrivateKeyFile : IHostAlgorithmsProvider, IDisposable
{ } in order to keep things simple while we can. Tagging @darinkes, @Kim-SSi as prior implementers of this interface in case you have any thoughts there. |
Ok ignore my musings there. We can just change |
Awesome description. I need some time to familiarize myself with this. |
Version 2023.0.0 has been published https://www.nuget.org/packages/SSH.NET/2023.0.0 |
Background
The public key algorithm
ssh-rsa
which uses RSA and the SHA-1 hash algorithm, is considered deficient. OpenSSH version 8.8 (released on 2021-09-26) disablesssh-rsa
by default. See RFC 8332 and the OpenSSH 8.8 release notes.This library does not currently support the stronger public key algorithms using RSA with SHA-2 (
rsa-sha2-256
andrsa-sha2-512
) resulting inHost key algorithm negotiation failed
or similar. It is probably the number one problem by number of issues and comments.There is a workaround/solution provided in #825, #971 (and subsequently #1156). The workaround creates new
RsaKey
andRsaDigitalSignature
classes for SHA-256 (and presumably more for SHA-512). The duplication is made understandably due to the library's coupling between theKey
andDigitalSignature
types (see also #1156 (comment)). The coupling is also understandable because until now one type of key has only had one type of signature. However, the workaround is IMO not adequate for the library implementation.This issue is a proposal for the implementation. I have opened PR #1170 to allow specifying the hash algorithm in the
RsaDigitalSignature
constructor. This proposal builds on that.Problem 1: specifying the hash algorithm when instantiating a
KeyHostAlgorithm
The
KeyHostAlgorithm
type performs signing/verification and (de)serialisation of the data to the binary message format. AKeyHostAlgorithm
takes aKey
, and the signature is performed via theKey.Sign
andKey.VerifySignature
methods, which are non-virtual and simply forward to theDigitalSignature.Sign
andDigitalSignature.Verify
methods. BecauseKeyHostAlgorithm
just accepts aKey
, there is no way to specify the signature type.Solution 1: add
RsaKey
constructors taking a factory methodWe add two new constructors to
RsaKey
taking aFunc<RsaKey, RsaDigitalSignature>
parameter. When theDigitalSignature
getter is invoked, if the delegate has been supplied then it will be invoked with a parameter ofthis
, and theRsaDigitalSignature
returned from the delegate is returned from the getter. If the delegate has not been supplied, the implementation will keep its current behaviour of instantiating a SHA-1RsaDigitalSignature
.Usage
Advantages
Disadvantages
RsaKey
type is concerned with the implementation of the signature. (Although it is already)Solution 2: supply a
DigitalSignature
instance toKeyHostAlgorithm
By adding a settable
DigitalSignature
property or a new constructor parameter toKeyHostAlgorithm
, we can allow specifying the signature to be used.Usage
Advantages
Key
if aDigitalSignature
has not been suppliedDisadvantages
DigitalSignature
uses the suppliedKey
, which may be a source of bugs and issues.Key
and via theDigitalSignature
) may be a source of confusion.Solution 3: decouple
Key
andDigitalSignature
We remove the signature functionality from
Key
and obsolete itsDigitalSignature
property.KeyHostAlgorithm
would then gain aDigitalSignature
property and constructors taking aDigitalSignature
instead of aKey
.DigitalSignature
would gain aKey
property. The old constructors would be obsoleted akin to:Usage
Advantages
Key
andDigitalSignature
no longer existsDisadvantages
Problem 2: specifying multiple host algorithms for one private key
An RSA private key should be able to be used for multiple host key algorithms (
ssh-rsa
,rsa-sha2-256
andrsa-sha2-512
). Currently,PrivateKeyFile
implements theIPrivateKeySource
interface:which is what's supplied and enumerated during authentication:
SSH.NET/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs
Line 41 in 9f1699b
Solution 1: introduce a new interface
We add a new interface which can provide multiple host algorithms:
The enumeration of
IPrivateKeySource
s during authentication would make a check for whether the instance is anIExtendedPrivateKeySource
and then enumerate itsHostKeys
too. TheHostKeys
property is anIReadOnlyList
to allow counting and indexing such that theHostAlgorithm
s can be supplied in order of preference.IExtendedPrivateKeySource
inheritsIPrivateKeySource
becausePrivateKeyAuthenticationMethod
would be the only place it is used in the library, meaning every implementation ofIExtendedPrivateKeySource
would have to implementIPrivateKeySource
anyway.IPrivateKeySource.HostKey
would generally defer toIExtendedPrivateKeySource .HostKeys[0]
representing the most preferred algorithm.On naming, the
IPrivateKeySource
is IMO named slightly awkwardly: functionally, it is an abstraction of something which provides aHostAlgorithm
, with no explicit relevance to a private key. And if we wanted such an abstraction for a different use, we would either be using this interface having an unrelated name, or an interface with the same definition but a different name. Both of these would be strange.The interface was introduced in bc99ada (March 22) meaning it does not exist in the latest released package, but there were a number of requests for it so it is safest to assume that it is in use in local builds.
While I would strongly prefer not to make any breaking changes in this feature, I would be comfortable with an exception to rename
IPrivateKeySource
to something more relevant, likeIHostAlgorithmProvider
with an obsoletion message at error severity, before the next release. The new interface proposed above would be calledIHostAlgorithmsProvider
. This solution 1 includes the rename.Advantages
Disadvantages
IPrivateKeySource
in local buildsIPrivateKeySource
in the new interface may be awkward and unnecessary (I do not feel strongly about it)Solution 1b: the same as solution 1 but without renaming
IPrivateKeySource
We should then decide whether to keep the new interface in line with the naming e.g.
IExtendedPrivateKeySource
or go the more generic route ofIHostAlgorithmsProvider
.Advantages
Disadvantages
Solution 2: add
HostKeys
property toPrivateKeyFile
onlyAnd then during authentication, check if the
IPrivateKeySource
is a concretePrivateKeyFile
and enumerate itsHostKeys
Disadvantages
Solution 3: change the
IPrivateKeySource
interfaceChange the
HostKey
property to a collection, or add the collection property directly to the interface.Advantages
Disadvantages
IPrivateKeySource
in local builds (even more than a rename)Thanks for reading down to here. My personal preference is for solution 1 to problem 1, and solution 1a to problem 2. I would be willing to implement that relatively quickly.
The text was updated successfully, but these errors were encountered: