Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
77 changes: 14 additions & 63 deletions cmd/cosign/cli/options/signblob.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,21 @@ import (
)

// SignBlobOptions is the top level wrapper for the sign-blob command.
// The new output-certificate flag is only in use when COSIGN_EXPERIMENTAL is enabled
type SignBlobOptions struct {
Key string
Cert string
CertChain string
Base64Output bool
Output string // deprecated: TODO remove when the output flag is fully deprecated
OutputSignature string // TODO: this should be the root output file arg.
OutputCertificate string
SecurityKey SecurityKeyOptions
Fulcio FulcioOptions
Rekor RekorOptions
OIDC OIDCOptions
Registry RegistryOptions
BundlePath string
NewBundleFormat bool
SkipConfirmation bool
TlogUpload bool
TSAClientCACert string
TSAClientCert string
TSAClientKey string
TSAServerName string
TSAServerURL string
RFC3161TimestampPath string
IssueCertificate bool
SigningAlgorithm string
Key string
Cert string
CertChain string
SecurityKey SecurityKeyOptions
Fulcio FulcioOptions
OIDC OIDCOptions
Comment thread
cmurphy marked this conversation as resolved.
Resolved
BundlePath string
SkipConfirmation bool
TSAClientCACert string
TSAClientCert string
TSAClientKey string
TSAServerName string
IssueCertificate bool
SigningAlgorithm string

UseSigningConfig bool
SigningConfigPath string
Expand All @@ -64,7 +53,6 @@ var _ Interface = (*SignBlobOptions)(nil)
func (o *SignBlobOptions) AddFlags(cmd *cobra.Command) {
o.SecurityKey.AddFlags(cmd)
o.Fulcio.AddFlags(cmd)
Comment thread
aaronlew02 marked this conversation as resolved.
Resolved
o.Rekor.AddFlags(cmd)
o.OIDC.AddFlags(cmd)
Comment thread
aaronlew02 marked this conversation as resolved.
Resolved

cmd.Flags().StringVar(&o.Key, "key", "",
Expand All @@ -82,33 +70,10 @@ func (o *SignBlobOptions) AddFlags(cmd *cobra.Command) {
"signing certificate and end with the root certificate.")
_ = cmd.MarkFlagFilename("certificate-chain", certificateExts...)

cmd.Flags().BoolVar(&o.Base64Output, "b64", true,
"whether to base64 encode the output")
_ = cmd.Flags().MarkDeprecated("b64", "please use --bundle, which already base64 encodes content as appropriate")

cmd.Flags().StringVar(&o.OutputSignature, "output-signature", "",
"write the signature to FILE")
_ = cmd.MarkFlagFilename("output-signature", signatureExts...)
_ = cmd.Flags().MarkDeprecated("output-signature", "please use --bundle to provide the output bundle location, which will include the signature")

// TODO: remove when output flag is fully deprecated
cmd.Flags().StringVar(&o.Output, "output", "", "write the signature to FILE")
_ = cmd.MarkFlagFilename("output", signatureExts...)
_ = cmd.Flags().MarkDeprecated("output", "please use --bundle to provide the output bundle location, which will include the signature")

cmd.Flags().StringVar(&o.OutputCertificate, "output-certificate", "",
"write the certificate to FILE")
_ = cmd.MarkFlagFilename("output-certificate", certificateExts...)
_ = cmd.Flags().MarkDeprecated("output-certificate", "please use --bundle to provide the output bundle location, which will include the certificate")

cmd.Flags().StringVar(&o.BundlePath, "bundle", "",
Comment thread
cmurphy marked this conversation as resolved.
Resolved
"write everything required to verify the blob to a FILE")
_ = cmd.MarkFlagFilename("bundle", bundleExts...)

cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", true,
"output bundle in new format that contains all verification material")
_ = cmd.Flags().MarkDeprecated("new-bundle-format", "this will be the only supported format in future versions")

cmd.Flags().BoolVar(&o.UseSigningConfig, "use-signing-config", true,
"whether to use a TUF-provided signing config for the service URLs. Must provide --bundle, which will output verification material in the new format")
Comment thread
cmurphy marked this conversation as resolved.
Resolved
_ = cmd.Flags().MarkDeprecated("use-signing-config", "an offline signing flag will be added in the future; TUF will continue to provide a signing config by default if one is not provided manually")
Expand All @@ -124,10 +89,6 @@ func (o *SignBlobOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().BoolVarP(&o.SkipConfirmation, "yes", "y", false,
"skip confirmation prompts for non-destructive operations")

cmd.Flags().BoolVar(&o.TlogUpload, "tlog-upload", true,
"whether or not to upload to the tlog")
_ = cmd.Flags().MarkDeprecated("tlog-upload", "prefer using a --signing-config file with no transparency log services")

cmd.Flags().StringVar(&o.TSAClientCACert, "timestamp-client-cacert", "",
"path to the X.509 CA certificate file in PEM format to be used for the connection to the TSA Server")
_ = cmd.MarkFlagFilename("timestamp-client-cacert", certificateExts...)
Expand All @@ -144,16 +105,6 @@ func (o *SignBlobOptions) AddFlags(cmd *cobra.Command) {
"SAN name to use as the 'ServerName' tls.Config field to verify the mTLS connection to the TSA Server")
_ = cmd.RegisterFlagCompletionFunc("timestamp-server-name", cobra.NoFileCompletions)

cmd.Flags().StringVar(&o.TSAServerURL, "timestamp-server-url", "",
"url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr")
_ = cmd.RegisterFlagCompletionFunc("timestamp-server-url", cobra.NoFileCompletions)
_ = cmd.Flags().MarkDeprecated("timestamp-server-url", "please use a signing config to specify a timestamp server url; see `cosign signing-config --help`")

cmd.Flags().StringVar(&o.RFC3161TimestampPath, "rfc3161-timestamp", "",
"write the RFC3161 timestamp to a file")
// _ = cmd.MarkFlagFilename("rfc3161-timestamp") // no typical extensions
_ = cmd.Flags().MarkDeprecated("rfc3161-timestamp", "please use --bundle to provide the output bundle location, which will include the signed timestamp")

cmd.Flags().BoolVar(&o.IssueCertificate, "issue-certificate", false,
"issue a code signing certificate from Fulcio, even if a key is provided")
_ = cmd.Flags().MarkDeprecated("issue-certificate", "support for this flag will be removed in the future")
Expand Down
130 changes: 16 additions & 114 deletions cmd/cosign/cli/sign/sign_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ package sign
import (
"context"
"crypto"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"os"
Expand All @@ -34,10 +32,8 @@ import (
"github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa/client"
"github.com/sigstore/cosign/v3/internal/ui"
cbundle "github.com/sigstore/cosign/v3/pkg/cosign/bundle"
protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1"
"github.com/sigstore/sigstore-go/pkg/sign"
"github.com/sigstore/sigstore/pkg/signature"
"google.golang.org/protobuf/encoding/protojson"
)

func getPayload(ctx context.Context, payloadPath string, hashFunction crypto.Hash) (internal.HashReader, func() error, error) {
Expand All @@ -53,38 +49,31 @@ func getPayload(ctx context.Context, payloadPath string, hashFunction crypto.Has
}

// nolint
Comment thread
cmurphy marked this conversation as resolved.
Resolved
func SignBlobCmd(ctx context.Context, ro *options.RootOptions, ko options.KeyOpts, payloadPath, certPath, certChainPath string, b64 bool, outputSignature string, outputCertificate string, tlogUpload bool) ([]byte, error) {
func SignBlobCmd(ctx context.Context, ro *options.RootOptions, ko options.KeyOpts, payloadPath, certPath, certChainPath string) error {
var payload internal.HashReader

ctx, cancel := context.WithTimeout(ctx, ro.Timeout)
defer cancel()

var uploadToTlog bool
var err error

if ko.SigningConfig == nil {
Comment thread
aaronlew02 marked this conversation as resolved.
Resolved
ko.SigningConfig, err = signcommon.NewSigningConfigFromKeyOpts(ko)
Comment thread
cmurphy marked this conversation as resolved.
Resolved
if err != nil {
return nil, fmt.Errorf("creating signing config: %w", err)
}
ko.SigningConfig = signcommon.NewEmptySigningConfig()
}
uploadToTlog = signcommon.ShouldUploadToTlog(ctx, ko, nil, tlogUpload)

if !uploadToTlog {
ko.SigningConfig = ko.SigningConfig.WithRekorLogURLs()
if err := signcommon.RequireFulcioForCertificate(ko); err != nil {
return err
}
if len(ko.SigningConfig.RekorLogURLs()) == 0 {
// To maintain backwards compatibility with older cosign versions,
// we do not use ed25519ph for ed25519 keys when the signatures are not
// uploaded to the Tlog.
ko.DefaultLoadOptions = &[]signature.LoadOption{}
}

if err := signcommon.ConfirmPrivacyStatement(ctx, ko); err != nil {
return nil, err
return err
}

keypair, certBytes, chainBytes, idToken, err := signcommon.GetKeypairAndToken(ctx, ko, certPath, certChainPath)
if err != nil {
return nil, fmt.Errorf("getting keypair and token: %w", err)
return fmt.Errorf("getting keypair and token: %w", err)
}
if closer, ok := keypair.(interface{ Close() }); ok {
defer closer.Close()
Expand All @@ -93,23 +82,12 @@ func SignBlobCmd(ctx context.Context, ro *options.RootOptions, ko options.KeyOpt
hashFunction := signcommon.ProtoHashAlgoToHash(keypair.GetHashAlgorithm())
payload, closePayload, err := getPayload(ctx, payloadPath, hashFunction)
if err != nil {
return nil, fmt.Errorf("getting payload: %w", err)
return fmt.Errorf("getting payload: %w", err)
}
defer closePayload()

if hashFunction != crypto.SHA256 && !ko.NewBundleFormat && (uploadToTlog || (!ko.Sk && ko.KeyRef == "")) {
ui.Infof(ctx, "Non SHA256 hash function is not supported for old bundle format. Use --new-bundle-format to use the new bundle format or use different signing key/algorithm.")
if !ko.SkipConfirmation {
if err := ui.ConfirmContinue(ctx); err != nil {
return nil, err
}
}
ui.Infof(ctx, "Continuing with non SHA256 hash function and old bundle format")
}

data, err := io.ReadAll(&payload)
if err != nil {
return nil, fmt.Errorf("reading payload: %w", err)
return fmt.Errorf("reading payload: %w", err)
}
content := &sign.PlainData{
Data: data,
Expand All @@ -119,94 +97,18 @@ func SignBlobCmd(ctx context.Context, ro *options.RootOptions, ko options.KeyOpt
if ko.TSAClientCACert != "" || (ko.TSAClientCert != "" && ko.TSAClientKey != "") {
tsaClientTransport, err = client.GetHTTPTransport(ko.TSAClientCACert, ko.TSAClientCert, ko.TSAClientKey, ko.TSAServerName, 30*time.Second)
if err != nil {
return nil, fmt.Errorf("getting TSA client transport: %w", err)
return fmt.Errorf("getting TSA client transport: %w", err)
}
}
signOpts := cbundle.SignOptions{TSAClientTransport: tsaClientTransport}
bundleBytes, err := cbundle.SignData(ctx, content, keypair, idToken, certBytes, chainBytes, ko.SigningConfig, ko.TrustedMaterial, signOpts)
if err != nil {
return nil, fmt.Errorf("signing bundle: %w", err)
}

if ko.NewBundleFormat {
if err := os.WriteFile(ko.BundlePath, bundleBytes, 0600); err != nil {
return nil, fmt.Errorf("create bundle file: %w", err)
}
ui.Infof(ctx, "Wrote bundle to file %s", ko.BundlePath)
return nil, nil
}

var pb protobundle.Bundle
if err := protojson.Unmarshal(bundleBytes, &pb); err != nil {
return nil, fmt.Errorf("unmarshalling bundle: %w", err)
}

bundleComponents, err := signcommon.ExtractComponentsFromProtoBundle(&pb)
if err != nil {
return nil, fmt.Errorf("extracting components from bundle: %w", err)
}

if ko.BundlePath != "" {
contents, err := signcommon.NewLegacyBundleFromProtoBundleComponents(bundleComponents)
if err != nil {
return nil, fmt.Errorf("creating legacy bundle: %w", err)
}

if err := os.WriteFile(ko.BundlePath, contents, 0600); err != nil {
return nil, fmt.Errorf("create bundle file: %w", err)
}
ui.Infof(ctx, "Wrote bundle to file %s", ko.BundlePath)
}

if outputSignature != "" {
bts := bundleComponents.Signature
if b64 {
bts = []byte(base64.StdEncoding.EncodeToString(bundleComponents.Signature))
}
if err := os.WriteFile(outputSignature, bts, 0600); err != nil {
return nil, fmt.Errorf("create signature file: %w", err)
}
ui.Infof(ctx, "Wrote signature to file %s", outputSignature)
} else {
bts := bundleComponents.Signature
if b64 {
bts = []byte(base64.StdEncoding.EncodeToString(bundleComponents.Signature))
fmt.Println(string(bts))
} else {
if _, err := os.Stdout.Write(bts); err != nil {
return nil, err
}
}
}

if outputCertificate != "" && len(bundleComponents.Certificates) > 0 {
certPem, _ := signcommon.EncodeCertificatesToPEM(bundleComponents.Certificates)
var bts []byte
if b64 {
bts = []byte(base64.StdEncoding.EncodeToString(certPem))
} else {
bts = certPem
}
if err := os.WriteFile(outputCertificate, bts, 0600); err != nil {
return nil, fmt.Errorf("create certificate file: %w", err)
}
ui.Infof(ctx, "Wrote certificate to file %s", outputCertificate)
}

if len(bundleComponents.RFC3161Timestamps) > 0 && ko.RFC3161TimestampPath != "" {
legacyTimestamp := cbundle.TimestampToRFC3161Timestamp(bundleComponents.RFC3161Timestamps[0].GetSignedTimestamp())
ts, err := json.Marshal(legacyTimestamp)
if err != nil {
return nil, fmt.Errorf("marshalling timestamp: %w", err)
}
if err := os.WriteFile(ko.RFC3161TimestampPath, ts, 0600); err != nil {
return nil, fmt.Errorf("create timestamp file: %w", err)
}
ui.Infof(ctx, "Wrote timestamp to file %s", ko.RFC3161TimestampPath)
return fmt.Errorf("signing bundle: %w", err)
}

if b64 {
return []byte(base64.StdEncoding.EncodeToString(bundleComponents.Signature)), nil
if err := os.WriteFile(ko.BundlePath, bundleBytes, 0600); err != nil {
return fmt.Errorf("create bundle file: %w", err)
}
return bundleComponents.Signature, nil
ui.Infof(ctx, "Wrote bundle to file %s", ko.BundlePath)
return nil
}
Loading
Loading