Skip to content

Commit 35b918f

Browse files
authored
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 <[email protected]> * as per review Signed-off-by: Andrew Thornton <[email protected]>
1 parent 98f7013 commit 35b918f

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

modules/ssh/ssh.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,66 @@ func Listen(host string, port int, ciphers []string, keyExchanges []string, macs
316316
}
317317
}
318318

319+
// Workaround slightly broken behaviour in x/crypto/ssh/handshake.go:458-463
320+
//
321+
// Fundamentally the issue here is that HostKeyAlgos make the incorrect assumption
322+
// that the PublicKey().Type() matches the signature algorithm.
323+
//
324+
// Therefore we need to add duplicates for the RSA with different signing algorithms.
325+
signers := make([]ssh.Signer, 0, len(srv.HostSigners))
326+
for _, signer := range srv.HostSigners {
327+
if signer.PublicKey().Type() == "ssh-rsa" {
328+
signers = append(signers,
329+
&wrapSigner{
330+
Signer: signer,
331+
algorithm: gossh.SigAlgoRSASHA2512,
332+
},
333+
&wrapSigner{
334+
Signer: signer,
335+
algorithm: gossh.SigAlgoRSASHA2256,
336+
},
337+
)
338+
}
339+
signers = append(signers, signer)
340+
}
341+
srv.HostSigners = signers
342+
319343
go listen(&srv)
320344

321345
}
322346

347+
// wrapSigner wraps a signer and overrides its public key type with the provided algorithm
348+
type wrapSigner struct {
349+
ssh.Signer
350+
algorithm string
351+
}
352+
353+
// PublicKey returns an associated PublicKey instance.
354+
func (s *wrapSigner) PublicKey() gossh.PublicKey {
355+
return &wrapPublicKey{
356+
PublicKey: s.Signer.PublicKey(),
357+
algorithm: s.algorithm,
358+
}
359+
}
360+
361+
// Sign returns raw signature for the given data. This method
362+
// will apply the hash specified for the keytype to the data using
363+
// the algorithm assigned for this key
364+
func (s *wrapSigner) Sign(rand io.Reader, data []byte) (*gossh.Signature, error) {
365+
return s.Signer.(gossh.AlgorithmSigner).SignWithAlgorithm(rand, data, s.algorithm)
366+
}
367+
368+
// wrapPublicKey wraps a PublicKey and overrides its type
369+
type wrapPublicKey struct {
370+
gossh.PublicKey
371+
algorithm string
372+
}
373+
374+
// Type returns the algorithm
375+
func (k *wrapPublicKey) Type() string {
376+
return k.algorithm
377+
}
378+
323379
// GenKeyPair make a pair of public and private keys for SSH access.
324380
// Public key is encoded in the format for inclusion in an OpenSSH authorized_keys file.
325381
// Private Key generated is PEM encoded

0 commit comments

Comments
 (0)