diff --git a/cmd/cosign/cli/fulcio/depcheck_test.go b/cmd/cosign/cli/fulcio/depcheck_test.go new file mode 100644 index 00000000000..39493e5a86c --- /dev/null +++ b/cmd/cosign/cli/fulcio/depcheck_test.go @@ -0,0 +1,36 @@ +// +// Copyright 2021 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 fulcio_test + +import ( + "testing" + + "knative.dev/pkg/depcheck" +) + +func TestNoDeps(t *testing.T) { + depcheck.AssertNoDependency(t, map[string][]string{ + "github.com/sigstore/cosign/cmd/cosign/cli/fulcio": { + // Avoid pulling in a variety of things that are massive dependencies. + "github.com/google/certificate-transparency-go", + "github.com/google/trillian", + "github.com/envoyproxy/go-control-plane", + "github.com/gogo/protobuf/protoc-gen-gogo", + "github.com/grpc-ecosystem/go-grpc-middleware", + "github.com/jhump/protoreflect", + }, + }) +} diff --git a/cmd/cosign/cli/fulcio/fulcio.go b/cmd/cosign/cli/fulcio/fulcio.go index 8ff9a832bed..7a69bddfbca 100644 --- a/cmd/cosign/cli/fulcio/fulcio.go +++ b/cmd/cosign/cli/fulcio/fulcio.go @@ -22,9 +22,7 @@ import ( "crypto/rand" "crypto/sha256" "crypto/x509" - _ "embed" // To enable the `go:embed` directive. "encoding/base64" - "encoding/json" "encoding/pem" "fmt" "os" @@ -32,10 +30,6 @@ import ( "github.com/go-openapi/runtime" httptransport "github.com/go-openapi/runtime/client" "github.com/go-openapi/strfmt" - ct "github.com/google/certificate-transparency-go" - "github.com/google/certificate-transparency-go/ctutil" - ctx509 "github.com/google/certificate-transparency-go/x509" - "github.com/google/certificate-transparency-go/x509util" "github.com/pkg/errors" "golang.org/x/term" @@ -60,15 +54,6 @@ type Resp struct { SCT []byte } -// This is the CT log public key -//go:embed ctfe.pub -var ctPublicKey string - -var ( - // For testing - VerifySCT = verifySCT -) - type oidcConnector interface { OIDConnect(string, string, string) (*oauthflow.OIDCIDToken, error) } @@ -136,34 +121,9 @@ func getCertForOauthID(priv *ecdsa.PrivateKey, scp signingCertProvider, connecto SCT: sct, } - // verify the sct - if err := VerifySCT(fr); err != nil { - return Resp{}, errors.Wrap(err, "verifying SCT") - } - fmt.Fprintln(os.Stderr, "Successfully verified SCT...") return fr, nil } -// verifySCT verifies the SCT against the Fulcio CT log public key -// The SCT is a `Signed Certificate Timestamp`, which promises that -// the certificate issued by Fulcio was also added to the public CT log within -// some defined time period -func verifySCT(fr Resp) error { - pubKey, err := cosign.PemToECDSAKey([]byte(ctPublicKey)) - if err != nil { - return err - } - cert, err := x509util.CertificateFromPEM(fr.CertPEM) - if err != nil { - return err - } - var sct ct.SignedCertificateTimestamp - if err := json.Unmarshal(fr.SCT, &sct); err != nil { - return errors.Wrap(err, "unmarshal") - } - return ctutil.VerifySCT(pubKey, []*ctx509.Certificate{cert}, &sct, false) -} - // GetCert returns the PEM-encoded signature of the OIDC identity returned as part of an interactive oauth2 flow plus the PEM-encoded cert chain. func GetCert(ctx context.Context, priv *ecdsa.PrivateKey, idToken, flow, oidcIssuer, oidcClientID string, fClient *fulcioClient.Fulcio) (Resp, error) { c := &realConnector{} @@ -215,6 +175,7 @@ func NewSigner(ctx context.Context, idToken, oidcIssuer, oidcClientID string, fC if err != nil { return nil, errors.Wrap(err, "retrieving cert") } + f := &Signer{ pub: &priv.PublicKey, ECDSASignerVerifier: signer, diff --git a/cmd/cosign/cli/fulcio/fulcio_test.go b/cmd/cosign/cli/fulcio/fulcio_test.go index b3cd566f0c6..461eb16c3ab 100644 --- a/cmd/cosign/cli/fulcio/fulcio_test.go +++ b/cmd/cosign/cli/fulcio/fulcio_test.go @@ -113,9 +113,6 @@ func TestGetCertForOauthID(t *testing.T) { err: tc.tokenGetterErr, } - VerifySCT = func(Resp) error { return nil } - defer func() { VerifySCT = verifySCT }() - resp, err := getCertForOauthID(testKey, tscp, &tf, "", "") if err != nil { diff --git a/cmd/cosign/cli/fulcio/ctfe.pub b/cmd/cosign/cli/fulcio/fulcioverifier/ctfe.pub similarity index 100% rename from cmd/cosign/cli/fulcio/ctfe.pub rename to cmd/cosign/cli/fulcio/fulcioverifier/ctfe.pub diff --git a/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go b/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go new file mode 100644 index 00000000000..f72f5d0ce3c --- /dev/null +++ b/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go @@ -0,0 +1,73 @@ +// +// Copyright 2021 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 fulcioverifier + +import ( + "context" + _ "embed" // To enable the `go:embed` directive. + "encoding/json" + "fmt" + "os" + + ct "github.com/google/certificate-transparency-go" + "github.com/google/certificate-transparency-go/ctutil" + ctx509 "github.com/google/certificate-transparency-go/x509" + "github.com/google/certificate-transparency-go/x509util" + "github.com/pkg/errors" + "github.com/sigstore/cosign/cmd/cosign/cli/fulcio" + "github.com/sigstore/cosign/pkg/cosign" + fulcioClient "github.com/sigstore/fulcio/pkg/generated/client" +) + +// This is the CT log public key +//go:embed ctfe.pub +var ctPublicKey string + +// verifySCT verifies the SCT against the Fulcio CT log public key +// The SCT is a `Signed Certificate Timestamp`, which promises that +// the certificate issued by Fulcio was also added to the public CT log within +// some defined time period +func verifySCT(certPEM, rawSCT []byte) error { + pubKey, err := cosign.PemToECDSAKey([]byte(ctPublicKey)) + if err != nil { + return err + } + cert, err := x509util.CertificateFromPEM(certPEM) + if err != nil { + return err + } + var sct ct.SignedCertificateTimestamp + if err := json.Unmarshal(rawSCT, &sct); err != nil { + return errors.Wrap(err, "unmarshal") + } + return ctutil.VerifySCT(pubKey, []*ctx509.Certificate{cert}, &sct, false) +} + +func NewSigner(ctx context.Context, idToken, oidcIssuer, oidcClientID string, fClient *fulcioClient.Fulcio) (*fulcio.Signer, error) { + fs, err := fulcio.NewSigner(ctx, idToken, oidcIssuer, oidcClientID, fClient) + if err != nil { + return nil, err + } + + // verify the sct + if err := verifySCT(fs.Cert, fs.SCT); err != nil { + return nil, errors.Wrap(err, "verifying SCT") + } + fmt.Fprintln(os.Stderr, "Successfully verified SCT...") + + return fs, nil + +} diff --git a/cmd/cosign/cli/sign.go b/cmd/cosign/cli/sign.go index 0a1fe33e680..da0731e047d 100644 --- a/cmd/cosign/cli/sign.go +++ b/cmd/cosign/cli/sign.go @@ -40,7 +40,7 @@ import ( "github.com/peterbourgon/ff/v3/ffcli" "github.com/pkg/errors" - "github.com/sigstore/cosign/cmd/cosign/cli/fulcio" + "github.com/sigstore/cosign/cmd/cosign/cli/fulcio/fulcioverifier" "github.com/sigstore/cosign/pkg/cosign" "github.com/sigstore/cosign/pkg/cosign/pivkey" cremote "github.com/sigstore/cosign/pkg/cosign/remote" @@ -523,7 +523,7 @@ func signerFromKeyOpts(ctx context.Context, certPath string, ko KeyOpts) (*certS return nil, errors.Wrap(err, "fetching ambient OIDC credentials") } } - k, err := fulcio.NewSigner(ctx, tok, ko.OIDCIssuer, ko.OIDCClientID, fClient) + k, err := fulcioverifier.NewSigner(ctx, tok, ko.OIDCIssuer, ko.OIDCClientID, fClient) if err != nil { return nil, errors.Wrap(err, "getting key from Fulcio") }