CVE-2023-50658 (published 2024-02-29T01:42Z)

The jose2go component before 1.6.0 for Go allows attackers to cause a denial of service (CPU consumption) via a large p2c (aka PBES2 Count) value.


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/dvsekhvalnov/jose2go
commit_details: repo_url: https://github.com/dvsekhvalnov/jose2go
author: DV
author_date: 2023-11-23 20:26:26+03:00
msg: Adding min/max iteration count guards to pbes2-hmac-aeskw algorithm
repository: repo_url: https://github.com/dvsekhvalnov/jose2go
repo_name: dvsekhvalnov/jose2go
description: Golang (GO) implementation of Javascript Object Signing and Encryption specification
repo_language: Go
owner: dvsekhvalnov
file_changes: filename: jose_test.go
change_type: ModificationType.MODIFY
diff: @@ -1634,6 +1634,40 @@ func (s *TestSuite) TestDecrypt_PBSE2_HS512_A256KW_A256CBC_HS512(c *C) {
 	c.Assert(test, Equals, `{"exp":1392553211,"sub":"alice","nbf":1392552611,"aud":["https:\/\/app-one.com","https:\/\/app-two.com"],"iss":"https:\/\/openid.net","jti":"586dd129-a29f-49c8-9de7-454af1155e27","iat":1392552611}`)
 }
 
