From a36870719ee2fe438745241fa96d283d129fbe5f Mon Sep 17 00:00:00 2001 From: Wim Date: Sat, 25 Dec 2021 23:51:17 +0100 Subject: [PATCH] Use SHA256 for SSH signing This also removes (again) support for SHA1. When using the SSH Agent signers we need to use a wrapper to actually allow signing with SHA256. --- algorithms.go | 52 +++++++++++++++++++++++++++++++++++++++++++-------- httpsig.go | 4 +--- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/algorithms.go b/algorithms.go index 9595941..897a130 100644 --- a/algorithms.go +++ b/algorithms.go @@ -5,7 +5,6 @@ import ( "crypto/ecdsa" "crypto/hmac" "crypto/rsa" - "crypto/sha1" "crypto/sha256" "crypto/sha512" "crypto/subtle" // Use should trigger great care @@ -68,10 +67,9 @@ var hashToDef = map[crypto.Hash]struct { // http://www.iana.org/assignments/signature-algorithms // // Note that the forbidden hashes have an invalid 'new' function. - crypto.MD4: {md4String, func(key []byte) (hash.Hash, error) { return nil, nil }}, - crypto.MD5: {md5String, func(key []byte) (hash.Hash, error) { return nil, nil }}, - // Temporarily enable SHA1 because of issue https://github.com/golang/go/issues/37278 - crypto.SHA1: {sha1String, func(key []byte) (hash.Hash, error) { return sha1.New(), nil }}, + crypto.MD4: {md4String, func(key []byte) (hash.Hash, error) { return nil, nil }}, + crypto.MD5: {md5String, func(key []byte) (hash.Hash, error) { return nil, nil }}, + crypto.SHA1: {sha1String, func(key []byte) (hash.Hash, error) { return nil, nil }}, crypto.SHA224: {sha224String, func(key []byte) (hash.Hash, error) { return sha256.New224(), nil }}, crypto.SHA256: {sha256String, func(key []byte) (hash.Hash, error) { return sha256.New(), nil }}, crypto.SHA384: {sha384String, func(key []byte) (hash.Hash, error) { return sha512.New384(), nil }}, @@ -192,11 +190,49 @@ func (r *rsaAlgorithm) setSig(b []byte) error { return nil } +// Code from https://github.com/cloudtools/ssh-cert-authority/pull/49/files +// This interface provides a way to reach the exported, but not accessible SignWithOpts() method +// in x/crypto/ssh/agent. Access to this is needed to sign with more secure signing algorithms +type agentKeyringSigner interface { + SignWithOpts(rand io.Reader, data []byte, opts crypto.SignerOpts) (*ssh.Signature, error) +} + +// A struct to wrap an SSH Signer with one that will switch to SHA256 Signatures. +// Replaces the call to Sign() with a call to SignWithOpts using HashFunc() algorithm. +type Sha256Signer struct { + ssh.Signer +} + +func (s Sha256Signer) HashFunc() crypto.Hash { + return crypto.SHA256 +} + +func (s Sha256Signer) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) { + if aks, ok := s.Signer.(agentKeyringSigner); !ok { + return nil, fmt.Errorf("ssh: can't wrap a non ssh agentKeyringSigner") + } else { + return aks.SignWithOpts(rand, data, s) + } +} + func (r *rsaAlgorithm) Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) { if r.sshSigner != nil { - sshsig, err := r.sshSigner.Sign(rand, sig) - if err != nil { - return nil, err + var ( + sshsig *ssh.Signature + err error + ) + // are we using an SSH Agent + if _, ok := r.sshSigner.(agentKeyringSigner); ok { + signer := Sha256Signer{r.sshSigner} + sshsig, err = signer.Sign(rand, sig) + if err != nil { + return nil, err + } + } else { + sshsig, err = r.sshSigner.(ssh.AlgorithmSigner).SignWithAlgorithm(rand, sig, ssh.SigAlgoRSASHA2256) + if err != nil { + return nil, err + } } return sshsig.Blob, nil diff --git a/httpsig.go b/httpsig.go index 17310c8..ee49129 100644 --- a/httpsig.go +++ b/httpsig.go @@ -43,7 +43,6 @@ const ( BLAKE2B_384 Algorithm = blake2b_384String BLAKE2B_512 Algorithm = blake2b_512String // RSA-based algorithms. - RSA_SHA1 Algorithm = rsaPrefix + "-" + sha1String RSA_SHA224 Algorithm = rsaPrefix + "-" + sha224String // RSA_SHA256 is the default algorithm. RSA_SHA256 Algorithm = rsaPrefix + "-" + sha256String @@ -234,7 +233,7 @@ func getSSHAlgorithm(pkType string) Algorithm { case strings.HasPrefix(pkType, sshPrefix+"-"+ed25519Prefix): return ED25519 case strings.HasPrefix(pkType, sshPrefix+"-"+rsaPrefix): - return RSA_SHA1 + return RSA_SHA256 } return "" @@ -324,7 +323,6 @@ func newSSHSigner(sshSigner ssh.Signer, algo Algorithm, dAlgo DigestAlgorithm, h } func newSigner(algo Algorithm, dAlgo DigestAlgorithm, headers []string, scheme SignatureScheme, expiresIn int64) (Signer, error) { - var expires, created int64 = 0, 0 if expiresIn != 0 { created = time.Now().Unix()