forked from notaryproject/notary
-
Notifications
You must be signed in to change notification settings - Fork 0
/
verify.go
118 lines (103 loc) · 3.27 KB
/
verify.go
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package signed
import (
"errors"
"fmt"
"strings"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/go/canonical/json"
"github.com/docker/notary/tuf/data"
)
// Various basic signing errors
var (
ErrMissingKey = errors.New("tuf: missing key")
ErrNoSignatures = errors.New("tuf: data has no signatures")
ErrInvalid = errors.New("tuf: signature verification failed")
ErrWrongMethod = errors.New("tuf: invalid signature type")
ErrUnknownRole = errors.New("tuf: unknown role")
ErrWrongType = errors.New("tuf: meta file has wrong type")
)
// Verify checks the signatures and metadata (expiry, version) for the signed role
// data
func Verify(s *data.Signed, role data.BaseRole, minVersion int) error {
if err := verifyMeta(s, role.Name, minVersion); err != nil {
return err
}
return VerifySignatures(s, role)
}
func verifyMeta(s *data.Signed, role string, minVersion int) error {
sm := &data.SignedCommon{}
if err := json.Unmarshal(*s.Signed, sm); err != nil {
return err
}
if !data.ValidTUFType(sm.Type, role) {
return ErrWrongType
}
if IsExpired(sm.Expires) {
logrus.Errorf("Metadata for %s expired", role)
return ErrExpired{Role: role, Expired: sm.Expires.Format("Mon Jan 2 15:04:05 MST 2006")}
}
if sm.Version < minVersion {
return ErrLowVersion{sm.Version, minVersion}
}
return nil
}
// IsExpired checks if the given time passed before the present time
func IsExpired(t time.Time) bool {
return t.Before(time.Now())
}
// VerifySignatures checks the we have sufficient valid signatures for the given role
func VerifySignatures(s *data.Signed, roleData data.BaseRole) error {
if len(s.Signatures) == 0 {
return ErrNoSignatures
}
if roleData.Threshold < 1 {
return ErrRoleThreshold{}
}
logrus.Debugf("%s role has key IDs: %s", roleData.Name, strings.Join(roleData.ListKeyIDs(), ","))
// remarshal the signed part so we can verify the signature, since the signature has
// to be of a canonically marshalled signed object
var decoded map[string]interface{}
if err := json.Unmarshal(*s.Signed, &decoded); err != nil {
return err
}
msg, err := json.MarshalCanonical(decoded)
if err != nil {
return err
}
valid := make(map[string]struct{})
for _, sig := range s.Signatures {
logrus.Debug("verifying signature for key ID: ", sig.KeyID)
key, ok := roleData.Keys[sig.KeyID]
if !ok {
logrus.Debugf("continuing b/c keyid lookup was nil: %s\n", sig.KeyID)
continue
}
// Check that the signature key ID actually matches the content ID of the key
if key.ID() != sig.KeyID {
return ErrInvalidKeyID{}
}
if err := VerifySignature(msg, sig, key); err != nil {
logrus.Debugf("continuing b/c %s", err.Error())
continue
}
valid[sig.KeyID] = struct{}{}
}
if len(valid) < roleData.Threshold {
return ErrRoleThreshold{}
}
return nil
}
// VerifySignature checks a single signature and public key against a payload
func VerifySignature(msg []byte, sig data.Signature, pk data.PublicKey) error {
// method lookup is consistent due to Unmarshal JSON doing lower case for us.
method := sig.Method
verifier, ok := Verifiers[method]
if !ok {
return fmt.Errorf("signing method is not supported: %s\n", sig.Method)
}
if err := verifier.Verify(pk, sig.Signature, msg); err != nil {
return fmt.Errorf("signature was invalid\n")
}
return nil
}