Skip to content

Commit bb50e9f

Browse files
committed
Rust: Add heuristic sinks for rust/hard-coded-cryptographic-value.
1 parent 8e09948 commit bb50e9f

File tree

3 files changed

+67
-9
lines changed

3 files changed

+67
-9
lines changed

rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ private import codeql.rust.dataflow.FlowSource
99
private import codeql.rust.dataflow.FlowSink
1010
private import codeql.rust.Concepts
1111
private import codeql.rust.security.SensitiveData
12+
private import codeql.rust.dataflow.internal.Node as Node
1213

1314
/**
1415
* A kind of cryptographic value.
@@ -98,6 +99,37 @@ module HardcodedCryptographicValue {
9899
override CryptographicValueKind getKind() { result = kind }
99100
}
100101

102+
/**
103+
* A heuristic sink for hard-coded cryptographic value vulnerabilities.
104+
*/
105+
private class HeuristicSinks extends Sink {
106+
CryptographicValueKind kind;
107+
108+
HeuristicSinks() {
109+
// any argument going to a parameter whose name matches a credential name
110+
exists(CallExprBase fc, Function f, int argIndex, string argName |
111+
fc.getArg(argIndex) = this.asExpr() and
112+
fc.getStaticTarget() = f and
113+
f.getParam(argIndex).getPat().(IdentPat).getName().getText() = argName and
114+
(
115+
argName = "password" and kind = "password"
116+
or
117+
argName = "key" and kind = "key"
118+
or
119+
argName = "iv" and kind = "iv"
120+
or
121+
argName = "nonce" and kind = "nonce"
122+
or
123+
argName = "salt" and kind = "salt"
124+
) and
125+
// don't duplicate modeled sinks
126+
not exists(ModelsAsDataSinks s | s.(Node::FlowSummaryNode).getSinkElement().getCall() = fc)
127+
)
128+
}
129+
130+
override CryptographicValueKind getKind() { result = kind }
131+
}
132+
101133
/**
102134
* A call to `getrandom` that is a barrier.
103135
*/

rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
| test_cookie.rs:21:28:21:34 | [0; 64] | test_cookie.rs:21:28:21:34 | [0; 64] | test_cookie.rs:22:16:22:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:22:16:22:24 | ...::from | a key |
1111
| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:42:14:42:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:42:14:42:32 | ...::from | a key |
1212
| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:53:14:53:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:53:14:53:32 | ...::from | a key |
13+
| test_heuristic.rs:37:32:37:39 | [0u8; 16] | test_heuristic.rs:37:32:37:39 | [0u8; 16] | test_heuristic.rs:38:31:38:39 | const_key | This hard-coded value is used as $@. | test_heuristic.rs:38:31:38:39 | const_key | a key |
14+
| test_heuristic.rs:40:31:40:38 | [0u8; 16] | test_heuristic.rs:40:31:40:38 | [0u8; 16] | test_heuristic.rs:41:41:41:48 | const_iv | This hard-coded value is used as $@. | test_heuristic.rs:41:41:41:48 | const_iv | an initialization vector |
15+
| test_heuristic.rs:59:30:59:37 | "secret" | test_heuristic.rs:59:30:59:37 | "secret" | test_heuristic.rs:59:30:59:37 | "secret" | This hard-coded value is used as $@. | test_heuristic.rs:59:30:59:37 | "secret" | a password |
16+
| test_heuristic.rs:60:20:60:27 | [0u8; 16] | test_heuristic.rs:60:20:60:27 | [0u8; 16] | test_heuristic.rs:60:19:60:27 | &... | This hard-coded value is used as $@. | test_heuristic.rs:60:19:60:27 | &... | a nonce |
17+
| test_heuristic.rs:61:31:61:38 | [0u8; 16] | test_heuristic.rs:61:31:61:38 | [0u8; 16] | test_heuristic.rs:61:30:61:38 | &... | This hard-coded value is used as $@. | test_heuristic.rs:61:30:61:38 | &... | a salt |
1318
edges
1419
| test_cipher.rs:18:9:18:14 | const1 [&ref] | test_cipher.rs:19:73:19:78 | const1 [&ref] | provenance | |
1520
| test_cipher.rs:18:28:18:36 | &... [&ref] | test_cipher.rs:18:9:18:14 | const1 [&ref] | provenance | |
@@ -62,6 +67,14 @@ edges
6267
| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:10 |
6368
| test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | test_cookie.rs:49:9:49:14 | array3 [element] | provenance | |
6469
| test_cookie.rs:53:34:53:39 | array3 [element] | test_cookie.rs:53:14:53:32 | ...::from | provenance | MaD:2 Sink:MaD:2 |
70+
| test_heuristic.rs:37:9:37:17 | const_key [&ref] | test_heuristic.rs:38:31:38:39 | const_key | provenance | |
71+
| test_heuristic.rs:37:31:37:39 | &... [&ref] | test_heuristic.rs:37:9:37:17 | const_key [&ref] | provenance | |
72+
| test_heuristic.rs:37:32:37:39 | [0u8; 16] | test_heuristic.rs:37:31:37:39 | &... [&ref] | provenance | |
73+
| test_heuristic.rs:40:9:40:16 | const_iv [&ref] | test_heuristic.rs:41:41:41:48 | const_iv | provenance | |
74+
| test_heuristic.rs:40:30:40:38 | &... [&ref] | test_heuristic.rs:40:9:40:16 | const_iv [&ref] | provenance | |
75+
| test_heuristic.rs:40:31:40:38 | [0u8; 16] | test_heuristic.rs:40:30:40:38 | &... [&ref] | provenance | |
76+
| test_heuristic.rs:60:20:60:27 | [0u8; 16] | test_heuristic.rs:60:19:60:27 | &... | provenance | |
77+
| test_heuristic.rs:61:31:61:38 | [0u8; 16] | test_heuristic.rs:61:30:61:38 | &... | provenance | |
6578
models
6679
| 1 | Sink: <_ as crypto_common::KeyInit>::new_from_slice; Argument[0]; credentials-key |
6780
| 2 | Sink: <biscotti::crypto::master::Key>::from; Argument[0]; credentials-key |
@@ -136,4 +149,17 @@ nodes
136149
| test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | semmle.label | ...::from_elem(...) [element] |
137150
| test_cookie.rs:53:14:53:32 | ...::from | semmle.label | ...::from |
138151
| test_cookie.rs:53:34:53:39 | array3 [element] | semmle.label | array3 [element] |
152+
| test_heuristic.rs:37:9:37:17 | const_key [&ref] | semmle.label | const_key [&ref] |
153+
| test_heuristic.rs:37:31:37:39 | &... [&ref] | semmle.label | &... [&ref] |
154+
| test_heuristic.rs:37:32:37:39 | [0u8; 16] | semmle.label | [0u8; 16] |
155+
| test_heuristic.rs:38:31:38:39 | const_key | semmle.label | const_key |
156+
| test_heuristic.rs:40:9:40:16 | const_iv [&ref] | semmle.label | const_iv [&ref] |
157+
| test_heuristic.rs:40:30:40:38 | &... [&ref] | semmle.label | &... [&ref] |
158+
| test_heuristic.rs:40:31:40:38 | [0u8; 16] | semmle.label | [0u8; 16] |
159+
| test_heuristic.rs:41:41:41:48 | const_iv | semmle.label | const_iv |
160+
| test_heuristic.rs:59:30:59:37 | "secret" | semmle.label | "secret" |
161+
| test_heuristic.rs:60:19:60:27 | &... | semmle.label | &... |
162+
| test_heuristic.rs:60:20:60:27 | [0u8; 16] | semmle.label | [0u8; 16] |
163+
| test_heuristic.rs:61:30:61:38 | &... | semmle.label | &... |
164+
| test_heuristic.rs:61:31:61:38 | [0u8; 16] | semmle.label | [0u8; 16] |
139165
subpaths

