1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
package sshsig
import (
"errors"
"io"
"golang.org/x/crypto/ssh"
)
var (
// ErrPublicKeyMismatch is returned by Verify if the public key in the signature
// does not match the public key used to verify the signature.
ErrPublicKeyMismatch = errors.New("public key does not match")
// ErrNamespaceMismatch is returned by Verify if the namespace in the signature
// does not match the namespace used to verify the signature.
ErrNamespaceMismatch = errors.New("namespace does not match")
)
// Verify verifies the message from the io.Reader matches the Signature using
// the given ssh.PublicKey and HashAlgorithm.
//
// The purpose of the namespace value is to specify an unambiguous interpretation
// domain for the signature, e.g. file signing. This prevents cross-protocol
// attacks caused by signatures intended for one intended domain being accepted
// in another. Unlike Sign, the namespace value is not required to allow
// verification of signatures created by looser implementations.
//
// Verify returns an error if the verification process fails.
func Verify(m io.Reader, sig *Signature, pub ssh.PublicKey, h HashAlgorithm, namespace string) error {
// Check that the public key in the signature matches the public key used to
// verify the signature. If this is e.g. tricked in to a hash collision, it
// will still be caught by the verification.
if ssh.FingerprintSHA256(pub) != ssh.FingerprintSHA256(sig.PublicKey) {
return ErrPublicKeyMismatch
}
// Check that namespace matches the namespace in the Signature.
// If this is malformed, it will still be caught by the verification.
if sig.Namespace != namespace {
return ErrNamespaceMismatch
}
if err := h.Available(); err != nil {
return err
}
hf := h.Hash()
if _, err := io.Copy(hf, m); err != nil {
return err
}
mh := hf.Sum(nil)
return pub.Verify(signedData{
Namespace: namespace,
HashAlgorithm: h.String(),
Hash: string(mh),
}.Marshal(), sig.Signature)
}
|