go 1.25.1 introduced the crypto.MessageSigner which allows an implementation to perform the digest operation on the raw data to sign. see issues/63405
Previously when you used crypto.Signer, an implementation expected the data to already be hashed.
this is a really trivial wrapper allows you to pass a crypto.Signer implementation and make use of crypto.MessageSigner interface.
to be honest, i don't know of any real-life implementation of this and you'll only likley find the very few i authored here for some time now
(i mostly wrote this because i filed a git issue)
Anyway, to use this, just acquire a crypto.Singer and pass that as a crypto.MessageSigner. The default hash is using the options provided hash function. One copmplication of using the opts hashFunc is that for certain backends like a tpmsigner if the underlying key is restricted, you need to allow the TPM to hash the data and return a validation ticket.
import (
"github.com/salrashid123/messagesigner"
)
// get any private key; rsa.privateKey implements crypto.Signer
mysigner, err := rsa.GenerateKey(rand.Reader, 2048)
// get the wrapper
r, err := messagesigner.NewMessageSigner(&MessageSignerConfig{
Signer: mysigner,
})
// raw data to sign
rawData := []byte("foo")
// hash it
h := sha256.New()
h.Write(rawData)
digest := h.Sum(nil)
// use as crypto.Signer on the digest
s, err := r.Sign(rand.Reader, digest, crypto.SHA256)
fmt.Printf("signature using Sign(): %s\n", base64.StdEncoding.EncodeToString(s))
// now just pass the raw data in
// the SignMessage will autohash the data
sr, err := r.SignMessage(rand.Reader, rawData, crypto.SHA256)
// the signatures are the same (in this case, for rsassa)
fmt.Printf("signature using MessageSigner: %s\n", base64.StdEncoding.EncodeToString(sr))