Skip to content

Potential Padding Oracle Attack Vulnerability

Moderate
lestrrat published GHSA-rm8v-mxj3-5rmq Jun 14, 2023

Package

gomod github.com/lestrrat-go/jwx/jwe (Go)

Affected versions

<= v1.2.25

Patched versions

v1.2.26
gomod github.com/lestrrat-go/jwx/v2/jwe (Go)
<= v2.0.10
v2.0.11

Description

Summary

Decrypting AES-CBC encrypted JWE has Potential Padding Oracle Attack Vulnerability.

Details

On v2.0.10, decrypting AES-CBC encrypted JWE may return an error "failed to generate plaintext from decrypted blocks: invalid padding":

plaintext, err := unpad(buf, c.blockCipher.BlockSize())
if err != nil {
return nil, fmt.Errorf(`failed to generate plaintext from decrypted blocks: %w`, err)
}

Reporting padding error causes Padding Oracle Attack Vulnerability.
RFC 7516 JSON Web Encryption (JWE) says that we MUST NOT do this.

11.5. Timing Attacks
To mitigate the attacks described in RFC 3218 [RFC3218], the
recipient MUST NOT distinguish between format, padding, and length
errors of encrypted keys. It is strongly recommended, in the event
of receiving an improperly formatted key, that the recipient
substitute a randomly generated CEK and proceed to the next step, to
mitigate timing attacks.

In addition, the time to remove padding depends on the length of the padding.
It may leak the length of the padding by Timing Attacks.

func unpad(buf []byte, n int) ([]byte, error) {
lbuf := len(buf)
rem := lbuf % n
// First, `buf` must be a multiple of `n`
if rem != 0 {
return nil, fmt.Errorf("input buffer must be multiple of block size %d", n)
}
// Find the last byte, which is the encoded padding
// i.e. 0x1 == 1 byte worth of padding
last := buf[lbuf-1]
// This is the number of padding bytes that we expect
expected := int(last)
if expected == 0 || /* we _have_ to have padding here. therefore, 0x0 is not an option */
expected > n || /* we also must make sure that we don't go over the block size (n) */
expected > lbuf /* finally, it can't be more than the buffer itself. unlikely, but could happen */ {
return nil, fmt.Errorf(`invalid padding byte at the end of buffer`)
}
// start i = 1 because we have already established that expected == int(last) where
// last = buf[lbuf-1].
//
// we also don't check against lbuf-i in range, because we have established expected <= lbuf
for i := 1; i < expected; i++ {
if buf[lbuf-i] != last {
return nil, fmt.Errorf(`invalid padding`)
}
}
return buf[:lbuf-expected], nil
}

To mitigate Timing Attacks, it MUST be done in constant time.

Impact

The authentication tag is verified, so it is not an immediate attack.

Severity

Moderate

CVE ID

No known CVE

Weaknesses

No CWEs

Credits