CVE-2017-12973 (Java, published 2017-08-20T16:29Z)
Description: value: Nimbus JOSE+JWT before 4.39 proceeds improperly after detection of an invalid HMAC in authenticated AES-CBC decryption, which allows attackers to conduct a padding oracle attack.
Severity: MEDIUM (CVSS v3 base score: 3.1)
Weakness: CWE-354 \u2014 Improper Validation of Integrity Check Value
The product does not validate or incorrectly validates the integrity check values or "checksums" of a message. This may prevent it from detecting if the data has been modified or corrupted in transmission.
Repository: https://bitbucket.org/connect2id/nimbus-jose-jwt
Files changed:
src/main/java/com/nimbusds/jose/crypto/AESCBC.java
src/test/java/com/nimbusds/jose/crypto/AESCBCTest.java
Commit message: Fixes HMAC return on authenticated AESCBC decrypt (iss #223)


Vulnerable code:
 * @version 2015-05-26
		boolean macCheckPassed = true;

			// Thwart timing attacks by delaying exception until after decryption
			macCheckPassed = false;
		}

		byte[] plainText = decrypt(compositeKey.getAESKey(), iv, cipherText, ceProvider);

		if (! macCheckPassed) {

		return plainText;

		SecretKey cekAlt = LegacyConcatKDF.generateCEK(secretKey, header.getEncryptionMethod(), epu, epv);

		final byte[] plainText = AESCBC.decrypt(cekAlt, iv.decode(), cipherText.decode(), ceProvider);





			throw new JOSEException("HMAC integrity check failed");
		return plainText;
 * @version 2015-05-17

Fixed code:
 * @version 2017-05-30
		return decrypt(compositeKey.getAESKey(), iv, cipherText, ceProvider);
		
		
		
		
			throw new JOSEException("MAC check failed");
		SecretKey cekAlt = LegacyConcatKDF.generateCEK(secretKey, header.getEncryptionMethod(), epu, epv);

		return AESCBC.decrypt(cekAlt, iv.decode(), cipherText.decode(), ceProvider);
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jose.util.Base64URL;
 * @version 2017-05-30
	
	
	public void testCBCPaddingOracleAttack()
		throws Exception {
		
		SecretKey inputKey = new SecretKeySpec(INPUT_KEY_256, "AES");
		
		Assert.assertArrayEquals("Input key", INPUT_KEY_256, inputKey.getEncoded());
		
		AuthenticatedCipherText act = AESCBC.encryptAuthenticated(inputKey, IV, PLAIN_TEXT, AAD, null, null);
		
		byte[] cipherText = act.getCipherText();
		
		// Now change the cipher text to make CBC padding invalid.
		cipherText[cipherText.length - 1] ^= 0x01;
		
		try {
			AESCBC.decryptAuthenticated(inputKey, IV, cipherText, AAD, act.getAuthenticationTag(), null, null);
		} catch (JOSEException e) {
			assertEquals("MAC check failed", e.getMessage());
		}
	}
	
	
	public void testCBCPaddingOracleAttackOldConcatKDF()
		throws Exception {
		
		SecretKey inputKey = new SecretKeySpec(INPUT_KEY_256, "AES");
		
		Assert.assertArrayEquals("Input key", INPUT_KEY_256, inputKey.getEncoded());
		
		AuthenticatedCipherText act = AESCBC.encryptWithConcatKDF(
			new JWEHeader(JWEAlgorithm.RSA1_5, EncryptionMethod.A128CBC_HS256_DEPRECATED),
			new SecretKeySpec(INPUT_KEY_256, "AES"),
			Base64URL.encode(INPUT_KEY_256), // mock
			IV,
			PLAIN_TEXT,
			null,
			null
			);
		
		byte[] cipherText = act.getCipherText();
		
		// Now change the cipher text to make CBC padding invalid.
		cipherText[cipherText.length - 1] ^= 0x01;
		
		try {
			AESCBC.decryptWithConcatKDF(
				new JWEHeader(JWEAlgorithm.RSA1_5, EncryptionMethod.A128CBC_HS256_DEPRECATED),
				new SecretKeySpec(INPUT_KEY_256, "AES"),
				Base64URL.encode(INPUT_KEY_256), // mock
				Base64URL.encode(IV),
				Base64URL.encode(cipherText),
				Base64URL.encode(act.getAuthenticationTag()),
				null,
				null
			);
		} catch (JOSEException e) {
			assertEquals("MAC check failed", e.getMessage());
		}
	}