Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
395d54b
Create Base.qll
nicolaswill Jan 23, 2025
1a7d8cb
WIP
nicolaswill Jan 24, 2025
7836234
WIP: hash types example and documentation
nicolaswill Jan 24, 2025
e027b0e
WIP: add properties
nicolaswill Jan 28, 2025
0cd3df9
Concepts for elliptic cureve and misc. updates.
bdrodes Jan 29, 2025
9af18bc
WIP: add dgml/dot output/remove test code
nicolaswill Jan 29, 2025
69a6385
Update CBOMGraph.ql
nicolaswill Jan 29, 2025
5f355c7
Add first sample JCA encryption model
knewbury01 Feb 4, 2025
86e51da
Improve JCA aes alg model, add test
knewbury01 Feb 5, 2025
efcf7ea
Add broken crypto query
knewbury01 Feb 5, 2025
cd70acd
Merge pull request #1 from nicolaswill/brodes/experiments
nicolaswill Feb 6, 2025
2e12bb5
Merge branch 'nic/crypto-test' into knewbury01/JCA-sample
knewbury01 Feb 6, 2025
3dc28c2
Move language-agnostic model to shared library
nicolaswill Feb 6, 2025
7a96f56
Merge pull request #3 from nicolaswill/nicolaswill/shared-crypto-library
nicolaswill Feb 6, 2025
60d931a
Update progress on JCA
knewbury01 Feb 7, 2025
6005437
Update JCA model with flow to call as AESuse and format JCA model
knewbury01 Feb 10, 2025
9c8ade7
Merge branch 'nic/crypto-test' into knewbury01/JCA-sample
knewbury01 Feb 10, 2025
59208bd
Update JCA model to use shared lib
knewbury01 Feb 10, 2025
1a12fb3
Update JCA model, refactor modes
knewbury01 Feb 10, 2025
4d44755
Refactor Model and CBOM print queries
nicolaswill Feb 11, 2025
874e3b5
Modify model to use newtypes, expand modeling
nicolaswill Feb 12, 2025
b777a22
Expand model and specialize newtype relations
nicolaswill Feb 14, 2025
df01fa7
Expand model and JCA modeling
nicolaswill Feb 16, 2025
8707e4d
Continue Artifact data-flow WIP
nicolaswill Feb 18, 2025
3871c6a
Adding support for encryption operation detection.
bdrodes Feb 18, 2025
9ee4a7a
Adding a sketch for a CipherOperation concept to model encryption/dec…
bdrodes Feb 20, 2025
83dc5b9
Fixing type bug
bdrodes Feb 20, 2025
011ed3f
Simplifying additional flow step logic.
bdrodes Feb 20, 2025
9ac9252
Adding a todo
bdrodes Feb 20, 2025
86cab46
Misc. updates to support all JCA cipher operations, including wrap, u…
bdrodes Feb 21, 2025
2b0b927
Add Nonce association to Operation, update graph
nicolaswill Feb 24, 2025
95544e2
Add model and sample query for constants used in key specs
knewbury01 Feb 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions cpp/ql/lib/experimental/Quantum/Language.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
private import codeql.cryptography.Model
private import cpp as Lang

module CryptoInput implements InputSig<Lang::Location> {
class LocatableElement = Lang::Locatable;

class UnknownLocation = Lang::UnknownDefaultLocation;
}

module Crypto = CryptographyBase<Lang::Location, CryptoInput>;

import OpenSSL
244 changes: 244 additions & 0 deletions cpp/ql/lib/experimental/Quantum/OpenSSL.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
import cpp
import semmle.code.cpp.dataflow.new.DataFlow

