diff --git a/pkg/cosign/tlog.go b/pkg/cosign/tlog.go index b3f60db980c..aae44ea6ce1 100644 --- a/pkg/cosign/tlog.go +++ b/pkg/cosign/tlog.go @@ -145,20 +145,42 @@ func GetTlogEntry(rekorClient *client.Rekor, uuid string) (*models.LogEntryAnon, return nil, errors.New("empty response") } +func proposedEntry(b64Sig string, payload, pubKey []byte) ([]models.ProposedEntry, error) { + var proposedEntry []models.ProposedEntry + signature, err := base64.StdEncoding.DecodeString(b64Sig) + if err != nil { + return nil, errors.Wrap(err, "decoding base64 signature") + } + + // The fact that there's no signature (or empty rather), implies + // that this is an Attestation that we're verifying. + if len(signature) == 0 { + te := intotoEntry(payload, pubKey) + entry := &models.Intoto{ + APIVersion: swag.String(te.APIVersion()), + Spec: te.IntotoObj, + } + proposedEntry = []models.ProposedEntry{entry} + } else { + re := rekorEntry(payload, signature, pubKey) + entry := &models.Rekord{ + APIVersion: swag.String(re.APIVersion()), + Spec: re.RekordObj, + } + proposedEntry = []models.ProposedEntry{entry} + } + return proposedEntry, nil +} + func FindTlogEntry(rekorClient *client.Rekor, b64Sig string, payload, pubKey []byte) (uuid string, index int64, err error) { searchParams := entries.NewSearchLogQueryParams() searchLogQuery := models.SearchLogQuery{} - signature, err := base64.StdEncoding.DecodeString(b64Sig) + proposedEntry, err := proposedEntry(b64Sig, payload, pubKey) if err != nil { - return "", 0, errors.Wrap(err, "decoding base64 signature") - } - re := rekorEntry(payload, signature, pubKey) - entry := &models.Rekord{ - APIVersion: swag.String(re.APIVersion()), - Spec: re.RekordObj, + return "", 0, err } - searchLogQuery.SetEntries([]models.ProposedEntry{entry}) + searchLogQuery.SetEntries(proposedEntry) searchParams.SetEntry(&searchLogQuery) resp, err := rekorClient.Entries.SearchLogQuery(searchParams) diff --git a/pkg/cosign/verify.go b/pkg/cosign/verify.go index b0dfe9fd542..4fe88b039c0 100644 --- a/pkg/cosign/verify.go +++ b/pkg/cosign/verify.go @@ -22,6 +22,7 @@ import ( "crypto/sha256" "crypto/x509" "encoding/base64" + "encoding/hex" "encoding/json" "fmt" "io" @@ -37,6 +38,7 @@ import ( ociremote "github.com/sigstore/cosign/pkg/oci/remote" rekor "github.com/sigstore/rekor/pkg/client" "github.com/sigstore/rekor/pkg/generated/client" + "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/dsse" @@ -426,9 +428,73 @@ func VerifyBundle(sig oci.Signature) (bool, error) { if err := checkExpiry(cert, time.Unix(bundle.Payload.IntegratedTime, 0)); err != nil { return false, errors.Wrap(err, "checking expiry on cert") } + + payload, err := sig.Payload() + if err != nil { + return false, errors.Wrap(err, "reading payload") + } + signature, err := sig.Base64Signature() + if err != nil { + return false, errors.Wrap(err, "reading base64signature") + } + + alg, bundlehash, err := bundleHash(bundle.Payload.Body.(string), signature) + h := sha256.Sum256(payload) + payloadHash := hex.EncodeToString(h[:]) + + if alg != "sha256" || bundlehash != payloadHash { + return false, errors.Wrap(err, "matching bundle to payload") + } return true, nil } +func bundleHash(bundleBody, signature string) (string, string, error) { + var toto models.Intoto + var rekord models.Rekord + var intotoObj models.IntotoV001Schema + var rekordObj models.RekordV001Schema + + bodyDecoded, err := base64.StdEncoding.DecodeString(bundleBody) + if err != nil { + return "", "", err + } + + // The fact that there's no signature (or empty rather), implies + // that this is an Attestation that we're verifying. + if len(signature) == 0 { + err = json.Unmarshal(bodyDecoded, &toto) + if err != nil { + return "", "", err + } + + specMarshal, err := json.Marshal(toto.Spec) + if err != nil { + return "", "", err + } + err = json.Unmarshal(specMarshal, &intotoObj) + if err != nil { + return "", "", err + } + + return *intotoObj.Content.Hash.Algorithm, *intotoObj.Content.Hash.Value, nil + } + + err = json.Unmarshal(bodyDecoded, &rekord) + if err != nil { + return "", "", err + } + + specMarshal, err := json.Marshal(rekord.Spec) + if err != nil { + return "", "", err + } + err = json.Unmarshal(specMarshal, &rekordObj) + if err != nil { + return "", "", err + } + return *rekordObj.Data.Hash.Algorithm, *rekordObj.Data.Hash.Value, nil +} + func VerifySET(bundlePayload oci.BundlePayload, signature []byte, pub *ecdsa.PublicKey) error { contents, err := json.Marshal(bundlePayload) if err != nil {