1 package dsse
2
3 import (
4 "context"
5 "crypto"
6 "errors"
7 "fmt"
8
9 "golang.org/x/crypto/ssh"
10 )
11
12
13 var ErrNoSignature = errors.New("no signature found")
14
15 type EnvelopeVerifier struct {
16 providers []Verifier
17 threshold int
18 }
19
20 type AcceptedKey struct {
21 Public crypto.PublicKey
22 KeyID string
23 Sig Signature
24 }
25
26 func (ev *EnvelopeVerifier) Verify(ctx context.Context, e *Envelope) ([]AcceptedKey, error) {
27 if e == nil {
28 return nil, errors.New("cannot verify a nil envelope")
29 }
30
31 if len(e.Signatures) == 0 {
32 return nil, ErrNoSignature
33 }
34
35
36 body, err := e.DecodeB64Payload()
37 if err != nil {
38 return nil, err
39 }
40
41 paeEnc := PAE(e.PayloadType, body)
42
43
44 var acceptedKeys []AcceptedKey
45 usedKeyids := make(map[string]string)
46 unverified_providers := ev.providers
47 for _, s := range e.Signatures {
48 sig, err := b64Decode(s.Sig)
49 if err != nil {
50 return nil, err
51 }
52
53
54
55
56
57 providers := unverified_providers
58 for i, v := range providers {
59 keyID, err := v.KeyID()
60
61
62 if err != nil || keyID == "" {
63 keyID, err = SHA256KeyID(v.Public())
64 if err != nil {
65 keyID = ""
66 }
67 }
68
69 if s.KeyID != "" && keyID != "" && err == nil && s.KeyID != keyID {
70 continue
71 }
72
73 err = v.Verify(ctx, paeEnc, sig)
74 if err != nil {
75 continue
76 }
77
78 acceptedKey := AcceptedKey{
79 Public: v.Public(),
80 KeyID: keyID,
81 Sig: s,
82 }
83 unverified_providers = removeIndex(providers, i)
84
85
86 if _, ok := usedKeyids[keyID]; ok {
87 fmt.Printf("Found envelope signed by different subkeys of the same main key, Only one of them is counted towards the step threshold, KeyID=%s\n", keyID)
88 continue
89 }
90
91 usedKeyids[keyID] = ""
92 acceptedKeys = append(acceptedKeys, acceptedKey)
93 break
94 }
95 }
96
97
98 if ev.threshold <= 0 || ev.threshold > len(ev.providers) {
99 return nil, errors.New("invalid threshold")
100 }
101
102 if len(usedKeyids) < ev.threshold {
103 return acceptedKeys, fmt.Errorf("accepted signatures do not match threshold, Found: %d, Expected %d", len(acceptedKeys), ev.threshold)
104 }
105
106 return acceptedKeys, nil
107 }
108
109 func NewEnvelopeVerifier(v ...Verifier) (*EnvelopeVerifier, error) {
110 return NewMultiEnvelopeVerifier(1, v...)
111 }
112
113 func NewMultiEnvelopeVerifier(threshold int, p ...Verifier) (*EnvelopeVerifier, error) {
114 if threshold <= 0 || threshold > len(p) {
115 return nil, errors.New("invalid threshold")
116 }
117
118 ev := EnvelopeVerifier{
119 providers: p,
120 threshold: threshold,
121 }
122
123 return &ev, nil
124 }
125
126 func SHA256KeyID(pub crypto.PublicKey) (string, error) {
127
128 sshpk, err := ssh.NewPublicKey(pub)
129 if err != nil {
130 return "", err
131 }
132 fingerprint := ssh.FingerprintSHA256(sshpk)
133 return fingerprint, nil
134 }
135
136 func removeIndex(v []Verifier, index int) []Verifier {
137 return append(v[:index], v[index+1:]...)
138 }
139
View as plain text