aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbleichen <bleichen@google.com>2023-02-13 05:20:11 -0800
committerCharles Lee <ckl@google.com>2023-02-27 16:44:39 -0800
commit41d9ff3e5098e352c876204880145b0a703373ab (patch)
tree732e51eeb3615ac2b41d2339aa7e300227a27443
parentf3beafbe9279ececb82af86ac20890eda4ea0cb8 (diff)
downloadwycheproof-41d9ff3e5098e352c876204880145b0a703373ab.tar.gz
Test vectors for PKCS #5 paddings
NOKEYCHECK=True PiperOrigin-RevId: 509198084
-rw-r--r--java/com/google/security/wycheproof/jose4j/JsonWebEncryptionTest.java166
-rw-r--r--testvectors/json_web_encryption_test.json50
2 files changed, 139 insertions, 77 deletions
diff --git a/java/com/google/security/wycheproof/jose4j/JsonWebEncryptionTest.java b/java/com/google/security/wycheproof/jose4j/JsonWebEncryptionTest.java
index ca25b4d..aacf3bb 100644
--- a/java/com/google/security/wycheproof/jose4j/JsonWebEncryptionTest.java
+++ b/java/com/google/security/wycheproof/jose4j/JsonWebEncryptionTest.java
@@ -98,6 +98,90 @@ public class JsonWebEncryptionTest {
return testParams;
}
+
+ private boolean checkKnownException(Exception ex, String[] expected) {
+ String actual = ex.toString();
+ for (String exception : expected) {
+ if (exception.equals(actual)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks exceptions agains padding attacks.
+ *
+ * Checks if an exception deviates from the expected result. Test vectors with
+ * certain flags have been constructed to check for padding oracles. For these test
+ * vectors we expect that the library returns the same exceptions so that distinct
+ * padding errors are not distinguishable. The current test runs each test vector
+ * individually. Hence it is not possible to collect all test vectors thrown and
+ * compare them with each other. Eventually the test should be rewritten to deal
+ * with this situation. Currently the exceptions thrown by jose4j are hard-coded
+ * into this function. Hard coding the exceptions has the disadvantage that
+ * tests will fail with new versions.
+ *
+ * @param ex the exceptions thrown for this test vector
+ * @return false if an unexpected exception was thrown
+ */
+ private boolean checkException(Exception ex) {
+ // Tests for PKCS #1 oracles.
+ if (containsFlag(testCase, "ModifiedPkcs15Padding")) {
+ // If the padding has been modified then jose4j typically throws one of the following
+ // exceptions. If trying to decrypt a modified ciphertext throws another exception then
+ // this may allow a PKCS #1 oracle.
+ String[] expectedExceptionsPkcs15 =
+ new String[] {
+ // Exception thrown when using jdk11
+ "org.jose4j.lang.JoseException: javax.crypto.AEADBadTagException: Tag mismatch!",
+ // Exception thrown when unsing jdk20
+ "org.jose4j.lang.JoseException: javax.crypto.AEADBadTagException: Tag mismatch"
+ };
+ return checkKnownException(ex, expectedExceptionsPkcs15);
+ }
+ // Tests for PKCS #5 padding oracles.
+ // Ciphertexts with modified PKCS #5 paddings should not be distinguishable from
+ // ciphertexts with valid PKCS #5 padding. The typical way to detect such modifications
+ // is to check the HMAC before decrypting the ciphertext. Some libraries do decryption
+ // and HMAC verification in the wrong order (see e.g., CVE-2021-29443)
+ if (containsFlag(testCase, "Pkcs5Padding")) {
+ // jose4j includes the tag into the error message.
+ if (ex.toString().startsWith(
+ "org.jose4j.lang.IntegrityException: Authentication tag check failed.")) {
+ return true;
+ }
+ }
+ if (containsFlag(testCase, "Pkcs15WithOaepKey")) {
+ // Test vectors with the flag "Pkcs15WithOaepKey" contain an OAEP key, but the header
+ // of the ciphertext has been modified to contain "alg":"RSA1_5".
+ // Decryption should notice the mismatch an throw an exception indicating the error.
+ // The current implementation tries to decrypt using PKCS #1.5 padding.
+ // Since the PKCS #1.5 decryption is broken, it is therefore also possible to break
+ // ciphertexts when the receiver uses RSA-OAEP keys.
+ //
+ // TODO(bleichen): expectedExceptionsOaep needs to be adjusted once the underlying bug has
+ // been fixed. Currently the following exceptions are being thrown:
+ // * org.jose4j.lang.JoseException: javax.crypto.AEADBadTagException: Tag mismatch!
+ // thrown when the ciphertext contains an invalid PKCS #1 padding
+ // or thrown when the ciphertext contains valid PKCS #1 padding and valid key size.
+ // * org.jose4j.lang.JoseException: Invalid key for AES/GCM/NoPadding
+ // thrown wehn the ciphertext contains a valid PKCS #1 v1.5 padding but an invalid key.
+ // The test currently expects that a random key is being generated when the padding is
+ // incorrect. Better would be to compare the algorithms in the key with the algorithm in
+ // the header and throw an exception before trying to decrypt.
+ String[] expectedExceptionsOaep =
+ new String[] {
+ // Exception thrown when using jdk11
+ "org.jose4j.lang.JoseException: javax.crypto.AEADBadTagException: Tag mismatch!",
+ // Exception thrown when unsing jdk20
+ "org.jose4j.lang.JoseException: javax.crypto.AEADBadTagException: Tag mismatch"
+ };
+ return checkKnownException(ex, expectedExceptionsOaep);
+ }
+ return true;
+ }
+
@Test
public void jsonWebEncryptionTestVector() {
// Housekeeping to make sure the implementation class wires things correctly.
@@ -176,6 +260,12 @@ public class JsonWebEncryptionTest {
testName, compactJwe, decryptionJwk, expectedPlaintext, ptHex);
return false;
} catch (JoseException e) {
+ if (!checkException(e)) {
+ logger.atInfo().withCause(e).log(
+ "Decryption contains a padding oracle.\ntestName:%s\njwe: %s\njwk: %s",
+ testName, compactJwe, decryptionJwk);
+ return false;
+ }
// Prints stack trace if decryption is expected to succeed, doesn't print the stack trace if
// decryption is expected to fail.
if (expectedResult) {
@@ -184,82 +274,6 @@ public class JsonWebEncryptionTest {
testName, compactJwe, decryptionJwk);
return false;
}
- // Tests for PKCS #1 oracles.
- if (containsFlag(testCase, "ModifiedPkcs15Padding")) {
- // If the padding has been modified then jose4j typically throws one of the following
- // exceptions. If trying to decrypt a modified ciphertext throws another exception then
- // this may allow a PKCS #1 oracle.
- String[] expectedExceptionsPkcs15 =
- new String[] {
- // Exception thrown when using jdk11
- "org.jose4j.lang.JoseException: javax.crypto.AEADBadTagException: Tag mismatch!",
- // Exception thrown when unsing jdk20
- "org.jose4j.lang.JoseException: javax.crypto.AEADBadTagException: Tag mismatch"
- };
- boolean expected = false;
- String actual = e.toString();
- for (String exception : expectedExceptionsPkcs15) {
- if (exception.equals(actual)) {
- expected = true;
- break;
- }
- }
- // The test above is in some sense too strict because it checks for actual error messages.
- // If the underlying provider changes the text in the exception then the test starts
- // failing.
- //
- // The reason for adding a strict test is that some versions of jose4j contain padding
- // oracles. An attacker, who can send modified ciphertexts to a receiver and observe the
- // resulting error message can distinguish between ciphertexts with a valid PKCS #1 padding
- // and ciphertexts with an invalid PKCS #1 padding. Being able to distinguish between
- // valid and invalid PKCS #1 paddings allows the attacker to decrypt and/or sign messages.
- if (!expected) {
- logger.atInfo().withCause(e).log(
- "Decryption may contain a padding oracle.\ntestName:%s\njwe: %s\njwk: %s",
- testName, compactJwe, decryptionJwk);
- return false;
- }
- }
- if (containsFlag(testCase, "Pkcs15WithOaepKey")) {
- // Test vectors with the flag "Pkcs15WithOaepKey" contain an OAEP key, but the header
- // of the ciphertext has been modified to contain "alg":"RSA1_5".
- // Decryption should notice the mismatch an throw an exception indicating the error.
- // The current implementation tries to decrypt using PKCS #1.5 padding.
- // Since the PKCS #1.5 decryption is broken, it is therefore also possible to break
- // ciphertexts when the receiver uses RSA-OAEP keys.
- //
- // TODO(bleichen): expectedExceptionsOaep needs to be adjusted once the underlying bug has
- // been fixed. Currently the following exceptions are being thrown:
- // * org.jose4j.lang.JoseException: javax.crypto.AEADBadTagException: Tag mismatch!
- // thrown when the ciphertext contains an invalid PKCS #1 padding
- // or thrown when the ciphertext contains valid PKCS #1 padding and valid key size.
- // * org.jose4j.lang.JoseException: Invalid key for AES/GCM/NoPadding
- // thrown wehn the ciphertext contains a valid PKCS #1 v1.5 padding but an invalid key.
- // The test currently expects that a random key is being generated when the padding is
- // incorrect. Better would be to compare the algorithms in the key with the algorithm in
- // the header and throw an exception before trying to decrypt.
- String[] expectedExceptionsOaep =
- new String[] {
- // Exception thrown when using jdk11
- "org.jose4j.lang.JoseException: javax.crypto.AEADBadTagException: Tag mismatch!",
- // Exception thrown when unsing jdk20
- "org.jose4j.lang.JoseException: javax.crypto.AEADBadTagException: Tag mismatch"
- };
- boolean expected = false;
- String actual = e.toString();
- for (String exception : expectedExceptionsOaep) {
- if (exception.equals(actual)) {
- expected = true;
- break;
- }
- }
- if (!expected) {
- logger.atInfo().withCause(e).log(
- "Decryption contains a padding oracle.\ntestName:%s\njwe: %s\njwk: %s",
- testName, compactJwe, decryptionJwk);
- return false;
- }
- }
// NOTE(bleichen): Even though an exception is expected here it may still be interesting
// to compare the actual exception with the expected exception to find more subtle
// problems. Logging the full stack trace would add too much clutter to the logs.
diff --git a/testvectors/json_web_encryption_test.json b/testvectors/json_web_encryption_test.json
index 20c6afc..5a3b294 100644
--- a/testvectors/json_web_encryption_test.json
+++ b/testvectors/json_web_encryption_test.json
@@ -1744,7 +1744,6 @@
}
]
},
-
{
"type": "JsonWebEncryption",
"comment": "rfc_7520",
@@ -1810,6 +1809,55 @@
"flags": ["CompressedPlaintext"]
}
]
+ },
+ {
+ "type": "JsonWebEncryption",
+ "comment": "Pkcs5Paddings",
+ "private": {
+ "kty": "oct",
+ "kid": "18ec08e1-bfa9-4d95-b205-2b4dd1d4321d",
+ "use": "enc",
+ "alg": "A256GCMKW",
+ "k": "qC57l_uxcm7Nm3K-ct4GFjx8tM1U8CZ0NLBvdQstiS8"
+ },
+ "tests": [
+ {
+ "tcId": 136,
+ "comment": "WrongPKCS5Padding",
+ "pt": "",
+ "enc": "A128CBC-HS256",
+ "jwe": "eyJhbGciOiJBMjU2R0NNS1ciLCJraWQiOiIxOGVjMDhlMS1iZmE5LTRkOTUtYjIwNS0yYjRkZDFkNDMyMWQiLCJ0YWciOiJrZlBkdVZRM1QzSDZ2bmV3dC0ta3N3IiwiaXYiOiJLa1lUMEdYXzJqSGxmcU5fIiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.lJf3HbOApxMEBkCMOoTnnABxs_CvTWUmZQ2ElLvYNok.gz6NjyEFNm_vm8Gj6FwoFQ.Jf5p9-ZhJlJy_IQ_byKFmI0Ro7w7G1QiaZpI8OaiVgD8EqoDZHyFKFBupS8iaEeVIgMqWmsuJKuoVgzR3YfzoMd3GxEm3VxNhzWyWtZKX0gxKdy6HgLvqoGNbZCzLjqcpDiF8q2_62EVAbr2uSc2oaxFmFuIQHLcqAHxy51449xkjZ7ewzZaGV3eFqhpco8o4DijXaG5_7kp3h2cajRfDgymuxUbWgLqaeNQaJtvJmSMFuEOSAzw9Hdeb6yhdTynCRmu-kqtO5Dec4lT2OMZKpnxc_F1_4yDJFcqb5CiDSmA-psB2k0JtjxAj4UPI61oONK7zzFIu4gBfjJCndsZfdvG7h8wGjV98QhrKEnR7xKZ3KCr0_qR1B-gxpnK2yWU.DKW7jrb4WaRSNfbXVPlT5g",
+ "result": "invalid",
+ "flags": ["Pkcs5Padding"]
+ },
+ {
+ "tcId": 137,
+ "comment": "ModifiedIV",
+ "pt": "",
+ "enc": "A128CBC-HS256",
+ "jwe": "eyJhbGciOiJBMjU2R0NNS1ciLCJraWQiOiIxOGVjMDhlMS1iZmE5LTRkOTUtYjIwNS0yYjRkZDFkNDMyMWQiLCJ0YWciOiJrZlBkdVZRM1QzSDZ2bmV3dC0ta3N3IiwiaXYiOiJLa1lUMEdYXzJqSGxmcU5fIiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.lJf3HbOApxMEBkCMOoTnnABxs_CvTWUmZQ2ElLvYNok.GZ6NjyEFNm_vm8Gj6FwoFQ.Jf5p9-ZhJlJy_IQ_byKFmI0Ro7w7G1QiaZpI8OaiVgD8EqoDZHyFKFBupS8iaEeVIgMqWmsuJKuoVgzR3YfzoMd3GxEm3VxNhzWyWtZKX0gxKdy6HgLvqoGNbZCzLjqcpDiF8q2_62EVAbr2uSc2oaxFmFuIQHLcqAHxy51449xkjZ7ewzZaGV3eFqhpco8o4DijXaG5_7kp3h2cajRfDgymuxUbWgLqaeNQaJtvJmSMFuEOSAzw9Hdeb6yhdTynCRmu-kqtO5Dec4lT2OMZKpnxc_F1_4yDJFcqb5CiDSmA-psB2k0JtjxAj4UPI61oONK7zzFIu4gBfjJCndsZfdvG7h8wGjV98QhrKEnR7xKZ3KCr0_qR1B-gxpNk3xWU.DKW7jrb4WaRSNfbXVPlT5g",
+ "result": "invalid",
+ "flags": ["Pkcs5Padding"]
+ },
+ {
+ "tcId": 138,
+ "comment": "ModifiedCiphertext",
+ "pt": "",
+ "enc": "A128CBC-HS256",
+ "jwe": "eyJhbGciOiJBMjU2R0NNS1ciLCJraWQiOiIxOGVjMDhlMS1iZmE5LTRkOTUtYjIwNS0yYjRkZDFkNDMyMWQiLCJ0YWciOiJrZlBkdVZRM1QzSDZ2bmV3dC0ta3N3IiwiaXYiOiJLa1lUMEdYXzJqSGxmcU5fIiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.lJf3HbOApxMEBkCMOoTnnABxs_CvTWUmZQ2ElLvYNok.gz6NjyEFNm_vm8Gj6FwoFQ.jF4p9-ZhJlJy_IQ_byKFmI0Ro7w7G1QiaZpI8OaiVgD8EqoDZHyFKFBupS8iaEeVIgMqWmsuJKuoVgzR3YfzoMd3GxEm3VxNhzWyWtZKX0gxKdy6HgLvqoGNbZCzLjqcpDiF8q2_62EVAbr2uSc2oaxFmFuIQHLcqAHxy51449xkjZ7ewzZaGV3eFqhpco8o4DijXaG5_7kp3h2cajRfDgymuxUbWgLqaeNQaJtvJmSMFuEOSAzw9Hdeb6yhdTynCRmu-kqtO5Dec4lT2OMZKpnxc_F1_4yDJFcqb5CiDSmA-psB2k0JtjxAj4UPI61oONK7zzFIu4gBfjJCndsZfdvG7h8wGjV98QhrKEnR7xKZ3KCr0_qR1B-gxpNk3xWU.DKW7jrb4WaRSNfbXVPlT5g",
+ "result": "invalid",
+ "flags": ["Pkcs5Padding"]
+ },
+ {
+ "tcId": 139,
+ "comment": "ModifiedHmac",
+ "pt": "",
+ "enc": "A128CBC-HS256",
+ "jwe": "eyJhbGciOiJBMjU2R0NNS1ciLCJraWQiOiIxOGVjMDhlMS1iZmE5LTRkOTUtYjIwNS0yYjRkZDFkNDMyMWQiLCJ0YWciOiJrZlBkdVZRM1QzSDZ2bmV3dC0ta3N3IiwiaXYiOiJLa1lUMEdYXzJqSGxmcU5fIiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.lJf3HbOApxMEBkCMOoTnnABxs_CvTWUmZQ2ElLvYNok.gz6NjyEFNm_vm8Gj6FwoFQ.Jf5p9-ZhJlJy_IQ_byKFmI0Ro7w7G1QiaZpI8OaiVgD8EqoDZHyFKFBupS8iaEeVIgMqWmsuJKuoVgzR3YfzoMd3GxEm3VxNhzWyWtZKX0gxKdy6HgLvqoGNbZCzLjqcpDiF8q2_62EVAbr2uSc2oaxFmFuIQHLcqAHxy51449xkjZ7ewzZaGV3eFqhpco8o4DijXaG5_7kp3h2cajRfDgymuxUbWgLqaeNQaJtvJmSMFuEOSAzw9Hdeb6yhdTynCRmu-kqtO5Dec4lT2OMZKpnxc_F1_4yDJFcqb5CiDSmA-psB2k0JtjxAj4UPI61oONK7zzFIu4gBfjJCndsZfdvG7h8wGjV98QhrKEnR7xKZ3KCr0_qR1B-gxpNk3xWU.xxxxjrb4WaRSNfbXVPlT5g",
+ "result": "invalid",
+ "flags": ["Pkcs5Padding"]
+ }
+ ]
}
]
}