Skip to content
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: 1 addition & 1 deletion api/tech/signing/handlers/init.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package handlers

import (
_ "github.com/sigstore/cosign/v2/pkg/providers/all"
_ "github.com/sigstore/cosign/v3/pkg/providers/all"
_ "ocm.software/ocm/api/tech/signing/handlers/rsa"
_ "ocm.software/ocm/api/tech/signing/handlers/rsa-pss"
_ "ocm.software/ocm/api/tech/signing/handlers/rsa-pss-signingservice"
Expand Down
91 changes: 69 additions & 22 deletions api/tech/signing/handlers/sigstore/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag/conv"
"github.com/mandelsoft/goutils/errors"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
"github.com/sigstore/cosign/v2/pkg/cosign"
"github.com/sigstore/cosign/v3/cmd/cosign/cli/fulcio"
"github.com/sigstore/cosign/v3/cmd/cosign/cli/options"
"github.com/sigstore/cosign/v3/pkg/cosign"
"github.com/sigstore/rekor/pkg/client"
"github.com/sigstore/rekor/pkg/generated/client/entries"
"github.com/sigstore/rekor/pkg/generated/models"
Expand All @@ -31,28 +31,37 @@ import (
)

// Algorithm defines the type for the RSA PKCS #1 v1.5 signature algorithm.
const Algorithm = "sigstore"
// Since "sigstore" contained a buggy implementation, we are introducing "sigstore-v3" as well.
// "sigstore-v3" correctly injects the Fulcio fs.Cert into the bundle, not just the public key like in "sigstore".
const (
Algorithm = "sigstore"
AlgorithmV3 = "sigstore-v3"
)

// MediaType defines the media type for a plain RSA signature.
const MediaType = "application/vnd.ocm.signature.sigstore"

// SignaturePEMBlockAlgorithmHeader defines the header in a signature pem block where the signature algorithm is defined.
const SignaturePEMBlockAlgorithmHeader = "Algorithm"

func init() {
signing.DefaultHandlerRegistry().RegisterSigner(Algorithm, Handler{})
signing.DefaultHandlerRegistry().RegisterSigner(Algorithm, Handler{algorithm: Algorithm})
signing.DefaultHandlerRegistry().RegisterSigner(AlgorithmV3, Handler{algorithm: AlgorithmV3})
}

// Handler is a signatures.Signer compatible struct to sign using sigstore
// and a signatures.Verifier compatible struct to verify using sigstore.
type Handler struct{}
// Uses "algorithm" field to distinguish between old "sigstore" and new "sigstore-v3" flows.
type Handler struct {
algorithm string
}

// Algorithm specifies the name of the signing algorithm.
func (h Handler) Algorithm() string {
return Algorithm
return h.algorithm
}

// Sign implements the signing functionality.
// Since the "sigstore" algorithm had a buggy implementation, we are introducing "sigstore-v3" as well.
// We use the algorithm name to decide if old sigstore or new sigstore-v3 flow is used to
// guarantee backwards compatibility.
func (h Handler) Sign(cctx credentials.Context, digest string, sctx signing.SigningContext) (*signing.Signature, error) {
hash := sctx.GetHash()
// exit immediately if hash alg is not SHA-256, rekor doesn't currently support other hash functions
Expand Down Expand Up @@ -137,8 +146,17 @@ func (h Handler) Sign(cctx credentials.Context, digest string, sctx signing.Sign
return nil, fmt.Errorf("failed to create rekor client: %w", err)
}

// decide which public material to use for rekor entry
// old "sigstore" flow uses only public key
// new "sigstore-v3" flow uses the fulcio certificate
// Since v3 the Fulcio certificate fs.Cert is already in PEM format
rekorPublicMaterial := publicKey
if h.Algorithm() == AlgorithmV3 {
rekorPublicMaterial = fs.Cert
}

// create a rekor hashed entry
hashedEntry := prepareRekorEntry(digest, sig, publicKey)
hashedEntry := prepareRekorEntry(digest, sig, rekorPublicMaterial)

// validate the rekor entry before submission
if _, err := hashedEntry.Canonicalize(ctx); err != nil {
Expand Down Expand Up @@ -169,10 +187,11 @@ func (h Handler) Sign(cctx credentials.Context, digest string, sctx signing.Sign
}

// store the rekor response in the signature value
// depending on the used algorithm, either "sigstore" or "sigstore-v3"
return &signing.Signature{
Value: base64.StdEncoding.EncodeToString(data),
MediaType: MediaType,
Algorithm: Algorithm,
Algorithm: h.Algorithm(),
Issuer: "",
}, nil
}
Expand Down Expand Up @@ -238,18 +257,13 @@ func (h Handler) Verify(digest string, sig *signing.Signature, sctx signing.Sign
return fmt.Errorf("failed to decode rekor public key: %w", err)
}

block, _ := pem.Decode(rekorPublicKeyRaw)
if block == nil {
return fmt.Errorf("failed to decode public key: %w", err)
}

rekorPublicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
rekorPublicKey, err := extractECDSAPublicKey(rekorPublicKeyRaw)
if err != nil {
return fmt.Errorf("failed to parse public key: %w", err)
return err
}

// verify signature
if err := ecdsa.VerifyASN1(rekorPublicKey.(*ecdsa.PublicKey), rawDigest, rekorSignature); !err {
if ok := ecdsa.VerifyASN1(rekorPublicKey, rawDigest, rekorSignature); !ok {
return errors.New("could not verify signature using public key")
}

Expand All @@ -270,8 +284,8 @@ func loadVerifier(ctx context.Context) (signature.Verifier, error) {
for _, pubKey := range publicKeys.Keys {
return signature.LoadVerifier(pubKey.PubKey, crypto.SHA256)
}

return nil, nil
// in rare case no public keys are found
return nil, errors.New("no Rekor public key found")
}

// based on: https://github.com/sigstore/cosign/blob/ff648d5fb4ed6d0d1c16eaaceff970411fa969e3/pkg/cosign/tlog.go#L233
Expand All @@ -295,3 +309,36 @@ func prepareRekorEntry(digest string, sig, publicKey []byte) hashedrekord_v001.V
},
}
}

