From bdb2f3d091d6ba4cc4305518764009bad27fe4ae Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:13:55 +0000 Subject: [PATCH 01/16] Rust: Add placeholder query and tests for 'cipher' module. --- .../security/CWE-327/BrokenCryptoAlgorithm.ql | 17 +++ .../CWE-327/BrokenCryptoAlgorithm.expected | 0 .../CWE-327/BrokenCryptoAlgorithm.qlref | 2 + .../query-tests/security/CWE-327/options.yml | 9 ++ .../security/CWE-327/test_cipher.rs | 117 ++++++++++++++++++ 5 files changed, 145 insertions(+) create mode 100644 rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql create mode 100644 rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected create mode 100644 rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.qlref create mode 100644 rust/ql/test/query-tests/security/CWE-327/options.yml create mode 100644 rust/ql/test/query-tests/security/CWE-327/test_cipher.rs diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql new file mode 100644 index 000000000000..3890d54c03b4 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql @@ -0,0 +1,17 @@ +/** + * @name Use of a broken or weak cryptographic algorithm + * @description Using broken or weak cryptographic algorithms can compromise security. + * @kind problem + * @problem.severity warning + * @security-severity 7.5 + * @precision high + * @id rust/weak-cryptographic-algorithm + * @tags security + * external/cwe/cwe-327 + */ + +import rust + +from int i +where none() +select i diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.qlref b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.qlref new file mode 100644 index 000000000000..6b7ff78b567a --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.qlref @@ -0,0 +1,2 @@ +query: queries/security/CWE-327/BrokenCryptoAlgorithm.ql +postprocess: utils/InlineExpectationsTestQuery.ql \ No newline at end of file diff --git a/rust/ql/test/query-tests/security/CWE-327/options.yml b/rust/ql/test/query-tests/security/CWE-327/options.yml new file mode 100644 index 000000000000..72d848f4ca06 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/options.yml @@ -0,0 +1,9 @@ +qltest_cargo_check: true +qltest_dependencies: + - cipher = { version = "0.4.4" } + - rc4 = { version = "0.1.0" } + - rabbit = { version = "0.4.1" } + - aes = { version = "0.8.4" } + - des = { version = "0.8.1" } + - rc2 = { version = "0.8.1" } + - rc5 = { version = "0.0.1" } diff --git a/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs new file mode 100644 index 000000000000..34f47130e3a4 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs @@ -0,0 +1,117 @@ + +use cipher::{consts::*, StreamCipher, KeyInit, KeyIvInit, BlockEncrypt, BlockDecrypt, BlockEncryptMut, BlockDecryptMut}; +use rc4::{Rc4}; +use rabbit::{Rabbit, RabbitKeyOnly}; +use aes::{Aes128, Aes192Enc, Aes256Dec}; +use des::{Des, TdesEde2, TdesEde3, TdesEee2, TdesEee3}; +use rc2::{Rc2}; +use rc5::{RC5_16_16_8, RC5_32_16_16}; + +// --- tests --- + +fn test_stream_cipher( + key128: &[u8;16], iv128: &[u8;16], plaintext: &str +) { + let mut data = plaintext.as_bytes().to_vec(); + + // rc4 (broken) + let rc4_key = rc4::Key::::from_slice(key128); + + let mut rc4_cipher1 = Rc4::<_>::new(rc4_key); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + rc4_cipher1.apply_keystream(&mut data); + + let mut rc4_cipher2 = Rc4::::new_from_slice(key128).unwrap(); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + rc4_cipher2.apply_keystream(&mut data); + + let mut rc4_cipher3 = Rc4::<_>::new(rc4_key); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let _ = rc4_cipher3.try_apply_keystream(&mut data); + + let mut rc4_cipher4 = Rc4::<_>::new(rc4_key); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let _ = rc4_cipher4.apply_keystream_b2b(plaintext.as_bytes(), &mut data); + + // rabbit + let rabbit_key = rabbit::Key::from_slice(key128); + let rabbit_iv = rabbit::Iv::from_slice(iv128); + + let mut rabbit_cipher1 = RabbitKeyOnly::new(rabbit_key); + rabbit_cipher1.apply_keystream(&mut data); + + let mut rabbit_cipher2 = Rabbit::new(rabbit_key, rabbit_iv); + rabbit_cipher2.apply_keystream(&mut data); +} + +fn test_block_cipher( + key: &[u8], key128: &[u8;16], key192: &[u8;24], key256: &[u8;32], + data: &mut [u8], input: &[u8], block128: &mut [u8;16] +) { + // aes + let aes_cipher1 = Aes128::new(key128.into()); + aes_cipher1.encrypt_block(block128.into()); + aes_cipher1.decrypt_block(block128.into()); + + let aes_cipher2 = Aes192Enc::new_from_slice(key192).unwrap(); + aes_cipher2.encrypt_block(block128.into()); + + let aes_cipher3 = Aes256Dec::new(key256.into()); + aes_cipher3.decrypt_block(block128.into()); + + // des (broken) + let des_cipher1 = Des::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + des_cipher1.encrypt_block(data.into()); + des_cipher1.decrypt_block(data.into()); + + let des_cipher2 = des::Des::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + des_cipher2.encrypt_block(data.into()); + des_cipher2.decrypt_block(data.into()); + + let des_cipher3 = Des::new_from_slice(key).expect("fail"); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + des_cipher3.encrypt_block(data.into()); + des_cipher3.decrypt_block(data.into()); + + let des_cipher4 = Des::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + des_cipher4.encrypt_block_b2b(input.into(), data.into()); + des_cipher4.decrypt_block_b2b(input.into(), data.into()); + + let mut des_cipher5 = Des::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + des_cipher5.encrypt_block_mut(data.into()); + des_cipher5.decrypt_block_mut(data.into()); + + // triple des (broken) + let tdes_cipher1 = TdesEde2::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + tdes_cipher1.encrypt_block(data.into()); + tdes_cipher1.decrypt_block(data.into()); + + let tdes_cipher2 = TdesEde3::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + tdes_cipher2.encrypt_block(data.into()); + tdes_cipher2.decrypt_block(data.into()); + + let tdes_cipher3 = TdesEee2::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + tdes_cipher3.encrypt_block(data.into()); + tdes_cipher3.decrypt_block(data.into()); + + let tdes_cipher4 = TdesEee3::new_from_slice(key).unwrap(); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + tdes_cipher4.encrypt_block(data.into()); + tdes_cipher4.decrypt_block(data.into()); + + // rc2 (broken) + let rc2_cipher1 = Rc2::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + rc2_cipher1.encrypt_block(data.into()); + rc2_cipher1.decrypt_block(data.into()); + + let rc2_cipher2 = Rc2::new_from_slice(key).expect("fail"); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + rc2_cipher2.encrypt_block(data.into()); + rc2_cipher2.decrypt_block(data.into()); + + let rc2_cipher3 = Rc2::new_with_eff_key_len(key, 64); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + rc2_cipher3.encrypt_block(data.into()); + rc2_cipher3.decrypt_block(data.into()); + + // rc5 (broken) + let rc5_cipher1 = RC5_16_16_8::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + rc5_cipher1.encrypt_block(data.into()); + rc5_cipher1.decrypt_block(data.into()); + + let rc5_cipher2 = RC5_32_16_16::new_from_slice(key).unwrap(); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + rc5_cipher2.encrypt_block(data.into()); + rc5_cipher2.decrypt_block(data.into()); +} From 6c4e0a99e22a2539fc27fa6ad6109595f5c7ec52 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 3 Dec 2024 18:00:46 +0000 Subject: [PATCH 02/16] Rust: A few more test cases. --- .../query-tests/security/CWE-327/options.yml | 1 + .../security/CWE-327/test_cipher.rs | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/rust/ql/test/query-tests/security/CWE-327/options.yml b/rust/ql/test/query-tests/security/CWE-327/options.yml index 72d848f4ca06..5a3cf0cab12e 100644 --- a/rust/ql/test/query-tests/security/CWE-327/options.yml +++ b/rust/ql/test/query-tests/security/CWE-327/options.yml @@ -7,3 +7,4 @@ qltest_dependencies: - des = { version = "0.8.1" } - rc2 = { version = "0.8.1" } - rc5 = { version = "0.0.1" } + - cbc = { version = "0.1.2" } diff --git a/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs index 34f47130e3a4..a02308810440 100644 --- a/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs @@ -115,3 +115,29 @@ fn test_block_cipher( rc5_cipher2.encrypt_block(data.into()); rc5_cipher2.decrypt_block(data.into()); } + +type MyDesEncryptor = cbc::Encryptor; + +fn test_cbc( + key: &[u8], key128: &[u8;16], iv: &[u8], iv128: &[u8;16], + input: &[u8], data: &mut [u8] +) { + let data_len = data.len(); + + // aes + let aes_cipher1 = cbc::Encryptor::::new(key128.into(), iv128.into()); + _ = aes_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); + + // des (broken) + let des_cipher1 = cbc::Encryptor::::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + _ = des_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); + + let des_cipher2 = MyDesEncryptor::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + _ = des_cipher2.encrypt_padded_mut::(data, data_len).unwrap(); + + let des_cipher3 = cbc::Encryptor::::new_from_slices(&key, &iv).unwrap(); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + _ = des_cipher3.encrypt_padded_mut::(data, data_len).unwrap(); + + let des_cipher4 = cbc::Encryptor::::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + _ = des_cipher4.encrypt_padded_b2b_mut::(input, data).unwrap(); +} From 07e3421f6f99381aa299e106cdf19cf52f559d44 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 4 Dec 2024 14:23:46 +0000 Subject: [PATCH 03/16] Rust: Add shared ConceptsShared.qll, CryptoAlgorithms.qll and CryptoAlgorithmNames.qll to Rust. --- config/identical-files.json | 9 +- .../codeql/rust/internal/ConceptsImports.qll | 7 + .../codeql/rust/internal/ConceptsShared.qll | 181 ++++++++++++++++++ .../codeql/rust/security/CryptoAlgorithms.qll | 117 +++++++++++ .../internal/CryptoAlgorithmNames.qll | 84 ++++++++ 5 files changed, 395 insertions(+), 3 deletions(-) create mode 100644 rust/ql/lib/codeql/rust/internal/ConceptsImports.qll create mode 100644 rust/ql/lib/codeql/rust/internal/ConceptsShared.qll create mode 100644 rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll create mode 100644 rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll diff --git a/config/identical-files.json b/config/identical-files.json index c4436872b9ae..064da36677d9 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -288,12 +288,14 @@ "CryptoAlgorithms Python/JS/Ruby": [ "javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll", "python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll", - "ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll" + "ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll", + "rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll" ], "CryptoAlgorithmNames Python/JS/Ruby": [ "javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll", "python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll", - "ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll" + "ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll", + "rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll" ], "SensitiveDataHeuristics Python/JS": [ "javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll", @@ -308,7 +310,8 @@ "Concepts Python/Ruby/JS": [ "python/ql/lib/semmle/python/internal/ConceptsShared.qll", "ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll", - "javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll" + "javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll", + "rust/ql/lib/codeql/rust/internal/ConceptsShared.qll" ], "ApiGraphModels": [ "javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll", diff --git a/rust/ql/lib/codeql/rust/internal/ConceptsImports.qll b/rust/ql/lib/codeql/rust/internal/ConceptsImports.qll new file mode 100644 index 000000000000..341f3ade509f --- /dev/null +++ b/rust/ql/lib/codeql/rust/internal/ConceptsImports.qll @@ -0,0 +1,7 @@ +/** + * This file contains imports required for the Rust version of `ConceptsShared.qll`. + * Since they are language-specific, they can't be placed directly in that file, as it is shared between languages. + */ + +import codeql.rust.dataflow.DataFlow::DataFlow as DataFlow +import codeql.rust.security.CryptoAlgorithms as CryptoAlgorithms diff --git a/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll new file mode 100644 index 000000000000..135f830e47dc --- /dev/null +++ b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll @@ -0,0 +1,181 @@ +/** + * Provides Concepts which are shared across languages. + * + * Each language has a language specific `Concepts.qll` file that can import the + * shared concepts from this file. A language can either re-export the concept directly, + * or can add additional member-predicates that are needed for that language. + * + * Moving forward, `Concepts.qll` will be the staging ground for brand new concepts from + * each language, but we will maintain a discipline of moving those concepts to + * `ConceptsShared.qll` ASAP. + */ + +private import ConceptsImports + +/** + * Provides models for cryptographic concepts. + * + * Note: The `CryptographicAlgorithm` class currently doesn't take weak keys into + * consideration for the `isWeak` member predicate. So RSA is always considered + * secure, although using a low number of bits will actually make it insecure. We plan + * to improve our libraries in the future to more precisely capture this aspect. + */ +module Cryptography { + class CryptographicAlgorithm = CryptoAlgorithms::CryptographicAlgorithm; + + class EncryptionAlgorithm = CryptoAlgorithms::EncryptionAlgorithm; + + class HashingAlgorithm = CryptoAlgorithms::HashingAlgorithm; + + class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; + + /** + * A data-flow node that is an application of a cryptographic algorithm. For example, + * encryption, decryption, signature-validation. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `CryptographicOperation::Range` instead. + */ + class CryptographicOperation extends DataFlow::Node instanceof CryptographicOperation::Range { + /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ + CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } + + /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + DataFlow::Node getInitialization() { result = super.getInitialization() } + + /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ + DataFlow::Node getAnInput() { result = super.getAnInput() } + + /** + * Gets the block mode used to perform this cryptographic operation. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. + */ + BlockMode getBlockMode() { result = super.getBlockMode() } + } + + /** Provides classes for modeling new applications of a cryptographic algorithms. */ + module CryptographicOperation { + /** + * A data-flow node that is an application of a cryptographic algorithm. For example, + * encryption, decryption, signature-validation. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `CryptographicOperation` instead. + */ + abstract class Range extends DataFlow::Node { + /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + abstract DataFlow::Node getInitialization(); + + /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ + abstract CryptographicAlgorithm getAlgorithm(); + + /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ + abstract DataFlow::Node getAnInput(); + + /** + * Gets the block mode used to perform this cryptographic operation. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. + */ + abstract BlockMode getBlockMode(); + } + } + + /** + * A cryptographic block cipher mode of operation. This can be used to encrypt + * data of arbitrary length using a block encryption algorithm. + */ + class BlockMode extends string { + BlockMode() { + this = + [ + "ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP", + "XTS", // https://csrc.nist.gov/publications/detail/sp/800-38e/final + "EAX" // https://en.wikipedia.org/wiki/EAX_mode + ] + } + + /** Holds if this block mode is considered to be insecure. */ + predicate isWeak() { this = "ECB" } + + /** Holds if the given string appears to match this block mode. */ + bindingset[s] + predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") } + } +} + +/** Provides classes for modeling HTTP-related APIs. */ +module Http { + /** Provides classes for modeling HTTP clients. */ + module Client { + /** + * A data-flow node that makes an outgoing HTTP request. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `Http::Client::Request::Range` instead. + */ + class Request extends DataFlow::Node instanceof Request::Range { + /** + * Gets a data-flow node that contributes to the URL of the request. + * Depending on the framework, a request may have multiple nodes which contribute to the URL. + */ + DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } + + /** Gets a string that identifies the framework used for this request. */ + string getFramework() { result = super.getFramework() } + + /** + * Holds if this request is made using a mode that disables SSL/TLS + * certificate validation, where `disablingNode` represents the point at + * which the validation was disabled, and `argumentOrigin` represents the origin + * of the argument that disabled the validation (which could be the same node as + * `disablingNode`). + */ + predicate disablesCertificateValidation( + DataFlow::Node disablingNode, DataFlow::Node argumentOrigin + ) { + super.disablesCertificateValidation(disablingNode, argumentOrigin) + } + } + + /** Provides a class for modeling new HTTP requests. */ + module Request { + /** + * A data-flow node that makes an outgoing HTTP request. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `Http::Client::Request` instead. + */ + abstract class Range extends DataFlow::Node { + /** + * Gets a data-flow node that contributes to the URL of the request. + * Depending on the framework, a request may have multiple nodes which contribute to the URL. + */ + abstract DataFlow::Node getAUrlPart(); + + /** Gets a string that identifies the framework used for this request. */ + abstract string getFramework(); + + /** + * Holds if this request is made using a mode that disables SSL/TLS + * certificate validation, where `disablingNode` represents the point at + * which the validation was disabled, and `argumentOrigin` represents the origin + * of the argument that disabled the validation (which could be the same node as + * `disablingNode`). + */ + abstract predicate disablesCertificateValidation( + DataFlow::Node disablingNode, DataFlow::Node argumentOrigin + ); + } + } + } +} diff --git a/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll b/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll new file mode 100644 index 000000000000..7176c666c573 --- /dev/null +++ b/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll @@ -0,0 +1,117 @@ +/** + * Provides classes modeling cryptographic algorithms, separated into strong and weak variants. + * + * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). + */ + +private import internal.CryptoAlgorithmNames + +/** + * A cryptographic algorithm. + */ +private newtype TCryptographicAlgorithm = + MkHashingAlgorithm(string name, boolean isWeak) { + isStrongHashingAlgorithm(name) and isWeak = false + or + isWeakHashingAlgorithm(name) and isWeak = true + } or + MkEncryptionAlgorithm(string name, boolean isWeak) { + isStrongEncryptionAlgorithm(name) and isWeak = false + or + isWeakEncryptionAlgorithm(name) and isWeak = true + } or + MkPasswordHashingAlgorithm(string name, boolean isWeak) { + isStrongPasswordHashingAlgorithm(name) and isWeak = false + or + isWeakPasswordHashingAlgorithm(name) and isWeak = true + } + +/** + * Gets the most specific `CryptographicAlgorithm` that matches the given `name`. + * A matching algorithm is one where the name of the algorithm matches the start of name, with allowances made for different name formats. + * In the case that multiple `CryptographicAlgorithm`s match the given `name`, the algorithm(s) with the longest name will be selected. This is intended to select more specific versions of algorithms when multiple versions could match - for example "SHA3_224" matches against both "SHA3" and "SHA3224", but the latter is a more precise match. + */ +bindingset[name] +private CryptographicAlgorithm getBestAlgorithmForName(string name) { + result = + max(CryptographicAlgorithm algorithm | + algorithm.getName() = + [ + name.toUpperCase(), // the full name + name.toUpperCase().regexpCapture("^([\\w]+)(?:-.*)?$", 1), // the name prior to any dashes or spaces + name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1) // the name prior to any dashes, spaces, or underscores + ].regexpReplaceAll("[-_ ]", "") // strip dashes, underscores, and spaces + | + algorithm order by algorithm.getName().length() + ) +} + +/** + * A cryptographic algorithm. + */ +abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { + /** Gets a textual representation of this element. */ + string toString() { result = this.getName() } + + /** + * Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores). + */ + abstract string getName(); + + /** + * Holds if the name of this algorithm is the most specific match for `name`. + * This predicate matches quite liberally to account for different ways of formatting algorithm names, e.g. using dashes, underscores, or spaces as separators, including or not including block modes of operation, etc. + */ + bindingset[name] + predicate matchesName(string name) { this = getBestAlgorithmForName(name) } + + /** + * Holds if this algorithm is weak. + */ + abstract predicate isWeak(); +} + +/** + * A hashing algorithm such as `MD5` or `SHA512`. + */ +class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } +} + +/** + * An encryption algorithm such as `DES` or `AES512`. + */ +class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } + + /** Holds if this algorithm is a stream cipher. */ + predicate isStreamCipher() { isStreamCipher(name) } +} + +/** + * A password hashing algorithm such as `PBKDF2` or `SCRYPT`. + */ +class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } +} diff --git a/rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll b/rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll new file mode 100644 index 000000000000..8bb63d97876a --- /dev/null +++ b/rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll @@ -0,0 +1,84 @@ +/** + * Names of cryptographic algorithms, separated into strong and weak variants. + * + * The names are normalized: upper-case, no spaces, dashes or underscores. + * + * The names are inspired by the names used in real world crypto libraries. + * + * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). + */ + +/** + * Holds if `name` corresponds to a strong hashing algorithm. + */ +predicate isStrongHashingAlgorithm(string name) { + name = + [ + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#blake2 + // and https://www.blake2.net/ + "BLAKE2", "BLAKE2B", "BLAKE2S", + // see https://github.com/BLAKE3-team/BLAKE3 + "BLAKE3", + // + "DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2", + "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#cryptography.hazmat.primitives.hashes.SHAKE128 + "SHAKE128", "SHAKE256", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#sm3 + "SM3", + // see https://security.stackexchange.com/a/216297 + "WHIRLPOOL", + ] +} + +/** + * Holds if `name` corresponds to a weak hashing algorithm. + */ +predicate isWeakHashingAlgorithm(string name) { + name = + [ + "HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160", + "RIPEMD320", "SHA0", "SHA1" + ] +} + +/** + * Holds if `name` corresponds to a strong encryption algorithm. + */ +predicate isStrongEncryptionAlgorithm(string name) { + name = + [ + "AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512", + "ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128", "CAMELLIA192", + "CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA", "GOST", "GOST89", + "IDEA", "RABBIT", "RSA", "SEED", "SM4" + ] +} + +/** + * Holds if `name` corresponds to a weak encryption algorithm. + */ +predicate isWeakEncryptionAlgorithm(string name) { + name = + [ + "DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", + "ARCFOUR", "ARC5", "RC5" + ] +} + +/** + * Holds if `name` corresponds to a strong password hashing algorithm. + */ +predicate isStrongPasswordHashingAlgorithm(string name) { + name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"] +} + +/** + * Holds if `name` corresponds to a weak password hashing algorithm. + */ +predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" } + +/** + * Holds if `name` corresponds to a stream cipher. + */ +predicate isStreamCipher(string name) { name = ["CHACHA", "RC4", "ARC4", "ARCFOUR", "RABBIT"] } From eeeb142f0b227682c47ded382d7e7392690cbbd5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 4 Dec 2024 14:49:25 +0000 Subject: [PATCH 04/16] Rust: Implement the query. --- rust/ql/lib/codeql/rust/Concepts.qll | 29 +++++++++++++++++++ .../security/CWE-327/BrokenCryptoAlgorithm.ql | 14 +++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/rust/ql/lib/codeql/rust/Concepts.qll b/rust/ql/lib/codeql/rust/Concepts.qll index 7e3ec0990ce3..070b8a118ccd 100644 --- a/rust/ql/lib/codeql/rust/Concepts.qll +++ b/rust/ql/lib/codeql/rust/Concepts.qll @@ -172,3 +172,32 @@ module SqlSanitization { */ abstract class Range extends DataFlow::Node { } } + +/** + * Provides models for cryptographic things. + */ +module Cryptography { + private import codeql.rust.internal.ConceptsShared::Cryptography as SC + + /** + * A data-flow node that is an application of a cryptographic algorithm. For example, + * encryption, decryption, signature-validation. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `CryptographicOperation::Range` instead. + */ + class CryptographicOperation extends SC::CryptographicOperation instanceof CryptographicOperation::Range + { } + + class EncryptionAlgorithm = SC::EncryptionAlgorithm; + + class HashingAlgorithm = SC::HashingAlgorithm; + + class PasswordHashingAlgorithm = SC::PasswordHashingAlgorithm; + + module CryptographicOperation = SC::CryptographicOperation; + + class BlockMode = SC::BlockMode; + + class CryptographicAlgorithm = SC::CryptographicAlgorithm; +} diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql index 3890d54c03b4..3d777b08539c 100644 --- a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql @@ -11,7 +11,15 @@ */ import rust +import codeql.rust.Concepts -from int i -where none() -select i +from Cryptography::CryptographicOperation operation, string msgPrefix +where + exists(Cryptography::EncryptionAlgorithm algorithm | algorithm = operation.getAlgorithm() | + algorithm.isWeak() and + msgPrefix = "The cryptographic algorithm " + algorithm.getName() + ) + or + operation.getBlockMode().isWeak() and msgPrefix = "The block mode " + operation.getBlockMode() +select operation, "$@ is broken or weak, and should not be used.", operation.getInitialization(), + msgPrefix From 94dbad7c95cf532dce9eb6a645ec9b7dee7f81e9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:32:25 +0000 Subject: [PATCH 05/16] Rust: Model for cipher traits. --- rust/ql/lib/codeql/rust/Frameworks.qll | 1 + .../lib/codeql/rust/frameworks/RustCrypto.qll | 35 +++++++++++++++++++ .../CWE-327/BrokenCryptoAlgorithm.expected | 13 +++++++ .../security/CWE-327/test_cipher.rs | 26 +++++++------- 4 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll diff --git a/rust/ql/lib/codeql/rust/Frameworks.qll b/rust/ql/lib/codeql/rust/Frameworks.qll index 0c6fc573d0fb..483056888ec6 100644 --- a/rust/ql/lib/codeql/rust/Frameworks.qll +++ b/rust/ql/lib/codeql/rust/Frameworks.qll @@ -3,5 +3,6 @@ */ private import codeql.rust.frameworks.Reqwest +private import codeql.rust.frameworks.RustCrypto private import codeql.rust.frameworks.stdlib.Env private import codeql.rust.frameworks.Sqlx diff --git a/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll new file mode 100644 index 000000000000..295ce8d9e638 --- /dev/null +++ b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll @@ -0,0 +1,35 @@ +/** + * Provides modeling for the `RustCrypto` family of crates (`cipher`, `digest` etc). + */ + +private import rust +private import codeql.rust.Concepts +private import codeql.rust.dataflow.DataFlow + +/** + * An operation that initializes a cipher through the `cipher::KeyInit` or + * `cipher::KeyIvInit` trait, for example `Des::new` or `cbc::Encryptor::new`. + */ +class StreamCipherInit extends Cryptography::CryptographicOperation::Range, DataFlow::Node { + string algorithmName; + + StreamCipherInit() { + // a call to `cipher::KeyInit::new`, `cipher::KeyInit::new_from_slice`, + // `cipher::KeyIvInit::new` or `cipher::KeyIvInit::new_from_slices`. + exists(Path p | + this.asExpr().getExpr().(CallExpr).getFunction().(PathExpr).getPath() = p and + p.getResolvedCrateOrigin().matches("%/RustCrypto%") and + p.getPart().getNameRef().getText() = + ["new", "new_from_slice", "new_from_slices"] and + algorithmName = p.getQualifier().getPart().getNameRef().getText() + ) + } + + override DataFlow::Node getInitialization() { result = this } + + override Cryptography::CryptographicAlgorithm getAlgorithm() { result.matchesName(algorithmName) } + + override DataFlow::Node getAnInput() { none() } + + override Cryptography::BlockMode getBlockMode() { result = "" } +} diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected index e69de29bb2d1..69f0fed8534e 100644 --- a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected @@ -0,0 +1,13 @@ +| test_cipher.rs:20:27:20:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:20:27:20:48 | ...::new(...) | The cryptographic algorithm RC4 | +| test_cipher.rs:23:27:23:60 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:23:27:23:60 | ...::new_from_slice(...) | The cryptographic algorithm RC4 | +| test_cipher.rs:26:27:26:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:26:27:26:48 | ...::new(...) | The cryptographic algorithm RC4 | +| test_cipher.rs:29:27:29:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:29:27:29:48 | ...::new(...) | The cryptographic algorithm RC4 | +| test_cipher.rs:59:23:59:42 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:59:23:59:42 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:63:23:63:47 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:63:23:63:47 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:67:23:67:46 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:67:23:67:46 | ...::new_from_slice(...) | The cryptographic algorithm DES | +| test_cipher.rs:71:23:71:42 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:71:23:71:42 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:75:27:75:46 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:75:27:75:46 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:97:23:97:42 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:97:23:97:42 | ...::new(...) | The cryptographic algorithm RC2 | +| test_cipher.rs:101:23:101:46 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:101:23:101:46 | ...::new_from_slice(...) | The cryptographic algorithm RC2 | +| test_cipher.rs:110:23:110:50 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:110:23:110:50 | ...::new(...) | The cryptographic algorithm RC5 | +| test_cipher.rs:114:23:114:55 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:114:23:114:55 | ...::new_from_slice(...) | The cryptographic algorithm RC5 | diff --git a/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs index a02308810440..bcb78b32db43 100644 --- a/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs @@ -17,16 +17,16 @@ fn test_stream_cipher( // rc4 (broken) let rc4_key = rc4::Key::::from_slice(key128); - let mut rc4_cipher1 = Rc4::<_>::new(rc4_key); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let mut rc4_cipher1 = Rc4::<_>::new(rc4_key); // $ Alert[rust/weak-cryptographic-algorithm] rc4_cipher1.apply_keystream(&mut data); - let mut rc4_cipher2 = Rc4::::new_from_slice(key128).unwrap(); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let mut rc4_cipher2 = Rc4::::new_from_slice(key128).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] rc4_cipher2.apply_keystream(&mut data); - let mut rc4_cipher3 = Rc4::<_>::new(rc4_key); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let mut rc4_cipher3 = Rc4::<_>::new(rc4_key); // $ Alert[rust/weak-cryptographic-algorithm] let _ = rc4_cipher3.try_apply_keystream(&mut data); - let mut rc4_cipher4 = Rc4::<_>::new(rc4_key); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let mut rc4_cipher4 = Rc4::<_>::new(rc4_key); // $ Alert[rust/weak-cryptographic-algorithm] let _ = rc4_cipher4.apply_keystream_b2b(plaintext.as_bytes(), &mut data); // rabbit @@ -56,23 +56,23 @@ fn test_block_cipher( aes_cipher3.decrypt_block(block128.into()); // des (broken) - let des_cipher1 = Des::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher1 = Des::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] des_cipher1.encrypt_block(data.into()); des_cipher1.decrypt_block(data.into()); - let des_cipher2 = des::Des::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher2 = des::Des::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] des_cipher2.encrypt_block(data.into()); des_cipher2.decrypt_block(data.into()); - let des_cipher3 = Des::new_from_slice(key).expect("fail"); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher3 = Des::new_from_slice(key).expect("fail"); // $ Alert[rust/weak-cryptographic-algorithm] des_cipher3.encrypt_block(data.into()); des_cipher3.decrypt_block(data.into()); - let des_cipher4 = Des::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher4 = Des::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] des_cipher4.encrypt_block_b2b(input.into(), data.into()); des_cipher4.decrypt_block_b2b(input.into(), data.into()); - let mut des_cipher5 = Des::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let mut des_cipher5 = Des::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] des_cipher5.encrypt_block_mut(data.into()); des_cipher5.decrypt_block_mut(data.into()); @@ -94,11 +94,11 @@ fn test_block_cipher( tdes_cipher4.decrypt_block(data.into()); // rc2 (broken) - let rc2_cipher1 = Rc2::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let rc2_cipher1 = Rc2::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] rc2_cipher1.encrypt_block(data.into()); rc2_cipher1.decrypt_block(data.into()); - let rc2_cipher2 = Rc2::new_from_slice(key).expect("fail"); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let rc2_cipher2 = Rc2::new_from_slice(key).expect("fail"); // $ Alert[rust/weak-cryptographic-algorithm] rc2_cipher2.encrypt_block(data.into()); rc2_cipher2.decrypt_block(data.into()); @@ -107,11 +107,11 @@ fn test_block_cipher( rc2_cipher3.decrypt_block(data.into()); // rc5 (broken) - let rc5_cipher1 = RC5_16_16_8::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let rc5_cipher1 = RC5_16_16_8::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] rc5_cipher1.encrypt_block(data.into()); rc5_cipher1.decrypt_block(data.into()); - let rc5_cipher2 = RC5_32_16_16::new_from_slice(key).unwrap(); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let rc5_cipher2 = RC5_32_16_16::new_from_slice(key).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] rc5_cipher2.encrypt_block(data.into()); rc5_cipher2.decrypt_block(data.into()); } From 6eb850c8cb5cadbd6ee66b0ceef9e13574957dcd Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:49:10 +0000 Subject: [PATCH 06/16] Rust: Improve the model. --- .../lib/codeql/rust/frameworks/RustCrypto.qll | 18 ++++++++++++++---- .../CWE-327/BrokenCryptoAlgorithm.expected | 8 ++++++++ .../security/CWE-327/test_cipher.rs | 16 ++++++++-------- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll index 295ce8d9e638..e2142cfe0d9a 100644 --- a/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll +++ b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll @@ -6,6 +6,12 @@ private import rust private import codeql.rust.Concepts private import codeql.rust.dataflow.DataFlow +bindingset[algorithmName] +string simplifyAlgorithmName(string algorithmName) { + // the cipher library gives triple-DES names like "TdesEee2" and "TdesEde2" + if algorithmName.matches("Tdes%") then result = "3des" else result = algorithmName +} + /** * An operation that initializes a cipher through the `cipher::KeyInit` or * `cipher::KeyIvInit` trait, for example `Des::new` or `cbc::Encryptor::new`. @@ -15,13 +21,17 @@ class StreamCipherInit extends Cryptography::CryptographicOperation::Range, Data StreamCipherInit() { // a call to `cipher::KeyInit::new`, `cipher::KeyInit::new_from_slice`, - // `cipher::KeyIvInit::new` or `cipher::KeyIvInit::new_from_slices`. - exists(Path p | + // `cipher::KeyIvInit::new`, `cipher::KeyIvInit::new_from_slices` or `rc2::Rc2::new_with_eff_key_len`. + exists(Path p, string rawAlgorithmName | this.asExpr().getExpr().(CallExpr).getFunction().(PathExpr).getPath() = p and p.getResolvedCrateOrigin().matches("%/RustCrypto%") and p.getPart().getNameRef().getText() = - ["new", "new_from_slice", "new_from_slices"] and - algorithmName = p.getQualifier().getPart().getNameRef().getText() + ["new", "new_from_slice", "new_from_slices", "new_with_eff_key_len"] and + ( + rawAlgorithmName = p.getQualifier().getPart().getNameRef().getText() or + rawAlgorithmName = p.getQualifier().getPart().getGenericArgList().getGenericArg(0).(TypeArg).getTy().(PathType).getPath().getPart().getNameRef().getText() + ) and + algorithmName = simplifyAlgorithmName(rawAlgorithmName) ) } diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected index 69f0fed8534e..f1395ff39ec0 100644 --- a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected @@ -7,7 +7,15 @@ | test_cipher.rs:67:23:67:46 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:67:23:67:46 | ...::new_from_slice(...) | The cryptographic algorithm DES | | test_cipher.rs:71:23:71:42 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:71:23:71:42 | ...::new(...) | The cryptographic algorithm DES | | test_cipher.rs:75:27:75:46 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:75:27:75:46 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:80:24:80:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:80:24:80:48 | ...::new(...) | The cryptographic algorithm 3DES | +| test_cipher.rs:84:24:84:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:84:24:84:48 | ...::new(...) | The cryptographic algorithm 3DES | +| test_cipher.rs:88:24:88:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:88:24:88:48 | ...::new(...) | The cryptographic algorithm 3DES | +| test_cipher.rs:92:24:92:52 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:92:24:92:52 | ...::new_from_slice(...) | The cryptographic algorithm 3DES | | test_cipher.rs:97:23:97:42 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:97:23:97:42 | ...::new(...) | The cryptographic algorithm RC2 | | test_cipher.rs:101:23:101:46 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:101:23:101:46 | ...::new_from_slice(...) | The cryptographic algorithm RC2 | +| test_cipher.rs:105:23:105:56 | ...::new_with_eff_key_len(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:105:23:105:56 | ...::new_with_eff_key_len(...) | The cryptographic algorithm RC2 | | test_cipher.rs:110:23:110:50 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:110:23:110:50 | ...::new(...) | The cryptographic algorithm RC5 | | test_cipher.rs:114:23:114:55 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:114:23:114:55 | ...::new_from_slice(...) | The cryptographic algorithm RC5 | +| test_cipher.rs:132:23:132:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:132:23:132:76 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:138:23:138:76 | ...::new_from_slices(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:138:23:138:76 | ...::new_from_slices(...) | The cryptographic algorithm DES | +| test_cipher.rs:141:23:141:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:141:23:141:76 | ...::new(...) | The cryptographic algorithm DES | diff --git a/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs index bcb78b32db43..0cf20c4c2782 100644 --- a/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs @@ -77,19 +77,19 @@ fn test_block_cipher( des_cipher5.decrypt_block_mut(data.into()); // triple des (broken) - let tdes_cipher1 = TdesEde2::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let tdes_cipher1 = TdesEde2::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] tdes_cipher1.encrypt_block(data.into()); tdes_cipher1.decrypt_block(data.into()); - let tdes_cipher2 = TdesEde3::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let tdes_cipher2 = TdesEde3::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] tdes_cipher2.encrypt_block(data.into()); tdes_cipher2.decrypt_block(data.into()); - let tdes_cipher3 = TdesEee2::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let tdes_cipher3 = TdesEee2::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] tdes_cipher3.encrypt_block(data.into()); tdes_cipher3.decrypt_block(data.into()); - let tdes_cipher4 = TdesEee3::new_from_slice(key).unwrap(); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let tdes_cipher4 = TdesEee3::new_from_slice(key).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] tdes_cipher4.encrypt_block(data.into()); tdes_cipher4.decrypt_block(data.into()); @@ -102,7 +102,7 @@ fn test_block_cipher( rc2_cipher2.encrypt_block(data.into()); rc2_cipher2.decrypt_block(data.into()); - let rc2_cipher3 = Rc2::new_with_eff_key_len(key, 64); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let rc2_cipher3 = Rc2::new_with_eff_key_len(key, 64); // $ Alert[rust/weak-cryptographic-algorithm] rc2_cipher3.encrypt_block(data.into()); rc2_cipher3.decrypt_block(data.into()); @@ -129,15 +129,15 @@ fn test_cbc( _ = aes_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); // des (broken) - let des_cipher1 = cbc::Encryptor::::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher1 = cbc::Encryptor::::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); let des_cipher2 = MyDesEncryptor::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] _ = des_cipher2.encrypt_padded_mut::(data, data_len).unwrap(); - let des_cipher3 = cbc::Encryptor::::new_from_slices(&key, &iv).unwrap(); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher3 = cbc::Encryptor::::new_from_slices(&key, &iv).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher3.encrypt_padded_mut::(data, data_len).unwrap(); - let des_cipher4 = cbc::Encryptor::::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher4 = cbc::Encryptor::::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher4.encrypt_padded_b2b_mut::(input, data).unwrap(); } From dd0fa791aa49bffe3fae5b57f92683396dbd916a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 5 Dec 2024 17:28:45 +0000 Subject: [PATCH 07/16] Rust: Add qhelp. --- .../CWE-327/BrokenCryptoAlgorithm.qhelp | 62 +++++++++++++++++++ .../CWE-327/BrokenCryptoAlgorithmBad.rs | 2 + .../CWE-327/BrokenCryptoAlgorithmGood.rs | 2 + 3 files changed, 66 insertions(+) create mode 100644 rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp create mode 100644 rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmBad.rs create mode 100644 rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmGood.rs diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp new file mode 100644 index 000000000000..f93c77e83f29 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp @@ -0,0 +1,62 @@ + + + +

