mirror of
https://github.com/docker/cli.git
synced 2026-11-06 13:10:41 -04:00
vendor: github.com/go-jose/go-jose/v4 v4.1.6
- contains a fix for CVE-2026-116587 / [GHSA-mgcc-cww5-fp2q]
full diff: https://github.com/go-jose/go-jose/compare/v4.1.5...v4.1.6
[GHSA-mgcc-cww5-fp2q]: https://github.com/go-jose/go-jose/security/advisories/GHSA-mgcc-cww5-fp2q
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit ccccec73b0)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
+1
-1
@@ -25,7 +25,7 @@ require (
|
||||
github.com/docker/go-connections v0.8.2
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/fvbommel/sortorder v1.2.1
|
||||
github.com/go-jose/go-jose/v4 v4.1.5
|
||||
github.com/go-jose/go-jose/v4 v4.1.6
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/google/go-cmp v0.7.0
|
||||
|
||||
+2
-2
@@ -51,8 +51,8 @@ github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeO
|
||||
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
|
||||
github.com/fvbommel/sortorder v1.2.1 h1:ASc85RbthwLEqzuiCk7WQQiopfyGWQiEYZVJ3Qa4A+U=
|
||||
github.com/fvbommel/sortorder v1.2.1/go.mod h1:LbhO04ijZIeUuvz9B9BkI/qYrpZZEn1gWhxv4QjUKVs=
|
||||
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=
|
||||
|
||||
+15
@@ -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)
|
||||
|
||||
+9
-9
@@ -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()
|
||||
|
||||
+43
-8
@@ -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 {
|
||||
|
||||
+17
-14
@@ -275,17 +275,18 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
|
||||
Signature: parsed.Signature,
|
||||
}
|
||||
|
||||
var err error
|
||||
signature.Header, err = signature.mergedHeaders().sanitized()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
alg := SignatureAlgorithm(signature.Header.Algorithm)
|
||||
mergedHeaders := signature.mergedHeaders()
|
||||
alg := mergedHeaders.getSignatureAlgorithm()
|
||||
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
|
||||
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
|
||||
}
|
||||
|
||||
var err error
|
||||
signature.Header, err = mergedHeaders.sanitized()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ var ErrNotValidYet = errors.New("go-jose/go-jose/jwt: validation failed, token n
|
||||
var ErrExpired = errors.New("go-jose/go-jose/jwt: validation failed, token is expired (exp)")
|
||||
|
||||
// ErrIssuedInTheFuture indicates that the iat field is in the future.
|
||||
var ErrIssuedInTheFuture = errors.New("go-jose/go-jose/jwt: validation field, token issued in the future (iat)")
|
||||
var ErrIssuedInTheFuture = errors.New("go-jose/go-jose/jwt: validation failed, token issued in the future (iat)")
|
||||
|
||||
// ErrInvalidContentType indicates that token requires JWT cty header.
|
||||
var ErrInvalidContentType = errors.New("go-jose/go-jose/jwt: expected content type to be JWT (cty header)")
|
||||
|
||||
+11
-20
@@ -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
|
||||
|
||||
+13
@@ -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", "./..."]
|
||||
+25
@@ -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.
|
||||
|
||||
Vendored
+1
-1
@@ -93,7 +93,7 @@ github.com/felixge/httpsnoop
|
||||
# github.com/fvbommel/sortorder v1.2.1
|
||||
## explicit; go 1.21
|
||||
github.com/fvbommel/sortorder
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user