Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added guac support in verifier #39

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
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
159 changes: 130 additions & 29 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import (
"path/filepath"
"strings"

"github.com/in-toto/attestation-verifier/parsers"
"github.com/in-toto/attestation-verifier/utils"
"github.com/in-toto/attestation-verifier/verifier"
"github.com/in-toto/in-toto-golang/in_toto"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
"github.com/spf13/cobra"
)
Expand All @@ -20,6 +23,10 @@ var (
layoutPath string
attestationsDir string
parametersPath string
graphqlEndpoint string
subject string
keyPath string
saveAttestation bool
)

func Execute() {
Expand Down Expand Up @@ -53,46 +60,91 @@ func init() {
"Path to JSON file containing key-value string pairs for parameter substitution in the layout",
)

rootCmd.MarkFlagRequired("layout")
rootCmd.MarkFlagRequired("attestations-directory")
rootCmd.Flags().StringVarP(
&subject,
"subject",
"s",
"",
"subject can either be purl for package or <alg>:<digest> for an artifact",
)

rootCmd.Flags().StringVarP(
&graphqlEndpoint,
"attestations-from",
"g",
"http://localhost:8080/query",
"endpoint used to connect to GUAC server (default: http://localhost:8080/query)",
)

rootCmd.Flags().StringVarP(
&keyPath,
"key",
"k",
"",
"Path to a PEM formatted private key file",
)

rootCmd.Flags().BoolVar(
&saveAttestation,
"save-attestation",
false,
"flag to save the retrieved attestation from GUAC server",
)
}

func verify(cmd *cobra.Command, args []string) error {
layout, err := verifier.LoadLayout(layoutPath)
if err != nil {
return err
}

dirEntries, err := os.ReadDir(attestationsDir)
if err != nil {
return err
key := &in_toto.Key{}
var err error

// maps stepname with subject
subjectStepMap := make(map[string]string, 0)
if subject != "" {
subjectStepMap[""] = subject
}

attestations := map[string]*dsse.Envelope{}
for _, e := range dirEntries {
name := e.Name()
ab, err := os.ReadFile(filepath.Join(attestationsDir, name))
if err != nil {
layout := &verifier.Layout{}
if len(layoutPath) > 0 {
if layout, err = verifier.LoadLayout(layoutPath); err != nil {
return err
}

// getting subjects from layout
for _, step := range layout.Steps {
if step.FromGUAC {
if len(step.Subject) > 0 {
subjectStepMap[step.Name] = step.Subject
}
}
}
// attestation := &attestationv1.Statement{}
// if err := json.Unmarshal(ab, attestation); err != nil {
// return err
// }
// encodedBytes, err := cjson.EncodeCanonical(attestation)
// if err != nil {
// return err
// }
// envelope := &dsse.Envelope{
// Payload: base64.StdEncoding.EncodeToString(encodedBytes),
// PayloadType: "application/vnd.in-toto+json",
// }
envelope := &dsse.Envelope{}
if err := json.Unmarshal(ab, envelope); err != nil {
}

// loading private key if available else creating one
if len(keyPath) != 0 || len(subjectStepMap) != 0 {
key, err = utils.LoadPrivateKey(keyPath)
if err != nil {
return err
}

attestations[strings.TrimSuffix(name, ".json")] = envelope
// adding key as functionary for attestation that are being retrieved from guac
if len(layout.Steps) != 0 {
a := verifier.Functionary{}
a.KeyID = key.KeyID
a.KeyIDHashAlgorithms = key.KeyIDHashAlgorithms
a.KeyType = key.KeyType
a.KeyVal = verifier.KeyVal{
Public: key.KeyVal.Public,
}
a.Scheme = key.Scheme
layout.Functionaries[key.KeyID] = a
for _, step := range layout.Steps {
if step.FromGUAC {
for i, expectedPredicate := range step.ExpectedPredicates {
step.ExpectedPredicates[i].Functionaries = append(expectedPredicate.Functionaries, key.KeyID)
}
}
}
}
}

parameters := map[string]string{}
Expand All @@ -107,5 +159,54 @@ func verify(cmd *cobra.Command, args []string) error {
}
}

attestations := map[string]*dsse.Envelope{}
if len(subjectStepMap) != 0 {
statements := parsers.GetAttestationFromPURL(subjectStepMap, graphqlEndpoint)
retrievedAttestation, err := utils.WrapEnvelope(statements, key)
if err != nil {
return err
}

if saveAttestation {
return utils.SaveAttestation(retrievedAttestation)
}

for name, attestation := range retrievedAttestation {
attestations[name] = attestation
}
}
if attestationsDir != "" {
dirEntries, err := os.ReadDir(attestationsDir)
if err != nil {
return err
}

for _, e := range dirEntries {
name := e.Name()
ab, err := os.ReadFile(filepath.Join(attestationsDir, name))
if err != nil {
return err
}
// attestation := &attestationv1.Statement{}
// if err := json.Unmarshal(ab, attestation); err != nil {
// return err
// }
// encodedBytes, err := cjson.EncodeCanonical(attestation)
// if err != nil {
// return err
// }
// envelope := &dsse.Envelope{
// Payload: base64.StdEncoding.EncodeToString(encodedBytes),
// PayloadType: "application/vnd.in-toto+json",
// }
envelope := &dsse.Envelope{}
if err := json.Unmarshal(ab, envelope); err != nil {
return err
}

attestations[strings.TrimSuffix(name, ".json")] = envelope
}
}

return verifier.Verify(layout, attestations, parameters)
}
38 changes: 33 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,26 +1,54 @@
module github.com/in-toto/attestation-verifier

go 1.20
go 1.21.8

toolchain go1.22.3

require (
github.com/CycloneDX/cyclonedx-go v0.9.0
github.com/Khan/genqlient v0.7.0
github.com/google/cel-go v0.21.0
github.com/guacsec/guac v0.7.2
github.com/in-toto/attestation v1.1.0
github.com/in-toto/in-toto-golang v0.9.0
github.com/secure-systems-lab/go-securesystemslib v0.8.0
github.com/sirupsen/logrus v1.9.3
github.com/spdx/tools-golang v0.5.5
github.com/spf13/cobra v1.8.1
google.golang.org/protobuf v1.34.2
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/ProtonMail/gluon v0.17.0 // indirect
github.com/anchore/go-struct-converter v0.0.0-20230627203149-c72ef8859ca9 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/package-url/packageurl-go v0.1.3 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect
golang.org/x/sys v0.15.0 // indirect
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/vektah/gqlparser/v2 v2.5.11 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)
Loading