1
- // Copyright (c) 2022-2023 , Sylabs Inc. All rights reserved.
1
+ // Copyright (c) 2022-2024 , Sylabs Inc. All rights reserved.
2
2
// This software is licensed under a 3-clause BSD license. Please consult the LICENSE.md file
3
3
// distributed with the sources of this project regarding your rights to use or distribute this
4
4
// software.
@@ -9,27 +9,39 @@ import (
9
9
"bytes"
10
10
"context"
11
11
"crypto"
12
+ "encoding/base64"
12
13
"encoding/json"
13
14
"errors"
14
15
"fmt"
15
16
"io"
16
17
17
- "github.com/secure-systems-lab/go-securesystemslib/dsse"
18
18
"github.com/sigstore/sigstore/pkg/signature"
19
+ "github.com/sigstore/sigstore/pkg/signature/dsse"
19
20
"github.com/sigstore/sigstore/pkg/signature/options"
20
21
)
21
22
22
23
const metadataMediaType = "application/vnd.sylabs.sif-metadata+json"
23
24
24
25
type dsseEncoder struct {
25
- es * dsse.EnvelopeSigner
26
- h crypto.Hash
27
- payloadType string
26
+ ss []signature.Signer
27
+ opts []signature.SignOption
28
28
}
29
29
30
30
// newDSSEEncoder returns an encoder that signs messages in DSSE format according to opts, with key
31
31
// material from ss. SHA256 is used as the hash algorithm, unless overridden by opts.
32
- func newDSSEEncoder (ss []signature.Signer , opts ... signature.SignOption ) (* dsseEncoder , error ) {
32
+ func newDSSEEncoder (ss []signature.Signer , opts ... signature.SignOption ) * dsseEncoder {
33
+ return & dsseEncoder {
34
+ ss : ss ,
35
+ opts : opts ,
36
+ }
37
+ }
38
+
39
+ // signMessage signs the message from r in DSSE format, and writes the result to w. On success, the
40
+ // hash function is returned.
41
+ func (en * dsseEncoder ) signMessage (ctx context.Context , w io.Writer , r io.Reader ) (crypto.Hash , error ) {
42
+ opts := en .opts
43
+ opts = append (opts , options .WithContext (ctx ))
44
+
33
45
var so crypto.SignerOpts
34
46
for _ , opt := range opts {
35
47
opt .ApplyCryptoSignerOpts (& so )
@@ -41,57 +53,25 @@ func newDSSEEncoder(ss []signature.Signer, opts ...signature.SignOption) (*dsseE
41
53
opts = append (opts , options .WithCryptoSignerOpts (so ))
42
54
}
43
55
44
- dss := make ([]dsse.Signer , 0 , len (ss ))
45
- for _ , s := range ss {
46
- ds , err := newDSSESigner (s , opts ... )
47
- if err != nil {
48
- return nil , err
49
- }
50
-
51
- dss = append (dss , ds )
52
- }
53
-
54
- es , err := dsse .NewEnvelopeSigner (dss ... )
55
- if err != nil {
56
- return nil , err
57
- }
58
-
59
- return & dsseEncoder {
60
- es : es ,
61
- h : so .HashFunc (),
62
- payloadType : metadataMediaType ,
63
- }, nil
64
- }
65
-
66
- // signMessage signs the message from r in DSSE format, and writes the result to w. On success, the
67
- // hash function is returned.
68
- func (en * dsseEncoder ) signMessage (ctx context.Context , w io.Writer , r io.Reader ) (crypto.Hash , error ) {
69
- body , err := io .ReadAll (r )
70
- if err != nil {
71
- return 0 , err
72
- }
73
-
74
- e , err := en .es .SignPayload (ctx , en .payloadType , body )
56
+ s := dsse .WrapMultiSigner (metadataMediaType , en .ss ... )
57
+ b , err := s .SignMessage (r , opts ... )
75
58
if err != nil {
76
59
return 0 , err
77
60
}
78
61
79
- return en .h , json .NewEncoder (w ).Encode (e )
62
+ _ , err = w .Write (b )
63
+ return so .HashFunc (), err
80
64
}
81
65
82
66
type dsseDecoder struct {
83
- vs []signature.Verifier
84
- threshold int
85
- payloadType string
67
+ vs []signature.Verifier
86
68
}
87
69
88
70
// newDSSEDecoder returns a decoder that verifies messages in DSSE format using key material from
89
71
// vs.
90
72
func newDSSEDecoder (vs ... signature.Verifier ) * dsseDecoder {
91
73
return & dsseDecoder {
92
- vs : vs ,
93
- threshold : 1 , // Envelope considered verified if at least one verifier succeeds.
94
- payloadType : metadataMediaType ,
74
+ vs : vs ,
95
75
}
96
76
}
97
77
@@ -103,112 +83,78 @@ var (
103
83
// verifyMessage reads a message from r, verifies its signature(s), and returns the message
104
84
// contents. On success, the accepted public keys are set in vr.
105
85
func (de * dsseDecoder ) verifyMessage (ctx context.Context , r io.Reader , h crypto.Hash , vr * VerifyResult ) ([]byte , error ) { //nolint:lll
106
- vs := make ([]dsse.Verifier , 0 , len (de .vs ))
86
+ // Wrap the verifiers so we can accumulate the accepted public keys.
87
+ vs := make ([]signature.Verifier , 0 , len (de .vs ))
107
88
for _ , v := range de .vs {
108
- dv , err := newDSSEVerifier (v , options .WithCryptoSignerOpts (h ))
109
- if err != nil {
110
- return nil , err
111
- }
112
-
113
- vs = append (vs , dv )
89
+ vs = append (vs , wrappedVerifier {
90
+ Verifier : v ,
91
+ keys : & vr .keys ,
92
+ })
114
93
}
115
94
116
- v , err := dsse . NewMultiEnvelopeVerifier ( de . threshold , vs ... )
95
+ raw , err := io . ReadAll ( r )
117
96
if err != nil {
118
97
return nil , err
119
98
}
120
99
121
- var e dsse.Envelope
122
- if err := json .NewDecoder (r ).Decode (& e ); err != nil {
123
- return nil , err
124
- }
100
+ v := dsse .WrapMultiVerifier (metadataMediaType , 1 , vs ... )
125
101
126
- vr .aks , err = v .Verify (ctx , & e )
127
- if err != nil {
102
+ if err := v .VerifySignature (bytes .NewReader (raw ), nil , options .WithContext (ctx ), options .WithHash (h )); err != nil {
128
103
return nil , fmt .Errorf ("%w: %w" , errDSSEVerifyEnvelopeFailed , err )
129
104
}
130
105
131
- if e .PayloadType != de .payloadType {
132
- return nil , fmt .Errorf ("%w: %v" , errDSSEUnexpectedPayloadType , e .PayloadType )
133
- }
134
-
135
- return e .DecodeB64Payload ()
136
- }
137
-
138
- type dsseSigner struct {
139
- s signature.Signer
140
- opts []signature.SignOption
141
- pub crypto.PublicKey
142
- }
143
-
144
- // newDSSESigner returns a dsse.Signer that uses s to sign according to opts.
145
- func newDSSESigner (s signature.Signer , opts ... signature.SignOption ) (* dsseSigner , error ) {
146
- pub , err := s .PublicKey ()
147
- if err != nil {
106
+ var e dsseEnvelope
107
+ if err := json .Unmarshal (raw , & e ); err != nil {
148
108
return nil , err
149
109
}
150
110
151
- return & dsseSigner {
152
- s : s ,
153
- opts : opts ,
154
- pub : pub ,
155
- }, nil
156
- }
157
-
158
- // Sign signs the supplied data.
159
- func (s * dsseSigner ) Sign (ctx context.Context , data []byte ) ([]byte , error ) {
160
- opts := s .opts
161
- opts = append (opts , options .WithContext (ctx ))
111
+ if e .PayloadType != metadataMediaType {
112
+ return nil , fmt .Errorf ("%w: %v" , errDSSEUnexpectedPayloadType , e .PayloadType )
113
+ }
162
114
163
- return s . s . SignMessage ( bytes . NewReader ( data ), opts ... )
115
+ return e . DecodedPayload ( )
164
116
}
165
117
166
- // KeyID returns the key ID associated with s.
167
- func ( s dsseSigner ) KeyID () ( string , error ) {
168
- return dsse . SHA256KeyID ( s . pub )
118
+ type wrappedVerifier struct {
119
+ signature. Verifier
120
+ keys * []crypto. PublicKey
169
121
}
170
122
171
- type dsseVerifier struct {
172
- v signature.Verifier
173
- opts []signature.VerifyOption
174
- pub crypto.PublicKey
175
- }
123
+ func (wv wrappedVerifier ) VerifySignature (signature , message io.Reader , opts ... signature.VerifyOption ) error {
124
+ err := wv .Verifier .VerifySignature (signature , message , opts ... )
125
+ if err == nil {
126
+ pub , err := wv .Verifier .PublicKey ()
127
+ if err != nil {
128
+ return err
129
+ }
176
130
177
- // newDSSEVerifier returns a dsse.Verifier that uses v to verify according to opts.
178
- func newDSSEVerifier (v signature.Verifier , opts ... signature.VerifyOption ) (* dsseVerifier , error ) {
179
- pub , err := v .PublicKey ()
180
- if err != nil {
181
- return nil , err
131
+ * wv .keys = append (* wv .keys , pub )
182
132
}
183
-
184
- return & dsseVerifier {
185
- v : v ,
186
- opts : opts ,
187
- pub : pub ,
188
- }, nil
189
- }
190
-
191
- // Verify verifies that sig is a valid signature of data.
192
- func (v * dsseVerifier ) Verify (ctx context.Context , data , sig []byte ) error {
193
- opts := v .opts
194
- opts = append (opts , options .WithContext (ctx ))
195
-
196
- return v .v .VerifySignature (bytes .NewReader (sig ), bytes .NewReader (data ), opts ... )
133
+ return err
197
134
}
198
135
199
- // Public returns the public key associated with v.
200
- func (v * dsseVerifier ) Public () crypto.PublicKey {
201
- return v .pub
136
+ // dsseEnvelope describes a DSSE envelope.
137
+ type dsseEnvelope struct {
138
+ PayloadType string `json:"payloadType"`
139
+ Payload string `json:"payload"`
140
+ Signatures []struct {
141
+ KeyID string `json:"keyid"`
142
+ Sig string `json:"sig"`
143
+ } `json:"signatures"`
202
144
}
203
145
204
- // KeyID returns the key ID associated with v.
205
- func (v * dsseVerifier ) KeyID () (string , error ) {
206
- return dsse .SHA256KeyID (v .pub )
146
+ // DecodedPayload returns the decoded payload from envelope e.
147
+ func (e * dsseEnvelope ) DecodedPayload () ([]byte , error ) {
148
+ b , err := base64 .StdEncoding .DecodeString (e .Payload )
149
+ if err != nil {
150
+ return base64 .URLEncoding .DecodeString (e .Payload )
151
+ }
152
+ return b , nil
207
153
}
208
154
209
155
// isDSSESignature returns true if r contains a signature in a DSSE envelope.
210
156
func isDSSESignature (r io.Reader ) bool {
211
- var e dsse. Envelope
157
+ var e dsseEnvelope
212
158
if err := json .NewDecoder (r ).Decode (& e ); err != nil {
213
159
return false
214
160
}
0 commit comments