Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions pkg/verify/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"time"

"golang.org/x/crypto/openpgp"
"k8s.io/apimachinery/pkg/util/errors"
"k8s.io/klog/v2"

"github.com/openshift/library-go/pkg/verify/store"
Expand All @@ -43,6 +44,19 @@ type Interface interface {
AddStore(additionalStore store.Store)
}

type wrapError struct {
msg string
err error
}

func (e *wrapError) Error() string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/Error()/ErrorStr()/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrapError is from Go, because I wanted fmt.Sprintf("...%w")'s Unwrap support, but without formatting the whole, possibly long aggregate error into the message. We need to use Error and Unwrap to match the error interface.

return e.msg
}

func (e *wrapError) Unwrap() error {
return e.err
}

type rejectVerifier struct{}

func (rejectVerifier) Verify(ctx context.Context, releaseDigest string) error {
Expand Down Expand Up @@ -171,19 +185,23 @@ func (v *releaseVerifier) Verify(ctx context.Context, releaseDigest string) erro
}

var signedWith [][]byte
var errs []error
err := v.store.Signatures(ctx, "", releaseDigest, func(ctx context.Context, signature []byte, errIn error) (done bool, err error) {
if errIn != nil {
klog.V(4).Infof("error retrieving signature for %s: %v", releaseDigest, errIn)
errs = append(errs, errIn)
return false, nil
}
for k, keyring := range remaining {
content, _, err := verifySignatureWithKeyring(bytes.NewReader(signature), keyring)
if err != nil {
klog.V(4).Infof("keyring %q could not verify signature for %s: %v", k, releaseDigest, err)
errs = append(errs, err)
continue
}
if err := verifyAtomicContainerSignature(content, releaseDigest); err != nil {
klog.V(4).Infof("signature for %s is not valid: %v", releaseDigest, err)
errs = append(errs, err)
continue
}
delete(remaining, k)
Expand All @@ -193,16 +211,21 @@ func (v *releaseVerifier) Verify(ctx context.Context, releaseDigest string) erro
})
if err != nil {
klog.V(4).Infof("Failed to retrieve signatures for %s (should never happen)", releaseDigest)
errs = append(errs, err)
return err
}

if len(remaining) > 0 {
if klog.V(4).Enabled() {
for k := range remaining {
klog.Infof("Unable to verify %s against keyring %s", releaseDigest, k)
}
remainingKeyRings := make([]string, 0, len(remaining))
for k := range remaining {
remainingKeyRings = append(remainingKeyRings, k)
}
return fmt.Errorf("unable to locate a valid signature for one or more sources")
err := &wrapError{
msg: fmt.Sprintf("unable to verify %s against keyrings: %s", releaseDigest, strings.Join(remainingKeyRings, ", ")),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we are logging the keys too. I am wondering if it is fine from security point of view>

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're logging the keyring name, which is already public in our GitHub source. The only secret keys here are internal to Red Hat's build-time release signing. By the time we get out to clusters verifying signatures, it's all public names and public keys.

err: errors.NewAggregate(errs),
}
klog.V(4).Info(err.Error())
return err
}

v.cacheVerification(releaseDigest, signedWith)
Expand Down
2 changes: 1 addition & 1 deletion pkg/verify/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ func Test_ReleaseVerifier_Signatures(t *testing.T) {
store: &memory.Store{},
signatureCache: make(map[string][][]byte),
}
if err := verifier.Verify(context.Background(), signedDigest); err == nil || err.Error() != "unable to locate a valid signature for one or more sources" {
if err := verifier.Verify(context.Background(), signedDigest); err == nil || err.Error() != fmt.Sprintf("unable to verify %s against keyrings: redhat", signedDigest) {
t.Fatal(err)
}
if sigs := verifier.Signatures(); len(sigs) != 0 {
Expand Down