From 16fbe8d96f9656d88754d0728e368a91f5a94a82 Mon Sep 17 00:00:00 2001 From: idrissrio Date: Tue, 2 Sep 2025 12:03:45 +0200 Subject: [PATCH 1/7] Java: add dataflow test for newly added KDF API --- .../dataflow/kdf/KDFDataflowTest.java | 70 +++++++++++++++++++ .../test/library-tests/dataflow/kdf/options | 1 + .../library-tests/dataflow/kdf/test.expected | 0 .../test/library-tests/dataflow/kdf/test.ql | 24 +++++++ 4 files changed, 95 insertions(+) create mode 100644 java/ql/test/library-tests/dataflow/kdf/KDFDataflowTest.java create mode 100644 java/ql/test/library-tests/dataflow/kdf/options create mode 100644 java/ql/test/library-tests/dataflow/kdf/test.expected create mode 100644 java/ql/test/library-tests/dataflow/kdf/test.ql diff --git a/java/ql/test/library-tests/dataflow/kdf/KDFDataflowTest.java b/java/ql/test/library-tests/dataflow/kdf/KDFDataflowTest.java new file mode 100644 index 000000000000..46885be1f4ca --- /dev/null +++ b/java/ql/test/library-tests/dataflow/kdf/KDFDataflowTest.java @@ -0,0 +1,70 @@ +import javax.crypto.KDF; +import javax.crypto.spec.HKDFParameterSpec; + +public class KDFDataflowTest { + public static void main(String[] args) throws Exception { + String userInput = args[0]; // source + byte[] taintedBytes = userInput.getBytes(); + + testBuilderPattern(taintedBytes); + testSeparateBuilder(taintedBytes); + testKDFWithSalt(taintedBytes); + testStaticParameterSpec(taintedBytes); + testCleanUsage(); + } + + public static void testBuilderPattern(byte[] taintedIKM) throws Exception { + HKDFParameterSpec.Builder builder = HKDFParameterSpec.ofExtract(); + builder.addIKM(taintedIKM); + HKDFParameterSpec spec = builder.thenExpand("info".getBytes(), 32); + + KDF kdf = KDF.getInstance("HKDF-SHA256"); + byte[] result = kdf.deriveData(spec); + sink(result); // should flag + } + + public static void testSeparateBuilder(byte[] taintedIKM) throws Exception { + HKDFParameterSpec.Builder builder1 = HKDFParameterSpec.ofExtract(); + HKDFParameterSpec.Builder builder2 = builder1.addIKM(taintedIKM); + HKDFParameterSpec spec = builder2.thenExpand("info".getBytes(), 32); + + KDF kdf = KDF.getInstance("HKDF-SHA256"); + byte[] result = kdf.deriveData(spec); + sink(result); // should flag + } + + public static void sink(Object o) {} + + public static void testKDFWithSalt(byte[] taintedIKM) throws Exception { + HKDFParameterSpec.Builder builder = HKDFParameterSpec.ofExtract(); + builder.addIKM(taintedIKM); + builder.addSalt("sensitive-salt".getBytes()); + HKDFParameterSpec spec = builder.thenExpand("info".getBytes(), 32); + + KDF kdf = KDF.getInstance("HKDF-SHA256"); + byte[] result = kdf.deriveData(spec); + sink(result); // should flag + } + + public static void testStaticParameterSpec(byte[] taintedIKM) throws Exception { + javax.crypto.spec.SecretKeySpec secretKey = new javax.crypto.spec.SecretKeySpec(taintedIKM, "AES"); + HKDFParameterSpec spec = HKDFParameterSpec.expandOnly( + secretKey, "info".getBytes(), 32); + + KDF kdf = KDF.getInstance("HKDF-SHA256"); + byte[] result = kdf.deriveData(spec); + sink(result); // should flag + } + + public static void testCleanUsage() throws Exception { + byte[] cleanKeyMaterial = "static-key-material".getBytes(); + + HKDFParameterSpec.Builder builder = HKDFParameterSpec.ofExtract(); + builder.addIKM(cleanKeyMaterial); // clean input + HKDFParameterSpec spec = builder.thenExpand("info".getBytes(), 32); + + KDF kdf = KDF.getInstance("HKDF-SHA256"); + byte[] cleanResult = kdf.deriveData(spec); + sink(cleanResult); // should NOT flag - no taint source + } +} \ No newline at end of file diff --git a/java/ql/test/library-tests/dataflow/kdf/options b/java/ql/test/library-tests/dataflow/kdf/options new file mode 100644 index 000000000000..f4edc64c0178 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/kdf/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args --enable-preview --release 25 \ No newline at end of file diff --git a/java/ql/test/library-tests/dataflow/kdf/test.expected b/java/ql/test/library-tests/dataflow/kdf/test.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/java/ql/test/library-tests/dataflow/kdf/test.ql b/java/ql/test/library-tests/dataflow/kdf/test.ql new file mode 100644 index 000000000000..43534d2d3d8a --- /dev/null +++ b/java/ql/test/library-tests/dataflow/kdf/test.ql @@ -0,0 +1,24 @@ +import java +import semmle.code.java.dataflow.TaintTracking + +module Config implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node n) { + exists(ArrayAccess aa | + aa.getArray().(VarAccess).getVariable().hasName("args") and + n.asExpr() = aa + ) + } + + predicate isSink(DataFlow::Node n) { + exists(MethodCall ma | + ma.getMethod().hasName("sink") and + n.asExpr() = ma.getAnArgument() + ) + } +} + +module Flow = TaintTracking::Global; + +from DataFlow::Node src, DataFlow::Node sink +where Flow::flow(src, sink) +select src, sink From f52a427295f613710226f391b6f155399861bf87 Mon Sep 17 00:00:00 2001 From: idrissrio Date: Tue, 2 Sep 2025 12:04:55 +0200 Subject: [PATCH 2/7] Java: Add MaDs for `java.crypto.KDF` --- java/ql/lib/ext/javax.crypto.model.yml | 15 +++++++++++++++ java/ql/lib/ext/javax.crypto.spec.model.yml | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/java/ql/lib/ext/javax.crypto.model.yml b/java/ql/lib/ext/javax.crypto.model.yml index 2b3bfc1abe85..dfdbb3cc7033 100644 --- a/java/ql/lib/ext/javax.crypto.model.yml +++ b/java/ql/lib/ext/javax.crypto.model.yml @@ -7,6 +7,21 @@ extensions: - ["javax.crypto", "Cipher", True, "init", "(int,Key,AlgorithmParameterSpec,SecureRandom)", "", "Argument[2]", "encryption-iv", "manual"] - ["javax.crypto", "Cipher", False, "unwrap", "(byte[],String,int)", "", "Argument[0]", "credentials-key", "hq-generated"] - ["javax.crypto", "CipherSpi", True, "engineUnwrap", "(byte[],String,int)", "", "Argument[0]", "credentials-key", "hq-generated"] + - addsTo: + pack: codeql/java-all + extensible: summaryModel + data: + - ["javax.crypto", "KDF", False, "getInstance", "(String)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"] + - ["javax.crypto", "KDF", False, "getInstance", "(String,Provider)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"] + - ["javax.crypto", "KDF", False, "getInstance", "(String,String)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"] + - ["javax.crypto", "KDF", False, "getInstance", "(String,KDFParameters)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"] + - ["javax.crypto", "KDF", False, "getInstance", "(String,KDFParameters,Provider)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"] + - ["javax.crypto", "KDF", False, "getInstance", "(String,KDFParameters,String)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"] + - ["javax.crypto", "KDF", True, "getAlgorithm", "()", "", "Argument[this].SyntheticField[javax.crypto.KDF.algorithm]", "ReturnValue", "value", "manual"] + - ["javax.crypto", "KDF", True, "getProvider", "()", "", "Argument[this]", "ReturnValue", "value", "manual"] + - ["javax.crypto", "KDF", True, "deriveKey", "(String,AlgorithmParameterSpec)", "", "Argument[1]", "ReturnValue", "taint", "manual"] + - ["javax.crypto", "KDF", True, "deriveData", "(AlgorithmParameterSpec)", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["javax.crypto", "SecretKey", True, "getEncoded", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] - addsTo: pack: codeql/java-all extensible: neutralModel diff --git a/java/ql/lib/ext/javax.crypto.spec.model.yml b/java/ql/lib/ext/javax.crypto.spec.model.yml index d2b7dbc99b8d..02cb3494fbac 100644 --- a/java/ql/lib/ext/javax.crypto.spec.model.yml +++ b/java/ql/lib/ext/javax.crypto.spec.model.yml @@ -7,6 +7,24 @@ extensions: - ["javax.crypto.spec", "GCMParameterSpec", True, "GCMParameterSpec", "", "", "Argument[1]", "Argument[this]", "taint", "manual"] - ["javax.crypto.spec", "RC2ParameterSpec", True, "RC2ParameterSpec", "", "", "Argument[1]", "Argument[this]", "taint", "manual"] - ["javax.crypto.spec", "RC5ParameterSpec", True, "RC5ParameterSpec", "", "", "Argument[3]", "Argument[this]", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(byte[])", "", "Argument[0]", "Argument[this]", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(byte[])", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(byte[])", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(SecretKey)", "", "Argument[0]", "Argument[this]", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(SecretKey)", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(SecretKey)", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(byte[])", "", "Argument[0]", "Argument[this]", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(byte[])", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(byte[])", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(SecretKey)", "", "Argument[0]", "Argument[this]", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(SecretKey)", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(SecretKey)", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "thenExpand", "(byte[],int)", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "thenExpand", "(byte[],int)", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec", False, "expandOnly", "(SecretKey,byte[],int)", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec", False, "expandOnly", "(SecretKey,byte[],int)", "", "Argument[1]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "SecretKeySpec", False, "SecretKeySpec", "(byte[],String)", "", "Argument[0]", "Argument[this]", "taint", "manual"] + - ["javax.crypto.spec", "SecretKeySpec", False, "SecretKeySpec", "(byte[],int,int,String)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - addsTo: pack: codeql/java-all extensible: sinkModel From 311690cffe0e4d10583e454ca1a839c7c38bd1b2 Mon Sep 17 00:00:00 2001 From: idrissrio Date: Tue, 2 Sep 2025 12:05:19 +0200 Subject: [PATCH 3/7] Java: accept new test results --- java/ql/test/library-tests/dataflow/kdf/test.expected | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/java/ql/test/library-tests/dataflow/kdf/test.expected b/java/ql/test/library-tests/dataflow/kdf/test.expected index e69de29bb2d1..a53c17f410e9 100644 --- a/java/ql/test/library-tests/dataflow/kdf/test.expected +++ b/java/ql/test/library-tests/dataflow/kdf/test.expected @@ -0,0 +1,4 @@ +| KDFDataflowTest.java:6:28:6:34 | ...[...] | KDFDataflowTest.java:23:14:23:19 | result | +| KDFDataflowTest.java:6:28:6:34 | ...[...] | KDFDataflowTest.java:33:14:33:19 | result | +| KDFDataflowTest.java:6:28:6:34 | ...[...] | KDFDataflowTest.java:46:14:46:19 | result | +| KDFDataflowTest.java:6:28:6:34 | ...[...] | KDFDataflowTest.java:56:14:56:19 | result | \ No newline at end of file From 89e080cd99b330cf478b8749608049b3036a9b28 Mon Sep 17 00:00:00 2001 From: idrissrio Date: Tue, 2 Sep 2025 13:30:56 +0200 Subject: [PATCH 4/7] Java: Add new change note --- java/ql/lib/change-notes/2025-09-02-kdf-api.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 java/ql/lib/change-notes/2025-09-02-kdf-api.md diff --git a/java/ql/lib/change-notes/2025-09-02-kdf-api.md b/java/ql/lib/change-notes/2025-09-02-kdf-api.md new file mode 100644 index 000000000000..db812e907780 --- /dev/null +++ b/java/ql/lib/change-notes/2025-09-02-kdf-api.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added taint flow model for `java.crypto.KDF`. \ No newline at end of file From 55ff71b7603365b7c72d0dca2a4c97dc90706dfe Mon Sep 17 00:00:00 2001 From: idrissrio Date: Fri, 5 Sep 2025 16:03:11 +0200 Subject: [PATCH 5/7] Java: Address review comment. Fix dataflow model --- java/ql/lib/ext/javax.crypto.model.yml | 2 +- java/ql/lib/ext/javax.crypto.spec.model.yml | 14 +-- .../dataflow/kdf/KDFDataflowTest.java | 22 +++-- .../library-tests/dataflow/kdf/test.expected | 93 ++++++++++++++++++- .../test/library-tests/dataflow/kdf/test.ql | 27 +----- 5 files changed, 111 insertions(+), 47 deletions(-) diff --git a/java/ql/lib/ext/javax.crypto.model.yml b/java/ql/lib/ext/javax.crypto.model.yml index dfdbb3cc7033..0a2d43fce17f 100644 --- a/java/ql/lib/ext/javax.crypto.model.yml +++ b/java/ql/lib/ext/javax.crypto.model.yml @@ -18,7 +18,7 @@ extensions: - ["javax.crypto", "KDF", False, "getInstance", "(String,KDFParameters,Provider)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"] - ["javax.crypto", "KDF", False, "getInstance", "(String,KDFParameters,String)", "", "Argument[0]", "ReturnValue.SyntheticField[javax.crypto.KDF.algorithm]", "value", "manual"] - ["javax.crypto", "KDF", True, "getAlgorithm", "()", "", "Argument[this].SyntheticField[javax.crypto.KDF.algorithm]", "ReturnValue", "value", "manual"] - - ["javax.crypto", "KDF", True, "getProvider", "()", "", "Argument[this]", "ReturnValue", "value", "manual"] + - ["javax.crypto", "KDF", True, "getProvider", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["javax.crypto", "KDF", True, "deriveKey", "(String,AlgorithmParameterSpec)", "", "Argument[1]", "ReturnValue", "taint", "manual"] - ["javax.crypto", "KDF", True, "deriveData", "(AlgorithmParameterSpec)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["javax.crypto", "SecretKey", True, "getEncoded", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] diff --git a/java/ql/lib/ext/javax.crypto.spec.model.yml b/java/ql/lib/ext/javax.crypto.spec.model.yml index 02cb3494fbac..e670af7622ad 100644 --- a/java/ql/lib/ext/javax.crypto.spec.model.yml +++ b/java/ql/lib/ext/javax.crypto.spec.model.yml @@ -8,19 +8,15 @@ extensions: - ["javax.crypto.spec", "RC2ParameterSpec", True, "RC2ParameterSpec", "", "", "Argument[1]", "Argument[this]", "taint", "manual"] - ["javax.crypto.spec", "RC5ParameterSpec", True, "RC5ParameterSpec", "", "", "Argument[3]", "Argument[this]", "taint", "manual"] - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(byte[])", "", "Argument[0]", "Argument[this]", "taint", "manual"] - - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(byte[])", "", "Argument[0]", "ReturnValue", "taint", "manual"] - - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(byte[])", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(byte[])", "", "Argument[this]", "ReturnValue", "value", "manual"] - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(SecretKey)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(SecretKey)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(SecretKey)", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addIKM", "(SecretKey)", "", "Argument[this]", "ReturnValue", "value", "manual"] - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(byte[])", "", "Argument[0]", "Argument[this]", "taint", "manual"] - - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(byte[])", "", "Argument[0]", "ReturnValue", "taint", "manual"] - - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(byte[])", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(byte[])", "", "Argument[this]", "ReturnValue", "value", "manual"] - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(SecretKey)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(SecretKey)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(SecretKey)", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(SecretKey)", "", "Argument[this]", "ReturnValue", "value", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "thenExpand", "(byte[],int)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "thenExpand", "(byte[],int)", "", "Argument[this]", "ReturnValue", "taint", "manual"] - - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "thenExpand", "(byte[],int)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["javax.crypto.spec", "HKDFParameterSpec", False, "expandOnly", "(SecretKey,byte[],int)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["javax.crypto.spec", "HKDFParameterSpec", False, "expandOnly", "(SecretKey,byte[],int)", "", "Argument[1]", "ReturnValue", "taint", "manual"] - ["javax.crypto.spec", "SecretKeySpec", False, "SecretKeySpec", "(byte[],String)", "", "Argument[0]", "Argument[this]", "taint", "manual"] diff --git a/java/ql/test/library-tests/dataflow/kdf/KDFDataflowTest.java b/java/ql/test/library-tests/dataflow/kdf/KDFDataflowTest.java index 46885be1f4ca..984cdd702a2b 100644 --- a/java/ql/test/library-tests/dataflow/kdf/KDFDataflowTest.java +++ b/java/ql/test/library-tests/dataflow/kdf/KDFDataflowTest.java @@ -2,8 +2,14 @@ import javax.crypto.spec.HKDFParameterSpec; public class KDFDataflowTest { + public static String source(String label) { + return "tainted"; + } + + public static void sink(Object o) {} + public static void main(String[] args) throws Exception { - String userInput = args[0]; // source + String userInput = source(""); byte[] taintedBytes = userInput.getBytes(); testBuilderPattern(taintedBytes); @@ -20,7 +26,7 @@ public static void testBuilderPattern(byte[] taintedIKM) throws Exception { KDF kdf = KDF.getInstance("HKDF-SHA256"); byte[] result = kdf.deriveData(spec); - sink(result); // should flag + sink(result); // $ hasTaintFlow } public static void testSeparateBuilder(byte[] taintedIKM) throws Exception { @@ -30,11 +36,9 @@ public static void testSeparateBuilder(byte[] taintedIKM) throws Exception { KDF kdf = KDF.getInstance("HKDF-SHA256"); byte[] result = kdf.deriveData(spec); - sink(result); // should flag + sink(result); // $ hasTaintFlow } - public static void sink(Object o) {} - public static void testKDFWithSalt(byte[] taintedIKM) throws Exception { HKDFParameterSpec.Builder builder = HKDFParameterSpec.ofExtract(); builder.addIKM(taintedIKM); @@ -43,7 +47,7 @@ public static void testKDFWithSalt(byte[] taintedIKM) throws Exception { KDF kdf = KDF.getInstance("HKDF-SHA256"); byte[] result = kdf.deriveData(spec); - sink(result); // should flag + sink(result); // $ hasTaintFlow } public static void testStaticParameterSpec(byte[] taintedIKM) throws Exception { @@ -53,18 +57,18 @@ public static void testStaticParameterSpec(byte[] taintedIKM) throws Exception { KDF kdf = KDF.getInstance("HKDF-SHA256"); byte[] result = kdf.deriveData(spec); - sink(result); // should flag + sink(result); // $ hasTaintFlow } public static void testCleanUsage() throws Exception { byte[] cleanKeyMaterial = "static-key-material".getBytes(); HKDFParameterSpec.Builder builder = HKDFParameterSpec.ofExtract(); - builder.addIKM(cleanKeyMaterial); // clean input + builder.addIKM(cleanKeyMaterial); HKDFParameterSpec spec = builder.thenExpand("info".getBytes(), 32); KDF kdf = KDF.getInstance("HKDF-SHA256"); byte[] cleanResult = kdf.deriveData(spec); - sink(cleanResult); // should NOT flag - no taint source + sink(cleanResult); // Safe - no taint } } \ No newline at end of file diff --git a/java/ql/test/library-tests/dataflow/kdf/test.expected b/java/ql/test/library-tests/dataflow/kdf/test.expected index a53c17f410e9..f2e5841b7f38 100644 --- a/java/ql/test/library-tests/dataflow/kdf/test.expected +++ b/java/ql/test/library-tests/dataflow/kdf/test.expected @@ -1,4 +1,89 @@ -| KDFDataflowTest.java:6:28:6:34 | ...[...] | KDFDataflowTest.java:23:14:23:19 | result | -| KDFDataflowTest.java:6:28:6:34 | ...[...] | KDFDataflowTest.java:33:14:33:19 | result | -| KDFDataflowTest.java:6:28:6:34 | ...[...] | KDFDataflowTest.java:46:14:46:19 | result | -| KDFDataflowTest.java:6:28:6:34 | ...[...] | KDFDataflowTest.java:56:14:56:19 | result | \ No newline at end of file +models +| 1 | Summary: java.lang; String; false; getBytes; ; ; Argument[this]; ReturnValue; taint; manual | +| 2 | Summary: javax.crypto.spec; HKDFParameterSpec$Builder; true; addIKM; (byte[]); ; Argument[0]; Argument[this]; taint; manual | +| 3 | Summary: javax.crypto.spec; HKDFParameterSpec$Builder; true; addIKM; (byte[]); ; Argument[this]; ReturnValue; value; manual | +| 4 | Summary: javax.crypto.spec; HKDFParameterSpec$Builder; true; thenExpand; (byte[],int); ; Argument[this]; ReturnValue; taint; manual | +| 5 | Summary: javax.crypto.spec; HKDFParameterSpec; false; expandOnly; (SecretKey,byte[],int); ; Argument[0]; ReturnValue; taint; manual | +| 6 | Summary: javax.crypto.spec; SecretKeySpec; false; SecretKeySpec; (byte[],String); ; Argument[0]; Argument[this]; taint; manual | +| 7 | Summary: javax.crypto; KDF; true; deriveData; (AlgorithmParameterSpec); ; Argument[0]; ReturnValue; taint; manual | +edges +| KDFDataflowTest.java:12:28:12:37 | source(...) : String | KDFDataflowTest.java:13:31:13:39 | userInput : String | provenance | | +| KDFDataflowTest.java:13:31:13:39 | userInput : String | KDFDataflowTest.java:13:31:13:50 | getBytes(...) : byte[] | provenance | MaD:1 | +| KDFDataflowTest.java:13:31:13:50 | getBytes(...) : byte[] | KDFDataflowTest.java:15:28:15:39 | taintedBytes : byte[] | provenance | | +| KDFDataflowTest.java:13:31:13:50 | getBytes(...) : byte[] | KDFDataflowTest.java:16:29:16:40 | taintedBytes : byte[] | provenance | | +| KDFDataflowTest.java:13:31:13:50 | getBytes(...) : byte[] | KDFDataflowTest.java:17:25:17:36 | taintedBytes : byte[] | provenance | | +| KDFDataflowTest.java:13:31:13:50 | getBytes(...) : byte[] | KDFDataflowTest.java:18:33:18:44 | taintedBytes : byte[] | provenance | | +| KDFDataflowTest.java:15:28:15:39 | taintedBytes : byte[] | KDFDataflowTest.java:22:43:22:59 | taintedIKM : byte[] | provenance | | +| KDFDataflowTest.java:16:29:16:40 | taintedBytes : byte[] | KDFDataflowTest.java:32:44:32:60 | taintedIKM : byte[] | provenance | | +| KDFDataflowTest.java:17:25:17:36 | taintedBytes : byte[] | KDFDataflowTest.java:42:40:42:56 | taintedIKM : byte[] | provenance | | +| KDFDataflowTest.java:18:33:18:44 | taintedBytes : byte[] | KDFDataflowTest.java:53:48:53:64 | taintedIKM : byte[] | provenance | | +| KDFDataflowTest.java:22:43:22:59 | taintedIKM : byte[] | KDFDataflowTest.java:24:24:24:33 | taintedIKM : byte[] | provenance | | +| KDFDataflowTest.java:24:9:24:15 | builder [post update] : Builder | KDFDataflowTest.java:25:34:25:40 | builder : Builder | provenance | | +| KDFDataflowTest.java:24:24:24:33 | taintedIKM : byte[] | KDFDataflowTest.java:24:9:24:15 | builder [post update] : Builder | provenance | MaD:2 | +| KDFDataflowTest.java:25:34:25:40 | builder : Builder | KDFDataflowTest.java:25:34:25:74 | thenExpand(...) : ExtractThenExpand | provenance | MaD:4 | +| KDFDataflowTest.java:25:34:25:74 | thenExpand(...) : ExtractThenExpand | KDFDataflowTest.java:28:40:28:43 | spec : ExtractThenExpand | provenance | | +| KDFDataflowTest.java:28:25:28:44 | deriveData(...) : byte[] | KDFDataflowTest.java:29:14:29:19 | result | provenance | | +| KDFDataflowTest.java:28:40:28:43 | spec : ExtractThenExpand | KDFDataflowTest.java:28:25:28:44 | deriveData(...) : byte[] | provenance | MaD:7 | +| KDFDataflowTest.java:32:44:32:60 | taintedIKM : byte[] | KDFDataflowTest.java:34:62:34:71 | taintedIKM : byte[] | provenance | | +| KDFDataflowTest.java:34:46:34:72 | addIKM(...) : Builder | KDFDataflowTest.java:35:34:35:41 | builder2 : Builder | provenance | | +| KDFDataflowTest.java:34:62:34:71 | taintedIKM : byte[] | KDFDataflowTest.java:34:46:34:72 | addIKM(...) : Builder | provenance | MaD:2+MaD:3 | +| KDFDataflowTest.java:35:34:35:41 | builder2 : Builder | KDFDataflowTest.java:35:34:35:75 | thenExpand(...) : ExtractThenExpand | provenance | MaD:4 | +| KDFDataflowTest.java:35:34:35:75 | thenExpand(...) : ExtractThenExpand | KDFDataflowTest.java:38:40:38:43 | spec : ExtractThenExpand | provenance | | +| KDFDataflowTest.java:38:25:38:44 | deriveData(...) : byte[] | KDFDataflowTest.java:39:14:39:19 | result | provenance | | +| KDFDataflowTest.java:38:40:38:43 | spec : ExtractThenExpand | KDFDataflowTest.java:38:25:38:44 | deriveData(...) : byte[] | provenance | MaD:7 | +| KDFDataflowTest.java:42:40:42:56 | taintedIKM : byte[] | KDFDataflowTest.java:44:24:44:33 | taintedIKM : byte[] | provenance | | +| KDFDataflowTest.java:44:9:44:15 | builder [post update] : Builder | KDFDataflowTest.java:46:34:46:40 | builder : Builder | provenance | | +| KDFDataflowTest.java:44:24:44:33 | taintedIKM : byte[] | KDFDataflowTest.java:44:9:44:15 | builder [post update] : Builder | provenance | MaD:2 | +| KDFDataflowTest.java:46:34:46:40 | builder : Builder | KDFDataflowTest.java:46:34:46:74 | thenExpand(...) : ExtractThenExpand | provenance | MaD:4 | +| KDFDataflowTest.java:46:34:46:74 | thenExpand(...) : ExtractThenExpand | KDFDataflowTest.java:49:40:49:43 | spec : ExtractThenExpand | provenance | | +| KDFDataflowTest.java:49:25:49:44 | deriveData(...) : byte[] | KDFDataflowTest.java:50:14:50:19 | result | provenance | | +| KDFDataflowTest.java:49:40:49:43 | spec : ExtractThenExpand | KDFDataflowTest.java:49:25:49:44 | deriveData(...) : byte[] | provenance | MaD:7 | +| KDFDataflowTest.java:53:48:53:64 | taintedIKM : byte[] | KDFDataflowTest.java:54:89:54:98 | taintedIKM : byte[] | provenance | | +| KDFDataflowTest.java:54:53:54:106 | new SecretKeySpec(...) : SecretKeySpec | KDFDataflowTest.java:56:13:56:21 | secretKey : SecretKeySpec | provenance | | +| KDFDataflowTest.java:54:89:54:98 | taintedIKM : byte[] | KDFDataflowTest.java:54:53:54:106 | new SecretKeySpec(...) : SecretKeySpec | provenance | MaD:6 | +| KDFDataflowTest.java:55:34:56:45 | expandOnly(...) : Expand | KDFDataflowTest.java:59:40:59:43 | spec : Expand | provenance | | +| KDFDataflowTest.java:56:13:56:21 | secretKey : SecretKeySpec | KDFDataflowTest.java:55:34:56:45 | expandOnly(...) : Expand | provenance | MaD:5 | +| KDFDataflowTest.java:59:25:59:44 | deriveData(...) : byte[] | KDFDataflowTest.java:60:14:60:19 | result | provenance | | +| KDFDataflowTest.java:59:40:59:43 | spec : Expand | KDFDataflowTest.java:59:25:59:44 | deriveData(...) : byte[] | provenance | MaD:7 | +nodes +| KDFDataflowTest.java:12:28:12:37 | source(...) : String | semmle.label | source(...) : String | +| KDFDataflowTest.java:13:31:13:39 | userInput : String | semmle.label | userInput : String | +| KDFDataflowTest.java:13:31:13:50 | getBytes(...) : byte[] | semmle.label | getBytes(...) : byte[] | +| KDFDataflowTest.java:15:28:15:39 | taintedBytes : byte[] | semmle.label | taintedBytes : byte[] | +| KDFDataflowTest.java:16:29:16:40 | taintedBytes : byte[] | semmle.label | taintedBytes : byte[] | +| KDFDataflowTest.java:17:25:17:36 | taintedBytes : byte[] | semmle.label | taintedBytes : byte[] | +| KDFDataflowTest.java:18:33:18:44 | taintedBytes : byte[] | semmle.label | taintedBytes : byte[] | +| KDFDataflowTest.java:22:43:22:59 | taintedIKM : byte[] | semmle.label | taintedIKM : byte[] | +| KDFDataflowTest.java:24:9:24:15 | builder [post update] : Builder | semmle.label | builder [post update] : Builder | +| KDFDataflowTest.java:24:24:24:33 | taintedIKM : byte[] | semmle.label | taintedIKM : byte[] | +| KDFDataflowTest.java:25:34:25:40 | builder : Builder | semmle.label | builder : Builder | +| KDFDataflowTest.java:25:34:25:74 | thenExpand(...) : ExtractThenExpand | semmle.label | thenExpand(...) : ExtractThenExpand | +| KDFDataflowTest.java:28:25:28:44 | deriveData(...) : byte[] | semmle.label | deriveData(...) : byte[] | +| KDFDataflowTest.java:28:40:28:43 | spec : ExtractThenExpand | semmle.label | spec : ExtractThenExpand | +| KDFDataflowTest.java:29:14:29:19 | result | semmle.label | result | +| KDFDataflowTest.java:32:44:32:60 | taintedIKM : byte[] | semmle.label | taintedIKM : byte[] | +| KDFDataflowTest.java:34:46:34:72 | addIKM(...) : Builder | semmle.label | addIKM(...) : Builder | +| KDFDataflowTest.java:34:62:34:71 | taintedIKM : byte[] | semmle.label | taintedIKM : byte[] | +| KDFDataflowTest.java:35:34:35:41 | builder2 : Builder | semmle.label | builder2 : Builder | +| KDFDataflowTest.java:35:34:35:75 | thenExpand(...) : ExtractThenExpand | semmle.label | thenExpand(...) : ExtractThenExpand | +| KDFDataflowTest.java:38:25:38:44 | deriveData(...) : byte[] | semmle.label | deriveData(...) : byte[] | +| KDFDataflowTest.java:38:40:38:43 | spec : ExtractThenExpand | semmle.label | spec : ExtractThenExpand | +| KDFDataflowTest.java:39:14:39:19 | result | semmle.label | result | +| KDFDataflowTest.java:42:40:42:56 | taintedIKM : byte[] | semmle.label | taintedIKM : byte[] | +| KDFDataflowTest.java:44:9:44:15 | builder [post update] : Builder | semmle.label | builder [post update] : Builder | +| KDFDataflowTest.java:44:24:44:33 | taintedIKM : byte[] | semmle.label | taintedIKM : byte[] | +| KDFDataflowTest.java:46:34:46:40 | builder : Builder | semmle.label | builder : Builder | +| KDFDataflowTest.java:46:34:46:74 | thenExpand(...) : ExtractThenExpand | semmle.label | thenExpand(...) : ExtractThenExpand | +| KDFDataflowTest.java:49:25:49:44 | deriveData(...) : byte[] | semmle.label | deriveData(...) : byte[] | +| KDFDataflowTest.java:49:40:49:43 | spec : ExtractThenExpand | semmle.label | spec : ExtractThenExpand | +| KDFDataflowTest.java:50:14:50:19 | result | semmle.label | result | +| KDFDataflowTest.java:53:48:53:64 | taintedIKM : byte[] | semmle.label | taintedIKM : byte[] | +| KDFDataflowTest.java:54:53:54:106 | new SecretKeySpec(...) : SecretKeySpec | semmle.label | new SecretKeySpec(...) : SecretKeySpec | +| KDFDataflowTest.java:54:89:54:98 | taintedIKM : byte[] | semmle.label | taintedIKM : byte[] | +| KDFDataflowTest.java:55:34:56:45 | expandOnly(...) : Expand | semmle.label | expandOnly(...) : Expand | +| KDFDataflowTest.java:56:13:56:21 | secretKey : SecretKeySpec | semmle.label | secretKey : SecretKeySpec | +| KDFDataflowTest.java:59:25:59:44 | deriveData(...) : byte[] | semmle.label | deriveData(...) : byte[] | +| KDFDataflowTest.java:59:40:59:43 | spec : Expand | semmle.label | spec : Expand | +| KDFDataflowTest.java:60:14:60:19 | result | semmle.label | result | +subpaths +testFailures diff --git a/java/ql/test/library-tests/dataflow/kdf/test.ql b/java/ql/test/library-tests/dataflow/kdf/test.ql index 43534d2d3d8a..b2ffe7d9a679 100644 --- a/java/ql/test/library-tests/dataflow/kdf/test.ql +++ b/java/ql/test/library-tests/dataflow/kdf/test.ql @@ -1,24 +1,3 @@ -import java -import semmle.code.java.dataflow.TaintTracking - -module Config implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node n) { - exists(ArrayAccess aa | - aa.getArray().(VarAccess).getVariable().hasName("args") and - n.asExpr() = aa - ) - } - - predicate isSink(DataFlow::Node n) { - exists(MethodCall ma | - ma.getMethod().hasName("sink") and - n.asExpr() = ma.getAnArgument() - ) - } -} - -module Flow = TaintTracking::Global; - -from DataFlow::Node src, DataFlow::Node sink -where Flow::flow(src, sink) -select src, sink +import utils.test.InlineFlowTest +import TaintFlowTest +import TaintFlow::PathGraph From 3aba4d3e1ebe7197fe30de925507a9e051ba26fc Mon Sep 17 00:00:00 2001 From: idrissrio Date: Mon, 8 Sep 2025 12:38:35 +0200 Subject: [PATCH 6/7] Java: Add test showing missing model for `thenExpand` --- .../library-tests/dataflow/kdf/KDFDataflowTest.java | 13 +++++++++++++ .../test/library-tests/dataflow/kdf/test.expected | 1 + 2 files changed, 14 insertions(+) diff --git a/java/ql/test/library-tests/dataflow/kdf/KDFDataflowTest.java b/java/ql/test/library-tests/dataflow/kdf/KDFDataflowTest.java index 984cdd702a2b..460cb2b309fd 100644 --- a/java/ql/test/library-tests/dataflow/kdf/KDFDataflowTest.java +++ b/java/ql/test/library-tests/dataflow/kdf/KDFDataflowTest.java @@ -71,4 +71,17 @@ public static void testCleanUsage() throws Exception { byte[] cleanResult = kdf.deriveData(spec); sink(cleanResult); // Safe - no taint } + + public static void testThenExpand(byte[] cleanIKM) throws Exception { + String userInput = source(""); + byte[] taintedInfo = userInput.getBytes(); + + HKDFParameterSpec.Builder builder = HKDFParameterSpec.ofExtract(); + builder.addIKM(cleanIKM); + HKDFParameterSpec spec = builder.thenExpand(taintedInfo, 32); + + KDF kdf = KDF.getInstance("HKDF-SHA256"); + byte[] result = kdf.deriveData(spec); + sink(result); // $ hasTaintFlow + } } \ No newline at end of file diff --git a/java/ql/test/library-tests/dataflow/kdf/test.expected b/java/ql/test/library-tests/dataflow/kdf/test.expected index f2e5841b7f38..da630b5ebb7e 100644 --- a/java/ql/test/library-tests/dataflow/kdf/test.expected +++ b/java/ql/test/library-tests/dataflow/kdf/test.expected @@ -87,3 +87,4 @@ nodes | KDFDataflowTest.java:60:14:60:19 | result | semmle.label | result | subpaths testFailures +| KDFDataflowTest.java:85:23:85:39 | // $ hasTaintFlow | Missing result: hasTaintFlow | From 728a4aff225e5af2be80f052bbec13e41c9e14e1 Mon Sep 17 00:00:00 2001 From: idrissrio Date: Mon, 8 Sep 2025 12:42:47 +0200 Subject: [PATCH 7/7] Java: Add model for `thenExpand` and accept new results --- java/ql/lib/ext/javax.crypto.spec.model.yml | 1 + .../library-tests/dataflow/kdf/test.expected | 43 +++++++++++++------ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/java/ql/lib/ext/javax.crypto.spec.model.yml b/java/ql/lib/ext/javax.crypto.spec.model.yml index e670af7622ad..e51c27c5088e 100644 --- a/java/ql/lib/ext/javax.crypto.spec.model.yml +++ b/java/ql/lib/ext/javax.crypto.spec.model.yml @@ -17,6 +17,7 @@ extensions: - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "addSalt", "(SecretKey)", "", "Argument[this]", "ReturnValue", "value", "manual"] - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "thenExpand", "(byte[],int)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "thenExpand", "(byte[],int)", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["javax.crypto.spec", "HKDFParameterSpec$Builder", True, "thenExpand", "(byte[],int)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["javax.crypto.spec", "HKDFParameterSpec", False, "expandOnly", "(SecretKey,byte[],int)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["javax.crypto.spec", "HKDFParameterSpec", False, "expandOnly", "(SecretKey,byte[],int)", "", "Argument[1]", "ReturnValue", "taint", "manual"] - ["javax.crypto.spec", "SecretKeySpec", False, "SecretKeySpec", "(byte[],String)", "", "Argument[0]", "Argument[this]", "taint", "manual"] diff --git a/java/ql/test/library-tests/dataflow/kdf/test.expected b/java/ql/test/library-tests/dataflow/kdf/test.expected index da630b5ebb7e..cab9b4bc0546 100644 --- a/java/ql/test/library-tests/dataflow/kdf/test.expected +++ b/java/ql/test/library-tests/dataflow/kdf/test.expected @@ -2,10 +2,11 @@ models | 1 | Summary: java.lang; String; false; getBytes; ; ; Argument[this]; ReturnValue; taint; manual | | 2 | Summary: javax.crypto.spec; HKDFParameterSpec$Builder; true; addIKM; (byte[]); ; Argument[0]; Argument[this]; taint; manual | | 3 | Summary: javax.crypto.spec; HKDFParameterSpec$Builder; true; addIKM; (byte[]); ; Argument[this]; ReturnValue; value; manual | -| 4 | Summary: javax.crypto.spec; HKDFParameterSpec$Builder; true; thenExpand; (byte[],int); ; Argument[this]; ReturnValue; taint; manual | -| 5 | Summary: javax.crypto.spec; HKDFParameterSpec; false; expandOnly; (SecretKey,byte[],int); ; Argument[0]; ReturnValue; taint; manual | -| 6 | Summary: javax.crypto.spec; SecretKeySpec; false; SecretKeySpec; (byte[],String); ; Argument[0]; Argument[this]; taint; manual | -| 7 | Summary: javax.crypto; KDF; true; deriveData; (AlgorithmParameterSpec); ; Argument[0]; ReturnValue; taint; manual | +| 4 | Summary: javax.crypto.spec; HKDFParameterSpec$Builder; true; thenExpand; (byte[],int); ; Argument[0]; ReturnValue; taint; manual | +| 5 | Summary: javax.crypto.spec; HKDFParameterSpec$Builder; true; thenExpand; (byte[],int); ; Argument[this]; ReturnValue; taint; manual | +| 6 | Summary: javax.crypto.spec; HKDFParameterSpec; false; expandOnly; (SecretKey,byte[],int); ; Argument[0]; ReturnValue; taint; manual | +| 7 | Summary: javax.crypto.spec; SecretKeySpec; false; SecretKeySpec; (byte[],String); ; Argument[0]; Argument[this]; taint; manual | +| 8 | Summary: javax.crypto; KDF; true; deriveData; (AlgorithmParameterSpec); ; Argument[0]; ReturnValue; taint; manual | edges | KDFDataflowTest.java:12:28:12:37 | source(...) : String | KDFDataflowTest.java:13:31:13:39 | userInput : String | provenance | | | KDFDataflowTest.java:13:31:13:39 | userInput : String | KDFDataflowTest.java:13:31:13:50 | getBytes(...) : byte[] | provenance | MaD:1 | @@ -20,31 +21,38 @@ edges | KDFDataflowTest.java:22:43:22:59 | taintedIKM : byte[] | KDFDataflowTest.java:24:24:24:33 | taintedIKM : byte[] | provenance | | | KDFDataflowTest.java:24:9:24:15 | builder [post update] : Builder | KDFDataflowTest.java:25:34:25:40 | builder : Builder | provenance | | | KDFDataflowTest.java:24:24:24:33 | taintedIKM : byte[] | KDFDataflowTest.java:24:9:24:15 | builder [post update] : Builder | provenance | MaD:2 | -| KDFDataflowTest.java:25:34:25:40 | builder : Builder | KDFDataflowTest.java:25:34:25:74 | thenExpand(...) : ExtractThenExpand | provenance | MaD:4 | +| KDFDataflowTest.java:25:34:25:40 | builder : Builder | KDFDataflowTest.java:25:34:25:74 | thenExpand(...) : ExtractThenExpand | provenance | MaD:5 | | KDFDataflowTest.java:25:34:25:74 | thenExpand(...) : ExtractThenExpand | KDFDataflowTest.java:28:40:28:43 | spec : ExtractThenExpand | provenance | | | KDFDataflowTest.java:28:25:28:44 | deriveData(...) : byte[] | KDFDataflowTest.java:29:14:29:19 | result | provenance | | -| KDFDataflowTest.java:28:40:28:43 | spec : ExtractThenExpand | KDFDataflowTest.java:28:25:28:44 | deriveData(...) : byte[] | provenance | MaD:7 | +| KDFDataflowTest.java:28:40:28:43 | spec : ExtractThenExpand | KDFDataflowTest.java:28:25:28:44 | deriveData(...) : byte[] | provenance | MaD:8 | | KDFDataflowTest.java:32:44:32:60 | taintedIKM : byte[] | KDFDataflowTest.java:34:62:34:71 | taintedIKM : byte[] | provenance | | | KDFDataflowTest.java:34:46:34:72 | addIKM(...) : Builder | KDFDataflowTest.java:35:34:35:41 | builder2 : Builder | provenance | | | KDFDataflowTest.java:34:62:34:71 | taintedIKM : byte[] | KDFDataflowTest.java:34:46:34:72 | addIKM(...) : Builder | provenance | MaD:2+MaD:3 | -| KDFDataflowTest.java:35:34:35:41 | builder2 : Builder | KDFDataflowTest.java:35:34:35:75 | thenExpand(...) : ExtractThenExpand | provenance | MaD:4 | +| KDFDataflowTest.java:35:34:35:41 | builder2 : Builder | KDFDataflowTest.java:35:34:35:75 | thenExpand(...) : ExtractThenExpand | provenance | MaD:5 | | KDFDataflowTest.java:35:34:35:75 | thenExpand(...) : ExtractThenExpand | KDFDataflowTest.java:38:40:38:43 | spec : ExtractThenExpand | provenance | | | KDFDataflowTest.java:38:25:38:44 | deriveData(...) : byte[] | KDFDataflowTest.java:39:14:39:19 | result | provenance | | -| KDFDataflowTest.java:38:40:38:43 | spec : ExtractThenExpand | KDFDataflowTest.java:38:25:38:44 | deriveData(...) : byte[] | provenance | MaD:7 | +| KDFDataflowTest.java:38:40:38:43 | spec : ExtractThenExpand | KDFDataflowTest.java:38:25:38:44 | deriveData(...) : byte[] | provenance | MaD:8 | | KDFDataflowTest.java:42:40:42:56 | taintedIKM : byte[] | KDFDataflowTest.java:44:24:44:33 | taintedIKM : byte[] | provenance | | | KDFDataflowTest.java:44:9:44:15 | builder [post update] : Builder | KDFDataflowTest.java:46:34:46:40 | builder : Builder | provenance | | | KDFDataflowTest.java:44:24:44:33 | taintedIKM : byte[] | KDFDataflowTest.java:44:9:44:15 | builder [post update] : Builder | provenance | MaD:2 | -| KDFDataflowTest.java:46:34:46:40 | builder : Builder | KDFDataflowTest.java:46:34:46:74 | thenExpand(...) : ExtractThenExpand | provenance | MaD:4 | +| KDFDataflowTest.java:46:34:46:40 | builder : Builder | KDFDataflowTest.java:46:34:46:74 | thenExpand(...) : ExtractThenExpand | provenance | MaD:5 | | KDFDataflowTest.java:46:34:46:74 | thenExpand(...) : ExtractThenExpand | KDFDataflowTest.java:49:40:49:43 | spec : ExtractThenExpand | provenance | | | KDFDataflowTest.java:49:25:49:44 | deriveData(...) : byte[] | KDFDataflowTest.java:50:14:50:19 | result | provenance | | -| KDFDataflowTest.java:49:40:49:43 | spec : ExtractThenExpand | KDFDataflowTest.java:49:25:49:44 | deriveData(...) : byte[] | provenance | MaD:7 | +| KDFDataflowTest.java:49:40:49:43 | spec : ExtractThenExpand | KDFDataflowTest.java:49:25:49:44 | deriveData(...) : byte[] | provenance | MaD:8 | | KDFDataflowTest.java:53:48:53:64 | taintedIKM : byte[] | KDFDataflowTest.java:54:89:54:98 | taintedIKM : byte[] | provenance | | | KDFDataflowTest.java:54:53:54:106 | new SecretKeySpec(...) : SecretKeySpec | KDFDataflowTest.java:56:13:56:21 | secretKey : SecretKeySpec | provenance | | -| KDFDataflowTest.java:54:89:54:98 | taintedIKM : byte[] | KDFDataflowTest.java:54:53:54:106 | new SecretKeySpec(...) : SecretKeySpec | provenance | MaD:6 | +| KDFDataflowTest.java:54:89:54:98 | taintedIKM : byte[] | KDFDataflowTest.java:54:53:54:106 | new SecretKeySpec(...) : SecretKeySpec | provenance | MaD:7 | | KDFDataflowTest.java:55:34:56:45 | expandOnly(...) : Expand | KDFDataflowTest.java:59:40:59:43 | spec : Expand | provenance | | -| KDFDataflowTest.java:56:13:56:21 | secretKey : SecretKeySpec | KDFDataflowTest.java:55:34:56:45 | expandOnly(...) : Expand | provenance | MaD:5 | +| KDFDataflowTest.java:56:13:56:21 | secretKey : SecretKeySpec | KDFDataflowTest.java:55:34:56:45 | expandOnly(...) : Expand | provenance | MaD:6 | | KDFDataflowTest.java:59:25:59:44 | deriveData(...) : byte[] | KDFDataflowTest.java:60:14:60:19 | result | provenance | | -| KDFDataflowTest.java:59:40:59:43 | spec : Expand | KDFDataflowTest.java:59:25:59:44 | deriveData(...) : byte[] | provenance | MaD:7 | +| KDFDataflowTest.java:59:40:59:43 | spec : Expand | KDFDataflowTest.java:59:25:59:44 | deriveData(...) : byte[] | provenance | MaD:8 | +| KDFDataflowTest.java:76:28:76:37 | source(...) : String | KDFDataflowTest.java:77:30:77:38 | userInput : String | provenance | | +| KDFDataflowTest.java:77:30:77:38 | userInput : String | KDFDataflowTest.java:77:30:77:49 | getBytes(...) : byte[] | provenance | MaD:1 | +| KDFDataflowTest.java:77:30:77:49 | getBytes(...) : byte[] | KDFDataflowTest.java:81:53:81:63 | taintedInfo : byte[] | provenance | | +| KDFDataflowTest.java:81:34:81:68 | thenExpand(...) : ExtractThenExpand | KDFDataflowTest.java:84:40:84:43 | spec : ExtractThenExpand | provenance | | +| KDFDataflowTest.java:81:53:81:63 | taintedInfo : byte[] | KDFDataflowTest.java:81:34:81:68 | thenExpand(...) : ExtractThenExpand | provenance | MaD:4 | +| KDFDataflowTest.java:84:25:84:44 | deriveData(...) : byte[] | KDFDataflowTest.java:85:14:85:19 | result | provenance | | +| KDFDataflowTest.java:84:40:84:43 | spec : ExtractThenExpand | KDFDataflowTest.java:84:25:84:44 | deriveData(...) : byte[] | provenance | MaD:8 | nodes | KDFDataflowTest.java:12:28:12:37 | source(...) : String | semmle.label | source(...) : String | | KDFDataflowTest.java:13:31:13:39 | userInput : String | semmle.label | userInput : String | @@ -85,6 +93,13 @@ nodes | KDFDataflowTest.java:59:25:59:44 | deriveData(...) : byte[] | semmle.label | deriveData(...) : byte[] | | KDFDataflowTest.java:59:40:59:43 | spec : Expand | semmle.label | spec : Expand | | KDFDataflowTest.java:60:14:60:19 | result | semmle.label | result | +| KDFDataflowTest.java:76:28:76:37 | source(...) : String | semmle.label | source(...) : String | +| KDFDataflowTest.java:77:30:77:38 | userInput : String | semmle.label | userInput : String | +| KDFDataflowTest.java:77:30:77:49 | getBytes(...) : byte[] | semmle.label | getBytes(...) : byte[] | +| KDFDataflowTest.java:81:34:81:68 | thenExpand(...) : ExtractThenExpand | semmle.label | thenExpand(...) : ExtractThenExpand | +| KDFDataflowTest.java:81:53:81:63 | taintedInfo : byte[] | semmle.label | taintedInfo : byte[] | +| KDFDataflowTest.java:84:25:84:44 | deriveData(...) : byte[] | semmle.label | deriveData(...) : byte[] | +| KDFDataflowTest.java:84:40:84:43 | spec : ExtractThenExpand | semmle.label | spec : ExtractThenExpand | +| KDFDataflowTest.java:85:14:85:19 | result | semmle.label | result | subpaths testFailures -| KDFDataflowTest.java:85:23:85:39 | // $ hasTaintFlow | Missing result: hasTaintFlow |