Skip to content

Commit 5468ddc

Browse files
authored
Patch support attestation log search and bundle to payload hash check (#1030)
* Patch support attestation log search and bundle to payload hash check Signed-off-by: houdini91 <[email protected]> * Fix lint Signed-off-by: houdini91 <[email protected]> * Typo Signed-off-by: houdini91 <[email protected]> * PR fix Signed-off-by: houdini91 <[email protected]> * PR add comment Signed-off-by: houdini91 <[email protected]> * PR fix lint Signed-off-by: houdini91 <[email protected]>
1 parent fe00315 commit 5468ddc

File tree

2 files changed

+96
-8
lines changed

2 files changed

+96
-8
lines changed

pkg/cosign/tlog.go

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -145,20 +145,42 @@ func GetTlogEntry(rekorClient *client.Rekor, uuid string) (*models.LogEntryAnon,
145145
return nil, errors.New("empty response")
146146
}
147147

148+
func proposedEntry(b64Sig string, payload, pubKey []byte) ([]models.ProposedEntry, error) {
149+
var proposedEntry []models.ProposedEntry
150+
signature, err := base64.StdEncoding.DecodeString(b64Sig)
151+
if err != nil {
152+
return nil, errors.Wrap(err, "decoding base64 signature")
153+
}
154+
155+
// The fact that there's no signature (or empty rather), implies
156+
// that this is an Attestation that we're verifying.
157+
if len(signature) == 0 {
158+
te := intotoEntry(payload, pubKey)
159+
entry := &models.Intoto{
160+
APIVersion: swag.String(te.APIVersion()),
161+
Spec: te.IntotoObj,
162+
}
163+
proposedEntry = []models.ProposedEntry{entry}
164+
} else {
165+
re := rekorEntry(payload, signature, pubKey)
166+
entry := &models.Rekord{
167+
APIVersion: swag.String(re.APIVersion()),
168+
Spec: re.RekordObj,
169+
}
170+
proposedEntry = []models.ProposedEntry{entry}
171+
}
172+
return proposedEntry, nil
173+
}
174+
148175
func FindTlogEntry(rekorClient *client.Rekor, b64Sig string, payload, pubKey []byte) (uuid string, index int64, err error) {
149176
searchParams := entries.NewSearchLogQueryParams()
150177
searchLogQuery := models.SearchLogQuery{}
151-
signature, err := base64.StdEncoding.DecodeString(b64Sig)
178+
proposedEntry, err := proposedEntry(b64Sig, payload, pubKey)
152179
if err != nil {
153-
return "", 0, errors.Wrap(err, "decoding base64 signature")
154-
}
155-
re := rekorEntry(payload, signature, pubKey)
156-
entry := &models.Rekord{
157-
APIVersion: swag.String(re.APIVersion()),
158-
Spec: re.RekordObj,
180+
return "", 0, err
159181
}
160182

161-
searchLogQuery.SetEntries([]models.ProposedEntry{entry})
183+
searchLogQuery.SetEntries(proposedEntry)
162184

163185
searchParams.SetEntry(&searchLogQuery)
164186
resp, err := rekorClient.Entries.SearchLogQuery(searchParams)

pkg/cosign/verify.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"crypto/sha256"
2323
"crypto/x509"
2424
"encoding/base64"
25+
"encoding/hex"
2526
"encoding/json"
2627
"fmt"
2728
"io"
@@ -37,6 +38,7 @@ import (
3738
ociremote "github.com/sigstore/cosign/pkg/oci/remote"
3839
rekor "github.com/sigstore/rekor/pkg/client"
3940
"github.com/sigstore/rekor/pkg/generated/client"
41+
"github.com/sigstore/rekor/pkg/generated/models"
4042
"github.com/sigstore/sigstore/pkg/cryptoutils"
4143
"github.com/sigstore/sigstore/pkg/signature"
4244
"github.com/sigstore/sigstore/pkg/signature/dsse"
@@ -426,9 +428,73 @@ func VerifyBundle(sig oci.Signature) (bool, error) {
426428
if err := checkExpiry(cert, time.Unix(bundle.Payload.IntegratedTime, 0)); err != nil {
427429
return false, errors.Wrap(err, "checking expiry on cert")
428430
}
431+
432+
payload, err := sig.Payload()
433+
if err != nil {
434+
return false, errors.Wrap(err, "reading payload")
435+
}
436+
signature, err := sig.Base64Signature()
437+
if err != nil {
438+
return false, errors.Wrap(err, "reading base64signature")
439+
}
440+
441+
alg, bundlehash, err := bundleHash(bundle.Payload.Body.(string), signature)
442+
h := sha256.Sum256(payload)
443+
payloadHash := hex.EncodeToString(h[:])
444+
445+
if alg != "sha256" || bundlehash != payloadHash {
446+
return false, errors.Wrap(err, "matching bundle to payload")
447+
}
429448
return true, nil
430449
}
431450

451+
func bundleHash(bundleBody, signature string) (string, string, error) {
452+
var toto models.Intoto
453+
var rekord models.Rekord
454+
var intotoObj models.IntotoV001Schema
455+
var rekordObj models.RekordV001Schema
456+
457+
bodyDecoded, err := base64.StdEncoding.DecodeString(bundleBody)
458+
if err != nil {
459+
return "", "", err
460+
}
461+
462+
// The fact that there's no signature (or empty rather), implies
463+
// that this is an Attestation that we're verifying.
464+
if len(signature) == 0 {
465+
err = json.Unmarshal(bodyDecoded, &toto)
466+
if err != nil {
467+
return "", "", err
468+
}
469+
470+
specMarshal, err := json.Marshal(toto.Spec)
471+
if err != nil {
472+
return "", "", err
473+
}
474+
err = json.Unmarshal(specMarshal, &intotoObj)
475+
if err != nil {
476+
return "", "", err
477+
}
478+
479+
return *intotoObj.Content.Hash.Algorithm, *intotoObj.Content.Hash.Value, nil
480+
}
481+
482+
err = json.Unmarshal(bodyDecoded, &rekord)
483+
if err != nil {
484+
return "", "", err
485+
}
486+
487+
specMarshal, err := json.Marshal(rekord.Spec)
488+
if err != nil {
489+
return "", "", err
490+
}
491+
err = json.Unmarshal(specMarshal, &rekordObj)
492+
if err != nil {
493+
return "", "", err
494+
}
495+
return *rekordObj.Data.Hash.Algorithm, *rekordObj.Data.Hash.Value, nil
496+
}
497+
432498
func VerifySET(bundlePayload oci.BundlePayload, signature []byte, pub *ecdsa.PublicKey) error {
433499
contents, err := json.Marshal(bundlePayload)
434500
if err != nil {

0 commit comments

Comments
 (0)