Skip to content

Commit

Permalink
Reorganize verify-blob code and add a unit test (#1286)
Browse files Browse the repository at this point in the history
Signed-off-by: Priya Wadhwa <priyawadhwa@google.com>
  • Loading branch information
priyawadhwa authored Jan 7, 2022
1 parent 419be8a commit b9d0d4a
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 54 deletions.
146 changes: 92 additions & 54 deletions cmd/cosign/cli/verify/verify_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,38 +55,18 @@ func isb64(data []byte) bool {
// nolint
func VerifyBlobCmd(ctx context.Context, ko sign.KeyOpts, certRef, sigRef, blobRef string) error {
var pubKey sigstoresigs.Verifier
var err error
var cert *x509.Certificate

if !options.OneOf(ko.KeyRef, ko.Sk, certRef) && !options.EnableExperimental() {
return &options.PubKeyParseError{}
}

var b64sig string
if sigRef == "" {
return fmt.Errorf("missing flag '--signature'")
}
targetSig, err := blob.LoadFileOrURL(sigRef)
sig, b64sig, err := signatures(sigRef)
if err != nil {
if !os.IsNotExist(err) {
// ignore if file does not exist, it can be a base64 encoded string as well
return err
}
targetSig = []byte(sigRef)
}

if isb64(targetSig) {
b64sig = string(targetSig)
} else {
b64sig = base64.StdEncoding.EncodeToString(targetSig)
return err
}

var blobBytes []byte
if blobRef == "-" {
blobBytes, err = io.ReadAll(os.Stdin)
} else {
blobBytes, err = blob.LoadFileOrURL(blobRef)
}
blobBytes, err := payloadBytes(blobRef)
if err != nil {
return err
}
Expand Down Expand Up @@ -148,53 +128,111 @@ func VerifyBlobCmd(ctx context.Context, ko sign.KeyOpts, certRef, sigRef, blobRe
}
}

sig, err := base64.StdEncoding.DecodeString(b64sig)
if err != nil {
// verify the signature
if err := pubKey.VerifySignature(bytes.NewReader([]byte(sig)), bytes.NewReader(blobBytes)); err != nil {
return err
}
if err := pubKey.VerifySignature(bytes.NewReader(sig), bytes.NewReader(blobBytes)); err != nil {

// verify the cert
if err := verifyCert(cert); err != nil {
return err
}

if cert != nil { // cert
if err := cosign.TrustedCert(cert, fulcio.GetRoots()); err != nil {
return err
}
fmt.Fprintln(os.Stderr, "Certificate is trusted by Fulcio Root CA")
fmt.Fprintln(os.Stderr, "Email:", cert.EmailAddresses)
for _, uri := range cert.URIs {
fmt.Fprintf(os.Stderr, "URI: %s://%s%s\n", uri.Scheme, uri.Host, uri.Path)
}
fmt.Fprintln(os.Stderr, "Issuer: ", sigs.CertIssuerExtension(cert))
// verify the rekor entry
if err := verifyRekorEntry(ctx, ko, pubKey, cert, b64sig, blobBytes); err != nil {
return err
}

fmt.Fprintln(os.Stderr, "Verified OK")
return nil
}

if options.EnableExperimental() {
rekorClient, err := rekor.NewClient(ko.RekorURL)
// signatures returns the raw signature and the base64 encoded signature
func signatures(sigRef string) (string, string, error) {
var targetSig []byte
var err error
switch {
case sigRef != "":
targetSig, err = blob.LoadFileOrURL(sigRef)
if err != nil {
return err
}
var pubBytes []byte
if pubKey != nil {
pubBytes, err = sigs.PublicKeyPem(pubKey, signatureoptions.WithContext(ctx))
if err != nil {
return err
if !os.IsNotExist(err) {
// ignore if file does not exist, it can be a base64 encoded string as well
return "", "", err
}
targetSig = []byte(sigRef)
}
if cert != nil {
pubBytes, err = cryptoutils.MarshalCertificateToPEM(cert)
if err != nil {
return err
}
default:
return "", "", fmt.Errorf("missing flag '--signature'")
}

var sig, b64sig string
if isb64(targetSig) {
b64sig = string(targetSig)
sigBytes, _ := base64.StdEncoding.DecodeString(b64sig)
sig = string(sigBytes)
} else {
sig = string(targetSig)
b64sig = base64.StdEncoding.EncodeToString(targetSig)
}
return sig, b64sig, nil
}

func payloadBytes(blobRef string) ([]byte, error) {
var blobBytes []byte
var err error
if blobRef == "-" {
blobBytes, err = io.ReadAll(os.Stdin)
} else {
blobBytes, err = blob.LoadFileOrURL(blobRef)
}
if err != nil {
return nil, err
}
return blobBytes, nil
}

func verifyCert(cert *x509.Certificate) error {
if cert == nil {
return nil
}
if err := cosign.TrustedCert(cert, fulcio.GetRoots()); err != nil {
return err
}
fmt.Fprintln(os.Stderr, "Certificate is trusted by Fulcio Root CA")
fmt.Fprintln(os.Stderr, "Email:", cert.EmailAddresses)
for _, uri := range cert.URIs {
fmt.Fprintf(os.Stderr, "URI: %s://%s%s\n", uri.Scheme, uri.Host, uri.Path)
}
fmt.Fprintln(os.Stderr, "Issuer: ", sigs.CertIssuerExtension(cert))
return nil
}

func verifyRekorEntry(ctx context.Context, ko sign.KeyOpts, pubKey sigstoresigs.Verifier, cert *x509.Certificate, b64sig string, blobBytes []byte) error {
if !options.EnableExperimental() {
return nil
}
rekorClient, err := rekor.NewClient(ko.RekorURL)
if err != nil {
return err
}
var pubBytes []byte
if pubKey != nil {
pubBytes, err = sigs.PublicKeyPem(pubKey, signatureoptions.WithContext(ctx))
if err != nil {
return err
}
uuid, index, err := cosign.FindTlogEntry(ctx, rekorClient, b64sig, blobBytes, pubBytes)
}
if cert != nil {
pubBytes, err = cryptoutils.MarshalCertificateToPEM(cert)
if err != nil {
return err
}
fmt.Fprintf(os.Stderr, "tlog entry verified with uuid: %q index: %d\n", uuid, index)
return nil
}

uuid, index, err := cosign.FindTlogEntry(ctx, rekorClient, b64sig, blobBytes, pubBytes)
if err != nil {
return err
}
fmt.Fprintf(os.Stderr, "tlog entry verified with uuid: %q index: %d\n", uuid, index)
return nil
}

Expand Down
59 changes: 59 additions & 0 deletions cmd/cosign/cli/verify/verify_blob_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2022 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 verify

import (
"testing"
)

func TestSignatures(t *testing.T) {
sig := "a=="
b64sig := "YT09"
tests := []struct {
description string
sigRef string
shouldErr bool
}{
{
description: "raw sig",
sigRef: sig,
},
{
description: "encoded sig",
sigRef: b64sig,
}, {
description: "empty ref",
shouldErr: true,
},
}

for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
gotSig, gotb64Sig, err := signatures(test.sigRef)
if test.shouldErr && err != nil {
return
}
if test.shouldErr {
t.Fatal("should have received an error")
}
if gotSig != sig {
t.Fatalf("unexpected signature, expected: %s got: %s", sig, gotSig)
}
if gotb64Sig != b64sig {
t.Fatalf("unexpected encoded signature, expected: %s got: %s", b64sig, gotb64Sig)
}
})
}
}

0 comments on commit b9d0d4a

Please sign in to comment.