Skip to content

Commit

Permalink
Merge pull request #70 from github/artifact-verification
Browse files Browse the repository at this point in the history
Add support for verifying with artifacts
  • Loading branch information
codysoyland authored Sep 25, 2023
2 parents 701d303 + bcf85d9 commit 06f3495
Show file tree
Hide file tree
Showing 10 changed files with 409 additions and 75 deletions.
24 changes: 7 additions & 17 deletions cmd/conformance/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,14 @@ func main() {
log.Fatal(err)
}

// Load artifact
file, err := os.Open(os.Args[len(os.Args)-1])
if err != nil {
log.Fatal(err)
}

// Configure verification options
policyConfig := []verify.PolicyOptionConfigurator{}
policyConfig := []verify.PolicyOptionConfigurator{verify.WithArtifact(file)}
if *certOIDC != "" || *certSAN != "" {
certID, err := verify.NewShortCertificateIdentity(*certOIDC, *certSAN, "", "")
if err != nil {
Expand Down Expand Up @@ -207,22 +213,6 @@ func main() {
if err != nil {
log.Fatal(err)
}

// Check file against bundle
fileBytes, err := os.ReadFile(os.Args[len(os.Args)-1])
if err != nil {
log.Fatal(err)
}

sigContent, err := b.SignatureContent()
if err != nil {
log.Fatal(err)
}

err = sigContent.EnsureFileMatchesDigest(fileBytes)
if err != nil {
log.Fatal(err)
}
default:
log.Fatalf("Unsupported command %s", os.Args[1])
}
Expand Down
22 changes: 22 additions & 0 deletions cmd/sigstore-verifier/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto"
"crypto/ecdsa"
"crypto/x509"
"encoding/hex"
"encoding/json"
"encoding/pem"
"errors"
Expand All @@ -19,6 +20,9 @@ import (
"github.com/sigstore/sigstore/pkg/signature"
)

var artifact *string
var artifactDigest *string
var artifactDigestAlgorithm *string
var expectedOIDIssuer *string
var expectedSAN *string
var expectedSANRegex *string
Expand All @@ -32,6 +36,9 @@ var tufRootURL *string
var tufDirectory *string

func init() {
artifact = flag.String("artifact", "", "Path to artifact to verify")
artifactDigest = flag.String("artifact-digest", "", "Hex-encoded digest of artifact to verify")
artifactDigestAlgorithm = flag.String("artifact-digest-algorithm", "sha256", "Digest algorithm")
expectedOIDIssuer = flag.String("expectedIssuer", "", "The expected OIDC issuer for the signing certificate")
expectedSAN = flag.String("expectedSAN", "", "The expected identity in the signing certificate's SAN extension")
expectedSANRegex = flag.String("expectedSANRegex", "", "The expected identity in the signing certificate's SAN extension")
Expand Down Expand Up @@ -144,6 +151,21 @@ func run() error {
return err
}

if *artifactDigest != "" {
artifactDigestBytes, err := hex.DecodeString(*artifactDigest)
if err != nil {
return err
}
policyConfig = append(policyConfig, verify.WithArtifactDigest(*artifactDigestAlgorithm, artifactDigestBytes))
}
if *artifact != "" {
file, err := os.Open(*artifact)
if err != nil {
return err
}
policyConfig = append(policyConfig, verify.WithArtifact(file))
}

res, err := sev.Verify(b, policyConfig...)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/github/sigstore-verifier

go 1.20
go 1.21

require (
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7
Expand Down
11 changes: 5 additions & 6 deletions pkg/bundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,11 @@ func (b *ProtobufBundle) SignatureContent() (verify.SignatureContent, error) {
}
return envelope, nil
case *protobundle.Bundle_MessageSignature:
messageSignature := MessageSignature{
digest: content.MessageSignature.MessageDigest.Digest,
digestAlgorithm: protocommon.HashAlgorithm_name[int32(content.MessageSignature.MessageDigest.Algorithm)],
signature: content.MessageSignature.Signature,
}
return &messageSignature, nil
return NewMessageSignature(
content.MessageSignature.MessageDigest.Digest,
protocommon.HashAlgorithm_name[int32(content.MessageSignature.MessageDigest.Algorithm)],
content.MessageSignature.Signature,
), nil
}
return nil, ErrMissingVerificationMaterial
}
Expand Down
30 changes: 8 additions & 22 deletions pkg/bundle/signature_content.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package bundle

import (
"bytes"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"

"github.com/github/sigstore-verifier/pkg/verify"
"github.com/in-toto/in-toto-golang/in_toto"
Expand All @@ -26,6 +23,14 @@ func (m *MessageSignature) DigestAlgorithm() string {
return m.digestAlgorithm
}

func NewMessageSignature(digest []byte, digestAlgorithm string, signature []byte) *MessageSignature {
return &MessageSignature{
digest: digest,
digestAlgorithm: digestAlgorithm,
signature: signature,
}
}

type Envelope struct {
*dsse.Envelope
}
Expand Down Expand Up @@ -67,25 +72,6 @@ func (m *MessageSignature) MessageSignatureContent() verify.MessageSignatureCont
return m
}

func (m *MessageSignature) EnsureFileMatchesDigest(fileBytes []byte) error {
if m.digestAlgorithm != "SHA2_256" {
return errors.New("Message has unsupported hash algorithm")
}

fileDigest := sha256.Sum256(fileBytes)
if !bytes.Equal(m.digest, fileDigest[:]) {
return errors.New("Message signature does not match supplied file")
}
return nil
}

func (e *Envelope) EnsureFileMatchesDigest(fileBytes []byte) error {
if e.Payload != base64.StdEncoding.EncodeToString(fileBytes) {
return errors.New("Envelope payload does not match supplied file")
}
return nil
}

func (m *MessageSignature) Signature() []byte {
return m.signature
}
Expand Down
92 changes: 86 additions & 6 deletions pkg/testing/ca/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func (ca *VirtualSigstore) AttestAtTime(identity, issuer string, envelopeBody []
return nil, err
}

envelope, err := dsseSigner.SignPayload(context.TODO(), "application/json", envelopeBody)
envelope, err := dsseSigner.SignPayload(context.TODO(), "application/vnd.in-toto+json", envelopeBody)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -192,6 +192,45 @@ func (ca *VirtualSigstore) AttestAtTime(identity, issuer string, envelopeBody []
}, nil
}

func (ca *VirtualSigstore) Sign(identity, issuer string, artifact []byte) (*TestEntity, error) {
return ca.SignAtTime(identity, issuer, artifact, time.Now().Add(5*time.Minute))
}

func (ca *VirtualSigstore) SignAtTime(identity, issuer string, artifact []byte, integratedTime time.Time) (*TestEntity, error) {
leafCert, leafPrivKey, err := ca.GenerateLeafCert(identity, issuer)
if err != nil {
return nil, err
}

signer, err := signature.LoadECDSASignerVerifier(leafPrivKey, crypto.SHA256)
if err != nil {
return nil, err
}

digest := sha256.Sum256(artifact)
sig, err := signer.SignMessage(bytes.NewReader(artifact))
if err != nil {
return nil, err
}

tsr, err := generateTimestampingResponse(sig, ca.tsaCA.Leaf, ca.tsaLeafKey)
if err != nil {
return nil, err
}

entry, err := ca.generateTlogEntryHashedRekord(leafCert, artifact, sig, integratedTime.Unix())
if err != nil {
return nil, err
}

return &TestEntity{
certChain: []*x509.Certificate{leafCert, ca.fulcioCA.Intermediates[0], ca.fulcioCA.Root},
timestamps: [][]byte{tsr},
messageSignature: bundle.NewMessageSignature(digest[:], "SHA2_256", sig),
tlogEntries: []*tlog.Entry{entry},
}, nil
}

func (ca *VirtualSigstore) generateTlogEntry(leafCert *x509.Certificate, envelope *dsse.Envelope, sig []byte, integratedTime int64) (*tlog.Entry, error) {
leafCertPem, err := cryptoutils.MarshalCertificateToPEM(leafCert)
if err != nil {
Expand Down Expand Up @@ -234,6 +273,43 @@ func (ca *VirtualSigstore) generateTlogEntry(leafCert *x509.Certificate, envelop
return tlog.NewEntry(rekorBodyRaw, integratedTime, logIndex, rekorLogIDRaw, set, nil)
}

func (ca *VirtualSigstore) generateTlogEntryHashedRekord(leafCert *x509.Certificate, artifact []byte, sig []byte, integratedTime int64) (*tlog.Entry, error) {
leafCertPem, err := cryptoutils.MarshalCertificateToPEM(leafCert)
if err != nil {
return nil, err
}

rekorBody, err := generateRekorEntry(hashedrekord.KIND, hashedrekord.New().DefaultVersion(), artifact, leafCertPem, sig)
if err != nil {
return nil, err
}

rekorLogID, err := getLogID(ca.rekorKey.Public())
if err != nil {
return nil, err
}

rekorLogIDRaw, err := hex.DecodeString(rekorLogID)
if err != nil {
return nil, err
}

logIndex := int64(1000)

b := createRekorBundle(rekorLogID, integratedTime, logIndex, rekorBody)
set, err := ca.rekorSignPayload(*b)
if err != nil {
return nil, err
}

rekorBodyRaw, err := base64.StdEncoding.DecodeString(rekorBody)
if err != nil {
return nil, err
}

return tlog.NewEntry(rekorBodyRaw, integratedTime, logIndex, rekorLogIDRaw, set, nil)
}

func (ca *VirtualSigstore) PublicKeyVerifier(keyID string) (root.TimeConstrainedVerifier, error) {
v, ok := ca.publicKeyVerifier[keyID]
if !ok {
Expand Down Expand Up @@ -379,10 +455,11 @@ func (ca *VirtualSigstore) CTlogAuthorities() map[string]*root.TlogAuthority {
}

type TestEntity struct {
certChain []*x509.Certificate
envelope *dsse.Envelope
timestamps [][]byte
tlogEntries []*tlog.Entry
certChain []*x509.Certificate
envelope *dsse.Envelope
messageSignature *bundle.MessageSignature
timestamps [][]byte
tlogEntries []*tlog.Entry
}

func (e *TestEntity) VerificationContent() (verify.VerificationContent, error) {
Expand All @@ -398,7 +475,10 @@ func (e *TestEntity) HasInclusionProof() bool {
}

func (e *TestEntity) SignatureContent() (verify.SignatureContent, error) {
return &bundle.Envelope{Envelope: e.envelope}, nil
if e.envelope != nil {
return &bundle.Envelope{Envelope: e.envelope}, nil
}
return e.messageSignature, nil
}

func (e *TestEntity) Timestamps() ([][]byte, error) {
Expand Down
1 change: 0 additions & 1 deletion pkg/verify/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ type VerificationContent interface {
}

type SignatureContent interface {
EnsureFileMatchesDigest([]byte) error
Signature() []byte
EnvelopeContent() EnvelopeContent
MessageSignatureContent() MessageSignatureContent
Expand Down
Loading

0 comments on commit 06f3495

Please sign in to comment.