module OpenSSLModel {

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in OpenSSLModel should be PascalCase/camelCase.
import Language

/**
* Hash function references in OpenSSL.
*/
predicate hash_ref_type_mapping_known(string name, Crypto::THashType algo) {
// `ma` name has an LN_ or SN_ prefix, which we want to ignore
// capture any name after the _ prefix using regex matching
name = ["sha1", "sha160"] and algo instanceof Crypto::SHA1
or
name = ["sha224", "sha256", "sha384", "sha512"] and algo instanceof Crypto::SHA2
or
name = ["sha3-224", "sha3-256", "sha3-384", "sha3-512"] and algo instanceof Crypto::SHA3

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in AlgorithmToEVPKeyDeriveConfig should be PascalCase/camelCase.
or
name = "md2" and algo instanceof Crypto::MD2
or
name = "md4" and algo instanceof Crypto::MD4
or
name = "md5" and algo instanceof Crypto::MD5
or
name = "ripemd160" and algo instanceof Crypto::RIPEMD160

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in AlgorithmToEVPKeyDeriveFlow should be PascalCase/camelCase.
or
name = "whirlpool" and algo instanceof Crypto::WHIRLPOOL
}

predicate hash_ref_type_mapping(FunctionCallOrMacroAccess ref, string name, Crypto::THashType algo) {
name = ref.getTargetName().regexpCapture("(?:SN_|LN_|EVP_)([a-z0-9]+)", 1) and
hash_ref_type_mapping_known(name, algo)
}

class FunctionCallOrMacroAccess extends Element {
FunctionCallOrMacroAccess() { this instanceof FunctionCall or this instanceof MacroAccess }

string getTargetName() {
result = this.(FunctionCall).getTarget().getName()
or
result = this.(MacroAccess).getMacroName()
}
}

class HashAlgorithmCallOrMacro extends Crypto::HashAlgorithmInstance instanceof FunctionCallOrMacroAccess
{
HashAlgorithmCallOrMacro() { hash_ref_type_mapping(this, _, _) }

string getTargetName() { result = this.(FunctionCallOrMacroAccess).getTargetName() }
}

class HashAlgorithm extends Crypto::HashAlgorithm {
HashAlgorithmCallOrMacro instance;

HashAlgorithm() { this = Crypto::THashAlgorithm(instance) }

override string getSHA2OrSHA3DigestSize(Location location) {
(
this.getHashType() instanceof Crypto::SHA2 or
this.getHashType() instanceof Crypto::SHA3
) and
exists(string name |
hash_ref_type_mapping(instance, name, this.getHashType()) and
result = name.regexpFind("\\d{3}", 0, _) and
location = instance.getLocation()
)
}

override string getRawAlgorithmName() { result = instance.getTargetName() }

override Crypto::THashType getHashType() { hash_ref_type_mapping(instance, _, result) }

Element getInstance() { result = instance }

override Location getLocation() { result = instance.getLocation() }
}

/**
* Data-flow configuration for key derivation algorithm flow to EVP_KDF_derive.
*/
module AlgorithmToEVPKeyDeriveConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr() = any(KeyDerivationAlgorithm a).getInstance()
}

predicate isSink(DataFlow::Node sink) {
exists(EVP_KDF_derive kdo |
sink.asExpr() = kdo.getCall().getAlgorithmArg()
or
sink.asExpr() = kdo.getCall().getContextArg() // via `EVP_KDF_CTX_set_params`
)
}

predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
none() // TODO
}
}

module AlgorithmToEVPKeyDeriveFlow = DataFlow::Global<AlgorithmToEVPKeyDeriveConfig>;

predicate algorithm_to_EVP_KDF_derive(KeyDerivationAlgorithm algo, EVP_KDF_derive derive) {
none()
}

/**
* Key derivation operation (e.g., `EVP_KDF_derive`)
*/

Check warning

Code scanning / CodeQL

Class QLDoc style. Warning

The QLDoc for a class should start with 'A', 'An', or 'The'.
class EVP_KDF_derive_FunctionCall extends Crypto::KeyDerivationOperationInstance instanceof FunctionCall
{
EVP_KDF_derive_FunctionCall() { this.getTarget().getName() = "EVP_KDF_derive" }

Expr getAlgorithmArg() { result = super.getArgument(3) }

Expr getContextArg() { result = super.getArgument(0) }
}

class EVP_KDF_derive extends Crypto::KeyDerivationOperation {
EVP_KDF_derive_FunctionCall instance;

EVP_KDF_derive() { this = Crypto::TKeyDerivationOperation(instance) }

override Crypto::Algorithm getAlgorithm() { algorithm_to_EVP_KDF_derive(result, this) }

EVP_KDF_derive_FunctionCall getCall() { result = instance }
}

/**
* Key derivation algorithm nodes
*/

Check warning

Code scanning / CodeQL

Class QLDoc style. Warning

The QLDoc for a class should start with 'A', 'An', or 'The'.
abstract class KeyDerivationAlgorithm extends Crypto::KeyDerivationAlgorithm {
abstract Expr getInstance();
}

/**
* `EVP_KDF_fetch` returns a key derivation algorithm.
*/

Check warning

Code scanning / CodeQL

Class QLDoc style. Warning

The QLDoc for a class should start with 'A', 'An', or 'The'.
class EVP_KDF_fetch_Call extends FunctionCall {
EVP_KDF_fetch_Call() { this.getTarget().getName() = "EVP_KDF_fetch" }

Expr getAlgorithmArg() { result = this.getArgument(1) }
}

class EVP_KDF_fetch_AlgorithmArg extends Crypto::KeyDerivationAlgorithmInstance instanceof Expr {
EVP_KDF_fetch_AlgorithmArg() { exists(EVP_KDF_fetch_Call call | this = call.getAlgorithmArg()) }
}

predicate kdf_names(string algo) { algo = ["HKDF", "PKCS12KDF", "PBKDF2"] }

class KDFAlgorithmStringLiteral extends StringLiteral {

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in KDFAlgorithmStringLiteral should be PascalCase/camelCase.
KDFAlgorithmStringLiteral() { kdf_names(this.getValue().toUpperCase()) }
}

private module AlgorithmStringToFetchConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof KDFAlgorithmStringLiteral }

predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof EVP_KDF_fetch_AlgorithmArg }
}

module AlgorithmStringToFetchFlow = DataFlow::Global<AlgorithmStringToFetchConfig>;

predicate algorithmStringToKDFFetchArgFlow(

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in algorithmStringToKDFFetchArgFlow should be PascalCase/camelCase.
string name, KDFAlgorithmStringLiteral origin, EVP_KDF_fetch_AlgorithmArg arg
) {
origin.getValue().toUpperCase() = name and
AlgorithmStringToFetchFlow::flow(DataFlow::exprNode(origin), DataFlow::exprNode(arg))
}

/**
* HKDF key derivation algorithm.
*/

Check warning

Code scanning / CodeQL

Class QLDoc style. Warning

The QLDoc for a class should start with 'A', 'An', or 'The'.
class HKDF extends KeyDerivationAlgorithm, Crypto::HKDF {
KDFAlgorithmStringLiteral origin;
EVP_KDF_fetch_AlgorithmArg instance;

Check notice

Code scanning / CodeQL

Field only used in CharPred Note

Field is only used in CharPred.

HKDF() {
this = Crypto::TKeyDerivationAlgorithm(instance) and
algorithmStringToKDFFetchArgFlow("HKDF", origin, instance)
}

override string getRawAlgorithmName() { result = origin.getValue() }

override Crypto::HashAlgorithm getHashAlgorithm() { none() }

override Crypto::LocatableElement getOrigin(string name) {
result = origin and name = origin.toString()
}

override Expr getInstance() { result = origin }
}

/**
* PBKDF2 key derivation algorithm.
*/

Check warning

Code scanning / CodeQL

Class QLDoc style. Warning

The QLDoc for a class should start with 'A', 'An', or 'The'.
class PBKDF2 extends KeyDerivationAlgorithm, Crypto::PBKDF2 {
KDFAlgorithmStringLiteral origin;
EVP_KDF_fetch_AlgorithmArg instance;

PBKDF2() {
this = Crypto::TKeyDerivationAlgorithm(instance) and
algorithmStringToKDFFetchArgFlow("PBKDF2", origin, instance)
}

override string getRawAlgorithmName() { result = origin.getValue() }

override string getIterationCount(Location location) { none() } // TODO

override string getKeyLength(Location location) { none() } // TODO

override Crypto::HashAlgorithm getHashAlgorithm() { none() } // TODO

override Crypto::LocatableElement getOrigin(string name) {
result = origin and name = origin.toString()
}

override Expr getInstance() { result = instance }
}

/**
* PKCS12KDF key derivation algorithm.
*/

Check warning

Code scanning / CodeQL

Class QLDoc style. Warning

The QLDoc for a class should start with 'A', 'An', or 'The'.
class PKCS12KDF extends KeyDerivationAlgorithm, Crypto::PKCS12KDF {
KDFAlgorithmStringLiteral origin;
EVP_KDF_fetch_AlgorithmArg instance;

PKCS12KDF() {
this = Crypto::TKeyDerivationAlgorithm(instance) and
algorithmStringToKDFFetchArgFlow("PKCS12KDF", origin, instance)
}

override string getRawAlgorithmName() { result = origin.getValue() }

override string getIterationCount(Location location) { none() } // TODO

override string getIDByte(Location location) { none() } // TODO

override Crypto::HashAlgorithm getHashAlgorithm() { none() } // TODO

override Crypto::LocatableElement getOrigin(string name) {
result = origin and name = origin.toString()
}

override Expr getInstance() { result = instance }
}
}
1 change: 1 addition & 0 deletions cpp/ql/lib/qlpack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ extractor: cpp
library: true
upgrades: upgrades
dependencies:
codeql/cryptography: ${workspace}
codeql/dataflow: ${workspace}
codeql/mad: ${workspace}
codeql/rangeanalysis: ${workspace}
Expand Down
21 changes: 21 additions & 0 deletions cpp/ql/src/experimental/Quantum/PrintCBOMGraph.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @name Print CBOM Graph
* @description Outputs a graph representation of the cryptographic bill of materials.
* This query only supports DGML output, as CodeQL DOT output omits properties.
* @kind graph
* @id cpp/print-cbom-graph
*/

import experimental.Quantum.Language

query predicate nodes(Crypto::NodeBase node, string key, string value) {
Crypto::nodes_graph_impl(node, key, value)
}

query predicate edges(Crypto::NodeBase source, Crypto::NodeBase target, string key, string value) {
Crypto::edges_graph_impl(source, target, key, value)
}

query predicate graphProperties(string key, string value) {
key = "semmle.graphKind" and value = "graph"
}
8 changes: 8 additions & 0 deletions cpp/ql/src/experimental/Quantum/Test2.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @name "PQC Test"
*/

import experimental.Quantum.Language

from Crypto::NodeBase node
select node
Loading
Loading