diff --git a/go.mod b/go.mod
index fef3c7487..db6b1d822 100644
--- a/go.mod
+++ b/go.mod
@@ -43,7 +43,7 @@ require (
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
- github.com/go-jose/go-jose/v4 v4.0.5 // indirect
+ github.com/go-jose/go-jose/v4 v4.1.6 // indirect
github.com/go-openapi/swag/cmdutils v0.25.1 // indirect
github.com/go-openapi/swag/conv v0.25.1 // indirect
github.com/go-openapi/swag/fileutils v0.25.1 // indirect
diff --git a/go.sum b/go.sum
index 03efe85f9..b8278aa85 100644
--- a/go.sum
+++ b/go.sum
@@ -139,8 +139,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY=
github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
-github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
-github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
+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-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
diff --git a/vendor/github.com/go-jose/go-jose/v4/CHANGELOG.md b/vendor/github.com/go-jose/go-jose/v4/CHANGELOG.md
deleted file mode 100644
index 6f717dbd8..000000000
--- a/vendor/github.com/go-jose/go-jose/v4/CHANGELOG.md
+++ /dev/null
@@ -1,96 +0,0 @@
-# v4.0.4
-
-## Fixed
-
- - Reverted "Allow unmarshalling JSONWebKeySets with unsupported key types" as a
- breaking change. See #136 / #137.
-
-# v4.0.3
-
-## Changed
-
- - Allow unmarshalling JSONWebKeySets with unsupported key types (#130)
- - Document that OpaqueKeyEncrypter can't be implemented (for now) (#129)
- - Dependency updates
-
-# v4.0.2
-
-## Changed
-
- - Improved documentation of Verify() to note that JSONWebKeySet is a supported
- argument type (#104)
- - Defined exported error values for missing x5c header and unsupported elliptic
- curves error cases (#117)
-
-# v4.0.1
-
-## Fixed
-
- - An attacker could send a JWE containing compressed data that used large
- amounts of memory and CPU when decompressed by `Decrypt` or `DecryptMulti`.
- Those functions now return an error if the decompressed data would exceed
- 250kB or 10x the compressed size (whichever is larger). Thanks to
- Enze Wang@Alioth and Jianjun Chen@Zhongguancun Lab (@zer0yu and @chenjj)
- for reporting.
-
-# v4.0.0
-
-This release makes some breaking changes in order to more thoroughly
-address the vulnerabilities discussed in [Three New Attacks Against JSON Web
-Tokens][1], "Sign/encrypt confusion", "Billion hash attack", and "Polyglot
-token".
-
-## Changed
-
- - Limit JWT encryption types (exclude password or public key types) (#78)
- - Enforce minimum length for HMAC keys (#85)
- - jwt: match any audience in a list, rather than requiring all audiences (#81)
- - jwt: accept only Compact Serialization (#75)
- - jws: Add expected algorithms for signatures (#74)
- - Require specifying expected algorithms for ParseEncrypted,
- ParseSigned, ParseDetached, jwt.ParseEncrypted, jwt.ParseSigned,
- jwt.ParseSignedAndEncrypted (#69, #74)
- - Usually there is a small, known set of appropriate algorithms for a program
- to use and it's a mistake to allow unexpected algorithms. For instance the
- "billion hash attack" relies in part on programs accepting the PBES2
- encryption algorithm and doing the necessary work even if they weren't
- specifically configured to allow PBES2.
- - Revert "Strip padding off base64 strings" (#82)
- - The specs require base64url encoding without padding.
- - Minimum supported Go version is now 1.21
-
-## Added
-
- - ParseSignedCompact, ParseSignedJSON, ParseEncryptedCompact, ParseEncryptedJSON.
- - These allow parsing a specific serialization, as opposed to ParseSigned and
- ParseEncrypted, which try to automatically detect which serialization was
- provided. It's common to require a specific serialization for a specific
- protocol - for instance JWT requires Compact serialization.
-
-[1]: https://i.blackhat.com/BH-US-23/Presentations/US-23-Tervoort-Three-New-Attacks-Against-JSON-Web-Tokens.pdf
-
-# v3.0.2
-
-## Fixed
-
- - DecryptMulti: handle decompression error (#19)
-
-## Changed
-
- - jwe/CompactSerialize: improve performance (#67)
- - Increase the default number of PBKDF2 iterations to 600k (#48)
- - Return the proper algorithm for ECDSA keys (#45)
-
-## Added
-
- - Add Thumbprint support for opaque signers (#38)
-
-# v3.0.1
-
-## Fixed
-
- - Security issue: an attacker specifying a large "p2c" value can cause
- JSONWebEncryption.Decrypt and JSONWebEncryption.DecryptMulti to consume large
- amounts of CPU, causing a DoS. Thanks to Matt Schwager (@mschwager) for the
- disclosure and to Tom Tervoort for originally publishing the category of attack.
- https://i.blackhat.com/BH-US-23/Presentations/US-23-Tervoort-Three-New-Attacks-Against-JSON-Web-Tokens.pdf
diff --git a/vendor/github.com/go-jose/go-jose/v4/README.md b/vendor/github.com/go-jose/go-jose/v4/README.md
index 02b574954..55c550917 100644
--- a/vendor/github.com/go-jose/go-jose/v4/README.md
+++ b/vendor/github.com/go-jose/go-jose/v4/README.md
@@ -3,7 +3,6 @@
[](https://pkg.go.dev/github.com/go-jose/go-jose/v4)
[](https://pkg.go.dev/github.com/go-jose/go-jose/v4/jwt)
[](https://raw.githubusercontent.com/go-jose/go-jose/master/LICENSE)
-[](https://github.com/go-jose/go-jose/actions)
Package jose aims to provide an implementation of the Javascript Object Signing
and Encryption set of standards. This includes support for JSON Web Encryption,
@@ -29,17 +28,20 @@ libraries in other languages.
### Versions
-[Version 4](https://github.com/go-jose/go-jose)
-([branch](https://github.com/go-jose/go-jose/tree/main),
-[doc](https://pkg.go.dev/github.com/go-jose/go-jose/v4), [releases](https://github.com/go-jose/go-jose/releases)) is the current stable version:
+The forthcoming Version 5 will be released with several breaking API changes,
+and will require Golang's `encoding/json/v2`, which is currently requires
+Go 1.25 built with GOEXPERIMENT=jsonv2.
+
+Version 4 is the current stable version:
import "github.com/go-jose/go-jose/v4"
-The old [square/go-jose](https://github.com/square/go-jose) repo contains the prior v1 and v2 versions, which
-are still useable but not actively developed anymore.
+It supports at least the current and previous Golang release. Currently it
+requires Golang 1.24.
+
+Version 3 is only receiving critical security updates. Migration to Version 4 is recommended.
-Version 3, in this repo, is still receiving security fixes but not functionality
-updates.
+Versions 1 and 2 are obsolete, but can be found in the old repository, [square/go-jose](https://github.com/square/go-jose).
### Supported algorithms
@@ -47,36 +49,36 @@ See below for a table of supported algorithms. Algorithm identifiers match
the names in the [JSON Web Algorithms](https://dx.doi.org/10.17487/RFC7518)
standard where possible. The Godoc reference has a list of constants.
- Key encryption | Algorithm identifier(s)
- :------------------------- | :------------------------------
- RSA-PKCS#1v1.5 | RSA1_5
- RSA-OAEP | RSA-OAEP, RSA-OAEP-256
- AES key wrap | A128KW, A192KW, A256KW
- AES-GCM key wrap | A128GCMKW, A192GCMKW, A256GCMKW
- ECDH-ES + AES key wrap | ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW
- ECDH-ES (direct) | ECDH-ES1
- Direct encryption | dir1
+| Key encryption | Algorithm identifier(s) |
+|:-----------------------|:-----------------------------------------------|
+| RSA-PKCS#1v1.5 | RSA1_5 |
+| RSA-OAEP | RSA-OAEP, RSA-OAEP-256 |
+| AES key wrap | A128KW, A192KW, A256KW |
+| AES-GCM key wrap | A128GCMKW, A192GCMKW, A256GCMKW |
+| ECDH-ES + AES key wrap | ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW |
+| ECDH-ES (direct) | ECDH-ES1 |
+| Direct encryption | dir1 |
1. Not supported in multi-recipient mode
- Signing / MAC | Algorithm identifier(s)
- :------------------------- | :------------------------------
- RSASSA-PKCS#1v1.5 | RS256, RS384, RS512
- RSASSA-PSS | PS256, PS384, PS512
- HMAC | HS256, HS384, HS512
- ECDSA | ES256, ES384, ES512
- Ed25519 | EdDSA2
+| Signing / MAC | Algorithm identifier(s) |
+|:------------------|:------------------------|
+| RSASSA-PKCS#1v1.5 | RS256, RS384, RS512 |
+| RSASSA-PSS | PS256, PS384, PS512 |
+| HMAC | HS256, HS384, HS512 |
+| ECDSA | ES256, ES384, ES512 |
+| Ed25519 | EdDSA2 |
2. Only available in version 2 of the package
- Content encryption | Algorithm identifier(s)
- :------------------------- | :------------------------------
- AES-CBC+HMAC | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512
- AES-GCM | A128GCM, A192GCM, A256GCM
+| Content encryption | Algorithm identifier(s) |
+|:-------------------|:--------------------------------------------|
+| AES-CBC+HMAC | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 |
+| AES-GCM | A128GCM, A192GCM, A256GCM |
- Compression | Algorithm identifiers(s)
- :------------------------- | -------------------------------
- DEFLATE (RFC 1951) | DEF
+| Compression | Algorithm identifiers(s) |
+|:-------------------|--------------------------|
+| DEFLATE (RFC 1951) | DEF |
### Supported key types
@@ -85,12 +87,12 @@ library, and can be passed to corresponding functions such as `NewEncrypter` or
`NewSigner`. Each of these keys can also be wrapped in a JWK if desired, which
allows attaching a key id.
- Algorithm(s) | Corresponding types
- :------------------------- | -------------------------------
- RSA | *[rsa.PublicKey](https://pkg.go.dev/crypto/rsa/#PublicKey), *[rsa.PrivateKey](https://pkg.go.dev/crypto/rsa/#PrivateKey)
- ECDH, ECDSA | *[ecdsa.PublicKey](https://pkg.go.dev/crypto/ecdsa/#PublicKey), *[ecdsa.PrivateKey](https://pkg.go.dev/crypto/ecdsa/#PrivateKey)
- EdDSA1 | [ed25519.PublicKey](https://pkg.go.dev/crypto/ed25519#PublicKey), [ed25519.PrivateKey](https://pkg.go.dev/crypto/ed25519#PrivateKey)
- AES, HMAC | []byte
+| Algorithm(s) | Corresponding types |
+|:------------------|--------------------------------------------------------------------------------------------------------------------------------------|
+| RSA | *[rsa.PublicKey](https://pkg.go.dev/crypto/rsa/#PublicKey), *[rsa.PrivateKey](https://pkg.go.dev/crypto/rsa/#PrivateKey) |
+| ECDH, ECDSA | *[ecdsa.PublicKey](https://pkg.go.dev/crypto/ecdsa/#PublicKey), *[ecdsa.PrivateKey](https://pkg.go.dev/crypto/ecdsa/#PrivateKey) |
+| EdDSA1 | [ed25519.PublicKey](https://pkg.go.dev/crypto/ed25519#PublicKey), [ed25519.PrivateKey](https://pkg.go.dev/crypto/ed25519#PrivateKey) |
+| AES, HMAC | []byte |
1. Only available in version 2 or later of the package
diff --git a/vendor/github.com/go-jose/go-jose/v4/asymmetric.go b/vendor/github.com/go-jose/go-jose/v4/asymmetric.go
index f8d5774ef..2b5607617 100644
--- a/vendor/github.com/go-jose/go-jose/v4/asymmetric.go
+++ b/vendor/github.com/go-jose/go-jose/v4/asymmetric.go
@@ -21,6 +21,7 @@ import (
"crypto/aes"
"crypto/ecdsa"
"crypto/ed25519"
+ "crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
@@ -195,11 +196,11 @@ func (ctx rsaEncrypterVerifier) encryptKey(cek []byte, alg KeyAlgorithm) (recipi
func (ctx rsaEncrypterVerifier) encrypt(cek []byte, alg KeyAlgorithm) ([]byte, error) {
switch alg {
case RSA1_5:
- return rsa.EncryptPKCS1v15(RandReader, ctx.publicKey, cek)
+ return rsa.EncryptPKCS1v15(randReader, ctx.publicKey, cek)
case RSA_OAEP:
- return rsa.EncryptOAEP(sha1.New(), RandReader, ctx.publicKey, cek, []byte{})
+ return rsa.EncryptOAEP(sha1.New(), randReader, ctx.publicKey, cek, []byte{})
case RSA_OAEP_256:
- return rsa.EncryptOAEP(sha256.New(), RandReader, ctx.publicKey, cek, []byte{})
+ return rsa.EncryptOAEP(sha256.New(), randReader, ctx.publicKey, cek, []byte{})
}
return nil, ErrUnsupportedAlgorithm
@@ -288,9 +289,9 @@ func (ctx rsaDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm
// TODO(https://github.com/go-jose/go-jose/issues/40): As of go1.20, the
// random parameter is legacy and ignored, and it can be nil.
// https://cs.opensource.google/go/go/+/refs/tags/go1.20:src/crypto/rsa/pkcs1v15.go;l=263;bpv=0;bpt=1
- out, err = rsa.SignPKCS1v15(RandReader, ctx.privateKey, hash, hashed)
+ out, err = rsa.SignPKCS1v15(randReader, ctx.privateKey, hash, hashed)
case PS256, PS384, PS512:
- out, err = rsa.SignPSS(RandReader, ctx.privateKey, hash, hashed, &rsa.PSSOptions{
+ out, err = rsa.SignPSS(randReader, ctx.privateKey, hash, hashed, &rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthEqualsHash,
})
}
@@ -391,7 +392,7 @@ func (ctx ecKeyGenerator) keySize() int {
// Get a content encryption key for ECDH-ES
func (ctx ecKeyGenerator) genKey() ([]byte, rawHeader, error) {
- priv, err := ecdsa.GenerateKey(ctx.publicKey.Curve, RandReader)
+ priv, err := ecdsa.GenerateKey(ctx.publicKey.Curve, randReader)
if err != nil {
return nil, rawHeader{}, err
}
@@ -414,6 +415,9 @@ func (ctx ecKeyGenerator) genKey() ([]byte, rawHeader, error) {
// Decrypt the given payload and return the content encryption key.
func (ctx ecDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
+ if recipient == nil {
+ return nil, errors.New("go-jose/go-jose: missing recipient")
+ }
epk, err := headers.getEPK()
if err != nil {
return nil, errors.New("go-jose/go-jose: invalid epk header")
@@ -461,13 +465,18 @@ func (ctx ecDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientI
return nil, ErrUnsupportedAlgorithm
}
+ encryptedKey := recipient.encryptedKey
+ if len(encryptedKey) == 0 {
+ return nil, errors.New("go-jose/go-jose: missing JWE Encrypted Key")
+ }
+
key := deriveKey(string(algorithm), keySize)
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
- return josecipher.KeyUnwrap(block, recipient.encryptedKey)
+ return josecipher.KeyUnwrap(block, encryptedKey)
}
func (ctx edDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
@@ -475,7 +484,7 @@ func (ctx edDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm)
return Signature{}, ErrUnsupportedAlgorithm
}
- sig, err := ctx.privateKey.Sign(RandReader, payload, crypto.Hash(0))
+ sig, err := ctx.privateKey.Sign(randReader, payload, crypto.Hash(0))
if err != nil {
return Signature{}, err
}
@@ -525,7 +534,7 @@ func (ctx ecDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm)
_, _ = hasher.Write(payload)
hashed := hasher.Sum(nil)
- r, s, err := ecdsa.Sign(RandReader, ctx.privateKey, hashed)
+ r, s, err := ecdsa.Sign(randReader, ctx.privateKey, hashed)
if err != nil {
return Signature{}, err
}
@@ -563,12 +572,21 @@ func (ctx ecEncrypterVerifier) verifyPayload(payload []byte, signature []byte, a
case ES256:
keySize = 32
hash = crypto.SHA256
+ if ctx.publicKey.Curve != elliptic.P256() {
+ return fmt.Errorf("go-jose/go-jose: signature uses different algorithm than public key")
+ }
case ES384:
keySize = 48
hash = crypto.SHA384
+ if ctx.publicKey.Curve != elliptic.P384() {
+ return fmt.Errorf("go-jose/go-jose: signature uses different algorithm than public key")
+ }
case ES512:
keySize = 66
hash = crypto.SHA512
+ if ctx.publicKey.Curve != elliptic.P521() {
+ return fmt.Errorf("go-jose/go-jose: signature uses different algorithm than public key")
+ }
default:
return ErrUnsupportedAlgorithm
}
diff --git a/vendor/github.com/go-jose/go-jose/v4/cipher/cbc_hmac.go b/vendor/github.com/go-jose/go-jose/v4/cipher/cbc_hmac.go
index af029cec0..a301ad9e2 100644
--- a/vendor/github.com/go-jose/go-jose/v4/cipher/cbc_hmac.go
+++ b/vendor/github.com/go-jose/go-jose/v4/cipher/cbc_hmac.go
@@ -51,6 +51,8 @@ func NewCBCHMAC(key []byte, newBlockCipher func([]byte) (cipher.Block, error)) (
hash = sha512.New384
case 32:
hash = sha512.New
+ default:
+ return nil, errors.New("go-jose/go-jose: invalid key size for CBC-HMAC")
}
return &cbcAEAD{
@@ -176,7 +178,9 @@ func padBuffer(buffer []byte, blockSize int) []byte {
// Remove padding
func unpadBuffer(buffer []byte, blockSize int) ([]byte, error) {
- if len(buffer)%blockSize != 0 {
+ // A padded buffer can't be empty because an empty input is padded with
+ // `blockSize` bytes, resulting in a non-empty ciphertext.
+ if len(buffer) == 0 || len(buffer)%blockSize != 0 {
return nil, errors.New("go-jose/go-jose: invalid padding")
}
diff --git a/vendor/github.com/go-jose/go-jose/v4/cipher/key_wrap.go b/vendor/github.com/go-jose/go-jose/v4/cipher/key_wrap.go
index b9effbca8..a2f86e3db 100644
--- a/vendor/github.com/go-jose/go-jose/v4/cipher/key_wrap.go
+++ b/vendor/github.com/go-jose/go-jose/v4/cipher/key_wrap.go
@@ -66,12 +66,20 @@ func KeyWrap(block cipher.Block, cek []byte) ([]byte, error) {
}
// KeyUnwrap implements NIST key unwrapping; it unwraps a content encryption key (cek) with the given block cipher.
+//
+// https://datatracker.ietf.org/doc/html/rfc7518#section-4.4
+// https://datatracker.ietf.org/doc/html/rfc7518#section-4.6
+// https://datatracker.ietf.org/doc/html/rfc7518#section-4.8
func KeyUnwrap(block cipher.Block, ciphertext []byte) ([]byte, error) {
+ n := (len(ciphertext) / 8) - 1
+ if n <= 0 {
+ return nil, errors.New("go-jose/go-jose: JWE Encrypted Key too short")
+ }
+
if len(ciphertext)%8 != 0 {
return nil, errors.New("go-jose/go-jose: key wrap input must be 8 byte blocks")
}
- n := (len(ciphertext) / 8) - 1
r := make([][]byte, n)
for i := range r {
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 d81b03b44..53636c57b 100644
--- a/vendor/github.com/go-jose/go-jose/v4/crypter.go
+++ b/vendor/github.com/go-jose/go-jose/v4/crypter.go
@@ -258,6 +258,10 @@ func (ctx *genericEncrypter) addRecipient(recipient Recipient) (err error) {
}
recipientInfo, err = makeJWERecipient(recipient.Algorithm, recipient.Key)
+ if err != nil {
+ return err
+ }
+
if recipient.KeyID != "" {
recipientInfo.keyID = recipient.KeyID
}
@@ -270,10 +274,8 @@ func (ctx *genericEncrypter) addRecipient(recipient Recipient) (err error) {
}
}
- if err == nil {
- ctx.recipients = append(ctx.recipients, recipientInfo)
- }
- return err
+ ctx.recipients = append(ctx.recipients, recipientInfo)
+ return nil
}
func makeJWERecipient(alg KeyAlgorithm, encryptionKey interface{}) (recipientKeyInfo, error) {
@@ -286,6 +288,10 @@ func makeJWERecipient(alg KeyAlgorithm, encryptionKey interface{}) (recipientKey
return newSymmetricRecipient(alg, encryptionKey)
case string:
return newSymmetricRecipient(alg, []byte(encryptionKey))
+ case JSONWebKey:
+ recipient, err := makeJWERecipient(alg, encryptionKey.Key)
+ recipient.keyID = encryptionKey.KeyID
+ return recipient, err
case *JSONWebKey:
recipient, err := makeJWERecipient(alg, encryptionKey.Key)
recipient.keyID = encryptionKey.KeyID
@@ -422,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.
@@ -450,13 +463,9 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
return nil, errors.New("go-jose/go-jose: too many recipients in payload; expecting only one")
}
- critical, err := headers.getCritical()
+ err := headers.checkNoCritical()
if err != nil {
- return nil, fmt.Errorf("go-jose/go-jose: invalid crit header")
- }
-
- if len(critical) > 0 {
- return nil, fmt.Errorf("go-jose/go-jose: unsupported crit header")
+ return nil, err
}
key, err := tryJWKS(decryptionKey, obj.Header)
@@ -490,21 +499,23 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
recipientHeaders := obj.mergedHeaders(&recipient)
cek, err := decrypter.decryptKey(recipientHeaders, &recipient, generator)
- if err == nil {
- // Found a valid CEK -- let's try to decrypt.
- plaintext, err = cipher.decrypt(cek, authData, parts)
+ if err != nil {
+ return nil, ErrCryptoFailure
+ }
+ err = validateContentEncryptionKeySize(cek, cipher)
+ if err != nil {
+ return nil, ErrCryptoFailure
}
- if plaintext == nil {
+ // Found a valid CEK -- let's try to decrypt.
+ plaintext, err = cipher.decrypt(cek, authData, parts)
+ if err != nil {
return nil, ErrCryptoFailure
}
- // The "zip" header parameter may only be present in the protected header.
- if comp := obj.protected.getCompression(); comp != "" {
- plaintext, err = decompress(comp, plaintext)
- if err != nil {
- return nil, fmt.Errorf("go-jose/go-jose: failed to decompress plaintext: %v", err)
- }
+ plaintext, err = obj.decompress(plaintext)
+ if err != nil {
+ return nil, err
}
return plaintext, nil
@@ -523,13 +534,9 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Header, []byte, error) {
globalHeaders := obj.mergedHeaders(nil)
- critical, err := globalHeaders.getCritical()
+ err := globalHeaders.checkNoCritical()
if err != nil {
- return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: invalid crit header")
- }
-
- if len(critical) > 0 {
- return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: unsupported crit header")
+ return -1, Header{}, nil, err
}
key, err := tryJWKS(decryptionKey, obj.Header)
@@ -563,31 +570,42 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade
var plaintext []byte
var headers rawHeader
+ if len(obj.recipients) == 0 {
+ return -1, Header{}, nil, errors.New("go-jose/go-jose: no recipients")
+ }
+
+ // Loop sets `err` in the function scope; don't shadow it.
for i, recipient := range obj.recipients {
recipientHeaders := obj.mergedHeaders(&recipient)
- cek, err := decrypter.decryptKey(recipientHeaders, &recipient, generator)
- if err == nil {
- // Found a valid CEK -- let's try to decrypt.
- plaintext, err = cipher.decrypt(cek, authData, parts)
- if err == nil {
- index = i
- headers = recipientHeaders
- break
- }
+ var cek []byte
+ cek, err = decrypter.decryptKey(recipientHeaders, &recipient, generator)
+ 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)
+ if err != nil {
+ continue
+ }
+
+ index = i
+ headers = recipientHeaders
+ break
}
- if plaintext == nil {
+ if err != nil {
return -1, Header{}, nil, ErrCryptoFailure
}
- // The "zip" header parameter may only be present in the protected header.
- if comp := obj.protected.getCompression(); comp != "" {
- plaintext, err = decompress(comp, plaintext)
- if err != nil {
- return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: failed to decompress plaintext: %v", err)
- }
+ plaintext, err = obj.decompress(plaintext)
+ if err != nil {
+ return -1, Header{}, nil, err
}
sanitized, err := headers.sanitized()
@@ -597,3 +615,22 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade
return index, sanitized, plaintext, err
}
+
+// decompress decompresses plaintext using the protected "zip" header, if present.
+// It returns plaintext unchanged when there is no protected header or "zip" value.
+func (obj JSONWebEncryption) decompress(plaintext []byte) ([]byte, error) {
+ if obj.protected == nil {
+ return plaintext, nil
+ }
+
+ comp := obj.protected.getCompression()
+ if comp == "" {
+ return plaintext, nil
+ }
+
+ plaintext, err := decompress(comp, plaintext)
+ if err != nil {
+ return nil, fmt.Errorf("go-jose/go-jose: failed to decompress plaintext: %v", err)
+ }
+ return plaintext, nil
+}
diff --git a/vendor/github.com/go-jose/go-jose/v4/json/scanner.go b/vendor/github.com/go-jose/go-jose/v4/json/scanner.go
index ee6622e8c..3bd29f397 100644
--- a/vendor/github.com/go-jose/go-jose/v4/json/scanner.go
+++ b/vendor/github.com/go-jose/go-jose/v4/json/scanner.go
@@ -140,6 +140,10 @@ const (
parseArrayValue // parsing array value
)
+// This limits the max nesting depth to prevent stack overflow.
+// This is permitted by https://tools.ietf.org/html/rfc7159#section-9
+const maxNestingDepth = 10000
+
// reset prepares the scanner for use.
// It must be called before calling s.step.
func (s *scanner) reset() {
@@ -170,8 +174,13 @@ func (s *scanner) eof() int {
}
// pushParseState pushes a new parse state p onto the parse stack.
-func (s *scanner) pushParseState(p int) {
- s.parseState = append(s.parseState, p)
+// an error state is returned if maxNestingDepth was exceeded, otherwise successState is returned.
+func (s *scanner) pushParseState(c byte, newParseState int, successState int) int {
+ s.parseState = append(s.parseState, newParseState)
+ if len(s.parseState) <= maxNestingDepth {
+ return successState
+ }
+ return s.error(c, "exceeded max depth")
}
// popParseState pops a parse state (already obtained) off the stack
@@ -211,12 +220,10 @@ func stateBeginValue(s *scanner, c byte) int {
switch c {
case '{':
s.step = stateBeginStringOrEmpty
- s.pushParseState(parseObjectKey)
- return scanBeginObject
+ return s.pushParseState(c, parseObjectKey, scanBeginObject)
case '[':
s.step = stateBeginValueOrEmpty
- s.pushParseState(parseArrayValue)
- return scanBeginArray
+ return s.pushParseState(c, parseArrayValue, scanBeginArray)
case '"':
s.step = stateInString
return scanBeginLiteral
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 9f1322dcc..a51690107 100644
--- a/vendor/github.com/go-jose/go-jose/v4/jwe.go
+++ b/vendor/github.com/go-jose/go-jose/v4/jwe.go
@@ -153,6 +153,10 @@ func ParseEncryptedJSON(
keyEncryptionAlgorithms []KeyAlgorithm,
contentEncryption []ContentEncryption,
) (*JSONWebEncryption, error) {
+ if len(input) == 0 {
+ return nil, errEmptyInput
+ }
+
var parsed rawJSONWebEncryption
err := json.Unmarshal([]byte(input), &parsed)
if err != nil {
@@ -198,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{
{
@@ -260,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()
@@ -274,7 +278,7 @@ func validateAlgEnc(headers rawHeader, keyAlgorithms []KeyAlgorithm, contentEncr
if alg != "" && !containsKeyAlgorithm(keyAlgorithms, alg) {
return fmt.Errorf("unexpected key algorithm %q; expected %q", alg, keyAlgorithms)
}
- if alg != "" && !containsContentEncryption(contentEncryption, enc) {
+ if enc != "" && !containsContentEncryption(contentEncryption, enc) {
return fmt.Errorf("unexpected content encryption algorithm %q; expected %q", enc, contentEncryption)
}
return nil
@@ -288,11 +292,24 @@ func ParseEncryptedCompact(
keyAlgorithms []KeyAlgorithm,
contentEncryption []ContentEncryption,
) (*JSONWebEncryption, error) {
- // Five parts is four separators
- if strings.Count(input, ".") != 4 {
- return nil, fmt.Errorf("go-jose/go-jose: compact JWE format must have five parts")
+ var parts [5]string
+ var ok bool
+
+ if len(input) == 0 {
+ return nil, errEmptyInput
+ }
+
+ for i := range 4 {
+ parts[i], input, ok = strings.Cut(input, ".")
+ if !ok {
+ return nil, errors.New("go-jose/go-jose: compact JWE format must have five parts")
+ }
+ }
+ // Validate that the last part does not contain more dots
+ if strings.ContainsRune(input, '.') {
+ return nil, errors.New("go-jose/go-jose: compact JWE format must have five parts")
}
- parts := strings.SplitN(input, ".", 5)
+ parts[4] = input
rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
if err != nil {
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 9e57e93ba..8b7aa05ec 100644
--- a/vendor/github.com/go-jose/go-jose/v4/jwk.go
+++ b/vendor/github.com/go-jose/go-jose/v4/jwk.go
@@ -107,7 +107,7 @@ func (k JSONWebKey) MarshalJSON() ([]byte, error) {
switch key := k.Key.(type) {
case ed25519.PublicKey:
- raw = fromEdPublicKey(key)
+ raw, err = fromEdPublicKey(key)
case *ecdsa.PublicKey:
raw, err = fromEcPublicKey(key)
case *rsa.PublicKey:
@@ -175,13 +175,31 @@ func (k JSONWebKey) MarshalJSON() ([]byte, error) {
}
// UnmarshalJSON reads a key from its JSON representation.
-func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
+//
+// Returns ErrUnsupportedKeyType for unrecognized or unsupported "kty" header values.
+//
+// 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)
@@ -205,21 +223,29 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
case "EC":
if raw.D != nil {
key, err = raw.ecPrivateKey()
- if err == nil {
- keyPub = key.(*ecdsa.PrivateKey).Public()
+ if err != nil {
+ return err
}
+ keyPub = key.(*ecdsa.PrivateKey).Public()
} else {
key, err = raw.ecPublicKey()
+ if err != nil {
+ return err
+ }
keyPub = key
}
case "RSA":
if raw.D != nil {
key, err = raw.rsaPrivateKey()
- if err == nil {
- keyPub = key.(*rsa.PrivateKey).Public()
+ if err != nil {
+ return err
}
+ keyPub = key.(*rsa.PrivateKey).Public()
} else {
key, err = raw.rsaPublicKey()
+ if err != nil {
+ return err
+ }
keyPub = key
}
case "oct":
@@ -227,26 +253,39 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
return errors.New("go-jose/go-jose: invalid JWK, found 'oct' (symmetric) key with cert chain")
}
key, err = raw.symmetricKey()
+ if err != nil {
+ return err
+ }
case "OKP":
- if raw.Crv == "Ed25519" && raw.X != nil {
+ if raw.Crv == "Ed25519" {
if raw.D != nil {
key, err = raw.edPrivateKey()
- if err == nil {
- keyPub = key.(ed25519.PrivateKey).Public()
+ if err != nil {
+ return err
}
+ keyPub = key.(ed25519.PrivateKey).Public()
} else {
key, err = raw.edPublicKey()
+ if err != nil {
+ return err
+ }
keyPub = key
}
- } else {
- return fmt.Errorf("go-jose/go-jose: unknown curve %s'", raw.Crv)
}
- default:
- return fmt.Errorf("go-jose/go-jose: unknown json web key type '%s'", raw.Kty)
+ case "":
+ // kty MUST be present
+ return fmt.Errorf("go-jose/go-jose: missing json web key type")
}
- if err != nil {
- return
+ if key == nil {
+ // RFC 7517:
+ // 5. JWK Set Format
+ // ...
+ // Implementations SHOULD ignore JWKs within a JWK Set that use "kty"
+ // (key type) values that are not understood by them, that are missing
+ // required members, or for which values are out of the supported
+ // ranges.
+ return ErrUnsupportedKeyType
}
if certPub != nil && keyPub != nil {
@@ -376,11 +415,12 @@ func rsaThumbprintInput(n *big.Int, e int) (string, error) {
func edThumbprintInput(ed ed25519.PublicKey) (string, error) {
crv := "Ed25519"
- if len(ed) > 32 {
- return "", errors.New("go-jose/go-jose: invalid elliptic key (too large)")
+ err := validateEd25519PublicKey(ed)
+ if err != nil {
+ return "", err
}
return fmt.Sprintf(edThumbprintTemplate, crv,
- newFixedSizeBuffer(ed, 32).base64()), nil
+ newFixedSizeBuffer(ed, ed25519.PublicKeySize).base64()), nil
}
// Thumbprint computes the JWK Thumbprint of a key using the
@@ -481,23 +521,39 @@ 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
}
-func fromEdPublicKey(pub ed25519.PublicKey) *rawJSONWebKey {
+func fromEdPublicKey(pub ed25519.PublicKey) (*rawJSONWebKey, error) {
+ err := validateEd25519PublicKey(pub)
+ if err != nil {
+ return nil, err
+ }
return &rawJSONWebKey{
Kty: "OKP",
Crv: "Ed25519",
X: newBuffer(pub),
- }
+ }, nil
}
func fromRsaPublicKey(pub *rsa.PublicKey) *rawJSONWebKey {
@@ -581,10 +637,10 @@ func fromEcPublicKey(pub *ecdsa.PublicKey) (*rawJSONWebKey, error) {
func (key rawJSONWebKey) edPrivateKey() (ed25519.PrivateKey, error) {
var missing []string
- switch {
- case key.D == nil:
+ if key.D == nil {
missing = append(missing, "D")
- case key.X == nil:
+ }
+ if key.X == nil {
missing = append(missing, "X")
}
@@ -592,52 +648,76 @@ func (key rawJSONWebKey) edPrivateKey() (ed25519.PrivateKey, error) {
return nil, fmt.Errorf("go-jose/go-jose: invalid Ed25519 private key, missing %s value(s)", strings.Join(missing, ", "))
}
- privateKey := make([]byte, ed25519.PrivateKeySize)
- copy(privateKey[0:32], key.D.bytes())
- copy(privateKey[32:], key.X.bytes())
- rv := ed25519.PrivateKey(privateKey)
- return rv, nil
+ publicKey := key.X.bytes()
+ err := validateEd25519PublicKey(publicKey)
+ if err != nil {
+ return nil, err
+ }
+
+ seed := key.D.bytes()
+ if len(seed) != ed25519.SeedSize {
+ return nil, fmt.Errorf("go-jose/go-jose: invalid Ed25519 private key, wrong length for d")
+ }
+
+ privateKey := ed25519.NewKeyFromSeed(seed)
+ derivedPublicKey := privateKey.Public().(ed25519.PublicKey)
+ if !bytes.Equal(derivedPublicKey, publicKey) {
+ return nil, errors.New("go-jose/go-jose: invalid Ed25519 private key, x does not match d")
+ }
+
+ return privateKey, nil
}
func (key rawJSONWebKey) edPublicKey() (ed25519.PublicKey, error) {
if key.X == nil {
return nil, fmt.Errorf("go-jose/go-jose: invalid Ed key, missing x value")
}
- publicKey := make([]byte, ed25519.PublicKeySize)
- copy(publicKey[0:32], key.X.bytes())
- rv := ed25519.PublicKey(publicKey)
- return rv, nil
+ publicKey := key.X.bytes()
+ err := validateEd25519PublicKey(publicKey)
+ if err != nil {
+ return nil, err
+ }
+ return ed25519.PublicKey(bytes.Clone(publicKey)), nil
}
func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
var missing []string
- switch {
- case key.N == nil:
+ if key.N == nil {
missing = append(missing, "N")
- case key.E == nil:
+ }
+ if key.E == nil {
missing = append(missing, "E")
- case key.D == nil:
+ }
+ if key.D == nil {
missing = append(missing, "D")
- case key.P == nil:
+ }
+ if key.P == nil {
missing = append(missing, "P")
- case key.Q == nil:
+ }
+ if key.Q == nil {
missing = append(missing, "Q")
}
-
if len(missing) > 0 {
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 {
@@ -655,9 +735,17 @@ func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
}
func fromEdPrivateKey(ed ed25519.PrivateKey) (*rawJSONWebKey, error) {
- raw := fromEdPublicKey(ed25519.PublicKey(ed[32:]))
+ if len(ed) != ed25519.PrivateKeySize {
+ return nil, errors.New("go-jose/go-jose: invalid Ed25519 private key length")
+ }
- raw.D = newBuffer(ed[0:32])
+ publicKey := ed.Public().(ed25519.PublicKey)
+ raw, err := fromEdPublicKey(publicKey)
+ if err != nil {
+ return nil, err
+ }
+
+ raw.D = newBuffer(ed.Seed())
return raw, nil
}
@@ -698,8 +786,19 @@ func (key rawJSONWebKey) ecPrivateKey() (*ecdsa.PrivateKey, error) {
return nil, fmt.Errorf("go-jose/go-jose: unsupported elliptic curve '%s'", key.Crv)
}
- if key.X == nil || key.Y == nil || key.D == nil {
- return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, missing x/y/d values")
+ var missing []string
+ if key.X == nil {
+ missing = append(missing, "X")
+ }
+ if key.Y == nil {
+ missing = append(missing, "Y")
+ }
+ if key.D == nil {
+ missing = append(missing, "D")
+ }
+
+ if len(missing) > 0 {
+ return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, missing %s value(s)", strings.Join(missing, ", "))
}
// The length of this octet string MUST be the full size of a coordinate for
@@ -785,7 +884,7 @@ var (
ErrJWKSKidNotFound = errors.New("go-jose/go-jose: JWK with matching kid not found in JWK Set")
)
-func tryJWKS(key interface{}, headers ...Header) (interface{}, error) {
+func tryJWKS(key interface{}, header Header) (interface{}, error) {
var jwks JSONWebKeySet
switch jwksType := key.(type) {
@@ -798,16 +897,8 @@ func tryJWKS(key interface{}, headers ...Header) (interface{}, error) {
return key, nil
}
- // Determine the KID to search for from the headers.
- var kid string
- for _, header := range headers {
- if header.KeyID != "" {
- kid = header.KeyID
- break
- }
- }
-
- // If no KID is specified in the headers, reject.
+ // If no KID is specified in the header, reject.
+ kid := header.KeyID
if kid == "" {
return nil, ErrJWKSKidNotFound
}
@@ -821,3 +912,107 @@ func tryJWKS(key interface{}, headers ...Header) (interface{}, error) {
return keys[0].Key, nil
}
+
+// weakEd25519PublicKeys contains the low-order Ed25519 encodings accepted by
+// Go's verifier that must not be accepted as JOSE verification keys.
+var weakEd25519PublicKeys = map[[ed25519.PublicKeySize]byte]struct{}{
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }: {},
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ }: {},
+ {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }: {},
+ {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ }: {},
+ {
+ 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
+ 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
+ 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
+ 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05,
+ }: {},
+ {
+ 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
+ 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
+ 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
+ 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85,
+ }: {},
+ {
+ 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
+ 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
+ 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
+ 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a,
+ }: {},
+ {
+ 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
+ 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
+ 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
+ 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa,
+ }: {},
+ {
+ 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ }: {},
+ {
+ 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ }: {},
+ {
+ 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ }: {},
+ {
+ 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ }: {},
+ {
+ 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ }: {},
+ {
+ 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ }: {},
+}
+
+func validateEd25519PublicKey(publicKey ed25519.PublicKey) error {
+ if len(publicKey) != ed25519.PublicKeySize {
+ return fmt.Errorf("go-jose/go-jose: invalid Ed25519 public key, wrong length for x")
+ }
+
+ var encoded [ed25519.PublicKeySize]byte
+ copy(encoded[:], publicKey)
+ _, ok := weakEd25519PublicKeys[encoded]
+ if ok {
+ return errors.New("go-jose/go-jose: invalid Ed25519 public key, low-order point")
+ }
+
+ return 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 d09d8ba50..18224df7d 100644
--- a/vendor/github.com/go-jose/go-jose/v4/jws.go
+++ b/vendor/github.com/go-jose/go-jose/v4/jws.go
@@ -22,6 +22,7 @@ import (
"errors"
"fmt"
"strings"
+ "unicode"
"github.com/go-jose/go-jose/v4/json"
)
@@ -75,22 +76,36 @@ type Signature struct {
original *rawSignatureInfo
}
-// ParseSigned parses a signed message in JWS Compact or JWS JSON Serialization.
+// ParseSigned parses a signed message in JWS Compact or JWS JSON Serialization. Validation fails if
+// the JWS is signed with an algorithm that isn't in the provided list of signature algorithms.
+// Applications should decide for themselves which signature algorithms are acceptable. If you're
+// not sure which signature algorithms your application might receive, consult the documentation of
+// the program which provides them or the protocol that you are implementing. You can also try
+// getting an example JWS and decoding it with a tool like https://jwt.io to see what its "alg"
+// header parameter indicates. The signature on the JWS does not get validated during parsing. Call
+// Verify() after parsing to validate the signature and obtain the payload.
//
// https://datatracker.ietf.org/doc/html/rfc7515#section-7
func ParseSigned(
signature string,
signatureAlgorithms []SignatureAlgorithm,
) (*JSONWebSignature, error) {
- signature = stripWhitespace(signature)
- if strings.HasPrefix(signature, "{") {
+ trimmed := strings.TrimLeftFunc(signature, unicode.IsSpace)
+ if strings.HasPrefix(trimmed, "{") {
return ParseSignedJSON(signature, signatureAlgorithms)
}
- return parseSignedCompact(signature, nil, signatureAlgorithms)
+ return parseSignedCompact(stripWhitespace(signature), nil, signatureAlgorithms)
}
-// ParseSignedCompact parses a message in JWS Compact Serialization.
+// ParseSignedCompact parses a message in JWS Compact Serialization. Validation fails if the JWS is
+// signed with an algorithm that isn't in the provided list of signature algorithms. Applications
+// should decide for themselves which signature algorithms are acceptable.If you're not sure which
+// signature algorithms your application might receive, consult the documentation of the program
+// which provides them or the protocol that you are implementing. You can also try getting an
+// example JWS and decoding it with a tool like https://jwt.io to see what its "alg" header
+// parameter indicates. The signature on the JWS does not get validated during parsing. Call
+// Verify() after parsing to validate the signature and obtain the payload.
//
// https://datatracker.ietf.org/doc/html/rfc7515#section-7.1
func ParseSignedCompact(
@@ -101,6 +116,15 @@ func ParseSignedCompact(
}
// ParseDetached parses a signed message in compact serialization format with detached payload.
+// Validation fails if the JWS is signed with an algorithm that isn't in the provided list of
+// signature algorithms. Applications should decide for themselves which signature algorithms are
+// acceptable. If you're not sure which signature algorithms your application might receive, consult
+// the documentation of the program which provides them or the protocol that you are implementing.
+// You can also try getting an example JWS and decoding it with a tool like https://jwt.io to see
+// what its "alg" header parameter indicates. The signature on the JWS does not get validated during
+// parsing. Call Verify() after parsing to validate the signature and obtain the payload.
+//
+// https://datatracker.ietf.org/doc/html/rfc7515#appendix-F
func ParseDetached(
signature string,
payload []byte,
@@ -163,6 +187,10 @@ func ParseSignedJSON(
input string,
signatureAlgorithms []SignatureAlgorithm,
) (*JSONWebSignature, error) {
+ if len(input) == 0 {
+ return nil, errEmptyInput
+ }
+
var parsed rawJSONWebSignature
err := json.Unmarshal([]byte(input), &parsed)
if err != nil {
@@ -181,6 +209,25 @@ func containsSignatureAlgorithm(haystack []SignatureAlgorithm, needle SignatureA
return false
}
+// ErrUnexpectedSignatureAlgorithm is returned when the signature algorithm in
+// the JWS header does not match one of the expected algorithms.
+type ErrUnexpectedSignatureAlgorithm struct {
+ // Got is the signature algorithm found in the JWS header.
+ Got SignatureAlgorithm
+ expected []SignatureAlgorithm
+}
+
+func (e *ErrUnexpectedSignatureAlgorithm) Error() string {
+ return fmt.Sprintf("unexpected signature algorithm %q; expected %q", e.Got, e.expected)
+}
+
+func newErrUnexpectedSignatureAlgorithm(got SignatureAlgorithm, expected []SignatureAlgorithm) error {
+ return &ErrUnexpectedSignatureAlgorithm{
+ Got: got,
+ expected: expected,
+ }
+}
+
// sanitized produces a cleaned-up JWS object from the raw JSON.
func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgorithm) (*JSONWebSignature, error) {
if len(signatureAlgorithms) == 0 {
@@ -228,18 +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, fmt.Errorf("go-jose/go-jose: unexpected signature algorithm %q; expected %q",
- alg, signatureAlgorithms)
- }
-
if signature.header != nil {
signature.Unprotected, err = signature.header.sanitized()
if err != nil {
@@ -277,18 +324,20 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
return nil, ErrUnprotectedNonce
}
+ obj.Signatures[i].header = sig.Header
+
+ 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 = obj.Signatures[i].mergedHeaders().sanitized()
+ obj.Signatures[i].Header, err = mergedHeaders.sanitized()
if err != nil {
return nil, err
}
- alg := SignatureAlgorithm(obj.Signatures[i].Header.Algorithm)
- if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
- return nil, fmt.Errorf("go-jose/go-jose: unexpected signature algorithm %q; expected %q",
- alg, signatureAlgorithms)
- }
-
if obj.Signatures[i].header != nil {
obj.Signatures[i].Unprotected, err = obj.Signatures[i].header.sanitized()
if err != nil {
@@ -314,42 +363,53 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
// Copy value of sig
original := sig
- obj.Signatures[i].header = sig.Header
obj.Signatures[i].original = &original
}
return obj, nil
}
+const tokenDelim = "."
+
// parseSignedCompact parses a message in compact format.
func parseSignedCompact(
input string,
payload []byte,
signatureAlgorithms []SignatureAlgorithm,
) (*JSONWebSignature, error) {
- // Three parts is two separators
- if strings.Count(input, ".") != 2 {
+ if len(input) == 0 {
+ return nil, errEmptyInput
+ }
+
+ protected, s, ok := strings.Cut(input, tokenDelim)
+ if !ok { // no period found
+ return nil, fmt.Errorf("go-jose/go-jose: compact JWS format must have three parts")
+ }
+ claims, sig, ok := strings.Cut(s, tokenDelim)
+ if !ok { // only one period found
+ return nil, fmt.Errorf("go-jose/go-jose: compact JWS format must have three parts")
+ }
+ if strings.ContainsRune(sig, '.') { // too many periods found
return nil, fmt.Errorf("go-jose/go-jose: compact JWS format must have three parts")
}
- parts := strings.SplitN(input, ".", 3)
- if parts[1] != "" && payload != nil {
+ if claims != "" && payload != nil {
return nil, fmt.Errorf("go-jose/go-jose: payload is not detached")
}
- rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
+ rawProtected, err := base64.RawURLEncoding.DecodeString(protected)
if err != nil {
return nil, err
}
if payload == nil {
- payload, err = base64.RawURLEncoding.DecodeString(parts[1])
+ payload, err = base64.RawURLEncoding.DecodeString(claims)
if err != nil {
return nil, err
}
}
- signature, err := base64.RawURLEncoding.DecodeString(parts[2])
+ signature, err := base64.RawURLEncoding.DecodeString(sig)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/go-jose/go-jose/v4/opaque.go b/vendor/github.com/go-jose/go-jose/v4/opaque.go
index 429427232..91a42fc1d 100644
--- a/vendor/github.com/go-jose/go-jose/v4/opaque.go
+++ b/vendor/github.com/go-jose/go-jose/v4/opaque.go
@@ -46,6 +46,11 @@ func newOpaqueSigner(alg SignatureAlgorithm, signer OpaqueSigner) (recipientSigI
return recipientSigInfo{}, ErrUnsupportedAlgorithm
}
+ pk := signer.Public()
+ if pk != nil && !pk.IsPublic() {
+ return recipientSigInfo{}, ErrNotPublic
+ }
+
return recipientSigInfo{
sigAlg: alg,
publicKey: signer.Public,
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 1ec339612..1e8bf8821 100644
--- a/vendor/github.com/go-jose/go-jose/v4/shared.go
+++ b/vendor/github.com/go-jose/go-jose/v4/shared.go
@@ -77,6 +77,15 @@ var (
// ErrUnsupportedEllipticCurve indicates unsupported or unknown elliptic curve has been found.
ErrUnsupportedEllipticCurve = errors.New("go-jose/go-jose: unsupported/unknown elliptic curve")
+
+ // ErrUnsupportedCriticalHeader is returned when a header is marked critical but not supported by go-jose.
+ ErrUnsupportedCriticalHeader = errors.New("go-jose/go-jose: unsupported critical header")
+
+ // errEmptyInput is returned when go-jose was asked to parse an empty string.
+ errEmptyInput = errors.New("go-jose/go-jose: empty input")
+
+ // ErrNotPublic indicates a private key was passed where a public key was expected
+ ErrNotPublic = errors.New("go-jose/go-jose: public key was unexpectedly not public")
)
// Key management algorithms
@@ -167,8 +176,8 @@ const (
)
// supportedCritical is the set of supported extensions that are understood and processed.
-var supportedCritical = map[string]bool{
- headerB64: true,
+var supportedCritical = map[string]struct{}{
+ headerB64: {},
}
// rawHeader represents the JOSE header for JWE/JWS objects (used for parsing).
@@ -288,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
@@ -316,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) {
@@ -346,6 +342,32 @@ func (parsed rawHeader) getCritical() ([]string, error) {
return q, nil
}
+// checkNoCritical verifies there are no critical headers present.
+func (parsed rawHeader) checkNoCritical() error {
+ if _, ok := parsed[headerCritical]; ok {
+ return ErrUnsupportedCriticalHeader
+ }
+
+ return nil
+}
+
+// checkSupportedCritical verifies there are no unsupported critical headers.
+// Supported headers are passed in as a set: map of names to empty structs
+func (parsed rawHeader) checkSupportedCritical(supported map[string]struct{}) error {
+ crit, err := parsed.getCritical()
+ if err != nil {
+ return err
+ }
+
+ for _, name := range crit {
+ if _, ok := supported[name]; !ok {
+ return ErrUnsupportedCriticalHeader
+ }
+ }
+
+ return nil
+}
+
// getS2C extracts parsed "p2c" from the raw JSON.
func (parsed rawHeader) getP2C() (int, error) {
v := parsed[headerP2C]
@@ -389,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/signing.go b/vendor/github.com/go-jose/go-jose/v4/signing.go
index 3dec0112b..5baf75cb2 100644
--- a/vendor/github.com/go-jose/go-jose/v4/signing.go
+++ b/vendor/github.com/go-jose/go-jose/v4/signing.go
@@ -130,6 +130,8 @@ type payloadVerifier interface {
verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error
}
+var errInvalidVerificationKey = errors.New("go-jose/go-jose: invalid verification key")
+
type genericSigner struct {
recipients []recipientSigInfo
nonceSource NonceSource
@@ -138,11 +140,21 @@ type genericSigner struct {
}
type recipientSigInfo struct {
- sigAlg SignatureAlgorithm
+ sigAlg SignatureAlgorithm
+ // publicKey returns a synthetic JSONWebKey for the signer.
+ // For opaque signers, it calls OpaqueSigner.Public().
publicKey func() *JSONWebKey
signer payloadSigner
}
+// getPublicKey gets the public key, with a nil check on the func.
+func (r recipientSigInfo) getPublicKey() *JSONWebKey {
+ if r.publicKey == nil {
+ return nil
+ }
+ return r.publicKey()
+}
+
func staticPublicKey(jwk *JSONWebKey) func() *JSONWebKey {
return func() *JSONWebKey {
return jwk
@@ -178,14 +190,23 @@ func NewMultiSigner(sigs []SigningKey, opts *SignerOptions) (Signer, error) {
func newVerifier(verificationKey interface{}) (payloadVerifier, error) {
switch verificationKey := verificationKey.(type) {
case ed25519.PublicKey:
+ if len(verificationKey) == 0 {
+ return nil, errInvalidVerificationKey
+ }
return &edEncrypterVerifier{
publicKey: verificationKey,
}, nil
case *rsa.PublicKey:
+ if verificationKey == nil {
+ return nil, errInvalidVerificationKey
+ }
return &rsaEncrypterVerifier{
publicKey: verificationKey,
}, nil
case *ecdsa.PublicKey:
+ if verificationKey == nil {
+ return nil, errInvalidVerificationKey
+ }
return &ecEncrypterVerifier{
publicKey: verificationKey,
}, nil
@@ -196,6 +217,9 @@ func newVerifier(verificationKey interface{}) (payloadVerifier, error) {
case JSONWebKey:
return newVerifier(verificationKey.Key)
case *JSONWebKey:
+ if verificationKey == nil {
+ return nil, errInvalidVerificationKey
+ }
return newVerifier(verificationKey.Key)
case OpaqueVerifier:
return &opaqueVerifier{verifier: verificationKey}, nil
@@ -240,18 +264,18 @@ func newJWKSigner(alg SignatureAlgorithm, signingKey JSONWebKey) (recipientSigIn
if err != nil {
return recipientSigInfo{}, err
}
- if recipient.publicKey != nil && recipient.publicKey() != nil {
+ if recipientPubKey := recipient.getPublicKey(); recipientPubKey != nil {
+ // This should be impossible, but let's check anyway.
+ if !recipientPubKey.IsPublic() {
+ return recipientSigInfo{}, ErrNotPublic
+ }
+
// recipient.publicKey is a JWK synthesized for embedding when recipientSigInfo
// was created for the inner key (such as a RSA or ECDSA public key). It contains
// the pub key for embedding, but doesn't have extra params like key id.
publicKey := signingKey
- publicKey.Key = recipient.publicKey().Key
+ publicKey.Key = recipientPubKey.Key
recipient.publicKey = staticPublicKey(&publicKey)
-
- // This should be impossible, but let's check anyway.
- if !recipient.publicKey().IsPublic() {
- return recipientSigInfo{}, errors.New("go-jose/go-jose: public key was unexpectedly not public")
- }
}
return recipient, nil
}
@@ -266,7 +290,7 @@ func (ctx *genericSigner) Sign(payload []byte) (*JSONWebSignature, error) {
headerAlgorithm: string(recipient.sigAlg),
}
- if recipient.publicKey != nil && recipient.publicKey() != nil {
+ if recipientPubKey := recipient.getPublicKey(); recipientPubKey != nil {
// We want to embed the JWK or set the kid header, but not both. Having a protected
// header that contains an embedded JWK while also simultaneously containing the kid
// header is confusing, and at least in ACME the two are considered to be mutually
@@ -274,11 +298,11 @@ func (ctx *genericSigner) Sign(payload []byte) (*JSONWebSignature, error) {
// result of the JOSE spec. We've decided that this library will only include one or
// the other to avoid this confusion.
//
- // See https://github.com/go-jose/go-jose/issues/157 for more context.
+ // See https://github.com/square/go-jose/issues/157 for more context.
if ctx.embedJWK {
- protected[headerJWK] = recipient.publicKey()
+ protected[headerJWK] = recipientPubKey
} else {
- keyID := recipient.publicKey().KeyID
+ keyID := recipientPubKey.KeyID
if keyID != "" {
protected[headerKeyID] = keyID
}
@@ -390,7 +414,13 @@ func (obj JSONWebSignature) UnsafePayloadWithoutVerification() []byte {
// The verificationKey argument must have one of the types allowed for the
// verificationKey argument of JSONWebSignature.Verify().
func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey interface{}) error {
- key, err := tryJWKS(verificationKey, obj.headers()...)
+ if len(obj.Signatures) > 1 {
+ return errors.New("go-jose/go-jose: too many signatures in payload; expecting only one")
+ }
+
+ signature := obj.Signatures[0]
+
+ key, err := tryJWKS(verificationKey, signature.Header)
if err != nil {
return err
}
@@ -399,20 +429,22 @@ func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey inter
return err
}
- if len(obj.Signatures) > 1 {
- return errors.New("go-jose/go-jose: too many signatures in payload; expecting only one")
- }
-
- signature := obj.Signatures[0]
- headers := signature.mergedHeaders()
- critical, err := headers.getCritical()
- if err != nil {
- return err
+ if signature.header != nil {
+ // Per https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11,
+ // 4.1.11. "crit" (Critical) Header Parameter
+ // "When used, this Header Parameter MUST be integrity
+ // protected; therefore, it MUST occur only within the JWS
+ // Protected Header."
+ err = signature.header.checkNoCritical()
+ if err != nil {
+ return err
+ }
}
- for _, name := range critical {
- if !supportedCritical[name] {
- return ErrCryptoFailure
+ if signature.protected != nil {
+ err = signature.protected.checkSupportedCritical(supportedCritical)
+ if err != nil {
+ return err
}
}
@@ -421,13 +453,14 @@ func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey inter
return ErrCryptoFailure
}
+ headers := signature.mergedHeaders()
alg := headers.getSignatureAlgorithm()
err = verifier.verifyPayload(input, signature.Signature, alg)
- if err == nil {
- return nil
+ if err != nil {
+ return ErrCryptoFailure
}
- return ErrCryptoFailure
+ return nil
}
// VerifyMulti validates (one of the multiple) signatures on the object and
@@ -458,48 +491,52 @@ func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signa
// The verificationKey argument must have one of the types allowed for the
// verificationKey argument of JSONWebSignature.Verify().
func (obj JSONWebSignature) DetachedVerifyMulti(payload []byte, verificationKey interface{}) (int, Signature, error) {
- key, err := tryJWKS(verificationKey, obj.headers()...)
- if err != nil {
- return -1, Signature{}, err
- }
- verifier, err := newVerifier(key)
- if err != nil {
- return -1, Signature{}, err
- }
-
-outer:
for i, signature := range obj.Signatures {
- headers := signature.mergedHeaders()
- critical, err := headers.getCritical()
- if err != nil {
- continue
+ if signature.header != nil {
+ // Per https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11,
+ // 4.1.11. "crit" (Critical) Header Parameter
+ // "When used, this Header Parameter MUST be integrity
+ // protected; therefore, it MUST occur only within the JWS
+ // Protected Header."
+ err := signature.header.checkNoCritical()
+ if err != nil {
+ continue
+ }
}
- for _, name := range critical {
- if !supportedCritical[name] {
- continue outer
+ if signature.protected != nil {
+ // Check for only supported critical headers
+ err := signature.protected.checkSupportedCritical(supportedCritical)
+ if err != nil {
+ continue
}
}
+ // If the verification key is a JWK Set, pick a key based on this signature's
+ // "kid" header. If no match, skip this signature.
+ key, err := tryJWKS(verificationKey, signature.Header)
+ if err != nil {
+ continue
+ }
+ verifier, err := newVerifier(key)
+ if err != nil {
+ continue
+ }
+
input, err := obj.computeAuthData(payload, &signature)
if err != nil {
continue
}
+ headers := signature.mergedHeaders()
alg := headers.getSignatureAlgorithm()
err = verifier.verifyPayload(input, signature.Signature, alg)
- if err == nil {
- return i, signature, nil
+ if err != nil {
+ continue
}
+
+ return i, signature, nil
}
return -1, Signature{}, ErrCryptoFailure
}
-
-func (obj JSONWebSignature) headers() []Header {
- headers := make([]Header, len(obj.Signatures))
- for i, sig := range obj.Signatures {
- headers[i] = sig.Header
- }
- return headers
-}
diff --git a/vendor/github.com/go-jose/go-jose/v4/symmetric.go b/vendor/github.com/go-jose/go-jose/v4/symmetric.go
index a69103b08..ca597d6a1 100644
--- a/vendor/github.com/go-jose/go-jose/v4/symmetric.go
+++ b/vendor/github.com/go-jose/go-jose/v4/symmetric.go
@@ -21,6 +21,7 @@ import (
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
+ "crypto/pbkdf2"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
@@ -30,13 +31,11 @@ import (
"hash"
"io"
- "golang.org/x/crypto/pbkdf2"
-
josecipher "github.com/go-jose/go-jose/v4/cipher"
)
-// RandReader is a cryptographically secure random number generator (stubbed out in tests).
-var RandReader = rand.Reader
+// randReader is a cryptographically secure random number generator (stubbed out in tests).
+var randReader = rand.Reader
const (
// RFC7518 recommends a minimum of 1,000 iterations:
@@ -154,7 +153,7 @@ func getPbkdf2Params(alg KeyAlgorithm) (int, func() hash.Hash) {
// getRandomSalt generates a new salt of the given size.
func getRandomSalt(size int) ([]byte, error) {
salt := make([]byte, size)
- _, err := io.ReadFull(RandReader, salt)
+ _, err := io.ReadFull(randReader, salt)
if err != nil {
return nil, err
}
@@ -199,7 +198,7 @@ func newSymmetricSigner(sigAlg SignatureAlgorithm, key []byte) (recipientSigInfo
// Generate a random key for the given content cipher
func (ctx randomKeyGenerator) genKey() ([]byte, rawHeader, error) {
key := make([]byte, ctx.size)
- _, err := io.ReadFull(RandReader, key)
+ _, err := io.ReadFull(randReader, key)
if err != nil {
return nil, rawHeader{}, err
}
@@ -239,7 +238,7 @@ func (ctx aeadContentCipher) encrypt(key, aad, pt []byte) (*aeadParts, error) {
// Initialize a new nonce
iv := make([]byte, aead.NonceSize())
- _, err = io.ReadFull(RandReader, iv)
+ _, err = io.ReadFull(randReader, iv)
if err != nil {
return nil, err
}
@@ -330,7 +329,10 @@ func (ctx *symmetricKeyCipher) encryptKey(cek []byte, alg KeyAlgorithm) (recipie
// derive key
keyLen, h := getPbkdf2Params(alg)
- key := pbkdf2.Key(ctx.key, salt, ctx.p2c, keyLen, h)
+ key, err := pbkdf2.Key(h, string(ctx.key), salt, ctx.p2c, keyLen)
+ if err != nil {
+ return recipientInfo{}, nil
+ }
// use AES cipher with derived key
block, err := aes.NewCipher(key)
@@ -364,11 +366,21 @@ func (ctx *symmetricKeyCipher) encryptKey(cek []byte, alg KeyAlgorithm) (recipie
// Decrypt the content encryption key.
func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
- switch headers.getAlgorithm() {
- case DIRECT:
- cek := make([]byte, len(ctx.key))
- copy(cek, ctx.key)
- return cek, nil
+ if recipient == nil {
+ return nil, fmt.Errorf("go-jose/go-jose: missing recipient")
+ }
+
+ alg := headers.getAlgorithm()
+ if alg == DIRECT {
+ return bytes.Clone(ctx.key), nil
+ }
+
+ encryptedKey := recipient.encryptedKey
+ if len(encryptedKey) == 0 {
+ return nil, fmt.Errorf("go-jose/go-jose: missing JWE Encrypted Key")
+ }
+
+ switch alg {
case A128GCMKW, A192GCMKW, A256GCMKW:
aead := newAESGCM(len(ctx.key))
@@ -383,7 +395,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
parts := &aeadParts{
iv: iv.bytes(),
- ciphertext: recipient.encryptedKey,
+ ciphertext: encryptedKey,
tag: tag.bytes(),
}
@@ -399,7 +411,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
return nil, err
}
- cek, err := josecipher.KeyUnwrap(block, recipient.encryptedKey)
+ cek, err := josecipher.KeyUnwrap(block, encryptedKey)
if err != nil {
return nil, err
}
@@ -432,7 +444,10 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
// derive key
keyLen, h := getPbkdf2Params(alg)
- key := pbkdf2.Key(ctx.key, salt, p2c, keyLen, h)
+ key, err := pbkdf2.Key(h, string(ctx.key), salt, p2c, keyLen)
+ if err != nil {
+ return nil, err
+ }
// use AES cipher with derived key
block, err := aes.NewCipher(key)
@@ -440,7 +455,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
return nil, err
}
- cek, err := josecipher.KeyUnwrap(block, recipient.encryptedKey)
+ cek, err := josecipher.KeyUnwrap(block, encryptedKey)
if err != nil {
return nil, err
}
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 000000000..b45da99bd
--- /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 000000000..c9e66d4c2
--- /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 a049eb221..64e4da50b 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -291,8 +291,8 @@ github.com/go-jose/go-jose/v3
github.com/go-jose/go-jose/v3/cipher
github.com/go-jose/go-jose/v3/json
github.com/go-jose/go-jose/v3/jwt
-# github.com/go-jose/go-jose/v4 v4.0.5
-## explicit; go 1.21
+# 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
github.com/go-jose/go-jose/v4/json