From 6f8d4326ee8d0058e72574d8bac2bd9f1e78db60 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Oct 2026 14:27:51 +0000 Subject: [PATCH] chore(deps): bump github.com/go-jose/go-jose/v4 from 4.1.5 to 4.1.6 Bumps [github.com/go-jose/go-jose/v4](https://github.com/go-jose/go-jose) from 4.1.5 to 4.1.6. - [Release notes](https://github.com/go-jose/go-jose/releases) - [Commits](https://github.com/go-jose/go-jose/compare/v4.1.5...v4.1.6) --- updated-dependencies: - dependency-name: github.com/go-jose/go-jose/v4 dependency-version: 4.1.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 +- .../github.com/go-jose/go-jose/v4/crypter.go | 15 ++++++ vendor/github.com/go-jose/go-jose/v4/jwe.go | 18 +++---- vendor/github.com/go-jose/go-jose/v4/jwk.go | 51 ++++++++++++++++--- vendor/github.com/go-jose/go-jose/v4/jws.go | 29 ++++++----- .../github.com/go-jose/go-jose/v4/shared.go | 31 ++++------- .../go-jose/go-jose/v4/tests.Containerfile | 13 +++++ .../go-jose/go-jose/v4/threat_model.md | 25 +++++++++ vendor/modules.txt | 2 +- 10 files changed, 136 insertions(+), 54 deletions(-) create mode 100644 vendor/github.com/go-jose/go-jose/v4/tests.Containerfile create mode 100644 vendor/github.com/go-jose/go-jose/v4/threat_model.md diff --git a/go.mod b/go.mod index f1ac4274bc..36f56adbe6 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/docker/cli v29.8.2+incompatible github.com/docker/docker v28.5.2+incompatible github.com/fatih/color v1.19.0 - github.com/go-jose/go-jose/v4 v4.1.5 + github.com/go-jose/go-jose/v4 v4.1.6 github.com/google/go-cmp v0.7.0 github.com/google/go-containerregistry v0.22.1 github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b diff --git a/go.sum b/go.sum index 265bdf3d05..b7a765ed49 100644 --- a/go.sum +++ b/go.sum @@ -157,8 +157,8 @@ github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxI github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI= github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= -github.com/go-jose/go-jose/v4 v4.1.5 h1:RjgjO2LOtWOJKUC5wpwY9LR3B3vwVAz6JS2YHfYU6eA= -github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-jose/go-jose/v4 v4.1.6 h1:sNRkftxFJxwsILiQukqp5z83QBSmntVwmgRY7AqBDO4= +github.com/go-jose/go-jose/v4 v4.1.6/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= diff --git a/vendor/github.com/go-jose/go-jose/v4/crypter.go b/vendor/github.com/go-jose/go-jose/v4/crypter.go index e3df79c2dc..53636c57b3 100644 --- a/vendor/github.com/go-jose/go-jose/v4/crypter.go +++ b/vendor/github.com/go-jose/go-jose/v4/crypter.go @@ -428,6 +428,13 @@ func (ctx *genericEncrypter) Options() EncrypterOptions { } } +func validateContentEncryptionKeySize(cek []byte, cipher contentCipher) error { + if len(cek) != cipher.keySize() { + return ErrInvalidKeySize + } + return nil +} + // Decrypt and validate the object and return the plaintext. This // function does not support multi-recipient. If you desire multi-recipient // decryption use DecryptMulti instead. @@ -495,6 +502,10 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) if err != nil { return nil, ErrCryptoFailure } + err = validateContentEncryptionKeySize(cek, cipher) + if err != nil { + return nil, ErrCryptoFailure + } // Found a valid CEK -- let's try to decrypt. plaintext, err = cipher.decrypt(cek, authData, parts) @@ -572,6 +583,10 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade if err != nil { continue } + err = validateContentEncryptionKeySize(cek, cipher) + if err != nil { + continue + } // Found a valid CEK -- let's try to decrypt. plaintext, err = cipher.decrypt(cek, authData, parts) diff --git a/vendor/github.com/go-jose/go-jose/v4/jwe.go b/vendor/github.com/go-jose/go-jose/v4/jwe.go index ae173461b7..a516901078 100644 --- a/vendor/github.com/go-jose/go-jose/v4/jwe.go +++ b/vendor/github.com/go-jose/go-jose/v4/jwe.go @@ -202,15 +202,6 @@ func (parsed *rawJSONWebEncryption) sanitized( } } - // Note: this must be called _after_ we parse the protected header, - // otherwise fields from the protected header will not get picked up. - var err error - mergedHeaders := obj.mergedHeaders(nil) - obj.Header, err = mergedHeaders.sanitized() - if err != nil { - return nil, fmt.Errorf("go-jose/go-jose: cannot sanitize merged headers: %v (%v)", err, mergedHeaders) - } - if len(parsed.Recipients) == 0 { obj.recipients = []recipientInfo{ { @@ -264,6 +255,15 @@ func (parsed *rawJSONWebEncryption) sanitized( } } + // Note: this must be called _after_ we parse the protected header, + // otherwise fields from the protected header will not get picked up. + mergedHeaders := obj.mergedHeaders(nil) + var err error + obj.Header, err = mergedHeaders.sanitized() + if err != nil { + return nil, fmt.Errorf("go-jose/go-jose: cannot sanitize merged headers: %w", err) + } + obj.iv = parsed.Iv.bytes() obj.ciphertext = parsed.Ciphertext.bytes() obj.tag = parsed.Tag.bytes() diff --git a/vendor/github.com/go-jose/go-jose/v4/jwk.go b/vendor/github.com/go-jose/go-jose/v4/jwk.go index f712ec7ec8..8b7aa05ec2 100644 --- a/vendor/github.com/go-jose/go-jose/v4/jwk.go +++ b/vendor/github.com/go-jose/go-jose/v4/jwk.go @@ -177,13 +177,29 @@ func (k JSONWebKey) MarshalJSON() ([]byte, error) { // UnmarshalJSON reads a key from its JSON representation. // // Returns ErrUnsupportedKeyType for unrecognized or unsupported "kty" header values. -func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) { +// +// Directly unmarshaling a JWK is not safe for untrusted input. +func (k *JSONWebKey) UnmarshalJSON(data []byte) error { + return k.unmarshalJSON(data, true) +} + +// unmarshalJSON reads a key from its JSON representation. +// +// If allowPrivate is false, a JWK with private key material is rejected and the +// function is safe for use against untrusted input. +func (k *JSONWebKey) unmarshalJSON(data []byte, allowPrivate bool) (err error) { var raw rawJSONWebKey err = json.Unmarshal(data, &raw) if err != nil { return err } + if !allowPrivate && + (raw.K != nil || raw.D != nil || raw.P != nil || raw.Q != nil || + raw.Dp != nil || raw.Dq != nil || raw.Qi != nil) { + return errors.New("go-jose/go-jose: JWK contains private parameters") + } + certs, err := parseCertificateChain(raw.X5c) if err != nil { return fmt.Errorf("go-jose/go-jose: failed to unmarshal x5c field: %s", err) @@ -505,13 +521,25 @@ func (k *JSONWebKey) Valid() bool { return true } +// MaxRSAModulusBits is the largest RSA modulus size, in bits, that will be +// accepted when parsing a JWK. Applications that need larger keys can raise +// this limit. +// +// If modifying MaxRSAModulusBits, do it before any parsing occurs. +var MaxRSAModulusBits = 4096 + func (key rawJSONWebKey) rsaPublicKey() (*rsa.PublicKey, error) { if key.N == nil || key.E == nil { return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, missing n/e values") } + n := key.N.bigInt() + if n.BitLen() > MaxRSAModulusBits { + return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, modulus too large") + } + return &rsa.PublicKey{ - N: key.N.bigInt(), + N: n, E: key.E.toInt(), }, nil } @@ -673,16 +701,23 @@ func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) { return nil, fmt.Errorf("go-jose/go-jose: invalid RSA private key, missing %s value(s)", strings.Join(missing, ", ")) } + n := key.N.bigInt() + if n.BitLen() > MaxRSAModulusBits { + return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, modulus too large") + } + + p, q := key.P.bigInt(), key.Q.bigInt() + if p.BitLen()+q.BitLen() > n.BitLen()+1 || new(big.Int).Mul(p, q).Cmp(n) != 0 { + return nil, errors.New("go-jose/go-jose: invalid RSA private key, p * q != n") + } + rv := &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ - N: key.N.bigInt(), + N: n, E: key.E.toInt(), }, - D: key.D.bigInt(), - Primes: []*big.Int{ - key.P.bigInt(), - key.Q.bigInt(), - }, + D: key.D.bigInt(), + Primes: []*big.Int{p, q}, } if key.Dp != nil { diff --git a/vendor/github.com/go-jose/go-jose/v4/jws.go b/vendor/github.com/go-jose/go-jose/v4/jws.go index 0444a5da05..18224df7d9 100644 --- a/vendor/github.com/go-jose/go-jose/v4/jws.go +++ b/vendor/github.com/go-jose/go-jose/v4/jws.go @@ -275,17 +275,18 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo Signature: parsed.Signature, } + mergedHeaders := signature.mergedHeaders() + alg := mergedHeaders.getSignatureAlgorithm() + if !containsSignatureAlgorithm(signatureAlgorithms, alg) { + return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms) + } + var err error - signature.Header, err = signature.mergedHeaders().sanitized() + signature.Header, err = mergedHeaders.sanitized() if err != nil { return nil, err } - alg := SignatureAlgorithm(signature.Header.Algorithm) - if !containsSignatureAlgorithm(signatureAlgorithms, alg) { - return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms) - } - if signature.header != nil { signature.Unprotected, err = signature.header.sanitized() if err != nil { @@ -323,17 +324,20 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo return nil, ErrUnprotectedNonce } - var err error - obj.Signatures[i].Header, err = obj.Signatures[i].mergedHeaders().sanitized() - if err != nil { - return nil, err - } + obj.Signatures[i].header = sig.Header - alg := SignatureAlgorithm(obj.Signatures[i].Header.Algorithm) + mergedHeaders := obj.Signatures[i].mergedHeaders() + alg := mergedHeaders.getSignatureAlgorithm() if !containsSignatureAlgorithm(signatureAlgorithms, alg) { return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms) } + var err error + obj.Signatures[i].Header, err = mergedHeaders.sanitized() + if err != nil { + return nil, err + } + if obj.Signatures[i].header != nil { obj.Signatures[i].Unprotected, err = obj.Signatures[i].header.sanitized() if err != nil { @@ -359,7 +363,6 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo // Copy value of sig original := sig - obj.Signatures[i].header = sig.Header obj.Signatures[i].original = &original } diff --git a/vendor/github.com/go-jose/go-jose/v4/shared.go b/vendor/github.com/go-jose/go-jose/v4/shared.go index 3df242ca6a..1e8bf88210 100644 --- a/vendor/github.com/go-jose/go-jose/v4/shared.go +++ b/vendor/github.com/go-jose/go-jose/v4/shared.go @@ -297,9 +297,10 @@ func (parsed rawHeader) getEPK() (*JSONWebKey, error) { if v == nil { return nil, nil } - var epk *JSONWebKey - err := json.Unmarshal(*v, &epk) - if err != nil { + // RFC 7518 Section 4.6.1.1: the "epk" header is the ephemeral public key + // of the originator. Reject private key material before parsing it. + epk := new(JSONWebKey) + if err := epk.unmarshalJSON(*v, false); err != nil { return nil, err } return epk, nil @@ -325,20 +326,6 @@ func (parsed rawHeader) getTag() (*byteBuffer, error) { return parsed.getByteBuffer(headerTag) } -// getJWK extracts parsed "jwk" from the raw JSON. -func (parsed rawHeader) getJWK() (*JSONWebKey, error) { - v := parsed[headerJWK] - if v == nil { - return nil, nil - } - var jwk *JSONWebKey - err := json.Unmarshal(*v, &jwk) - if err != nil { - return nil, err - } - return jwk, nil -} - // getCritical extracts parsed "crit" from the raw JSON. If omitted, it // returns an empty slice. func (parsed rawHeader) getCritical() ([]string, error) { @@ -424,10 +411,14 @@ func (parsed rawHeader) sanitized() (h Header, err error) { } switch k { case headerJWK: - var jwk *JSONWebKey - err = json.Unmarshal(*v, &jwk) + // RFC 7515 Section 4.1.3 and RFC 7516 Section 4.1.5: the "jwk" + // header is the public key that corresponds to the key used to + // sign the JWS or encrypt the JWE. Reject private key material + // before parsing it. + jwk := new(JSONWebKey) + err = jwk.unmarshalJSON(*v, false) if err != nil { - err = fmt.Errorf("failed to unmarshal JWK: %v: %#v", err, string(*v)) + err = fmt.Errorf("failed to unmarshal JWK: %w", err) return } h.JSONWebKey = jwk diff --git a/vendor/github.com/go-jose/go-jose/v4/tests.Containerfile b/vendor/github.com/go-jose/go-jose/v4/tests.Containerfile new file mode 100644 index 0000000000..b45da99bd2 --- /dev/null +++ b/vendor/github.com/go-jose/go-jose/v4/tests.Containerfile @@ -0,0 +1,13 @@ +# This containerfile can be used to run the go-jose tests and cli + +FROM golang:1.27-trixie +ENV GOTOOLCHAIN=local + +COPY . /src +WORKDIR /src + +# Install the jose-util cli, which will also build the library +RUN go build -o /usr/local/bin/jose-util ./jose-util + +# By default, run the tests +CMD ["go", "test", "./..."] diff --git a/vendor/github.com/go-jose/go-jose/v4/threat_model.md b/vendor/github.com/go-jose/go-jose/v4/threat_model.md new file mode 100644 index 0000000000..c9e66d4c20 --- /dev/null +++ b/vendor/github.com/go-jose/go-jose/v4/threat_model.md @@ -0,0 +1,25 @@ +# Threat model + +## What this project does and where untrusted input enters +go-jose is a Go implementation of JOSE family of algorithms. + +It is a library which will parse attacker-controlled data in network-reachable +services. + +## Components that matter most / least +The primary attack surface of interest is parsing and validating JWS, JWE, JWK, +etc when this library is used to implement authentication and authorization. + +## How to exercise it +Testing is primarily done by Golang unit tests, which can be run with the +tests.Container file's default CMD. + +## How you rate severity +Any authentication bypass enabled by a go-jose issue is a high+ severity. + +Denial-of-service attacks are of interest when the functions may be used in a protocol like OIDC, ACME, etc +which could have a server processing attacker-controlled data. + +## Anything to leave alone +Any bug which only affects the jose-util CLI tool, but it can be used to exercise the library. + diff --git a/vendor/modules.txt b/vendor/modules.txt index 2857a671e5..7dc3f5f321 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -151,7 +151,7 @@ github.com/go-chi/chi/v5 # github.com/go-errors/errors v1.4.2 ## explicit; go 1.14 github.com/go-errors/errors -# github.com/go-jose/go-jose/v4 v4.1.5 +# github.com/go-jose/go-jose/v4 v4.1.6 ## explicit; go 1.24.0 github.com/go-jose/go-jose/v4 github.com/go-jose/go-jose/v4/cipher