Skip to content

Commit 11e8139

Browse files
committed
Crypto: Updated default flows to use taint tracking (this is needed to fix false positives in the unknown IV/Nonce query). Add the unknown IV/Nonce query and associated test cases. Fix unknown IV/Nonce query to focus on cases where the oepration isn't known or the operation subtype is not encrypt or wrap.
1 parent 75b5a9f commit 11e8139

File tree

9 files changed

+108
-50
lines changed

9 files changed

+108
-50
lines changed

java/ql/lib/experimental/quantum/Language.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ module ArtifactFlowConfig implements DataFlow::ConfigSig {
230230

231231
module GenericDataSourceFlow = TaintTracking::Global<GenericDataSourceFlowConfig>;
232232

233-
module ArtifactFlow = DataFlow::Global<ArtifactFlowConfig>;
233+
module ArtifactFlow = TaintTracking::Global<ArtifactFlowConfig>;
234234

235235
// Import library-specific modeling
236236
import JCA

java/ql/src/experimental/quantum/Analysis/UnknownIVorNonceInitialization.ql

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* @name Unknown nonce/iv source
3+
* @id java/quantum/unknown-iv-or-nonce-source
4+
* @description A nonce/iv is generated from a source that is not secure. Failure to initialize
5+
* an IV or nonce properly can lead to vulnerabilities such as replay attacks or key recovery.
6+
* IV may be unknown at a decryption operation (IV would be provided alongside the ciphertext).
7+
* These cases are ignored.
8+
* @kind problem
9+
* @problem.severity error
10+
* @precision high
11+
* @tags quantum
12+
* experimental
13+
*/
14+
15+
import experimental.quantum.Language
16+
17+
from Crypto::NonceArtifactNode nonce, Crypto::NodeBase op, string msg
18+
where
19+
not exists(nonce.getSourceNode()) and
20+
(
21+
// Nonce not associated with any known cipher operation, assume unknown as insecure
22+
not exists(Crypto::CipherOperationNode o | o.getANonce() = nonce) and
23+
op = nonce and
24+
msg =
25+
"Unknown IV/Nonce initialization source with no observed nonce usage (assuming could be for encryption)."
26+
or
27+
// Nonce associated cipher operation where the mode is not explicitly encryption
28+
op.(Crypto::CipherOperationNode).getANonce() = nonce and
29+
(
30+
op.(Crypto::CipherOperationNode).getKeyOperationSubtype() instanceof Crypto::TEncryptMode
31+
or
32+
op.(Crypto::CipherOperationNode).getKeyOperationSubtype() instanceof Crypto::TWrapMode
33+
) and
34+
msg = "Unknown IV/Nonce initialization source at encryption operation $@"
35+
)
36+
select nonce, msg, op, op.toString()

java/ql/test/experimental/library-tests/quantum/node_edges.expected

Lines changed: 55 additions & 22 deletions
Large diffs are not rendered by default.

java/ql/test/experimental/query-tests/quantum/InsecureNonceSource/InsecureIVorNonceSource.expected renamed to java/ql/test/experimental/query-tests/quantum/InsecureOrUnknownNonceSource/InsecureIVorNonceSource.expected

File renamed without changes.

java/ql/test/experimental/query-tests/quantum/InsecureNonceSource/InsecureIVorNonceSource.java renamed to java/ql/test/experimental/query-tests/quantum/InsecureOrUnknownNonceSource/InsecureIVorNonceSource.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class InsecureIVorNonceSource {
1111

1212
// BAD: AES-GCM with static IV from a byte array
1313
public byte[] encryptWithStaticIvByteArrayWithInitializer(byte[] key, byte[] plaintext) throws Exception {
14-
byte[] iv = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 }; // $Source
14+
byte[] iv = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 };
1515

1616
GCMParameterSpec ivSpec = new GCMParameterSpec(128, iv);
1717
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
@@ -24,20 +24,20 @@ public byte[] encryptWithStaticIvByteArrayWithInitializer(byte[] key, byte[] pla
2424

2525
// BAD: AES-GCM with static IV from zero-initialized byte array
2626
public byte[] encryptWithZeroStaticIvByteArray(byte[] key, byte[] plaintext) throws Exception {
27-
byte[] iv = new byte[16]; // $Source
27+
byte[] iv = new byte[16];
2828

2929
GCMParameterSpec ivSpec = new GCMParameterSpec(128, iv);
3030
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
3131

3232
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
33-
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $Alert[java/quantum/unknown-iv-or-nonce-initialization]
33+
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $Alert[java/quantum/unknown-iv-or-nonce-source]
3434
cipher.update(plaintext);
3535
return cipher.doFinal();
3636
}
3737

3838
// BAD: AES-CBC with static IV from 1-initialized byte array
3939
public byte[] encryptWithStaticIvByteArray(byte[] key, byte[] plaintext) throws Exception {
40-
byte[] iv = new byte[16]; // $Source
40+
byte[] iv = new byte[16];
4141
for (byte i = 0; i < iv.length; i++) {
4242
iv[i] = 1;
4343
}
@@ -56,7 +56,7 @@ public byte[] encryptWithOneOfStaticIvs01(byte[] key, byte[] plaintext) throws E
5656
byte[][] staticIvs = new byte[][] {
5757
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 },
5858
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 42 }
59-
}; // $Source
59+
};
6060

