From 84cf7fd955912c68f8ebc7e6e7a42e89ea78fd1b 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 When using the SSH Agent signers we need to use a wrapper to actually allow signing with SHA256. --- algorithms.go | 49 +++++++++++++++++++++++++++++++++++++++++++------ go.mod | 2 +- go.sum | 19 +++++++++++-------- httpsig.go | 3 +-- 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/algorithms.go b/algorithms.go index 9595941..b30bb0a 100644 --- a/algorithms.go +++ b/algorithms.go @@ -68,9 +68,8 @@ 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.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 sha1.New(), 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 }}, @@ -192,11 +191,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/go.mod b/go.mod index a407692..1fbe8d0 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ module github.com/go-fed/httpsig -require golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 +require golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 go 1.13 diff --git a/go.sum b/go.sum index 8b7d318..146b2ae 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,11 @@ -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/httpsig.go b/httpsig.go index 17310c8..7735a4b 100644 --- a/httpsig.go +++ b/httpsig.go @@ -234,7 +234,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 +324,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()