Skip to content

Commit fe1a39e

Browse files
author
dlorenc
authored
Refactor the way certs are handled. (#457)
Remove duplication between sign and sign-blob. Signed-off-by: Dan Lorenc <[email protected]>
1 parent d08c803 commit fe1a39e

File tree

2 files changed

+114
-125
lines changed

2 files changed

+114
-125
lines changed

cmd/cosign/cli/sign.go

Lines changed: 107 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ import (
4141

4242
"github.com/sigstore/cosign/pkg/cosign"
4343
"github.com/sigstore/cosign/pkg/cosign/fulcio"
44+
"github.com/sigstore/cosign/pkg/cosign/pivkey"
4445
cremote "github.com/sigstore/cosign/pkg/cosign/remote"
4546
"github.com/sigstore/rekor/pkg/generated/models"
4647

47-
"github.com/sigstore/cosign/pkg/cosign/pivkey"
4848
rekorClient "github.com/sigstore/rekor/pkg/client"
4949
"github.com/sigstore/sigstore/pkg/signature"
5050
"github.com/sigstore/sigstore/pkg/signature/options"
@@ -223,86 +223,9 @@ func SignCmd(ctx context.Context, ko KeyOpts, annotations map[string]interface{}
223223
}
224224
toSign = append(toSign, imgs...)
225225
}
226-
227-
var signerVerifier signature.SignerVerifier
228-
var cert, chain string
229-
switch {
230-
case ko.Sk:
231-
sk, err := pivkey.GetKeyWithSlot(ko.Slot)
232-
defer sk.Close()
233-
if err != nil {
234-
return err
235-
}
236-
sv, err := sk.SignerVerifier()
237-
if err != nil {
238-
return err
239-
}
240-
signerVerifier = sv
241-
242-
// Handle the -cert flag.
243-
// With PIV, we assume the certificate is in the same slot on the PIV
244-
// token as the private key. If it's not there, show a warning to the
245-
// user.
246-
certFromPIV, err := sk.Certificate()
247-
if err != nil {
248-
fmt.Fprintln(os.Stderr, "warning: no x509 certificate retrieved from the PIV token")
249-
break
250-
}
251-
cert = string(cosign.CertToPem(certFromPIV))
252-
253-
case ko.KeyRef != "":
254-
k, err := signerVerifierFromKeyRef(ctx, ko.KeyRef, ko.PassFunc)
255-
if err != nil {
256-
return errors.Wrap(err, "reading key")
257-
}
258-
signerVerifier = k
259-
260-
// Handle the -cert flag
261-
if certPath == "" {
262-
break
263-
}
264-
certBytes, err := ioutil.ReadFile(certPath)
265-
if err != nil {
266-
return errors.Wrap(err, "read certificate")
267-
}
268-
// Handle PEM.
269-
if bytes.HasPrefix(certBytes, []byte("-----")) {
270-
decoded, _ := pem.Decode(certBytes)
271-
if decoded.Type != "CERTIFICATE" {
272-
return fmt.Errorf("supplied PEM file is not a certificate: %s", certPath)
273-
}
274-
certBytes = decoded.Bytes
275-
}
276-
parsedCert, err := x509.ParseCertificate(certBytes)
277-
if err != nil {
278-
return errors.Wrap(err, "parse x509 certificate")
279-
}
280-
pk, err := k.PublicKey()
281-
if err != nil {
282-
return errors.Wrap(err, "get public key")
283-
}
284-
switch kt := parsedCert.PublicKey.(type) {
285-
case *ecdsa.PublicKey:
286-
if !kt.Equal(pk) {
287-
return errors.New("public key in certificate does not match that in the signing key")
288-
}
289-
case *rsa.PublicKey:
290-
if !kt.Equal(pk) {
291-
return errors.New("public key in certificate does not match that in the signing key")
292-
}
293-
default:
294-
return fmt.Errorf("unsupported key type: %T", parsedCert.PublicKey)
295-
}
296-
cert = string(cosign.CertToPem(parsedCert))
297-
298-
default: // Keyless!
299-
fmt.Fprintln(os.Stderr, "Generating ephemeral keys...")
300-
k, err := fulcio.NewSigner(ctx, ko.IDToken)
301-
if err != nil {
302-
return errors.Wrap(err, "getting key from Fulcio")
303-
}
304-
signerVerifier = k
305-
cert, chain = k.Cert, k.Chain
226+
sv, err := signerFromKeyOpts(ctx, certPath, ko)
227+
if err != nil {
228+
return errors.Wrap(err, "getting signer")
306229
}
307230

308231
// Check if the image is public (no auth in Get)
@@ -325,10 +248,10 @@ func SignCmd(ctx context.Context, ko KeyOpts, annotations map[string]interface{}
325248
var rekorBytes []byte
326249
if uploadTLog {
327250
// Upload the cert or the public key, depending on what we have
328-
if cert != "" {
329-
rekorBytes = []byte(cert)
251+
if sv.Cert != "" {
252+
rekorBytes = []byte(sv.Cert)
330253
} else {
331-
pemBytes, err := cosign.PublicKeyPem(signerVerifier, options.WithContext(ctx))
254+
pemBytes, err := cosign.PublicKeyPem(sv, options.WithContext(ctx))
332255
if err != nil {
333256
return err
334257
}
@@ -360,7 +283,7 @@ func SignCmd(ctx context.Context, ko KeyOpts, annotations map[string]interface{}
360283
}
361284
}
362285

363-
sig, err := signerVerifier.SignMessage(bytes.NewReader(payload), options.WithContext(ctx))
286+
sig, err := sv.SignMessage(bytes.NewReader(payload), options.WithContext(ctx))
364287
if err != nil {
365288
return errors.Wrap(err, "signing")
366289
}
@@ -385,9 +308,9 @@ func SignCmd(ctx context.Context, ko KeyOpts, annotations map[string]interface{}
385308
}, cosign.SuffixSignature)
386309

387310
uo := cremote.UploadOpts{
388-
Cert: cert,
389-
Chain: chain,
390-
DupeDetector: signerVerifier,
311+
Cert: sv.Cert,
312+
Chain: sv.Chain,
313+
DupeDetector: sv,
391314
RemoteOpts: remoteOpts,
392315
}
393316

@@ -438,3 +361,99 @@ func parseAnnotations(entry *models.LogEntryAnon) map[string]string {
438361
}
439362
return annts
440363
}
364+
365+
func signerFromKeyOpts(ctx context.Context, certPath string, ko KeyOpts) (*certSignVerifier, error) {
366+
switch {
367+
case ko.Sk:
368+
sk, err := pivkey.GetKeyWithSlot(ko.Slot)
369+
defer sk.Close()
370+
if err != nil {
371+
return nil, err
372+
}
373+
sv, err := sk.SignerVerifier()
374+
if err != nil {
375+
return nil, err
376+
}
377+
378+
// Handle the -cert flag.
379+
// With PIV, we assume the certificate is in the same slot on the PIV
380+
// token as the private key. If it's not there, show a warning to the
381+
// user.
382+
certFromPIV, err := sk.Certificate()
383+
if err != nil {
384+
fmt.Fprintln(os.Stderr, "warning: no x509 certificate retrieved from the PIV token")
385+
break
386+
}
387+
cert := string(cosign.CertToPem(certFromPIV))
388+
return &certSignVerifier{
389+
Cert: cert,
390+
SignerVerifier: sv,
391+
}, nil
392+
393+
case ko.KeyRef != "":
394+
k, err := signerVerifierFromKeyRef(ctx, ko.KeyRef, ko.PassFunc)
395+
if err != nil {
396+
return nil, errors.Wrap(err, "reading key")
397+
}
398+
399+
certSigner := &certSignVerifier{
400+
SignerVerifier: k,
401+
}
402+
// Handle the -cert flag
403+
if certPath == "" {
404+
return certSigner, nil
405+
}
406+
407+
certBytes, err := ioutil.ReadFile(certPath)
408+
if err != nil {
409+
return nil, errors.Wrap(err, "read certificate")
410+
}
411+
// Handle PEM.
412+
if bytes.HasPrefix(certBytes, []byte("-----")) {
413+
decoded, _ := pem.Decode(certBytes)
414+
if decoded.Type != "CERTIFICATE" {
415+
return nil, fmt.Errorf("supplied PEM file is not a certificate: %s", certPath)
416+
}
417+
certBytes = decoded.Bytes
418+
}
419+
parsedCert, err := x509.ParseCertificate(certBytes)
420+
if err != nil {
421+
return nil, errors.Wrap(err, "parse x509 certificate")
422+
}
423+
pk, err := k.PublicKey()
424+
if err != nil {
425+
return nil, errors.Wrap(err, "get public key")
426+
}
427+
switch kt := parsedCert.PublicKey.(type) {
428+
case *ecdsa.PublicKey:
429+
if !kt.Equal(pk) {
430+
return nil, errors.New("public key in certificate does not match that in the signing key")
431+
}
432+
case *rsa.PublicKey:
433+
if !kt.Equal(pk) {
434+
return nil, errors.New("public key in certificate does not match that in the signing key")
435+
}
436+
default:
437+
return nil, fmt.Errorf("unsupported key type: %T", parsedCert.PublicKey)
438+
}
439+
certSigner.Cert = string(cosign.CertToPem(parsedCert))
440+
return certSigner, nil
441+
}
442+
// Default Keyless!
443+
fmt.Fprintln(os.Stderr, "Generating ephemeral keys...")
444+
k, err := fulcio.NewSigner(ctx, ko.IDToken)
445+
if err != nil {
446+
return nil, errors.Wrap(err, "getting key from Fulcio")
447+
}
448+
return &certSignVerifier{
449+
Cert: k.Cert,
450+
Chain: k.Chain,
451+
SignerVerifier: k,
452+
}, nil
453+
}
454+
455+
type certSignVerifier struct {
456+
Cert string
457+
Chain string
458+
signature.SignerVerifier
459+
}

cmd/cosign/cli/sign_blob.go

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,12 @@ import (
2525
"os"
2626
"path/filepath"
2727

28-
"github.com/sigstore/sigstore/pkg/signature"
2928
"github.com/sigstore/sigstore/pkg/signature/options"
3029

3130
"github.com/peterbourgon/ff/v3/ffcli"
3231
"github.com/pkg/errors"
3332

3433
"github.com/sigstore/cosign/pkg/cosign"
35-
"github.com/sigstore/cosign/pkg/cosign/fulcio"
36-
"github.com/sigstore/cosign/pkg/cosign/pivkey"
3734
rekorClient "github.com/sigstore/rekor/pkg/client"
3835
)
3936

@@ -121,50 +118,23 @@ func SignBlobCmd(ctx context.Context, ko KeyOpts, payloadPath string, b64 bool,
121118
return nil, err
122119
}
123120

124-
var cert string
125-
var signer signature.Signer
126-
switch {
127-
case ko.KeyRef != "":
128-
k, err := signerFromKeyRef(ctx, ko.KeyRef, ko.PassFunc)
129-
if err != nil {
130-
return nil, errors.Wrap(err, "loading key")
131-
}
132-
signer = k
133-
case ko.Sk:
134-
sk, err := pivkey.GetKeyWithSlot(ko.Slot)
135-
if err != nil {
136-
return nil, errors.Wrap(err, "opening piv token")
137-
}
138-
defer sk.Close()
139-
k, err := sk.SignerVerifier()
140-
if err != nil {
141-
return nil, errors.Wrap(err, "initializing signer on piv token")
142-
}
143-
signer = k
144-
default:
145-
// Keyless!
146-
fmt.Fprintln(os.Stderr, "Generating ephemeral keys...")
147-
k, err := fulcio.NewSigner(ctx, ko.IDToken)
148-
if err != nil {
149-
return nil, errors.Wrap(err, "getting key from Fulcio")
150-
}
151-
signer = k
152-
cert = k.Cert
153-
fmt.Fprintf(os.Stderr, "Signing with certificate:\n%s\n", cert)
121+
sv, err := signerFromKeyOpts(ctx, "", ko)
122+
if err != nil {
123+
return nil, err
154124
}
155125

156-
sig, err := signer.SignMessage(bytes.NewReader(payload), options.WithContext(ctx))
126+
sig, err := sv.SignMessage(bytes.NewReader(payload), options.WithContext(ctx))
157127
if err != nil {
158128
return nil, errors.Wrap(err, "signing blob")
159129
}
160130

161131
if EnableExperimental() {
162132
// TODO: Refactor with sign.go
163133
var rekorBytes []byte
164-
if cert != "" {
165-
rekorBytes = []byte(cert)
134+
if sv.Cert != "" {
135+
rekorBytes = []byte(sv.Cert)
166136
} else {
167-
pemBytes, err := cosign.PublicKeyPem(signer, options.WithContext(ctx))
137+
pemBytes, err := cosign.PublicKeyPem(sv, options.WithContext(ctx))
168138
if err != nil {
169139
return nil, err
170140
}

0 commit comments

Comments
 (0)