-
Notifications
You must be signed in to change notification settings - Fork 853
Expand file tree
/
Copy pathfilesigner.go
More file actions
94 lines (75 loc) · 2.81 KB
/
Copy pathfilesigner.go
File metadata and controls
94 lines (75 loc) · 2.81 KB
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package guardiansigner
import (
"context"
"crypto/ecdsa"
"fmt"
"github.com/ethereum/go-ethereum/crypto"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/certusone/wormhole/node/pkg/common"
)
// FileSigner is a signer that loads a guardian key from a file. The URI is expected to be
// in the format file://<path-to-file>.
type FileSigner struct {
keyPath string
privateKey *ecdsa.PrivateKey
}
const (
GuardianKeyArmoredBlock = "WORMHOLE GUARDIAN PRIVATE KEY"
)
// The FileSigner is a signer that reads a guardian key from a file (signerKeyPath). The key is
// expected to be armored with an OpenPGP armor block, and the key itself is expected to be a
// protobuf-encoded GuardianKey message.
func NewFileSigner(_ context.Context, unsafeDevMode bool, signerKeyPath string) (*FileSigner, error) {
fileSigner := &FileSigner{
keyPath: signerKeyPath,
}
gk, err := common.LoadArmoredKey(signerKeyPath, GuardianKeyArmoredBlock, unsafeDevMode)
if err != nil {
return nil, err
}
fileSigner.privateKey = gk
return fileSigner, nil
}
// Sign signs a hash using the go-ethereum/crypto package's `Sign` function.
//
// As noted in the go-ethereum documentation, this function is subject to
// chosen-plaintext attacks. As a result, the input to this function must
// be a hash of the message that is being signed. This function will
// return an error if the hash is not the correct size.
func (fs *FileSigner) Sign(ctx context.Context, hash []byte) ([]byte, error) {
// Ensure hash is 32 bytes.
// This check is also performed by the Sign() function below, but we do it here
// to ensure the integrity of Guardian's signed messages even if
// go-ethereum/crypto is updated in the future.
const digestLength = 32
if len(hash) != digestLength {
return nil, fmt.Errorf("hash is required to be exactly %d bytes (%d)", digestLength, len(hash))
}
// Sign the hash
sig, err := crypto.Sign(hash, fs.privateKey)
if err != nil {
return nil, fmt.Errorf("failed to sign hash: %w", err)
}
return sig, nil
}
// PublicKey returns the public key of the signer.
func (fs *FileSigner) PublicKey(ctx context.Context) ecdsa.PublicKey {
return fs.privateKey.PublicKey
}
// Verify verifies a signature against a hash using the go-ethereum/crypto
// package's `SigToPub` function.
func (fs *FileSigner) Verify(ctx context.Context, sig []byte, hash []byte) (bool, error) {
// Recover the public key from the signature.
recoveredPubKey, err := ethcrypto.SigToPub(hash, sig)
if err != nil {
return false, err
}
// Need to use fs.privateKey.Public() instead of PublicKey to ensure
// the returned public key has the right interface for Equal() to work.
fsPubkey := fs.privateKey.Public()
return recoveredPubKey.Equal(fsPubkey), nil
}
// Return the signer type as "file".
func (fs *FileSigner) TypeAsString() string {
return "file"
}