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

Add support for SigningConfig #367

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
/tufdata
/conformance
/pkg/tuf/testing.local.json
/examples/oci-image-verification/oci-image-verification
/examples/sigstore-go-signing/sigstore-go-signing
4 changes: 2 additions & 2 deletions examples/oci-image-verification/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ replace github.com/sigstore/sigstore-go => ../../

require (
github.com/google/go-containerregistry v0.20.2
github.com/sigstore/protobuf-specs v0.3.2
github.com/sigstore/protobuf-specs v0.3.3-0.20241218070516-b4ea46eb6f7b
github.com/sigstore/sigstore v1.8.11
github.com/sigstore/sigstore-go v0.6.2
)
Expand Down Expand Up @@ -91,7 +91,7 @@ require (
golang.org/x/term v0.27.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect
google.golang.org/protobuf v1.35.2 // indirect
google.golang.org/protobuf v1.36.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
Expand Down
8 changes: 4 additions & 4 deletions examples/oci-image-verification/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,8 @@ github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=
github.com/sigstore/protobuf-specs v0.3.2 h1:nCVARCN+fHjlNCk3ThNXwrZRqIommIeNKWwQvORuRQo=
github.com/sigstore/protobuf-specs v0.3.2/go.mod h1:RZ0uOdJR4OB3tLQeAyWoJFbNCBFrPQdcokntde4zRBA=
github.com/sigstore/protobuf-specs v0.3.3-0.20241218070516-b4ea46eb6f7b h1:via4M7tXznyLDUoj7oi71z2Id3x0xM1xffb0+0Ous6w=
github.com/sigstore/protobuf-specs v0.3.3-0.20241218070516-b4ea46eb6f7b/go.mod h1:FaGuR+Emg7JTQ82axlgsQj+3h6Xzu/N79F64TYmMz5s=
github.com/sigstore/rekor v1.3.7 h1:Z5UW5TmqbTZnyOFkMRfi32q/CWcxK6VuzIkx+33mbq8=
github.com/sigstore/rekor v1.3.7/go.mod h1:TihqJscZ6L6398x68EHY82t0AOnGYfrQ0siXe3WgbR4=
github.com/sigstore/sigstore v1.8.11 h1:tEqeQqbT+awtM87ec9KEeSUxT/AFvJNawneYJyAkFrQ=
Expand Down Expand Up @@ -396,8 +396,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=
google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
Expand Down
36 changes: 23 additions & 13 deletions examples/sigstore-go-signing/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,18 @@ func main() {
log.Fatal(err)
}

trustedRootJSON, err := tufClient.GetTarget("trusted_root.json")
trustedRoot, err := root.GetTrustedRoot(tufClient)
if err != nil {
log.Fatal(err)
}

trustedRoot, err := root.NewTrustedRootFromJSON(trustedRootJSON)
// TODO: Uncomment once the TUF staging root distributes this file
// signingConfig, err := root.GetSigningConfig(tufClient)
signingConfig, err := root.NewSigningConfig(root.SigningConfigMediaType01,
"https://fulcio.sigstage.dev",
"https://oauth2.sigstage.dev/auth",
[]string{"https://rekor.sigstage.dev"},
[]string{"https://timestamp.githubapp.com/api/v1/timestamp"})
if err != nil {
log.Fatal(err)
}
Expand All @@ -110,7 +116,7 @@ func main() {

if *idToken != "" {
fulcioOpts := &sign.FulcioOptions{
BaseURL: "https://fulcio.sigstage.dev",
BaseURL: signingConfig.FulcioCertificateAuthorityURL(),
Timeout: time.Duration(30 * time.Second),
Retries: 1,
}
Expand All @@ -121,24 +127,28 @@ func main() {
}

if *tsa {
tsaOpts := &sign.TimestampAuthorityOptions{
URL: "https://timestamp.githubapp.com/api/v1/timestamp",
Timeout: time.Duration(30 * time.Second),
Retries: 1,
for _, tsaURL := range signingConfig.TimestampAuthorityURLs() {
tsaOpts := &sign.TimestampAuthorityOptions{
URL: tsaURL,
Timeout: time.Duration(30 * time.Second),
Retries: 1,
}
opts.TimestampAuthorities = append(opts.TimestampAuthorities, sign.NewTimestampAuthority(tsaOpts))
}
opts.TimestampAuthorities = append(opts.TimestampAuthorities, sign.NewTimestampAuthority(tsaOpts))

// staging TUF repo doesn't have accessible timestamp authorities
opts.TrustedRoot = nil
}

if *rekor {
rekorOpts := &sign.RekorOptions{
BaseURL: "https://rekor.sigstage.dev",
Timeout: time.Duration(90 * time.Second),
Retries: 1,
for _, rekorURL := range signingConfig.RekorLogURLs() {
rekorOpts := &sign.RekorOptions{
BaseURL: rekorURL,
Timeout: time.Duration(90 * time.Second),
Retries: 1,
}
opts.TransparencyLogs = append(opts.TransparencyLogs, sign.NewRekor(rekorOpts))
}
opts.TransparencyLogs = append(opts.TransparencyLogs, sign.NewRekor(rekorOpts))
}

bundle, err := sign.Bundle(content, keypair, opts)
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ require (
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.9.0
github.com/sigstore/protobuf-specs v0.3.2
github.com/sigstore/protobuf-specs v0.3.3-0.20241218070516-b4ea46eb6f7b
github.com/sigstore/rekor v1.3.7
github.com/sigstore/sigstore v1.8.11
github.com/sigstore/timestamp-authority v1.2.3
github.com/stretchr/testify v1.10.0
github.com/theupdateframework/go-tuf/v2 v2.0.2
golang.org/x/crypto v0.31.0
golang.org/x/mod v0.22.0
google.golang.org/protobuf v1.35.2
google.golang.org/protobuf v1.36.0
)

require (
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,8 @@ github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=
github.com/sigstore/protobuf-specs v0.3.2 h1:nCVARCN+fHjlNCk3ThNXwrZRqIommIeNKWwQvORuRQo=
github.com/sigstore/protobuf-specs v0.3.2/go.mod h1:RZ0uOdJR4OB3tLQeAyWoJFbNCBFrPQdcokntde4zRBA=
github.com/sigstore/protobuf-specs v0.3.3-0.20241218070516-b4ea46eb6f7b h1:via4M7tXznyLDUoj7oi71z2Id3x0xM1xffb0+0Ous6w=
github.com/sigstore/protobuf-specs v0.3.3-0.20241218070516-b4ea46eb6f7b/go.mod h1:FaGuR+Emg7JTQ82axlgsQj+3h6Xzu/N79F64TYmMz5s=
github.com/sigstore/rekor v1.3.7 h1:Z5UW5TmqbTZnyOFkMRfi32q/CWcxK6VuzIkx+33mbq8=
github.com/sigstore/rekor v1.3.7/go.mod h1:TihqJscZ6L6398x68EHY82t0AOnGYfrQ0siXe3WgbR4=
github.com/sigstore/sigstore v1.8.11 h1:tEqeQqbT+awtM87ec9KEeSUxT/AFvJNawneYJyAkFrQ=
Expand Down Expand Up @@ -441,8 +441,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=
google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
Expand Down
130 changes: 130 additions & 0 deletions pkg/root/signing_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Copyright 2024 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package root

import (
"fmt"
"os"

prototrustroot "github.com/sigstore/protobuf-specs/gen/pb-go/trustroot/v1"
"github.com/sigstore/sigstore-go/pkg/tuf"
"google.golang.org/protobuf/encoding/protojson"
)

const SigningConfigMediaType01 = "application/vnd.dev.sigstore.signingconfig.v0.1+json"

type SigningConfig struct {
signingConfig *prototrustroot.SigningConfig
}

func (sc *SigningConfig) FulcioCertificateAuthorityURL() string {
return sc.signingConfig.GetCaUrl()
}

func (sc *SigningConfig) OIDCProviderURL() string {
return sc.signingConfig.GetOidcUrl()
}

func (sc *SigningConfig) RekorLogURLs() []string {
return sc.signingConfig.GetTlogUrls()
}

func (sc *SigningConfig) TimestampAuthorityURLs() []string {
return sc.signingConfig.GetTsaUrls()
}

// NewSigningConfig initializes a SigningConfig object from a mediaType string, Fulcio certificate
// authority URL, OIDC provider URL, list of Rekor transpraency log URLs, and a list of
// timestamp authorities.
func NewSigningConfig(mediaType string,
fulcioCertificateAuthority string,
oidcProvider string,
rekorLogs []string,
timestampAuthorities []string) (*SigningConfig, error) {
if mediaType != SigningConfigMediaType01 {
return nil, fmt.Errorf("unsupported SigningConfig media type, must be: %s", SigningConfigMediaType01)
}
sc := &SigningConfig{
signingConfig: &prototrustroot.SigningConfig{
MediaType: mediaType,
CaUrl: fulcioCertificateAuthority,
OidcUrl: oidcProvider,
TlogUrls: rekorLogs,
TsaUrls: timestampAuthorities,
},
}
return sc, nil
}

// NewSigningConfigFromProtobuf returns a Sigstore signing configuration.
func NewSigningConfigFromProtobuf(sc *prototrustroot.SigningConfig) (*SigningConfig, error) {
if sc.GetMediaType() != SigningConfigMediaType01 {
return nil, fmt.Errorf("unsupported SigningConfig media type: %s", sc.GetMediaType())
}
return &SigningConfig{signingConfig: sc}, nil
}

// NewSigningConfigFromPath returns a Sigstore signing configuration from a file.
func NewSigningConfigFromPath(path string) (*SigningConfig, error) {
scJSON, err := os.ReadFile(path)
if err != nil {
return nil, err
}

return NewSigningConfigFromJSON(scJSON)
}

// NewSigningConfigFromJSON returns a Sigstore signing configuration from JSON.
func NewSigningConfigFromJSON(rootJSON []byte) (*SigningConfig, error) {
pbSC, err := NewSigningConfigProtobuf(rootJSON)
if err != nil {
return nil, err
}

return NewSigningConfigFromProtobuf(pbSC)
}

// NewSigningConfigProtobuf returns a Sigstore signing configuration as a protobuf.
func NewSigningConfigProtobuf(scJSON []byte) (*prototrustroot.SigningConfig, error) {
pbSC := &prototrustroot.SigningConfig{}
err := protojson.Unmarshal(scJSON, pbSC)
if err != nil {
return nil, err
}
return pbSC, nil
}

// FetchSigningConfig fetches the public-good Sigstore signing configuration from TUF.
func FetchSigningConfig() (*SigningConfig, error) {
return FetchSigningConfigWithOptions(tuf.DefaultOptions())
}

// FetchSigningConfig fetches the public-good Sigstore signing configuration with the given options from TUF.
func FetchSigningConfigWithOptions(opts *tuf.Options) (*SigningConfig, error) {
client, err := tuf.New(opts)
if err != nil {
return nil, err
}
return GetSigningConfig(client)
}

// FetchSigningConfig fetches the public-good Sigstore signing configuration target from TUF.
func GetSigningConfig(c *tuf.Client) (*SigningConfig, error) {
jsonBytes, err := c.GetTarget("signing_config.json")
if err != nil {
return nil, err
}
return NewSigningConfigFromJSON(jsonBytes)
}
Loading
Loading