+func (s *TestSuite) TestDecrypt_PBSE2_HS512_A256KW_A256CBC_HS512_MinIterationViolation(c *C) {
+	//given
+	pbes2Hs512 := DeregisterJwa(PBES2_HS512_A256KW)
+	RegisterJwa(NewPbse2HmacAesKWAlg(256, 300000, 10000))
+	token := "eyJhbGciOiJQQkVTMi1IUzUxMitBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwicDJjIjo4MTkyLCJwMnMiOiJCUlkxQ1M3VXNpaTZJNzhkIn0.ovjAL7yRnB_XdJbK8lAaUDRZ-CyVeio8f4pnqOt1FPj1PoQAdEX3S5x6DlzR8aqN_WR5LUwdqDSyUDYhSurnmq8VLfzd3AEe.YAjH6g_zekXJIlPN4Ooo5Q.tutaltxpeVyayXZ9pQovGXTWTf_GWWvtu25Jeg9jgoH0sUX9KCnL00A69e4GJR6EMxalmWsa45AItffbwjUBmwdyklC4ZbTgaovVRs-UwqsZFBO2fpEb7qLajjwra7o4OegzgXDD0jhrKrUusvRWGBvenvumb5euibUxmIfBUcVF1JbdfYxx7ztFeS-QKJpDkE00zyEkViq-QxfrMVl5p7LGmTz8hMrFL3LXLokypZSDgFBfsUzChJf3mlYzxiGaGUqhs7NksQJDoUYf6prPow.XwRVfVTTPogO74RnxZD_9Mse26fTSehna1pbWy4VHfY"
+
+	//when
+	test, headers, err := Decode(token, "top secret")
+	fmt.Printf("\np2c min iteration err= %v\n", err)
+
+	//then
+	RegisterJwa(pbes2Hs512)
+	c.Assert(err, NotNil)
+	c.Assert(test, Equals, "")
+	c.Assert(headers, IsNil)
+}
+
+func (s *TestSuite) TestDecrypt_PBSE2_HS512_A256KW_A256CBC_HS512_MaxIterationViolation(c *C) {
+	//given
+	pbes2Hs512 := DeregisterJwa(PBES2_HS512_A256KW)
+	RegisterJwa(NewPbse2HmacAesKWAlg(256, 8000, 0))
+	token := "eyJhbGciOiJQQkVTMi1IUzUxMitBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwicDJjIjo4MTkyLCJwMnMiOiJCUlkxQ1M3VXNpaTZJNzhkIn0.ovjAL7yRnB_XdJbK8lAaUDRZ-CyVeio8f4pnqOt1FPj1PoQAdEX3S5x6DlzR8aqN_WR5LUwdqDSyUDYhSurnmq8VLfzd3AEe.YAjH6g_zekXJIlPN4Ooo5Q.tutaltxpeVyayXZ9pQovGXTWTf_GWWvtu25Jeg9jgoH0sUX9KCnL00A69e4GJR6EMxalmWsa45AItffbwjUBmwdyklC4ZbTgaovVRs-UwqsZFBO2fpEb7qLajjwra7o4OegzgXDD0jhrKrUusvRWGBvenvumb5euibUxmIfBUcVF1JbdfYxx7ztFeS-QKJpDkE00zyEkViq-QxfrMVl5p7LGmTz8hMrFL3LXLokypZSDgFBfsUzChJf3mlYzxiGaGUqhs7NksQJDoUYf6prPow.XwRVfVTTPogO74RnxZD_9Mse26fTSehna1pbWy4VHfY"
+
+	//when
+	test, headers, err := Decode(token, "top secret")
+	fmt.Printf("\np2c max iteration err= %v\n", err)
+
+	//then
+	RegisterJwa(pbes2Hs512)
+	c.Assert(err, NotNil)
+	c.Assert(test, Equals, "")
+	c.Assert(headers, IsNil)
+}
+
 func (s *TestSuite) TestEncrypt_PBSE2_HS256_A128KW_A128GCM(c *C) {
 	//given
 	payload := `{"hello": "world"}`

programming_language: Go
filename: pbse2_hmac_aeskw.go
change_type: ModificationType.MODIFY
diff: @@ -4,6 +4,7 @@ import (
 	"crypto/sha256"
 	"crypto/sha512"
 	"errors"
+	"fmt"
 	"hash"
 
 	"github.com/dvsekhvalnov/jose2go/arrays"
@@ -12,15 +13,28 @@ import (
 )
 
 func init() {
-	RegisterJwa(&Pbse2HmacAesKW{keySizeBits: 128, aesKW: &AesKW{keySizeBits: 128}})
-	RegisterJwa(&Pbse2HmacAesKW{keySizeBits: 192, aesKW: &AesKW{keySizeBits: 192}})
-	RegisterJwa(&Pbse2HmacAesKW{keySizeBits: 256, aesKW: &AesKW{keySizeBits: 256}})
+	RegisterJwa(NewPbse2HmacAesKWAlg(128, 310000, 0))
+	RegisterJwa(NewPbse2HmacAesKWAlg(192, 250000, 0))
+	RegisterJwa(NewPbse2HmacAesKWAlg(256, 120000, 0))
 }
 
 // PBSE2 with HMAC key management algorithm implementation
 type Pbse2HmacAesKW struct {
-	keySizeBits int
-	aesKW       JwaAlgorithm
+	keySizeBits   int
+	aesKW         JwaAlgorithm
+	maxIterations int64
+	minIterations int64
+}
+
+func NewPbse2HmacAesKWAlg(keySize int, maxIters int64, minIters int64) JwaAlgorithm {
+	switch keySize {
+	case 128:
+		return &Pbse2HmacAesKW{keySizeBits: 128, maxIterations: maxIters, minIterations: minIters, aesKW: &AesKW{keySizeBits: 128}}
+	case 192:
+		return &Pbse2HmacAesKW{keySizeBits: 192, maxIterations: maxIters, minIterations: minIters, aesKW: &AesKW{keySizeBits: 192}}
+	default:
+		return &Pbse2HmacAesKW{keySizeBits: 256, maxIterations: maxIters, minIterations: minIters, aesKW: &AesKW{keySizeBits: 256}}
+	}
 }
 
 func (alg *Pbse2HmacAesKW) Name() string {
@@ -46,6 +60,21 @@ func (alg *Pbse2HmacAesKW) WrapNewKey(cekSizeBits int, key interface{}, header m
 			return nil, nil, err
 		}
 
+		// use user provided iteration counts if any
+		if p2c, ok := header["p2c"].(int); ok {
+			iterationCount = p2c
+		}
+
+		if int64(iterationCount) > alg.maxIterations {
+			return nil, nil, errors.New(
+				fmt.Sprintf("Pbse2HmacAesKW.Unwrap(): expected 'p2c' to be less than %v but got %v", alg.maxIterations, iterationCount))
+		}
+
+		if int64(iterationCount) < alg.minIterations {
+			return nil, nil, errors.New(
+				fmt.Sprintf("Pbse2HmacAesKW.Unwrap(): expected 'p2c' to be higher than %v but got %v", alg.minIterations, iterationCount))
+		}
+
 		header["p2c"] = iterationCount
 		header["p2s"] = base64url.Encode(saltInput)
 
@@ -69,8 +98,18 @@ func (alg *Pbse2HmacAesKW) Unwrap(encryptedCek []byte, key interface{}, cekSizeB
 			return nil, errors.New("Pbse2HmacAesKW.Unwrap(): expected 'p2c' param in JWT header, but was not found.")
 		}
 
+		if int64(p2c) > alg.maxIterations {
+			return nil, errors.New(
+				fmt.Sprintf("Pbse2HmacAesKW.Unwrap(): expected 'p2c' to be less than %v but got %v", alg.maxIterations, p2c))
+		}
+
+		if int64(p2c) < alg.minIterations {
+			return nil, errors.New(
+				fmt.Sprintf("Pbse2HmacAesKW.Unwrap(): expected 'p2c' to be higher than %v but got %v", alg.minIterations, p2c))
+		}
+
 		if p2s, ok = header["p2s"].(string); !ok {
-			return nil, errors.New("Pbse2HmacAesKW.Unwrap(): expected 'p2s' param in JWT header, but was not found.")
+			return nil, errors.New("Pbse2HmacAesKW.Unwrap(): expected 'p2s' param in JWT header, but was not found")
 		}
 
 		var saltInput []byte

programming_language: Go