6161
GCMParameterSpec ivSpec = new GCMParameterSpec(128, staticIvs[1]);
6262
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
@@ -72,7 +72,7 @@ public byte[] encryptWithOneOfStaticIvs02(byte[] key, byte[] plaintext) throws E
7272
byte[][] staticIvs = new byte[][] {
7373
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 },
7474
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 42 }
75-
}; // $Source
75+
};
7676

7777
GCMParameterSpec ivSpec = new GCMParameterSpec(128, staticIvs[1]);
7878
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
@@ -86,15 +86,15 @@ public byte[] encryptWithOneOfStaticIvs02(byte[] key, byte[] plaintext) throws E
8686
// BAD: AES-GCM with static IV from a zero-initialized multidimensional byte array
8787
public byte[] encryptWithOneOfStaticZeroIvs(byte[] key, byte[] plaintext) throws Exception {
8888
byte[][] ivs = new byte[][] {
89-
new byte[8], // $Source
90-
new byte[16] // $Source
89+
new byte[8],
90+
new byte[16]
9191
};
9292

9393
GCMParameterSpec ivSpec = new GCMParameterSpec(128, ivs[1]);
9494
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
9595

9696
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
97-
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $Alert[java/quantum/unknown-iv-or-nonce-initialization]
97+
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $Alert[java/quantum/unknown-iv-or-nonce-source]
9898
cipher.update(plaintext);
9999
return cipher.doFinal();
100100
}
@@ -191,7 +191,7 @@ public byte[] encryptWithGeneratedIvByteArray(byte[] key, byte[] plaintext) thro
191191
public byte[] generateInsecureRandomBytes(int numBytes) {
192192
Random random = new Random();
193193
byte[] bytes = new byte[numBytes];
194-
random.nextBytes(bytes); // $Source
194+
random.nextBytes(bytes);
195195
return bytes;
196196
}
197197

java/ql/test/experimental/query-tests/quantum/InsecureNonceSource/InsecureIVorNonceSource.qlref renamed to java/ql/test/experimental/query-tests/quantum/InsecureOrUnknownNonceSource/InsecureIVorNonceSource.qlref

File renamed without changes.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| InsecureIVorNonceSource.java:33:51:33:56 | Nonce | Unknown IV/Nonce initialization source. |
2+
| InsecureIVorNonceSource.java:97:51:97:56 | Nonce | Unknown IV/Nonce initialization source. |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
query: experimental/quantum/Analysis/UnknownIVorNonceSource.ql
2+
postprocess:
3+
- utils/test/PrettyPrintModels.ql
4+
- utils/test/InlineExpectationsTestQuery.ql

0 commit comments

Comments
 (0)