func extractECDSAPublicKey(pubKeyBytes []byte) (*ecdsa.PublicKey, error) {
block, _ := pem.Decode(pubKeyBytes)
if block == nil {
return nil, fmt.Errorf("no PEM block found in Fulcio public key")
}
switch block.Type {
case "PUBLIC KEY":
result, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse public key: %w", err)
}
// cast to ecdsa.PublicKey as we use this in the verification
pub, ok := result.(*ecdsa.PublicKey)
if !ok {
return nil, fmt.Errorf("unexpected public key type: %T", result)
}
return pub, nil
case "CERTIFICATE":
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse Fulcio certificate: %w", err)
}
// cast to ecdsa.PublicKey as we use this in the verification
pub, ok := cert.PublicKey.(*ecdsa.PublicKey)
if !ok {
return nil, fmt.Errorf("unexpected certificate public key type: %T", cert.PublicKey)
}
return pub, nil
default:
return nil, fmt.Errorf("unsupported PEM block type: %s", block.Type)
}
}
1 change: 1 addition & 0 deletions docs/reference/ocm_sign_componentversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ The following signing types are supported with option <code>--algorithm</code>:
- <code>rsa-signingservice</code>
- <code>rsapss-signingservice</code>
- <code>sigstore</code>
- <code>sigstore-v3</code>


