From 76903a39fabe679a93b1908197abe733f66d010f Mon Sep 17 00:00:00 2001
From: Jacob Hoffman-Andrews <github@hoffman-andrews.com>
Date: Wed, 15 Jul 2026 17:23:49 +0800
Subject: [PATCH] backport to fix CVE-2026-34986
.../go-jose/go-jose/v3/asymmetric.go | 10 ++++++-
.../go-jose/go-jose/v3/cipher/key_wrap.go | 6 +++-
.../go-jose/go-jose/v3/symmetric.go | 26 +++++++++++------
.../gopkg.in/go-jose/go-jose.v2/asymmetric.go | 10 ++++++-
.../go-jose/go-jose.v2/cipher/key_wrap.go | 6 +++-
.../gopkg.in/go-jose/go-jose.v2/symmetric.go | 28 +++++++++++++------
6 files changed, 65 insertions(+), 21 deletions(-)
@@ -411,6 +411,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")
@@ -458,13 +461,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) {
@@ -67,11 +67,15 @@ 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.
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 {
@@ -359,11 +359,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))
@@ -378,7 +388,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
parts := &aeadParts{
iv: iv.bytes(),
- ciphertext: recipient.encryptedKey,
+ ciphertext: encryptedKey,
tag: tag.bytes(),
}
@@ -394,7 +404,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
}
@@ -435,7 +445,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
}
@@ -411,6 +411,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")
@@ -458,13 +461,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) {
@@ -67,11 +67,15 @@ 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.
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 {
@@ -31,7 +31,7 @@ import (
"io"
"golang.org/x/crypto/pbkdf2"
- "gopkg.in/go-jose/go-jose.v2/cipher"
+ josecipher "gopkg.in/go-jose/go-jose.v2/cipher"
)
// Random reader (stubbed out in tests)
@@ -346,11 +346,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))
@@ -365,7 +375,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
parts := &aeadParts{
iv: iv.bytes(),
- ciphertext: recipient.encryptedKey,
+ ciphertext: encryptedKey,
tag: tag.bytes(),
}
@@ -381,7 +391,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
}
@@ -417,7 +427,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
}
--
2.54.0