rust/ql/test/query-tests/security/CWE-798/test_heuristic.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ impl MyCryptor {
3232
}
3333

3434
fn test(var_string: &str, var_data: &[u8;16]) {
35-
encrypt_with("plaintext", var_data, var_data); // $ MISSING: Sink
35+
encrypt_with("plaintext", var_data, var_data);
3636

37-
let const_key: &[u8;16] = &[0u8;16]; // $ MISSING: Alert[rust/hard-coded-cryptographic-value]
38-
encrypt_with("plaintext", const_key, var_data); // $ MISSING: Sink
37+
let const_key: &[u8;16] = &[0u8;16]; // $ Alert[rust/hard-coded-cryptographic-value]
38+
encrypt_with("plaintext", const_key, var_data); // $ Sink
3939

40-
let const_iv: &[u8;16] = &[0u8;16]; // $ MISSING: Alert[rust/hard-coded-cryptographic-value]
41-
encrypt_with("plaintext", var_data, const_iv); // $ MISSING: Sink
40+
let const_iv: &[u8;16] = &[0u8;16]; // $ Alert[rust/hard-coded-cryptographic-value]
41+
encrypt_with("plaintext", var_data, const_iv); // $ Sink
4242

43-
encrypt2("plaintext", var_data, var_data); // $ MISSING: Sink
43+
encrypt2("plaintext", var_data, var_data);
4444

4545
let const_key2: &[u8;16] = &[1u8;16]; // $ MISSING: Alert[rust/hard-coded-cryptographic-value]
4646
encrypt2("plaintext", const_key2, var_data); // $ MISSING: Sink
@@ -56,7 +56,7 @@ fn test(var_string: &str, var_data: &[u8;16]) {
5656
mc1.set_nonce(var_data);
5757
mc1.encrypt("plaintext", var_data);
5858

59-
let mc2 = MyCryptor::new("secret"); // $ MISSING: Alert[rust/hard-coded-cryptographic-value]
60-
mc2.set_nonce(&[0u8;16]); // $ MISSING: Alert[rust/hard-coded-cryptographic-value]
61-
mc2.encrypt("plaintext", &[0u8;16]); // $ MISSING: Alert[rust/hard-coded-cryptographic-value]
59+
let mc2 = MyCryptor::new("secret"); // $ Alert[rust/hard-coded-cryptographic-value]
60+
mc2.set_nonce(&[0u8;16]); // $ Alert[rust/hard-coded-cryptographic-value]
61+
mc2.encrypt("plaintext", &[0u8;16]); // $ Alert[rust/hard-coded-cryptographic-value]
6262
}

0 commit comments

Comments
 (0)