Skip to content

Commit fc6a037

Browse files
committed
refactor: use DSSE wrappers from sigstore
1 parent d63ee14 commit fc6a037

13 files changed

+93
-164
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ require (
77
github.com/google/go-containerregistry v0.19.2
88
github.com/google/uuid v1.6.0
99
github.com/sebdah/goldie/v2 v2.5.3
10-
github.com/secure-systems-lab/go-securesystemslib v0.8.0
1110
github.com/sigstore/sigstore v1.8.4
1211
github.com/spf13/cobra v1.8.1
1312
github.com/spf13/pflag v1.0.5
@@ -20,6 +19,7 @@ require (
2019
github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e // indirect
2120
github.com/opencontainers/go-digest v1.0.0 // indirect
2221
github.com/pmezard/go-difflib v1.0.0 // indirect
22+
github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect
2323
github.com/sergi/go-diff v1.2.0 // indirect
2424
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
2525
golang.org/x/crypto v0.23.0 // indirect

pkg/integrity/dsse.go

+67-121
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2022-2023, Sylabs Inc. All rights reserved.
1+
// Copyright (c) 2022-2024, Sylabs Inc. All rights reserved.
22
// This software is licensed under a 3-clause BSD license. Please consult the LICENSE.md file
33
// distributed with the sources of this project regarding your rights to use or distribute this
44
// software.
@@ -9,27 +9,39 @@ import (
99
"bytes"
1010
"context"
1111
"crypto"
12+
"encoding/base64"
1213
"encoding/json"
1314
"errors"
1415
"fmt"
1516
"io"
1617

17-
"github.com/secure-systems-lab/go-securesystemslib/dsse"
1818
"github.com/sigstore/sigstore/pkg/signature"
19+
"github.com/sigstore/sigstore/pkg/signature/dsse"
1920
"github.com/sigstore/sigstore/pkg/signature/options"
2021
)
2122

2223
const metadataMediaType = "application/vnd.sylabs.sif-metadata+json"
2324

2425
type dsseEncoder struct {
25-
es *dsse.EnvelopeSigner
26-
h crypto.Hash
27-
payloadType string
26+
ss []signature.Signer
27+
opts []signature.SignOption
2828
}
2929

3030
// newDSSEEncoder returns an encoder that signs messages in DSSE format according to opts, with key
3131
// 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+
3345
var so crypto.SignerOpts
3446
for _, opt := range opts {
3547
opt.ApplyCryptoSignerOpts(&so)
@@ -41,57 +53,25 @@ func newDSSEEncoder(ss []signature.Signer, opts ...signature.SignOption) (*dsseE
4153
opts = append(opts, options.WithCryptoSignerOpts(so))
4254
}
4355

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...)
7558
if err != nil {
7659
return 0, err
7760
}
7861

79-
return en.h, json.NewEncoder(w).Encode(e)
62+
_, err = w.Write(b)
63+
return so.HashFunc(), err
8064
}
8165

8266
type dsseDecoder struct {
83-
vs []signature.Verifier
84-
threshold int
85-
payloadType string
67+
vs []signature.Verifier
8668
}
8769

8870
// newDSSEDecoder returns a decoder that verifies messages in DSSE format using key material from
8971
// vs.
9072
func newDSSEDecoder(vs ...signature.Verifier) *dsseDecoder {
9173
return &dsseDecoder{
92-
vs: vs,
93-
threshold: 1, // Envelope considered verified if at least one verifier succeeds.
94-
payloadType: metadataMediaType,
74+
vs: vs,
9575
}
9676
}
9777

@@ -103,112 +83,78 @@ var (
10383
// verifyMessage reads a message from r, verifies its signature(s), and returns the message
10484
// contents. On success, the accepted public keys are set in vr.
10585
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))
10788
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+
})
11493
}
11594

116-
v, err := dsse.NewMultiEnvelopeVerifier(de.threshold, vs...)
95+
raw, err := io.ReadAll(r)
11796
if err != nil {
11897
return nil, err
11998
}
12099

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...)
125101

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 {
128103
return nil, fmt.Errorf("%w: %w", errDSSEVerifyEnvelopeFailed, err)
129104
}
130105

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 {
148108
return nil, err
149109
}
150110

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+
}
162114

163-
return s.s.SignMessage(bytes.NewReader(data), opts...)
115+
return e.DecodedPayload()
164116
}
165117

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
169121
}
170122

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+
}
176130

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)
182132
}
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
197134
}
198135

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"`
202144
}
203145

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
207153
}
208154

209155
// isDSSESignature returns true if r contains a signature in a DSSE envelope.
210156
func isDSSESignature(r io.Reader) bool {
211-
var e dsse.Envelope
157+
var e dsseEnvelope
212158
if err := json.NewDecoder(r).Decode(&e); err != nil {
213159
return false
214160
}

0 commit comments

Comments
 (0)