-
Notifications
You must be signed in to change notification settings - Fork 547
/
sig.go
140 lines (121 loc) · 3.38 KB
/
sig.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//
// Copyright 2021 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package attach
import (
"context"
"errors"
"io"
"os"
"path/filepath"
"github.com/google/go-containerregistry/pkg/name"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
"github.com/sigstore/cosign/v2/pkg/cosign"
"github.com/sigstore/cosign/v2/pkg/oci/mutate"
ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote"
"github.com/sigstore/cosign/v2/pkg/oci/static"
)
func SignatureCmd(ctx context.Context, regOpts options.RegistryOptions, sigRef, payloadRef, certRef, certChainRef, imageRef string) error {
b64SigBytes, err := signatureBytes(sigRef)
if err != nil {
return err
} else if len(b64SigBytes) == 0 {
return errors.New("empty signature")
}
ref, err := name.ParseReference(imageRef, regOpts.NameOptions()...)
if err != nil {
return err
}
ociremoteOpts, err := regOpts.ClientOpts(ctx)
if err != nil {
return err
}
digest, err := ociremote.ResolveDigest(ref, ociremoteOpts...)
if err != nil {
return err
}
// Overwrite "ref" with a digest to avoid a race where we use a tag
// multiple times, and it potentially points to different things at
// each access.
ref = digest // nolint
var payload []byte
if payloadRef == "" {
payload, err = cosign.ObsoletePayload(ctx, digest)
} else {
payload, err = os.ReadFile(filepath.Clean(payloadRef))
}
if err != nil {
return err
}
sig, err := static.NewSignature(payload, string(b64SigBytes))
if err != nil {
return err
}
var cert []byte
var certChain []byte
if certRef != "" {
cert, err = os.ReadFile(filepath.Clean(certRef))
if err != nil {
return err
}
}
if certChainRef != "" {
certChain, err = os.ReadFile(filepath.Clean(certChainRef))
if err != nil {
return err
}
}
newSig, err := mutate.Signature(sig, mutate.WithCertChain(cert, certChain))
if err != nil {
return err
}
se, err := ociremote.SignedEntity(digest, ociremoteOpts...)
if err != nil {
return err
}
// Attach the signature to the entity.
newSE, err := mutate.AttachSignatureToEntity(se, newSig)
if err != nil {
return err
}
// Publish the signatures associated with this entity
return ociremote.WriteSignatures(digest.Repository, newSE, ociremoteOpts...)
}
type SignatureArgType uint8
const (
StdinSignature SignatureArgType = iota
RawSignature SignatureArgType = iota
FileSignature SignatureArgType = iota
)
func signatureBytes(sigRef string) ([]byte, error) {
// sigRef can be "-", a string or a file.
switch signatureType(sigRef) {
case StdinSignature:
return io.ReadAll(os.Stdin)
case RawSignature:
return []byte(sigRef), nil
case FileSignature:
return os.ReadFile(filepath.Clean(sigRef))
default:
return nil, errors.New("unknown signature arg type")
}
}
func signatureType(sigRef string) SignatureArgType {
switch {
case sigRef == "-":
return StdinSignature
default:
return FileSignature
}
}