Skip to content

Commit ae0f4f1

Browse files
committed
Rust: Add hash function sinks.
1 parent d72b978 commit ae0f4f1

File tree

5 files changed

+97
-13
lines changed

5 files changed

+97
-13
lines changed

rust/ql/lib/codeql/rust/Frameworks.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
*/
44

55
private import codeql.rust.frameworks.Reqwest
6-
private import codeql.rust.frameworks.RustCrypto
6+
private import codeql.rust.frameworks.rustcrypto.RustCrypto
77
private import codeql.rust.frameworks.stdlib.Env
88
private import codeql.rust.frameworks.Sqlx

rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll renamed to rust/ql/lib/codeql/rust/frameworks/rustcrypto/RustCrypto.qll

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
private import rust
66
private import codeql.rust.Concepts
77
private import codeql.rust.dataflow.DataFlow
8+
private import codeql.rust.dataflow.FlowSource
9+
private import codeql.rust.dataflow.FlowSink
10+
private import codeql.rust.dataflow.internal.DataFlowImpl
811

912
bindingset[algorithmName]
1013
private string simplifyAlgorithmName(string algorithmName) {
@@ -55,3 +58,28 @@ class StreamCipherInit extends Cryptography::CryptographicOperation::Range {
5558

5659
override Cryptography::BlockMode getBlockMode() { result = "" }
5760
}
61+
62+
/**
63+
* An externally modelled operation that hashes data, for example a call to `md5::Md5::digest(data)`.
64+
*/
65+
class ModelledHashOperation extends Cryptography::CryptographicOperation::Range {
66+
DataFlow::Node input;
67+
CallExpr call;
68+
string algorithmName;
69+
70+
ModelledHashOperation() {
71+
sinkNode(input, "hasher-input") and
72+
call = input.(Node::FlowSummaryNode).getSinkElement().getCall() and
73+
call = this.asExpr().getExpr() and
74+
algorithmName =
75+
call.getFunction().(PathExpr).getPath().getQualifier().getPart().getNameRef().getText()
76+
}
77+
78+
override DataFlow::Node getInitialization() { result = this }
79+
80+
override Cryptography::CryptographicAlgorithm getAlgorithm() { result.matchesName(algorithmName) }
81+
82+
override DataFlow::Node getAnInput() { result = input }
83+
84+
override Cryptography::BlockMode getBlockMode() { none() } // (does not apply for hashing)
85+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/rust-all
4+
extensible: sinkModel
5+
data:
6+
- ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::new_with_prefix", "Argument[0]", "hasher-input", "manual"]
7+
- ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::update", "Argument[0]", "hasher-input", "manual"]
8+
- ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::chain_update", "Argument[0]", "hasher-input", "manual"]
9+
- ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::digest", "Argument[0]", "hasher-input", "manual"]

rust/ql/test/query-tests/security/CWE-328/WeakSensitiveDataHashing.expected

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,51 @@
1+
#select
2+
| test.rs:14:9:14:24 | ...::digest | test.rs:14:26:14:39 | credit_card_no | test.rs:14:9:14:24 | ...::digest | $@ is used in a hashing algorithm (MD5) that is insecure. | test.rs:14:26:14:39 | credit_card_no | Sensitive data (private) |
3+
| test.rs:15:9:15:24 | ...::digest | test.rs:15:26:15:33 | password | test.rs:15:9:15:24 | ...::digest | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:15:26:15:33 | password | Sensitive data (password) |
4+
| test.rs:26:9:26:26 | ...::digest | test.rs:26:28:26:41 | credit_card_no | test.rs:26:9:26:26 | ...::digest | $@ is used in a hashing algorithm (SHA1) that is insecure. | test.rs:26:28:26:41 | credit_card_no | Sensitive data (private) |
5+
| test.rs:27:9:27:26 | ...::digest | test.rs:27:28:27:35 | password | test.rs:27:9:27:26 | ...::digest | $@ is used in a hashing algorithm (SHA1) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:27:28:27:35 | password | Sensitive data (password) |
6+
| test.rs:32:9:32:34 | ...::digest | test.rs:32:36:32:49 | credit_card_no | test.rs:32:9:32:34 | ...::digest | $@ is used in a hashing algorithm (SHA1) that is insecure. | test.rs:32:36:32:49 | credit_card_no | Sensitive data (private) |
7+
| test.rs:33:9:33:34 | ...::digest | test.rs:33:36:33:43 | password | test.rs:33:9:33:34 | ...::digest | $@ is used in a hashing algorithm (SHA1) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:33:36:33:43 | password | Sensitive data (password) |
8+
| test.rs:39:9:39:30 | ...::digest | test.rs:39:32:39:39 | password | test.rs:39:9:39:30 | ...::digest | $@ is used in a hashing algorithm (SHA3256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:39:32:39:39 | password | Sensitive data (password) |
9+
| test.rs:60:9:60:24 | ...::digest | test.rs:60:26:60:37 | password_str | test.rs:60:9:60:24 | ...::digest | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:60:26:60:37 | password_str | Sensitive data (password) |
10+
| test.rs:62:9:62:24 | ...::digest | test.rs:62:26:62:37 | password_arr | test.rs:62:9:62:24 | ...::digest | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:62:26:62:37 | password_arr | Sensitive data (password) |
11+
| test.rs:64:9:64:24 | ...::digest | test.rs:64:26:64:37 | password_vec | test.rs:64:9:64:24 | ...::digest | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:64:26:64:37 | password_vec | Sensitive data (password) |
12+
| test.rs:77:9:77:33 | ...::new_with_prefix | test.rs:77:35:77:42 | password | test.rs:77:9:77:33 | ...::new_with_prefix | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:77:35:77:42 | password | Sensitive data (password) |
113
edges
14+
| test.rs:14:26:14:39 | credit_card_no | test.rs:14:9:14:24 | ...::digest | provenance | MaD:1 |
15+
| test.rs:15:26:15:33 | password | test.rs:15:9:15:24 | ...::digest | provenance | MaD:1 |
16+
| test.rs:26:28:26:41 | credit_card_no | test.rs:26:9:26:26 | ...::digest | provenance | MaD:1 |
17+
| test.rs:27:28:27:35 | password | test.rs:27:9:27:26 | ...::digest | provenance | MaD:1 |
18+
| test.rs:32:36:32:49 | credit_card_no | test.rs:32:9:32:34 | ...::digest | provenance | MaD:1 |
19+
| test.rs:33:36:33:43 | password | test.rs:33:9:33:34 | ...::digest | provenance | MaD:1 |
20+
| test.rs:39:32:39:39 | password | test.rs:39:9:39:30 | ...::digest | provenance | MaD:1 |
21+
| test.rs:60:26:60:37 | password_str | test.rs:60:9:60:24 | ...::digest | provenance | MaD:1 |
22+
| test.rs:62:26:62:37 | password_arr | test.rs:62:9:62:24 | ...::digest | provenance | MaD:1 |
23+
| test.rs:64:26:64:37 | password_vec | test.rs:64:9:64:24 | ...::digest | provenance | MaD:1 |
24+
| test.rs:77:35:77:42 | password | test.rs:77:9:77:33 | ...::new_with_prefix | provenance | MaD:2 |
25+
models
26+
| 1 | Sink: repo:https://github.com/RustCrypto/traits:digest; <_ as crate::digest::Digest>::digest; hasher-input; Argument[0] |
27+
| 2 | Sink: repo:https://github.com/RustCrypto/traits:digest; <_ as crate::digest::Digest>::new_with_prefix; hasher-input; Argument[0] |
228
nodes
29+
| test.rs:14:9:14:24 | ...::digest | semmle.label | ...::digest |
30+
| test.rs:14:26:14:39 | credit_card_no | semmle.label | credit_card_no |
31+
| test.rs:15:9:15:24 | ...::digest | semmle.label | ...::digest |
32+
| test.rs:15:26:15:33 | password | semmle.label | password |
33+
| test.rs:26:9:26:26 | ...::digest | semmle.label | ...::digest |
34+
| test.rs:26:28:26:41 | credit_card_no | semmle.label | credit_card_no |
35+
| test.rs:27:9:27:26 | ...::digest | semmle.label | ...::digest |
36+
| test.rs:27:28:27:35 | password | semmle.label | password |
37+
| test.rs:32:9:32:34 | ...::digest | semmle.label | ...::digest |
38+
| test.rs:32:36:32:49 | credit_card_no | semmle.label | credit_card_no |
39+
| test.rs:33:9:33:34 | ...::digest | semmle.label | ...::digest |
40+
| test.rs:33:36:33:43 | password | semmle.label | password |
41+
| test.rs:39:9:39:30 | ...::digest | semmle.label | ...::digest |
42+
| test.rs:39:32:39:39 | password | semmle.label | password |
43+
| test.rs:60:9:60:24 | ...::digest | semmle.label | ...::digest |
44+
| test.rs:60:26:60:37 | password_str | semmle.label | password_str |
45+
| test.rs:62:9:62:24 | ...::digest | semmle.label | ...::digest |
46+
| test.rs:62:26:62:37 | password_arr | semmle.label | password_arr |
47+
| test.rs:64:9:64:24 | ...::digest | semmle.label | ...::digest |
48+
| test.rs:64:26:64:37 | password_vec | semmle.label | password_vec |
49+
| test.rs:77:9:77:33 | ...::new_with_prefix | semmle.label | ...::new_with_prefix |
50+
| test.rs:77:35:77:42 | password | semmle.label | password |
351
subpaths
4-
#select

rust/ql/test/query-tests/security/CWE-328/test.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ fn test_hash_algorithms(
1111

1212
// MD5
1313
_ = md5::Md5::digest(harmless);
14-
_ = md5::Md5::digest(credit_card_no); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
15-
_ = md5::Md5::digest(password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
14+
_ = md5::Md5::digest(credit_card_no); // $ Source Alert[rust/weak-sensitive-data-hashing]
15+
_ = md5::Md5::digest(password); // $ Source Alert[rust/weak-sensitive-data-hashing]
1616
_ = md5::Md5::digest(encrypted_password);
1717

1818
// MD5 (alternative / older library)
@@ -23,20 +23,20 @@ fn test_hash_algorithms(
2323

2424
// SHA-1
2525
_ = sha1::Sha1::digest(harmless);
26-
_ = sha1::Sha1::digest(credit_card_no); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
27-
_ = sha1::Sha1::digest(password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
26+
_ = sha1::Sha1::digest(credit_card_no); // $ Source Alert[rust/weak-sensitive-data-hashing]
27+
_ = sha1::Sha1::digest(password); // $ Source Alert[rust/weak-sensitive-data-hashing]
2828
_ = sha1::Sha1::digest(encrypted_password);
2929

3030
// SHA-1 checked
3131
_ = sha1_checked::Sha1::digest(harmless);
32-
_ = sha1_checked::Sha1::digest(credit_card_no); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
33-
_ = sha1_checked::Sha1::digest(password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
32+
_ = sha1_checked::Sha1::digest(credit_card_no); // $ Source Alert[rust/weak-sensitive-data-hashing]
33+
_ = sha1_checked::Sha1::digest(password); // $ Source Alert[rust/weak-sensitive-data-hashing]
3434
_ = sha1_checked::Sha1::digest(encrypted_password);
3535

3636
// SHA-256 (appropriate for sensitive data hashing)
3737
_ = sha3::Sha3_256::digest(harmless);
3838
_ = sha3::Sha3_256::digest(credit_card_no);
39-
_ = sha3::Sha3_256::digest(password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
39+
_ = sha3::Sha3_256::digest(password); // $ Source Alert[rust/weak-sensitive-data-hashing]
4040
_ = sha3::Sha3_256::digest(encrypted_password);
4141

4242
// Argon2 (appropriate for password hashing)
@@ -57,11 +57,11 @@ fn test_hash_code_patterns(
5757

5858
// hash different types of data
5959
_ = md5::Md5::digest(harmless_str);
60-
_ = md5::Md5::digest(password_str); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
60+
_ = md5::Md5::digest(password_str); // $ Source Alert[rust/weak-sensitive-data-hashing]
6161
_ = md5::Md5::digest(harmless_arr);
62-
_ = md5::Md5::digest(password_arr); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
62+
_ = md5::Md5::digest(password_arr); // $ Source Alert[rust/weak-sensitive-data-hashing]
6363
_ = md5::Md5::digest(harmless_vec);
64-
_ = md5::Md5::digest(password_vec); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
64+
_ = md5::Md5::digest(password_vec); // $ Source Alert[rust/weak-sensitive-data-hashing]
6565

6666
// hash through a hasher object
6767
let mut md5_hasher = md5::Md5::new();
@@ -74,7 +74,7 @@ fn test_hash_code_patterns(
7474
_ = md5::Md5::new().chain_update(harmless).chain_update(password).chain_update(harmless).finalize(); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
7575

7676
_ = md5::Md5::new_with_prefix(harmless).finalize();
77-
_ = md5::Md5::new_with_prefix(password).finalize(); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
77+
_ = md5::Md5::new_with_prefix(password).finalize(); // $ Source Alert[rust/weak-sensitive-data-hashing]
7878

7979
// hash transformed data
8080
_ = md5::Md5::digest(harmless.trim());

0 commit comments

Comments
 (0)