From 2c5ab4a67384bf651765eda406b5089bcc47f9b2 Mon Sep 17 00:00:00 2001 From: "renovate-rancher[bot]" <119870437+renovate-rancher[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2026 05:50:43 +0000 Subject: [PATCH] Update module github.com/sigstore/sigstore to v1.10.8 --- go.mod | 7 +- go.sum | 14 +- .../go-securesystemslib/dsse/envelope.go | 26 +- .../go-securesystemslib/dsse/verify.go | 22 +- .../sigstore/pkg/cryptoutils/privatekey.go | 34 ++ .../sigstore/pkg/signature/dsse/dsse.go | 36 +- .../sigstore/pkg/signature/dsse/multidsse.go | 55 +++- .../sigstore/pkg/signature/dsse/options.go | 53 +++ vendor/github.com/youmark/pkcs8/.gitignore | 23 ++ vendor/github.com/youmark/pkcs8/LICENSE | 21 ++ vendor/github.com/youmark/pkcs8/README | 1 + vendor/github.com/youmark/pkcs8/README.md | 22 ++ vendor/github.com/youmark/pkcs8/cipher.go | 60 ++++ .../github.com/youmark/pkcs8/cipher_3des.go | 24 ++ vendor/github.com/youmark/pkcs8/cipher_aes.go | 84 +++++ vendor/github.com/youmark/pkcs8/kdf_pbkdf2.go | 91 ++++++ vendor/github.com/youmark/pkcs8/kdf_scrypt.go | 62 ++++ vendor/github.com/youmark/pkcs8/pkcs8.go | 309 ++++++++++++++++++ vendor/modules.txt | 11 +- 19 files changed, 913 insertions(+), 42 deletions(-) create mode 100644 vendor/github.com/sigstore/sigstore/pkg/signature/dsse/options.go create mode 100644 vendor/github.com/youmark/pkcs8/.gitignore create mode 100644 vendor/github.com/youmark/pkcs8/LICENSE create mode 100644 vendor/github.com/youmark/pkcs8/README create mode 100644 vendor/github.com/youmark/pkcs8/README.md create mode 100644 vendor/github.com/youmark/pkcs8/cipher.go create mode 100644 vendor/github.com/youmark/pkcs8/cipher_3des.go create mode 100644 vendor/github.com/youmark/pkcs8/cipher_aes.go create mode 100644 vendor/github.com/youmark/pkcs8/kdf_pbkdf2.go create mode 100644 vendor/github.com/youmark/pkcs8/kdf_scrypt.go create mode 100644 vendor/github.com/youmark/pkcs8/pkcs8.go diff --git a/go.mod b/go.mod index 0a93718e4..0893fa17d 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/quay/clair/v2 v2.1.8 github.com/sigstore/cosign/v3 v3.0.6 github.com/sigstore/rekor v1.5.1 - github.com/sigstore/sigstore v1.10.6 + github.com/sigstore/sigstore v1.10.8 github.com/sirupsen/logrus v1.9.4 github.com/stretchr/testify v1.11.1 github.com/theupdateframework/go-tuf v0.7.0 @@ -110,7 +110,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.6 // indirect github.com/knqyf263/go-rpmdb v0.1.1 // indirect - github.com/letsencrypt/boulder v0.20260223.0 // indirect + github.com/letsencrypt/boulder v0.20260309.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/miekg/pkcs11 v1.1.2 // indirect @@ -140,7 +140,7 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/sassoftware/relic v7.2.1+incompatible // indirect - github.com/secure-systems-lab/go-securesystemslib v0.10.0 // indirect + github.com/secure-systems-lab/go-securesystemslib v0.11.0 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/sigstore/protobuf-specs v0.5.0 // indirect github.com/sigstore/rekor-tiles/v2 v2.2.1 // indirect @@ -159,6 +159,7 @@ require ( github.com/vishvananda/netlink v1.3.1 // indirect github.com/vishvananda/netns v0.0.5 // indirect github.com/x448/float16 v0.8.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect gitlab.com/gitlab-org/api/client-go v1.46.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect diff --git a/go.sum b/go.sum index e307fe795..50da5fda3 100644 --- a/go.sum +++ b/go.sum @@ -399,8 +399,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/letsencrypt/boulder v0.20260223.0 h1:xdS2OnJNUasR6TgVIOpqqcvdkOu47+PQQMBk9ThuWBw= -github.com/letsencrypt/boulder v0.20260223.0/go.mod h1:r3aTSA7UZ7dbDfiGK+HLHJz0bWNbHk6YSPiXgzl23sA= +github.com/letsencrypt/boulder v0.20260309.0 h1:kZynrxK3QfqLGx6hhoz+Rfs3hgltJs1p9Mp+4+VwnY0= +github.com/letsencrypt/boulder v0.20260309.0/go.mod h1:yG8lj8pNPZ8taq3oNdTpfBS+eC74IaEuiewqzVpXiWE= github.com/lib/pq v0.0.0-20170324204654-2704adc878c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -520,8 +520,8 @@ github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGq github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk= github.com/sassoftware/relic/v7 v7.6.2 h1:rS44Lbv9G9eXsukknS4mSjIAuuX+lMq/FnStgmZlUv4= github.com/sassoftware/relic/v7 v7.6.2/go.mod h1:kjmP0IBVkJZ6gXeAu35/KCEfca//+PKM6vTAsyDPY+k= -github.com/secure-systems-lab/go-securesystemslib v0.10.0 h1:l+H5ErcW0PAehBNrBxoGv1jjNpGYdZ9RcheFkB2WI14= -github.com/secure-systems-lab/go-securesystemslib v0.10.0/go.mod h1:MRKONWmRoFzPNQ9USRF9i1mc7MvAVvF1LlW8X5VWDvk= +github.com/secure-systems-lab/go-securesystemslib v0.11.0 h1:iuCR9kcMFD4QurdKrGvPLoKZLv9YvwPYVr0473BdtFs= +github.com/secure-systems-lab/go-securesystemslib v0.11.0/go.mod h1:+PMOTjUGwHj2vcZ+TFKlb1tXRbrdWE1LYDT5i9JC80Q= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= @@ -534,8 +534,8 @@ github.com/sigstore/rekor v1.5.1 h1:Ca1egHRWRuDvXV4tZu9aXEXc3Gej9FG+HKeapV9OAMQ= github.com/sigstore/rekor v1.5.1/go.mod h1:gTLDuZuo3SyQCuZvKqwRPA79Qo/2rw39/WtLP/rZjUQ= github.com/sigstore/rekor-tiles/v2 v2.2.1 h1:UmV1CBQ3SjxxPGpFmwDoOhoIwiKpM2Qm1pU5tPGmvNk= github.com/sigstore/rekor-tiles/v2 v2.2.1/go.mod h1:z8n6l6oidpaLjjE6rJERuQqY9X38ulnHZCXyL+DEL7U= -github.com/sigstore/sigstore v1.10.6 h1:YWhMQfTrJSK80QB1pbxjYeAwGKx+5UwWPPAY9hrPPZg= -github.com/sigstore/sigstore v1.10.6/go.mod h1:k/mcVVXw3I87dYG/iCVTSW2xTrW7vPzxxGic4KqsqXs= +github.com/sigstore/sigstore v1.10.8 h1:1Mgkxvkw4AXMfIP1DOjc6kw0GkUgA8pGVpveN/EfOq4= +github.com/sigstore/sigstore v1.10.8/go.mod h1:f9+B/4iaYimvUkySyb2mvc73n3RLqNn24grHZM/ET8M= github.com/sigstore/sigstore-go v1.1.4 h1:wTTsgCHOfqiEzVyBYA6mDczGtBkN7cM8mPpjJj5QvMg= github.com/sigstore/sigstore-go v1.1.4/go.mod h1:2U/mQOT9cjjxrtIUeKDVhL+sHBKsnWddn8URlswdBsg= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.5 h1:aqHRubTITULckG9JAcq2FEhtKkT/RRE8oErfuV3smSI= @@ -603,6 +603,8 @@ github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zd github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns= github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= diff --git a/vendor/github.com/secure-systems-lab/go-securesystemslib/dsse/envelope.go b/vendor/github.com/secure-systems-lab/go-securesystemslib/dsse/envelope.go index 8e48cc6fe..933057650 100644 --- a/vendor/github.com/secure-systems-lab/go-securesystemslib/dsse/envelope.go +++ b/vendor/github.com/secure-systems-lab/go-securesystemslib/dsse/envelope.go @@ -1,8 +1,10 @@ package dsse import ( + "bytes" "encoding/base64" "fmt" + "strconv" ) /* @@ -42,9 +44,27 @@ PAE implements the DSSE Pre-Authentic Encoding https://github.com/secure-systems-lab/dsse/blob/master/protocol.md#signature-definition */ func PAE(payloadType string, payload []byte) []byte { - return []byte(fmt.Sprintf("DSSEv1 %d %s %d %s", - len(payloadType), payloadType, - len(payload), payload)) + // Pre-size to avoid reallocation. Previously fmt.Sprintf copied payload + // into a string and []byte(...) copied it again. + const prefix = "DSSEv1 " + const sep = " " + // Max decimal digits for a non-negative int (len() result) on any + // platform: len("9223372036854775807") == 19. Grow is a hint, so a + // slight overestimate is harmless. + const maxDecimalLen = 19 + var b bytes.Buffer + b.Grow(len(prefix) + + maxDecimalLen + len(sep) + len(payloadType) + len(sep) + + maxDecimalLen + len(sep) + len(payload)) + b.WriteString(prefix) + b.WriteString(strconv.Itoa(len(payloadType))) + b.WriteByte(' ') + b.WriteString(payloadType) + b.WriteByte(' ') + b.WriteString(strconv.Itoa(len(payload))) + b.WriteByte(' ') + b.Write(payload) + return b.Bytes() } /* diff --git a/vendor/github.com/secure-systems-lab/go-securesystemslib/dsse/verify.go b/vendor/github.com/secure-systems-lab/go-securesystemslib/dsse/verify.go index 034e4faaf..5c83d2ec0 100644 --- a/vendor/github.com/secure-systems-lab/go-securesystemslib/dsse/verify.go +++ b/vendor/github.com/secure-systems-lab/go-securesystemslib/dsse/verify.go @@ -24,18 +24,26 @@ type AcceptedKey struct { } func (ev *EnvelopeVerifier) Verify(ctx context.Context, e *Envelope) ([]AcceptedKey, error) { + keys, _, err := ev.VerifyAndDecode(ctx, e) + return keys, err +} + +// VerifyAndDecode behaves identically to Verify but also returns the decoded +// envelope payload, allowing callers who need the payload bytes (e.g., for +// hashing or further parsing) to avoid a second base64 decode. +func (ev *EnvelopeVerifier) VerifyAndDecode(ctx context.Context, e *Envelope) ([]AcceptedKey, []byte, error) { if e == nil { - return nil, errors.New("cannot verify a nil envelope") + return nil, nil, errors.New("cannot verify a nil envelope") } if len(e.Signatures) == 0 { - return nil, ErrNoSignature + return nil, nil, ErrNoSignature } // Decode payload (i.e serialized body) body, err := e.DecodeB64Payload() if err != nil { - return nil, err + return nil, nil, err } // Generate PAE(payloadtype, serialized body) paeEnc := PAE(e.PayloadType, body) @@ -48,7 +56,7 @@ func (ev *EnvelopeVerifier) Verify(ctx context.Context, e *Envelope) ([]Accepted for _, s := range e.Signatures { sig, err := b64Decode(s.Sig) if err != nil { - return nil, err + return nil, nil, err } // Loop over the providers. @@ -97,14 +105,14 @@ func (ev *EnvelopeVerifier) Verify(ctx context.Context, e *Envelope) ([]Accepted // Sanity if with some reflect magic this happens. if ev.threshold <= 0 || ev.threshold > len(ev.providers) { - return nil, errors.New("invalid threshold") + return nil, nil, errors.New("invalid threshold") } if len(usedKeyids) < ev.threshold { - return acceptedKeys, fmt.Errorf("accepted signatures do not match threshold, Found: %d, Expected %d", len(acceptedKeys), ev.threshold) + return acceptedKeys, nil, fmt.Errorf("accepted signatures do not match threshold, Found: %d, Expected %d", len(acceptedKeys), ev.threshold) } - return acceptedKeys, nil + return acceptedKeys, body, nil } func NewEnvelopeVerifier(v ...Verifier) (*EnvelopeVerifier, error) { diff --git a/vendor/github.com/sigstore/sigstore/pkg/cryptoutils/privatekey.go b/vendor/github.com/sigstore/sigstore/pkg/cryptoutils/privatekey.go index 325813d69..5ecf346db 100644 --- a/vendor/github.com/sigstore/sigstore/pkg/cryptoutils/privatekey.go +++ b/vendor/github.com/sigstore/sigstore/pkg/cryptoutils/privatekey.go @@ -27,6 +27,7 @@ import ( "fmt" "github.com/secure-systems-lab/go-securesystemslib/encrypted" + "github.com/youmark/pkcs8" ) const ( @@ -107,6 +108,26 @@ func UnmarshalPEMToPrivateKey(pemBytes []byte, pf PassFunc) (crypto.PrivateKey, if derBlock == nil { return nil, errors.New("PEM decoding failed") } + + // Handle legacy encrypted PEM blocks + if x509.IsEncryptedPEMBlock(derBlock) { //nolint:staticcheck + if pf == nil { + return nil, errors.New("private key is encrypted, but no password function was provided") + } + password, err := pf(false) + if err != nil { + return nil, err + } + decryptedBytes, err := x509.DecryptPEMBlock(derBlock, password) //nolint:staticcheck + if err != nil { + return nil, fmt.Errorf("failed to decrypt legacy PEM block: %w", err) + } + derBlock = &pem.Block{ + Type: derBlock.Type, + Bytes: decryptedBytes, + } + } + switch derBlock.Type { case string(PrivateKeyPEMType): return x509.ParsePKCS8PrivateKey(derBlock.Bytes) @@ -114,6 +135,19 @@ func UnmarshalPEMToPrivateKey(pemBytes []byte, pf PassFunc) (crypto.PrivateKey, return x509.ParsePKCS1PrivateKey(derBlock.Bytes) case string(ECPrivateKeyPEMType): return x509.ParseECPrivateKey(derBlock.Bytes) + case "ENCRYPTED PRIVATE KEY": + if pf == nil { + return nil, errors.New("private key is encrypted, but no password function was provided") + } + password, err := pf(false) + if err != nil { + return nil, err + } + decryptedKey, err := pkcs8.ParsePKCS8PrivateKey(derBlock.Bytes, password) + if err != nil { + return nil, fmt.Errorf("failed to decrypt and parse encrypted private key: %w", err) + } + return decryptedKey, nil case string(EncryptedSigstorePrivateKeyPEMType), string(encryptedCosignPrivateKeyPEMType): derBytes := derBlock.Bytes if pf != nil { diff --git a/vendor/github.com/sigstore/sigstore/pkg/signature/dsse/dsse.go b/vendor/github.com/sigstore/sigstore/pkg/signature/dsse/dsse.go index 628e2413c..c2c34c16a 100644 --- a/vendor/github.com/sigstore/sigstore/pkg/signature/dsse/dsse.go +++ b/vendor/github.com/sigstore/sigstore/pkg/signature/dsse/dsse.go @@ -21,6 +21,7 @@ import ( "crypto" "encoding/base64" "encoding/json" + "fmt" "io" "github.com/secure-systems-lab/go-securesystemslib/dsse" @@ -70,14 +71,17 @@ func (w *wrappedSigner) SignMessage(r io.Reader, opts ...signature.SignOption) ( } // WrapVerifier returns a signature.Verifier that uses the DSSE encoding format -func WrapVerifier(v signature.Verifier) signature.Verifier { +func WrapVerifier(v signature.Verifier, opts ...Option) signature.Verifier { + cfg := applyWrapOpts(opts) return &wrappedVerifier{ - v: v, + v: v, + cfg: cfg, } } type wrappedVerifier struct { - v signature.Verifier + v signature.Verifier + cfg wrapConfig } // PublicKey returns the public key associated with the verifier @@ -97,6 +101,10 @@ func (w *wrappedVerifier) VerifySignature(s, _ io.Reader, _ ...signature.VerifyO return err } + if w.cfg.expectedPayloadType != "" && env.PayloadType != w.cfg.expectedPayloadType { + return fmt.Errorf("dsse: unexpected payload type: got %q, want %q", env.PayloadType, w.cfg.expectedPayloadType) + } + pub, err := w.PublicKey() if err != nil { return err @@ -111,18 +119,30 @@ func (w *wrappedVerifier) VerifySignature(s, _ io.Reader, _ ...signature.VerifyO return err } - _, err = verifier.Verify(context.Background(), &env) - return err + _, payload, err := verifier.VerifyAndDecode(context.Background(), &env) + if err != nil { + return err + } + if w.cfg.decodedPayload != nil { + *w.cfg.decodedPayload = payload + } + return nil } -// WrapSignerVerifier returns a signature.SignerVerifier that uses the DSSE encoding format -func WrapSignerVerifier(sv signature.SignerVerifier, payloadType string) signature.SignerVerifier { +// WrapSignerVerifier returns a signature.SignerVerifier that uses the DSSE encoding format. +// The payloadType is automatically enforced during verification via +// WithExpectedPayloadType; callers may supply additional Option values +// which are applied after the implicit payload-type option. +func WrapSignerVerifier(sv signature.SignerVerifier, payloadType string, opts ...Option) signature.SignerVerifier { + opts = append([]Option{WithExpectedPayloadType(payloadType)}, opts...) + cfg := applyWrapOpts(opts) signer := &wrappedSigner{ payloadType: payloadType, s: sv, } verifier := &wrappedVerifier{ - v: sv, + v: sv, + cfg: cfg, } return &wrappedSignerVerifier{ diff --git a/vendor/github.com/sigstore/sigstore/pkg/signature/dsse/multidsse.go b/vendor/github.com/sigstore/sigstore/pkg/signature/dsse/multidsse.go index 34ebd5a41..29eab3c83 100644 --- a/vendor/github.com/sigstore/sigstore/pkg/signature/dsse/multidsse.go +++ b/vendor/github.com/sigstore/sigstore/pkg/signature/dsse/multidsse.go @@ -20,6 +20,7 @@ import ( "crypto" "encoding/json" "errors" + "fmt" "io" "github.com/secure-systems-lab/go-securesystemslib/dsse" @@ -86,13 +87,25 @@ func (wL *wrappedMultiSigner) SignMessage(r io.Reader, _ ...signature.SignOption } type wrappedMultiVerifier struct { - vLAdapters []dsse.Verifier - threshold int - payloadType string + vLAdapters []dsse.Verifier + threshold int + cfg wrapConfig } -// WrapMultiVerifier returns a signature.Verifier that uses the DSSE encoding format +// WrapMultiVerifier returns a signature.Verifier that uses the DSSE encoding format. +// +// Deprecated: Use WrapMultiVerifierWithOpts instead. func WrapMultiVerifier(payloadType string, threshold int, vL ...signature.Verifier) signature.Verifier { + return WrapMultiVerifierWithOpts(payloadType, threshold, vL) +} + +// WrapMultiVerifierWithOpts returns a signature.Verifier that uses the DSSE encoding format. +// If payloadType is non-empty, WithExpectedPayloadType is automatically applied +// before any caller-supplied options. +func WrapMultiVerifierWithOpts(payloadType string, threshold int, vL []signature.Verifier, opts ...Option) signature.Verifier { + if payloadType != "" { + opts = append([]Option{WithExpectedPayloadType(payloadType)}, opts...) + } verifierAdapterL := make([]dsse.Verifier, 0, len(vL)) for _, v := range vL { pub, err := v.PublicKey() @@ -114,10 +127,11 @@ func WrapMultiVerifier(payloadType string, threshold int, vL ...signature.Verifi verifierAdapterL = append(verifierAdapterL, verifierAdapter) } + cfg := applyWrapOpts(opts) return &wrappedMultiVerifier{ - vLAdapters: verifierAdapterL, - payloadType: payloadType, - threshold: threshold, + vLAdapters: verifierAdapterL, + threshold: threshold, + cfg: cfg, } } @@ -138,17 +152,36 @@ func (wL *wrappedMultiVerifier) VerifySignature(s, _ io.Reader, _ ...signature.V return err } + if wL.cfg.expectedPayloadType != "" && env.PayloadType != wL.cfg.expectedPayloadType { + return fmt.Errorf("dsse: unexpected payload type: got %q, want %q", env.PayloadType, wL.cfg.expectedPayloadType) + } + envVerifier, err := dsse.NewMultiEnvelopeVerifier(wL.threshold, wL.vLAdapters...) if err != nil { return err } - _, err = envVerifier.Verify(context.Background(), &env) - return err + _, payload, err := envVerifier.VerifyAndDecode(context.Background(), &env) + if err != nil { + return err + } + if wL.cfg.decodedPayload != nil { + *wL.cfg.decodedPayload = payload + } + return nil } -// WrapMultiSignerVerifier returns a signature.SignerVerifier that uses the DSSE encoding format +// WrapMultiSignerVerifier returns a signature.SignerVerifier that uses the DSSE encoding format. +// +// Deprecated: Use WrapMultiSignerVerifierWithOpts instead. func WrapMultiSignerVerifier(payloadType string, threshold int, svL ...signature.SignerVerifier) signature.SignerVerifier { + return WrapMultiSignerVerifierWithOpts(payloadType, threshold, svL) +} + +// WrapMultiSignerVerifierWithOpts returns a signature.SignerVerifier that uses the DSSE encoding format. +// The payloadType is automatically enforced during verification via +// WrapMultiVerifierWithOpts; callers may supply additional Option values. +func WrapMultiSignerVerifierWithOpts(payloadType string, threshold int, svL []signature.SignerVerifier, opts ...Option) signature.SignerVerifier { signerL := make([]signature.Signer, 0, len(svL)) verifierL := make([]signature.Verifier, 0, len(svL)) for _, sv := range svL { @@ -157,7 +190,7 @@ func WrapMultiSignerVerifier(payloadType string, threshold int, svL ...signature } sL := WrapMultiSigner(payloadType, signerL...) - vL := WrapMultiVerifier(payloadType, threshold, verifierL...) + vL := WrapMultiVerifierWithOpts(payloadType, threshold, verifierL, opts...) return &wrappedMultiSignerVerifier{ signer: sL, diff --git a/vendor/github.com/sigstore/sigstore/pkg/signature/dsse/options.go b/vendor/github.com/sigstore/sigstore/pkg/signature/dsse/options.go new file mode 100644 index 000000000..62f574d2d --- /dev/null +++ b/vendor/github.com/sigstore/sigstore/pkg/signature/dsse/options.go @@ -0,0 +1,53 @@ +// +// Copyright 2026 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 dsse + +// Option is a functional option for WrapVerifier, WrapSignerVerifier, +// WrapMultiVerifierWithOpts, and WrapMultiSignerVerifierWithOpts. +type Option func(*wrapConfig) + +type wrapConfig struct { + decodedPayload *[]byte + expectedPayloadType string +} + +// WithDecodedPayload returns an Option that causes the verifier to write +// the decoded envelope payload into the provided byte slice pointer. This +// avoids a redundant base64 decode when callers need the payload after +// verification. +func WithDecodedPayload(p *[]byte) Option { + return func(c *wrapConfig) { + c.decodedPayload = p + } +} + +// WithExpectedPayloadType returns an Option that causes the verifier to +// check the envelope's payload type against the expected value before +// verifying. If the types do not match, verification fails immediately. +// When this option is not set, any payload type is accepted. +func WithExpectedPayloadType(t string) Option { + return func(c *wrapConfig) { + c.expectedPayloadType = t + } +} + +func applyWrapOpts(opts []Option) wrapConfig { + var cfg wrapConfig + for _, o := range opts { + o(&cfg) + } + return cfg +} diff --git a/vendor/github.com/youmark/pkcs8/.gitignore b/vendor/github.com/youmark/pkcs8/.gitignore new file mode 100644 index 000000000..836562412 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/.gitignore @@ -0,0 +1,23 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test diff --git a/vendor/github.com/youmark/pkcs8/LICENSE b/vendor/github.com/youmark/pkcs8/LICENSE new file mode 100644 index 000000000..c939f4481 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 youmark + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/youmark/pkcs8/README b/vendor/github.com/youmark/pkcs8/README new file mode 100644 index 000000000..376fcaf64 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/README @@ -0,0 +1 @@ +pkcs8 package: implement PKCS#8 private key parsing and conversion as defined in RFC5208 and RFC5958 diff --git a/vendor/github.com/youmark/pkcs8/README.md b/vendor/github.com/youmark/pkcs8/README.md new file mode 100644 index 000000000..ef6c76257 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/README.md @@ -0,0 +1,22 @@ +pkcs8 +=== +OpenSSL can generate private keys in both "traditional format" and PKCS#8 format. Newer applications are advised to use more secure PKCS#8 format. Go standard crypto package provides a [function](http://golang.org/pkg/crypto/x509/#ParsePKCS8PrivateKey) to parse private key in PKCS#8 format. There is a limitation to this function. It can only handle unencrypted PKCS#8 private keys. To use this function, the user has to save the private key in file without encryption, which is a bad practice to leave private keys unprotected on file systems. In addition, Go standard package lacks the functions to convert RSA/ECDSA private keys into PKCS#8 format. + +pkcs8 package fills the gap here. It implements functions to process private keys in PKCS#8 format, as defined in [RFC5208](https://tools.ietf.org/html/rfc5208) and [RFC5958](https://tools.ietf.org/html/rfc5958). It can handle both unencrypted PKCS#8 PrivateKeyInfo format and EncryptedPrivateKeyInfo format with PKCS#5 (v2.0) algorithms. + + +[**Godoc**](http://godoc.org/github.com/youmark/pkcs8) + +## Installation +Supports Go 1.10+. Release v1.1 is the last release supporting Go 1.9 + +```text +go get github.com/youmark/pkcs8 +``` +## dependency +This package depends on golang.org/x/crypto/pbkdf2 and golang.org/x/crypto/scrypt packages. Use the following command to retrieve them +```text +go get golang.org/x/crypto/pbkdf2 +go get golang.org/x/crypto/scrypt +``` + diff --git a/vendor/github.com/youmark/pkcs8/cipher.go b/vendor/github.com/youmark/pkcs8/cipher.go new file mode 100644 index 000000000..2946c93e8 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/cipher.go @@ -0,0 +1,60 @@ +package pkcs8 + +import ( + "bytes" + "crypto/cipher" + "encoding/asn1" +) + +type cipherWithBlock struct { + oid asn1.ObjectIdentifier + ivSize int + keySize int + newBlock func(key []byte) (cipher.Block, error) +} + +func (c cipherWithBlock) IVSize() int { + return c.ivSize +} + +func (c cipherWithBlock) KeySize() int { + return c.keySize +} + +func (c cipherWithBlock) OID() asn1.ObjectIdentifier { + return c.oid +} + +func (c cipherWithBlock) Encrypt(key, iv, plaintext []byte) ([]byte, error) { + block, err := c.newBlock(key) + if err != nil { + return nil, err + } + return cbcEncrypt(block, key, iv, plaintext) +} + +func (c cipherWithBlock) Decrypt(key, iv, ciphertext []byte) ([]byte, error) { + block, err := c.newBlock(key) + if err != nil { + return nil, err + } + return cbcDecrypt(block, key, iv, ciphertext) +} + +func cbcEncrypt(block cipher.Block, key, iv, plaintext []byte) ([]byte, error) { + mode := cipher.NewCBCEncrypter(block, iv) + paddingLen := block.BlockSize() - (len(plaintext) % block.BlockSize()) + ciphertext := make([]byte, len(plaintext)+paddingLen) + copy(ciphertext, plaintext) + copy(ciphertext[len(plaintext):], bytes.Repeat([]byte{byte(paddingLen)}, paddingLen)) + mode.CryptBlocks(ciphertext, ciphertext) + return ciphertext, nil +} + +func cbcDecrypt(block cipher.Block, key, iv, ciphertext []byte) ([]byte, error) { + mode := cipher.NewCBCDecrypter(block, iv) + plaintext := make([]byte, len(ciphertext)) + mode.CryptBlocks(plaintext, ciphertext) + // TODO: remove padding + return plaintext, nil +} diff --git a/vendor/github.com/youmark/pkcs8/cipher_3des.go b/vendor/github.com/youmark/pkcs8/cipher_3des.go new file mode 100644 index 000000000..562966440 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/cipher_3des.go @@ -0,0 +1,24 @@ +package pkcs8 + +import ( + "crypto/des" + "encoding/asn1" +) + +var ( + oidDESEDE3CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 3, 7} +) + +func init() { + RegisterCipher(oidDESEDE3CBC, func() Cipher { + return TripleDESCBC + }) +} + +// TripleDESCBC is the 168-bit key 3DES cipher in CBC mode. +var TripleDESCBC = cipherWithBlock{ + ivSize: des.BlockSize, + keySize: 24, + newBlock: des.NewTripleDESCipher, + oid: oidDESEDE3CBC, +} diff --git a/vendor/github.com/youmark/pkcs8/cipher_aes.go b/vendor/github.com/youmark/pkcs8/cipher_aes.go new file mode 100644 index 000000000..c0372d1ee --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/cipher_aes.go @@ -0,0 +1,84 @@ +package pkcs8 + +import ( + "crypto/aes" + "encoding/asn1" +) + +var ( + oidAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2} + oidAES128GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 6} + oidAES192CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 22} + oidAES192GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 26} + oidAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42} + oidAES256GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 46} +) + +func init() { + RegisterCipher(oidAES128CBC, func() Cipher { + return AES128CBC + }) + RegisterCipher(oidAES128GCM, func() Cipher { + return AES128GCM + }) + RegisterCipher(oidAES192CBC, func() Cipher { + return AES192CBC + }) + RegisterCipher(oidAES192GCM, func() Cipher { + return AES192GCM + }) + RegisterCipher(oidAES256CBC, func() Cipher { + return AES256CBC + }) + RegisterCipher(oidAES256GCM, func() Cipher { + return AES256GCM + }) +} + +// AES128CBC is the 128-bit key AES cipher in CBC mode. +var AES128CBC = cipherWithBlock{ + ivSize: aes.BlockSize, + keySize: 16, + newBlock: aes.NewCipher, + oid: oidAES128CBC, +} + +// AES128GCM is the 128-bit key AES cipher in GCM mode. +var AES128GCM = cipherWithBlock{ + ivSize: aes.BlockSize, + keySize: 16, + newBlock: aes.NewCipher, + oid: oidAES128GCM, +} + +// AES192CBC is the 192-bit key AES cipher in CBC mode. +var AES192CBC = cipherWithBlock{ + ivSize: aes.BlockSize, + keySize: 24, + newBlock: aes.NewCipher, + oid: oidAES192CBC, +} + +// AES192GCM is the 912-bit key AES cipher in GCM mode. +var AES192GCM = cipherWithBlock{ + ivSize: aes.BlockSize, + keySize: 24, + newBlock: aes.NewCipher, + oid: oidAES192GCM, +} + +// AES256CBC is the 256-bit key AES cipher in CBC mode. +var AES256CBC = cipherWithBlock{ + ivSize: aes.BlockSize, + keySize: 32, + newBlock: aes.NewCipher, + oid: oidAES256CBC, +} + +// AES256GCM is the 256-bit key AES cipher in GCM mode. +var AES256GCM = cipherWithBlock{ + ivSize: aes.BlockSize, + keySize: 32, + newBlock: aes.NewCipher, + oid: oidAES256GCM, +} diff --git a/vendor/github.com/youmark/pkcs8/kdf_pbkdf2.go b/vendor/github.com/youmark/pkcs8/kdf_pbkdf2.go new file mode 100644 index 000000000..79697dd82 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/kdf_pbkdf2.go @@ -0,0 +1,91 @@ +package pkcs8 + +import ( + "crypto" + "crypto/sha1" + "crypto/sha256" + "crypto/x509/pkix" + "encoding/asn1" + "errors" + "hash" + + "golang.org/x/crypto/pbkdf2" +) + +var ( + oidPKCS5PBKDF2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 12} + oidHMACWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 7} + oidHMACWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 9} +) + +func init() { + RegisterKDF(oidPKCS5PBKDF2, func() KDFParameters { + return new(pbkdf2Params) + }) +} + +func newHashFromPRF(ai pkix.AlgorithmIdentifier) (func() hash.Hash, error) { + switch { + case len(ai.Algorithm) == 0 || ai.Algorithm.Equal(oidHMACWithSHA1): + return sha1.New, nil + case ai.Algorithm.Equal(oidHMACWithSHA256): + return sha256.New, nil + default: + return nil, errors.New("pkcs8: unsupported hash function") + } +} + +func newPRFParamFromHash(h crypto.Hash) (pkix.AlgorithmIdentifier, error) { + switch h { + case crypto.SHA1: + return pkix.AlgorithmIdentifier{ + Algorithm: oidHMACWithSHA1, + Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil + case crypto.SHA256: + return pkix.AlgorithmIdentifier{ + Algorithm: oidHMACWithSHA256, + Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil + } + return pkix.AlgorithmIdentifier{}, errors.New("pkcs8: unsupported hash function") +} + +type pbkdf2Params struct { + Salt []byte + IterationCount int + PRF pkix.AlgorithmIdentifier `asn1:"optional"` +} + +func (p pbkdf2Params) DeriveKey(password []byte, size int) (key []byte, err error) { + h, err := newHashFromPRF(p.PRF) + if err != nil { + return nil, err + } + return pbkdf2.Key(password, p.Salt, p.IterationCount, size, h), nil +} + +// PBKDF2Opts contains options for the PBKDF2 key derivation function. +type PBKDF2Opts struct { + SaltSize int + IterationCount int + HMACHash crypto.Hash +} + +func (p PBKDF2Opts) DeriveKey(password, salt []byte, size int) ( + key []byte, params KDFParameters, err error) { + + key = pbkdf2.Key(password, salt, p.IterationCount, size, p.HMACHash.New) + prfParam, err := newPRFParamFromHash(p.HMACHash) + if err != nil { + return nil, nil, err + } + params = pbkdf2Params{salt, p.IterationCount, prfParam} + return key, params, nil +} + +func (p PBKDF2Opts) GetSaltSize() int { + return p.SaltSize +} + +func (p PBKDF2Opts) OID() asn1.ObjectIdentifier { + return oidPKCS5PBKDF2 +} diff --git a/vendor/github.com/youmark/pkcs8/kdf_scrypt.go b/vendor/github.com/youmark/pkcs8/kdf_scrypt.go new file mode 100644 index 000000000..36c4f4f59 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/kdf_scrypt.go @@ -0,0 +1,62 @@ +package pkcs8 + +import ( + "encoding/asn1" + + "golang.org/x/crypto/scrypt" +) + +var ( + oidScrypt = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11591, 4, 11} +) + +func init() { + RegisterKDF(oidScrypt, func() KDFParameters { + return new(scryptParams) + }) +} + +type scryptParams struct { + Salt []byte + CostParameter int + BlockSize int + ParallelizationParameter int +} + +func (p scryptParams) DeriveKey(password []byte, size int) (key []byte, err error) { + return scrypt.Key(password, p.Salt, p.CostParameter, p.BlockSize, + p.ParallelizationParameter, size) +} + +// ScryptOpts contains options for the scrypt key derivation function. +type ScryptOpts struct { + SaltSize int + CostParameter int + BlockSize int + ParallelizationParameter int +} + +func (p ScryptOpts) DeriveKey(password, salt []byte, size int) ( + key []byte, params KDFParameters, err error) { + + key, err = scrypt.Key(password, salt, p.CostParameter, p.BlockSize, + p.ParallelizationParameter, size) + if err != nil { + return nil, nil, err + } + params = scryptParams{ + BlockSize: p.BlockSize, + CostParameter: p.CostParameter, + ParallelizationParameter: p.ParallelizationParameter, + Salt: salt, + } + return key, params, nil +} + +func (p ScryptOpts) GetSaltSize() int { + return p.SaltSize +} + +func (p ScryptOpts) OID() asn1.ObjectIdentifier { + return oidScrypt +} diff --git a/vendor/github.com/youmark/pkcs8/pkcs8.go b/vendor/github.com/youmark/pkcs8/pkcs8.go new file mode 100644 index 000000000..f27f62752 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/pkcs8.go @@ -0,0 +1,309 @@ +// Package pkcs8 implements functions to parse and convert private keys in PKCS#8 format, as defined in RFC5208 and RFC5958 +package pkcs8 + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "errors" + "fmt" +) + +// DefaultOpts are the default options for encrypting a key if none are given. +// The defaults can be changed by the library user. +var DefaultOpts = &Opts{ + Cipher: AES256CBC, + KDFOpts: PBKDF2Opts{ + SaltSize: 8, + IterationCount: 10000, + HMACHash: crypto.SHA256, + }, +} + +// KDFOpts contains options for a key derivation function. +// An implementation of this interface must be specified when encrypting a PKCS#8 key. +type KDFOpts interface { + // DeriveKey derives a key of size bytes from the given password and salt. + // It returns the key and the ASN.1-encodable parameters used. + DeriveKey(password, salt []byte, size int) (key []byte, params KDFParameters, err error) + // GetSaltSize returns the salt size specified. + GetSaltSize() int + // OID returns the OID of the KDF specified. + OID() asn1.ObjectIdentifier +} + +// KDFParameters contains parameters (salt, etc.) for a key deriviation function. +// It must be a ASN.1-decodable structure. +// An implementation of this interface is created when decoding an encrypted PKCS#8 key. +type KDFParameters interface { + // DeriveKey derives a key of size bytes from the given password. + // It uses the salt from the decoded parameters. + DeriveKey(password []byte, size int) (key []byte, err error) +} + +var kdfs = make(map[string]func() KDFParameters) + +// RegisterKDF registers a function that returns a new instance of the given KDF +// parameters. This allows the library to support client-provided KDFs. +func RegisterKDF(oid asn1.ObjectIdentifier, params func() KDFParameters) { + kdfs[oid.String()] = params +} + +// Cipher represents a cipher for encrypting the key material. +type Cipher interface { + // IVSize returns the IV size of the cipher, in bytes. + IVSize() int + // KeySize returns the key size of the cipher, in bytes. + KeySize() int + // Encrypt encrypts the key material. + Encrypt(key, iv, plaintext []byte) ([]byte, error) + // Decrypt decrypts the key material. + Decrypt(key, iv, ciphertext []byte) ([]byte, error) + // OID returns the OID of the cipher specified. + OID() asn1.ObjectIdentifier +} + +var ciphers = make(map[string]func() Cipher) + +// RegisterCipher registers a function that returns a new instance of the given +// cipher. This allows the library to support client-provided ciphers. +func RegisterCipher(oid asn1.ObjectIdentifier, cipher func() Cipher) { + ciphers[oid.String()] = cipher +} + +// Opts contains options for encrypting a PKCS#8 key. +type Opts struct { + Cipher Cipher + KDFOpts KDFOpts +} + +// Unecrypted PKCS8 +var ( + oidPBES2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 13} +) + +type encryptedPrivateKeyInfo struct { + EncryptionAlgorithm pkix.AlgorithmIdentifier + EncryptedData []byte +} + +type pbes2Params struct { + KeyDerivationFunc pkix.AlgorithmIdentifier + EncryptionScheme pkix.AlgorithmIdentifier +} + +type privateKeyInfo struct { + Version int + PrivateKeyAlgorithm pkix.AlgorithmIdentifier + PrivateKey []byte +} + +func parseKeyDerivationFunc(keyDerivationFunc pkix.AlgorithmIdentifier) (KDFParameters, error) { + oid := keyDerivationFunc.Algorithm.String() + newParams, ok := kdfs[oid] + if !ok { + return nil, fmt.Errorf("pkcs8: unsupported KDF (OID: %s)", oid) + } + params := newParams() + _, err := asn1.Unmarshal(keyDerivationFunc.Parameters.FullBytes, params) + if err != nil { + return nil, errors.New("pkcs8: invalid KDF parameters") + } + return params, nil +} + +func parseEncryptionScheme(encryptionScheme pkix.AlgorithmIdentifier) (Cipher, []byte, error) { + oid := encryptionScheme.Algorithm.String() + newCipher, ok := ciphers[oid] + if !ok { + return nil, nil, fmt.Errorf("pkcs8: unsupported cipher (OID: %s)", oid) + } + cipher := newCipher() + var iv []byte + if _, err := asn1.Unmarshal(encryptionScheme.Parameters.FullBytes, &iv); err != nil { + return nil, nil, errors.New("pkcs8: invalid cipher parameters") + } + return cipher, iv, nil +} + +// ParsePrivateKey parses a DER-encoded PKCS#8 private key. +// Password can be nil. +// This is equivalent to ParsePKCS8PrivateKey. +func ParsePrivateKey(der []byte, password []byte) (interface{}, KDFParameters, error) { + // No password provided, assume the private key is unencrypted + if len(password) == 0 { + privateKey, err := x509.ParsePKCS8PrivateKey(der) + return privateKey, nil, err + } + + // Use the password provided to decrypt the private key + var privKey encryptedPrivateKeyInfo + if _, err := asn1.Unmarshal(der, &privKey); err != nil { + return nil, nil, errors.New("pkcs8: only PKCS #5 v2.0 supported") + } + + if !privKey.EncryptionAlgorithm.Algorithm.Equal(oidPBES2) { + return nil, nil, errors.New("pkcs8: only PBES2 supported") + } + + var params pbes2Params + if _, err := asn1.Unmarshal(privKey.EncryptionAlgorithm.Parameters.FullBytes, ¶ms); err != nil { + return nil, nil, errors.New("pkcs8: invalid PBES2 parameters") + } + + cipher, iv, err := parseEncryptionScheme(params.EncryptionScheme) + if err != nil { + return nil, nil, err + } + + kdfParams, err := parseKeyDerivationFunc(params.KeyDerivationFunc) + if err != nil { + return nil, nil, err + } + + keySize := cipher.KeySize() + symkey, err := kdfParams.DeriveKey(password, keySize) + if err != nil { + return nil, nil, err + } + + encryptedKey := privKey.EncryptedData + decryptedKey, err := cipher.Decrypt(symkey, iv, encryptedKey) + if err != nil { + return nil, nil, err + } + + key, err := x509.ParsePKCS8PrivateKey(decryptedKey) + if err != nil { + return nil, nil, errors.New("pkcs8: incorrect password") + } + return key, kdfParams, nil +} + +// MarshalPrivateKey encodes a private key into DER-encoded PKCS#8 with the given options. +// Password can be nil. +func MarshalPrivateKey(priv interface{}, password []byte, opts *Opts) ([]byte, error) { + if len(password) == 0 { + return x509.MarshalPKCS8PrivateKey(priv) + } + + if opts == nil { + opts = DefaultOpts + } + + // Convert private key into PKCS8 format + pkey, err := x509.MarshalPKCS8PrivateKey(priv) + if err != nil { + return nil, err + } + + encAlg := opts.Cipher + salt := make([]byte, opts.KDFOpts.GetSaltSize()) + _, err = rand.Read(salt) + if err != nil { + return nil, err + } + iv := make([]byte, encAlg.IVSize()) + _, err = rand.Read(iv) + if err != nil { + return nil, err + } + key, kdfParams, err := opts.KDFOpts.DeriveKey(password, salt, encAlg.KeySize()) + if err != nil { + return nil, err + } + + encryptedKey, err := encAlg.Encrypt(key, iv, pkey) + if err != nil { + return nil, err + } + + marshalledParams, err := asn1.Marshal(kdfParams) + if err != nil { + return nil, err + } + keyDerivationFunc := pkix.AlgorithmIdentifier{ + Algorithm: opts.KDFOpts.OID(), + Parameters: asn1.RawValue{FullBytes: marshalledParams}, + } + marshalledIV, err := asn1.Marshal(iv) + if err != nil { + return nil, err + } + encryptionScheme := pkix.AlgorithmIdentifier{ + Algorithm: encAlg.OID(), + Parameters: asn1.RawValue{FullBytes: marshalledIV}, + } + + encryptionAlgorithmParams := pbes2Params{ + EncryptionScheme: encryptionScheme, + KeyDerivationFunc: keyDerivationFunc, + } + marshalledEncryptionAlgorithmParams, err := asn1.Marshal(encryptionAlgorithmParams) + if err != nil { + return nil, err + } + encryptionAlgorithm := pkix.AlgorithmIdentifier{ + Algorithm: oidPBES2, + Parameters: asn1.RawValue{FullBytes: marshalledEncryptionAlgorithmParams}, + } + + encryptedPkey := encryptedPrivateKeyInfo{ + EncryptionAlgorithm: encryptionAlgorithm, + EncryptedData: encryptedKey, + } + + return asn1.Marshal(encryptedPkey) +} + +// ParsePKCS8PrivateKey parses encrypted/unencrypted private keys in PKCS#8 format. To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. +func ParsePKCS8PrivateKey(der []byte, v ...[]byte) (interface{}, error) { + var password []byte + if len(v) > 0 { + password = v[0] + } + privateKey, _, err := ParsePrivateKey(der, password) + return privateKey, err +} + +// ParsePKCS8PrivateKeyRSA parses encrypted/unencrypted private keys in PKCS#8 format. To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. +func ParsePKCS8PrivateKeyRSA(der []byte, v ...[]byte) (*rsa.PrivateKey, error) { + key, err := ParsePKCS8PrivateKey(der, v...) + if err != nil { + return nil, err + } + typedKey, ok := key.(*rsa.PrivateKey) + if !ok { + return nil, errors.New("key block is not of type RSA") + } + return typedKey, nil +} + +// ParsePKCS8PrivateKeyECDSA parses encrypted/unencrypted private keys in PKCS#8 format. To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. +func ParsePKCS8PrivateKeyECDSA(der []byte, v ...[]byte) (*ecdsa.PrivateKey, error) { + key, err := ParsePKCS8PrivateKey(der, v...) + if err != nil { + return nil, err + } + typedKey, ok := key.(*ecdsa.PrivateKey) + if !ok { + return nil, errors.New("key block is not of type ECDSA") + } + return typedKey, nil +} + +// ConvertPrivateKeyToPKCS8 converts the private key into PKCS#8 format. +// To encrypt the private key, the password of []byte type should be provided as the second parameter. +// +// The only supported key types are RSA and ECDSA (*rsa.PrivateKey or *ecdsa.PrivateKey for priv) +func ConvertPrivateKeyToPKCS8(priv interface{}, v ...[]byte) ([]byte, error) { + var password []byte + if len(v) > 0 { + password = v[0] + } + return MarshalPrivateKey(priv, password, nil) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 0c3a77d7a..551a5c072 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -508,7 +508,7 @@ github.com/knqyf263/go-rpmdb/pkg/bdb github.com/knqyf263/go-rpmdb/pkg/db github.com/knqyf263/go-rpmdb/pkg/ndb github.com/knqyf263/go-rpmdb/pkg/sqlite3 -# github.com/letsencrypt/boulder v0.20260223.0 +# github.com/letsencrypt/boulder v0.20260309.0 ## explicit; go 1.25.0 github.com/letsencrypt/boulder/core github.com/letsencrypt/boulder/core/proto @@ -661,8 +661,8 @@ github.com/rivo/uniseg ## explicit github.com/sassoftware/relic/lib/pkcs7 github.com/sassoftware/relic/lib/x509tools -# github.com/secure-systems-lab/go-securesystemslib v0.10.0 -## explicit; go 1.24.0 +# github.com/secure-systems-lab/go-securesystemslib v0.11.0 +## explicit; go 1.25.0 github.com/secure-systems-lab/go-securesystemslib/cjson github.com/secure-systems-lab/go-securesystemslib/dsse github.com/secure-systems-lab/go-securesystemslib/encrypted @@ -747,7 +747,7 @@ github.com/sigstore/rekor-tiles/v2/pkg/generated/protobuf github.com/sigstore/rekor-tiles/v2/pkg/note github.com/sigstore/rekor-tiles/v2/pkg/types/verifier github.com/sigstore/rekor-tiles/v2/pkg/verify -# github.com/sigstore/sigstore v1.10.6 +# github.com/sigstore/sigstore v1.10.8 ## explicit; go 1.25.0 github.com/sigstore/sigstore/pkg/cryptoutils github.com/sigstore/sigstore/pkg/cryptoutils/goodkey @@ -864,6 +864,9 @@ github.com/vishvananda/netns # github.com/x448/float16 v0.8.4 ## explicit; go 1.11 github.com/x448/float16 +# github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 +## explicit; go 1.17 +github.com/youmark/pkcs8 # gitlab.com/gitlab-org/api/client-go v1.46.0 ## explicit; go 1.24.0 gitlab.com/gitlab-org/api/client-go