The following normalization modes are supported with option <code>--normalization</code>:
Expand Down
65 changes: 24 additions & 41 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ require (
github.com/pkg/errors v0.9.1
github.com/redis/go-redis/v9 v9.17.2
github.com/rogpeppe/go-internal v1.14.1
github.com/sigstore/cosign/v2 v2.6.1
github.com/sigstore/cosign/v3 v3.0.3
github.com/sigstore/rekor v1.4.3
github.com/sigstore/sigstore v1.10.3
github.com/sirupsen/logrus v1.9.3
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
github.com/stretchr/testify v1.11.1
Expand Down Expand Up @@ -96,16 +96,11 @@ require (
require (
4d63.com/gocheckcompilerdirectives v1.3.0 // indirect
4d63.com/gochecknoglobals v0.2.2 // indirect
cel.dev/expr v0.25.0 // indirect
cloud.google.com/go v0.123.0 // indirect
cloud.google.com/go/auth v0.17.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
cloud.google.com/go/iam v1.5.3 // indirect
cloud.google.com/go/longrunning v0.7.0 // indirect
cloud.google.com/go/monitoring v1.24.3 // indirect
cloud.google.com/go/spanner v1.86.1 // indirect
cloud.google.com/go/storage v1.57.1 // indirect
codeberg.org/chavacava/garif v0.2.0 // indirect
github.com/4meepo/tagalign v1.4.2 // indirect
github.com/Abirdcfly/dupword v0.1.6 // indirect
Expand All @@ -127,10 +122,6 @@ require (
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 // indirect
github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.3 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
Expand Down Expand Up @@ -177,7 +168,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect
github.com/aws/smithy-go v1.24.0 // indirect
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.10.1 // indirect
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.11.0 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bkielbasa/cyclop v1.2.3 // indirect
Expand All @@ -188,7 +179,7 @@ require (
github.com/bombsimon/wsl/v5 v5.1.1 // indirect
github.com/breml/bidichk v0.3.3 // indirect
github.com/breml/errchkjson v0.4.1 // indirect
github.com/buildkite/agent/v3 v3.111.0 // indirect
github.com/buildkite/agent/v3 v3.114.1 // indirect
github.com/buildkite/go-pipeline v0.16.0 // indirect
github.com/buildkite/interpolate v0.1.5 // indirect
github.com/buildkite/roko v1.4.0 // indirect
Expand All @@ -203,7 +194,7 @@ require (
github.com/charithe/durationcheck v0.0.10 // indirect
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
github.com/charmbracelet/lipgloss v1.1.0 // indirect
github.com/charmbracelet/x/ansi v0.10.1 // indirect
github.com/charmbracelet/x/ansi v0.10.2 // indirect
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect
Expand All @@ -212,7 +203,6 @@ require (
github.com/clipperhouse/stringish v0.1.1 // indirect
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/cncf/xds/go v0.0.0-20251031190108-5cf4b1949528 // indirect
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
Expand Down Expand Up @@ -242,8 +232,6 @@ require (
github.com/elliotchance/orderedmap v1.8.0 // indirect
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
github.com/ettle/strcase v0.2.0 // indirect
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
Expand Down Expand Up @@ -273,17 +261,17 @@ require (
github.com/go-openapi/loads v0.23.2 // indirect
github.com/go-openapi/runtime v0.29.2 // indirect
github.com/go-openapi/spec v0.22.1 // indirect
github.com/go-openapi/swag v0.25.1 // indirect
github.com/go-openapi/swag/cmdutils v0.25.1 // indirect
github.com/go-openapi/swag/fileutils v0.25.1 // indirect
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
github.com/go-openapi/swag/jsonutils v0.25.1 // indirect
github.com/go-openapi/swag/loading v0.25.1 // indirect
github.com/go-openapi/swag/mangling v0.25.1 // indirect
github.com/go-openapi/swag/netutils v0.25.1 // indirect
github.com/go-openapi/swag/stringutils v0.25.1 // indirect
github.com/go-openapi/swag v0.25.4 // indirect
github.com/go-openapi/swag/cmdutils v0.25.4 // indirect
github.com/go-openapi/swag/fileutils v0.25.4 // indirect
github.com/go-openapi/swag/jsonname v0.25.4 // indirect
github.com/go-openapi/swag/jsonutils v0.25.4 // indirect
github.com/go-openapi/swag/loading v0.25.4 // indirect
github.com/go-openapi/swag/mangling v0.25.4 // indirect
github.com/go-openapi/swag/netutils v0.25.4 // indirect
github.com/go-openapi/swag/stringutils v0.25.4 // indirect
github.com/go-openapi/swag/typeutils v0.25.4 // indirect
github.com/go-openapi/swag/yamlutils v0.25.1 // indirect
github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
github.com/go-openapi/validate v0.25.1 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/go-toolsmith/astcast v1.1.0 // indirect
Expand Down Expand Up @@ -371,9 +359,10 @@ require (
github.com/ldez/tagliatelle v0.7.1 // indirect
github.com/ldez/usetesting v0.5.0 // indirect
github.com/leonklingele/grouper v1.1.2 // indirect
github.com/letsencrypt/boulder v0.20251110.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
github.com/macabu/inamedparam v0.2.0 // indirect
github.com/magiconair/properties v1.8.10 // indirect
Expand All @@ -386,7 +375,6 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.19 // indirect
github.com/mgechev/revive v1.11.0 // indirect
github.com/miekg/dns v1.1.61 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
Expand All @@ -413,7 +401,6 @@ require (
github.com/nishanths/predeclared v0.2.2 // indirect
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
github.com/nunnatsa/ginkgolinter v0.20.0 // indirect
github.com/nxadm/tail v1.4.11 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/oleiade/reflections v1.1.0 // indirect
github.com/opencontainers/runtime-spec v1.3.0 // indirect
Expand All @@ -422,7 +409,6 @@ require (
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pjbgf/sha1cd v0.5.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/polyfloyd/go-errorlint v1.8.0 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
Expand All @@ -436,7 +422,6 @@ require (
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
github.com/raeperd/recvcheck v0.2.0 // indirect
github.com/redis/go-redis/extra/redisotel/v9 v9.5.3 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rubenv/sql-migrate v1.8.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
Expand All @@ -457,9 +442,9 @@ require (
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sigstore/fulcio v1.8.4 // indirect
github.com/sigstore/protobuf-specs v0.5.0 // indirect
github.com/sigstore/rekor-tiles v0.1.11 // indirect
github.com/sigstore/sigstore-go v1.1.3 // indirect
github.com/sigstore/timestamp-authority v1.2.9 // indirect
github.com/sigstore/rekor-tiles/v2 v2.0.1 // indirect
github.com/sigstore/sigstore-go v1.1.4-0.20251201121426-2cdedea80894 // indirect
github.com/sigstore/timestamp-authority/v2 v2.0.3 // indirect
github.com/sivchari/containedctx v1.0.3 // indirect
github.com/skeema/knownhosts v1.3.2 // indirect
github.com/sonatard/noctx v0.4.0 // indirect
Expand All @@ -480,14 +465,14 @@ require (
github.com/theupdateframework/go-tuf/v2 v2.3.0 // indirect
github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 // indirect
github.com/timonwong/loggercheck v0.11.0 // indirect
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/tklauser/go-sysconf v0.3.15 // indirect
github.com/tklauser/numcpus v0.10.0 // indirect
github.com/tomarrell/wrapcheck/v2 v2.11.0 // indirect
github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
github.com/transparency-dev/formats v0.0.0-20251103090025-99ec6f4410eb // indirect
github.com/transparency-dev/merkle v0.0.2 // indirect
github.com/transparency-dev/tessera v1.0.0 // indirect
github.com/ultraware/funlen v0.2.0 // indirect
github.com/ultraware/whitespace v0.2.0 // indirect
github.com/uudashr/gocognit v1.2.0 // indirect
Expand All @@ -508,21 +493,19 @@ require (
github.com/yuin/gopher-lua v1.1.1 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
gitlab.com/bosi/decorder v0.4.2 // indirect
gitlab.com/gitlab-org/api/client-go v0.159.0 // indirect
gitlab.com/gitlab-org/api/client-go v0.160.0 // indirect
go-simpler.org/musttag v0.13.1 // indirect
go-simpler.org/sloglint v0.11.1 // indirect
go.augendre.info/arangolint v0.2.0 // indirect
go.augendre.info/fatcontext v0.8.0 // indirect
go.mongodb.org/mongo-driver v1.17.6 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
go.opentelemetry.io/otel v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
Expand Down Expand Up @@ -559,7 +542,7 @@ require (
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
k8s.io/kubectl v0.35.0 // indirect
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
mvdan.cc/gofumpt v0.8.0 // indirect
mvdan.cc/gofumpt v0.9.2 // indirect
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/kustomize/api v0.20.1 // indirect
Expand Down
Loading
Loading