diff options
author | zeripath <art27@cantab.net> | 2021-10-20 20:55:33 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-20 15:55:33 -0400 |
commit | 35b918f574464eeca89fcf0d5f3a07a58a4b5a38 (patch) | |
tree | e313796b0aa74127a93673a252809e85059ee8d3 /modules/ssh | |
parent | 98f70137567481c7caca68062017516498c039c4 (diff) | |
download | gitea-35b918f574464eeca89fcf0d5f3a07a58a4b5a38.tar.gz gitea-35b918f574464eeca89fcf0d5f3a07a58a4b5a38.zip |
Offer rsa-sha2-512 and rsa-sha2-256 algorithms in internal SSH (#17281)
* Offer rsa-sha2-512 and rsa-sha2-256 algorithms in internal SSH
There is a subtle bug in the SSH library x/crypto/ssh which makes the incorrect
assumption that the public key type is the same as the signature algorithm type.
This means that only ssh-rsa signatures are offered by default.
This PR adds a workaround around this problem.
Fix #17175
Signed-off-by: Andrew Thornton <art27@cantab.net>
* as per review
Signed-off-by: Andrew Thornton <art27@cantab.net>
Diffstat (limited to 'modules/ssh')
-rw-r--r-- | modules/ssh/ssh.go | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index efe9525345..909ed32c5e 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -316,10 +316,66 @@ func Listen(host string, port int, ciphers []string, keyExchanges []string, macs } } + // Workaround slightly broken behaviour in x/crypto/ssh/handshake.go:458-463 + // + // Fundamentally the issue here is that HostKeyAlgos make the incorrect assumption + // that the PublicKey().Type() matches the signature algorithm. + // + // Therefore we need to add duplicates for the RSA with different signing algorithms. + signers := make([]ssh.Signer, 0, len(srv.HostSigners)) + for _, signer := range srv.HostSigners { + if signer.PublicKey().Type() == "ssh-rsa" { + signers = append(signers, + &wrapSigner{ + Signer: signer, + algorithm: gossh.SigAlgoRSASHA2512, + }, + &wrapSigner{ + Signer: signer, + algorithm: gossh.SigAlgoRSASHA2256, + }, + ) + } + signers = append(signers, signer) + } + srv.HostSigners = signers + go listen(&srv) } +// wrapSigner wraps a signer and overrides its public key type with the provided algorithm +type wrapSigner struct { + ssh.Signer + algorithm string +} + +// PublicKey returns an associated PublicKey instance. +func (s *wrapSigner) PublicKey() gossh.PublicKey { + return &wrapPublicKey{ + PublicKey: s.Signer.PublicKey(), + algorithm: s.algorithm, + } +} + +// Sign returns raw signature for the given data. This method +// will apply the hash specified for the keytype to the data using +// the algorithm assigned for this key +func (s *wrapSigner) Sign(rand io.Reader, data []byte) (*gossh.Signature, error) { + return s.Signer.(gossh.AlgorithmSigner).SignWithAlgorithm(rand, data, s.algorithm) +} + +// wrapPublicKey wraps a PublicKey and overrides its type +type wrapPublicKey struct { + gossh.PublicKey + algorithm string +} + +// Type returns the algorithm +func (k *wrapPublicKey) Type() string { + return k.algorithm +} + // GenKeyPair make a pair of public and private keys for SSH access. // Public key is encoded in the format for inclusion in an OpenSSH authorized_keys file. // Private Key generated is PEM encoded |