Skip to content

Commit

Permalink
Offer rsa-sha2-512 and rsa-sha2-256 algorithms in internal SSH (go-gi…
Browse files Browse the repository at this point in the history
…tea#17281)

Backport go-gitea#17281

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 go-gitea#17175

Signed-off-by: Andrew Thornton <art27@cantab.net>
  • Loading branch information
zeripath committed Oct 20, 2021
1 parent 79a3d27 commit 3b2dd78
Showing 1 changed file with 56 additions and 0 deletions.
56 changes: 56 additions & 0 deletions modules/ssh/ssh.go
Expand Up @@ -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
Expand Down

0 comments on commit 3b2dd78

Please sign in to comment.