+ Using broken or weak cryptographic algorithms can leave data + vulnerable to being decrypted or forged by an attacker. +

+ +

+ Many cryptographic algorithms provided by cryptography + libraries are known to be weak, or flawed. Using such an + algorithm means that encrypted or hashed data is less + secure than it appears to be. +

+ +

+ This query alerts on any use of a weak cryptographic algorithm, that is + not a hashing algorithm. Use of broken or weak cryptographic hash + functions are handled by the + rust/weak-sensitive-data-hashing query. +

+ +
+ + +

+ Ensure that you use a strong, modern cryptographic + algorithm, such as AES-128 or RSA-2048. +

+ +
+ + +

+ The following code uses the des crate from the + RustCrypto family to encrypt some secret data. The + DES algorithm is old and considered very weak. +

+ + + +

+ Instead we should use a strong modern algorithm. In this + case we have selected the 256-bit version of the AES + algorithm. +

+ + + +
+ + +
  • NIST, FIPS 140 Annex a: Approved Security Functions.
  • +
  • NIST, SP 800-131A: Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths.
  • +
  • OWASP: Cryptographic Storage Cheat Sheet - Algorithms. +
  • +
    + +
    diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmBad.rs b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmBad.rs new file mode 100644 index 000000000000..3e86462c62a2 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmBad.rs @@ -0,0 +1,2 @@ +let des_cipher = cbc::Encryptor::::new(key.into(), iv.into()); // BAD: weak encryption +let encryption_result = des_cipher.encrypt_padded_mut::(data, data_len); diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmGood.rs b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmGood.rs new file mode 100644 index 000000000000..6cafbc69bf7d --- /dev/null +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmGood.rs @@ -0,0 +1,2 @@ +let aes_cipher = cbc::Encryptor::::new(key.into(), iv.into()); // GOOD: strong encryption +let encryption_result = aes_cipher.encrypt_padded_mut::(data, data_len); From 4e418d3d4da22e3f093069869fdc3c302de23d1a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 5 Dec 2024 18:54:15 +0000 Subject: [PATCH 08/16] Rust: Update for latest main, and autoformat. --- .../lib/codeql/rust/frameworks/RustCrypto.qll | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll index e2142cfe0d9a..1037c95b4368 100644 --- a/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll +++ b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll @@ -22,14 +22,26 @@ class StreamCipherInit extends Cryptography::CryptographicOperation::Range, Data StreamCipherInit() { // a call to `cipher::KeyInit::new`, `cipher::KeyInit::new_from_slice`, // `cipher::KeyIvInit::new`, `cipher::KeyIvInit::new_from_slices` or `rc2::Rc2::new_with_eff_key_len`. - exists(Path p, string rawAlgorithmName | - this.asExpr().getExpr().(CallExpr).getFunction().(PathExpr).getPath() = p and + exists(PathExpr p, string rawAlgorithmName | + this.asExpr().getExpr().(CallExpr).getFunction() = p and p.getResolvedCrateOrigin().matches("%/RustCrypto%") and - p.getPart().getNameRef().getText() = + p.getPath().getPart().getNameRef().getText() = ["new", "new_from_slice", "new_from_slices", "new_with_eff_key_len"] and ( - rawAlgorithmName = p.getQualifier().getPart().getNameRef().getText() or - rawAlgorithmName = p.getQualifier().getPart().getGenericArgList().getGenericArg(0).(TypeArg).getTy().(PathType).getPath().getPart().getNameRef().getText() + rawAlgorithmName = p.getPath().getQualifier().getPart().getNameRef().getText() or + rawAlgorithmName = + p.getPath() + .getQualifier() + .getPart() + .getGenericArgList() + .getGenericArg(0) + .(TypeArg) + .getTypeRepr() + .(PathTypeRepr) + .getPath() + .getPart() + .getNameRef() + .getText() ) and algorithmName = simplifyAlgorithmName(rawAlgorithmName) ) From 129f21af2988531249ceb22304e93fe34b4836f5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 6 Dec 2024 09:37:41 +0000 Subject: [PATCH 09/16] Rust: Make a predicate private. --- rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll index 1037c95b4368..d88a276091c7 100644 --- a/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll +++ b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll @@ -7,7 +7,7 @@ private import codeql.rust.Concepts private import codeql.rust.dataflow.DataFlow bindingset[algorithmName] -string simplifyAlgorithmName(string algorithmName) { +private string simplifyAlgorithmName(string algorithmName) { // the cipher library gives triple-DES names like "TdesEee2" and "TdesEde2" if algorithmName.matches("Tdes%") then result = "3des" else result = algorithmName } From f637b3b1f3588c4a80b6e4bc06941c1ffb20bb14 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 6 Dec 2024 14:20:40 +0000 Subject: [PATCH 10/16] Apply suggestions from code review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- .../queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp index f93c77e83f29..e24222e09fc5 100644 --- a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp @@ -42,8 +42,8 @@

    - Instead we should use a strong modern algorithm. In this - case we have selected the 256-bit version of the AES + Instead, we should use a strong modern algorithm. In this + case, we have selected the 256-bit version of the AES algorithm.

    @@ -52,8 +52,8 @@ -
  • NIST, FIPS 140 Annex a: Approved Security Functions.
  • -
  • NIST, SP 800-131A: Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths.
  • +
  • NIST, FIPS 140 Annex A: Approved Security Functions.
  • +
  • NIST, SP 800-131A Revision 2: Transitioning the Use of Cryptographic Algorithms and Key Lengths.
  • OWASP: Cryptographic Storage Cheat Sheet - Algorithms.
  • From ad75906672b37784e3f887275327f0f48f741500 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:44:00 +0000 Subject: [PATCH 11/16] Apply suggestions from code review Co-authored-by: Tom Hvitved --- rust/ql/lib/codeql/rust/Concepts.qll | 10 +--------- rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/rust/ql/lib/codeql/rust/Concepts.qll b/rust/ql/lib/codeql/rust/Concepts.qll index 070b8a118ccd..74db9ab7be8f 100644 --- a/rust/ql/lib/codeql/rust/Concepts.qll +++ b/rust/ql/lib/codeql/rust/Concepts.qll @@ -179,15 +179,7 @@ module SqlSanitization { module Cryptography { private import codeql.rust.internal.ConceptsShared::Cryptography as SC - /** - * A data-flow node that is an application of a cryptographic algorithm. For example, - * encryption, decryption, signature-validation. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `CryptographicOperation::Range` instead. - */ - class CryptographicOperation extends SC::CryptographicOperation instanceof CryptographicOperation::Range - { } + final class CryptographicOperation = SC:: CryptographicOperation; class EncryptionAlgorithm = SC::EncryptionAlgorithm; diff --git a/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll index d88a276091c7..9dd40004766a 100644 --- a/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll +++ b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll @@ -16,7 +16,7 @@ private string simplifyAlgorithmName(string algorithmName) { * An operation that initializes a cipher through the `cipher::KeyInit` or * `cipher::KeyIvInit` trait, for example `Des::new` or `cbc::Encryptor::new`. */ -class StreamCipherInit extends Cryptography::CryptographicOperation::Range, DataFlow::Node { +class StreamCipherInit extends Cryptography::CryptographicOperation::Range { string algorithmName; StreamCipherInit() { From 591db0561090f921e031ee1b0b0d4005a06cb791 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:49:07 +0000 Subject: [PATCH 12/16] Rust: Formatting. --- rust/ql/lib/codeql/rust/Concepts.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/Concepts.qll b/rust/ql/lib/codeql/rust/Concepts.qll index 74db9ab7be8f..a632527e1107 100644 --- a/rust/ql/lib/codeql/rust/Concepts.qll +++ b/rust/ql/lib/codeql/rust/Concepts.qll @@ -179,7 +179,7 @@ module SqlSanitization { module Cryptography { private import codeql.rust.internal.ConceptsShared::Cryptography as SC - final class CryptographicOperation = SC:: CryptographicOperation; + final class CryptographicOperation = SC::CryptographicOperation; class EncryptionAlgorithm = SC::EncryptionAlgorithm; From d2cfcb4c9eaef32c99e7555f596d8e0576e86708 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:28:04 +0000 Subject: [PATCH 13/16] Update rust/ql/lib/codeql/rust/internal/ConceptsShared.qll Co-authored-by: Simon Friis Vindum --- rust/ql/lib/codeql/rust/internal/ConceptsShared.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll index 135f830e47dc..78e454fe28bf 100644 --- a/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll +++ b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll @@ -30,7 +30,7 @@ module Cryptography { class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to refine existing API models. If you want to model new APIs, From 1d72b750b7ca29264a1d404e228c68699ef039a2 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:29:23 +0000 Subject: [PATCH 14/16] Rust: data-flow -> data flow. --- rust/ql/lib/codeql/rust/Concepts.qll | 12 ++++++------ .../codeql/rust/dataflow/internal/DataFlowImpl.qll | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust/ql/lib/codeql/rust/Concepts.qll b/rust/ql/lib/codeql/rust/Concepts.qll index a632527e1107..51d601070000 100644 --- a/rust/ql/lib/codeql/rust/Concepts.qll +++ b/rust/ql/lib/codeql/rust/Concepts.qll @@ -105,7 +105,7 @@ module RemoteSource { } /** - * A data-flow node that constructs a SQL statement (for later execution). + * A data flow node that constructs a SQL statement (for later execution). * * Often, it is worthy of an alert if a SQL statement is constructed such that * executing it would be a security risk. @@ -122,7 +122,7 @@ final class SqlConstruction = SqlConstruction::Range; */ module SqlConstruction { /** - * A data-flow node that constructs a SQL statement. + * A data flow node that constructs a SQL statement. */ abstract class Range extends DataFlow::Node { /** @@ -133,7 +133,7 @@ module SqlConstruction { } /** - * A data-flow node that constructs and executes SQL statements. + * A data flow node that constructs and executes SQL statements. * * If the context of interest is such that merely constructing a SQL statement * would be valuable to report, consider also using `SqlConstruction`. @@ -148,7 +148,7 @@ final class SqlExecution = SqlExecution::Range; */ module SqlExecution { /** - * A data-flow node that executes SQL statements. + * A data flow node that executes SQL statements. */ abstract class Range extends DataFlow::Node { /** @@ -159,7 +159,7 @@ module SqlExecution { } /** - * A data-flow node that performs SQL sanitization. + * A data flow node that performs SQL sanitization. */ final class SqlSanitization = SqlSanitization::Range; @@ -168,7 +168,7 @@ final class SqlSanitization = SqlSanitization::Range; */ module SqlSanitization { /** - * A data-flow node that performs SQL sanitization. + * A data flow node that performs SQL sanitization. */ abstract class Range extends DataFlow::Node { } } diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index b22b27c4db65..1eb651314c2c 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -330,7 +330,7 @@ module Node { override ReturnKind getKind() { result = rk } } - /** A data-flow node that represents the output of a call. */ + /** A data flow node that represents the output of a call. */ abstract class OutNode extends Node { /** Gets the underlying call for this node. */ abstract DataFlowCall getCall(ReturnKind kind); From 611d04e221ea7411d84fce518ac9ceb27cffb847 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:30:23 +0000 Subject: [PATCH 15/16] Rust: Revert stylistic change in shared file. --- rust/ql/lib/codeql/rust/internal/ConceptsShared.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll index 78e454fe28bf..135f830e47dc 100644 --- a/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll +++ b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll @@ -30,7 +30,7 @@ module Cryptography { class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; /** - * A data flow node that is an application of a cryptographic algorithm. For example, + * A data-flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to refine existing API models. If you want to model new APIs, From 44a0ad29422cb2601a29e3c5ba3ceb24b5876e1d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:34:41 +0000 Subject: [PATCH 16/16] Update data-flow -> data flow in all versions of ConceptsShared.qll. --- .../javascript/internal/ConceptsShared.qll | 16 ++++++++-------- .../semmle/python/internal/ConceptsShared.qll | 16 ++++++++-------- .../lib/codeql/ruby/internal/ConceptsShared.qll | 16 ++++++++-------- .../lib/codeql/rust/internal/ConceptsShared.qll | 16 ++++++++-------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll index 135f830e47dc..1b13e4ebb17e 100644 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll +++ b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll @@ -30,7 +30,7 @@ module Cryptography { class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to refine existing API models. If you want to model new APIs, @@ -40,7 +40,7 @@ module Cryptography { /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ DataFlow::Node getInitialization() { result = super.getInitialization() } /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ @@ -61,14 +61,14 @@ module Cryptography { /** Provides classes for modeling new applications of a cryptographic algorithms. */ module CryptographicOperation { /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `CryptographicOperation` instead. */ abstract class Range extends DataFlow::Node { - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ abstract DataFlow::Node getInitialization(); /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ @@ -118,14 +118,14 @@ module Http { /** Provides classes for modeling HTTP clients. */ module Client { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to refine existing API models. If you want to model new APIs, * extend `Http::Client::Request::Range` instead. */ class Request extends DataFlow::Node instanceof Request::Range { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } @@ -150,14 +150,14 @@ module Http { /** Provides a class for modeling new HTTP requests. */ module Request { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `Http::Client::Request` instead. */ abstract class Range extends DataFlow::Node { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ abstract DataFlow::Node getAUrlPart(); diff --git a/python/ql/lib/semmle/python/internal/ConceptsShared.qll b/python/ql/lib/semmle/python/internal/ConceptsShared.qll index 135f830e47dc..1b13e4ebb17e 100644 --- a/python/ql/lib/semmle/python/internal/ConceptsShared.qll +++ b/python/ql/lib/semmle/python/internal/ConceptsShared.qll @@ -30,7 +30,7 @@ module Cryptography { class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to refine existing API models. If you want to model new APIs, @@ -40,7 +40,7 @@ module Cryptography { /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ DataFlow::Node getInitialization() { result = super.getInitialization() } /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ @@ -61,14 +61,14 @@ module Cryptography { /** Provides classes for modeling new applications of a cryptographic algorithms. */ module CryptographicOperation { /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `CryptographicOperation` instead. */ abstract class Range extends DataFlow::Node { - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ abstract DataFlow::Node getInitialization(); /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ @@ -118,14 +118,14 @@ module Http { /** Provides classes for modeling HTTP clients. */ module Client { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to refine existing API models. If you want to model new APIs, * extend `Http::Client::Request::Range` instead. */ class Request extends DataFlow::Node instanceof Request::Range { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } @@ -150,14 +150,14 @@ module Http { /** Provides a class for modeling new HTTP requests. */ module Request { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `Http::Client::Request` instead. */ abstract class Range extends DataFlow::Node { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ abstract DataFlow::Node getAUrlPart(); diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll index 135f830e47dc..1b13e4ebb17e 100644 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll +++ b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll @@ -30,7 +30,7 @@ module Cryptography { class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to refine existing API models. If you want to model new APIs, @@ -40,7 +40,7 @@ module Cryptography { /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ DataFlow::Node getInitialization() { result = super.getInitialization() } /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ @@ -61,14 +61,14 @@ module Cryptography { /** Provides classes for modeling new applications of a cryptographic algorithms. */ module CryptographicOperation { /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `CryptographicOperation` instead. */ abstract class Range extends DataFlow::Node { - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ abstract DataFlow::Node getInitialization(); /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ @@ -118,14 +118,14 @@ module Http { /** Provides classes for modeling HTTP clients. */ module Client { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to refine existing API models. If you want to model new APIs, * extend `Http::Client::Request::Range` instead. */ class Request extends DataFlow::Node instanceof Request::Range { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } @@ -150,14 +150,14 @@ module Http { /** Provides a class for modeling new HTTP requests. */ module Request { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `Http::Client::Request` instead. */ abstract class Range extends DataFlow::Node { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ abstract DataFlow::Node getAUrlPart(); diff --git a/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll index 135f830e47dc..1b13e4ebb17e 100644 --- a/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll +++ b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll @@ -30,7 +30,7 @@ module Cryptography { class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to refine existing API models. If you want to model new APIs, @@ -40,7 +40,7 @@ module Cryptography { /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ DataFlow::Node getInitialization() { result = super.getInitialization() } /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ @@ -61,14 +61,14 @@ module Cryptography { /** Provides classes for modeling new applications of a cryptographic algorithms. */ module CryptographicOperation { /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `CryptographicOperation` instead. */ abstract class Range extends DataFlow::Node { - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ abstract DataFlow::Node getInitialization(); /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ @@ -118,14 +118,14 @@ module Http { /** Provides classes for modeling HTTP clients. */ module Client { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to refine existing API models. If you want to model new APIs, * extend `Http::Client::Request::Range` instead. */ class Request extends DataFlow::Node instanceof Request::Range { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } @@ -150,14 +150,14 @@ module Http { /** Provides a class for modeling new HTTP requests. */ module Request { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `Http::Client::Request` instead. */ abstract class Range extends DataFlow::Node { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ abstract DataFlow::Node getAUrlPart();