mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
WIP
This commit is contained in:
@@ -6,8 +6,6 @@ import codeql.util.Location
|
||||
import codeql.util.Option
|
||||
|
||||
signature module InputSig<LocationSig Location> {
|
||||
class KnownUnknownLocation extends Location;
|
||||
|
||||
class LocatableElement {
|
||||
Location getLocation();
|
||||
}
|
||||
@@ -16,14 +14,7 @@ signature module InputSig<LocationSig Location> {
|
||||
module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
final class LocatableElement = Input::LocatableElement;
|
||||
|
||||
newtype TNode =
|
||||
TNodeUnknown() or
|
||||
TNodeAsset() or
|
||||
TNodeValue() // currently unused
|
||||
|
||||
class KnownNode = TNodeAsset or TNodeValue;
|
||||
|
||||
abstract class NodeBase extends TNode {
|
||||
abstract class NodeBase instanceof LocatableElement {
|
||||
/**
|
||||
* Returns a string representation of this node, usually the name of the operation/algorithm/property.
|
||||
*/
|
||||
@@ -32,14 +23,19 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
/**
|
||||
* Returns the location of this node in the code.
|
||||
*/
|
||||
abstract Location getLocation();
|
||||
Location getLocation() { result = super.getLocation() }
|
||||
|
||||
/**
|
||||
* Returns the child of this node with the given edge name.
|
||||
*
|
||||
* This predicate is used by derived classes to construct the graph of cryptographic operations.
|
||||
*/
|
||||
NodeBase getChild(string edgeName) { none() }
|
||||
NodeBase getChild(string edgeName) { edgeName = "origin" and result = this.getOrigin() }
|
||||
|
||||
/**
|
||||
* Gets the origin of this node, e.g., a string literal in source describing it.
|
||||
*/
|
||||
NodeBase getOrigin() { none() }
|
||||
|
||||
/**
|
||||
* Returns the parent of this node.
|
||||
@@ -47,30 +43,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
final NodeBase getAParent() { result.getChild(_) = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing an unknown value.
|
||||
*
|
||||
* If a property should have a value but that value is unknown, `UnknownNode` to represent that value.
|
||||
*/
|
||||
final class UnknownNode extends NodeBase, TNodeUnknown {
|
||||
override string toString() { result = "unknown" }
|
||||
|
||||
override Location getLocation() { result instanceof Input::KnownUnknownLocation }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node with a known location in the code.
|
||||
*/
|
||||
abstract class LocatableNode extends NodeBase, TNodeAsset {
|
||||
abstract LocatableElement toElement();
|
||||
|
||||
override Location getLocation() { result = this.toElement().getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a known asset, i.e., an algorithm, operation, or property.
|
||||
*/
|
||||
class Asset = LocatableNode;
|
||||
class Asset = NodeBase;
|
||||
|
||||
/**
|
||||
* A cryptographic operation, such as hashing or encryption.
|
||||
@@ -79,12 +52,6 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
/**
|
||||
* Gets the algorithm associated with this operation.
|
||||
*/
|
||||
private NodeBase getAlgorithmOrUnknown() {
|
||||
if exists(this.getAlgorithm())
|
||||
then result = this.getAlgorithm()
|
||||
else result instanceof UnknownNode
|
||||
}
|
||||
|
||||
abstract Algorithm getAlgorithm();
|
||||
|
||||
/**
|
||||
@@ -95,8 +62,10 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
final override string toString() { result = this.getOperationName() }
|
||||
|
||||
override NodeBase getChild(string edgeName) {
|
||||
result = super.getChild(edgeName)
|
||||
or
|
||||
edgeName = "algorithm" and
|
||||
this.getAlgorithmOrUnknown() = result
|
||||
if exists(this.getAlgorithm()) then result = this.getAlgorithm() else result = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +94,10 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
*/
|
||||
abstract class HashAlgorithm extends Algorithm { }
|
||||
|
||||
abstract class SHA1 extends HashAlgorithm {
|
||||
override string getAlgorithmName() { result = "SHA1" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An operation that derives one or more keys from an input value.
|
||||
*/
|
||||
@@ -142,24 +115,27 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
/**
|
||||
* HKDF Extract+Expand key derivation function.
|
||||
*/
|
||||
abstract class HKDFAlgorithm extends KeyDerivationAlgorithm {
|
||||
abstract class HKDF extends KeyDerivationAlgorithm {
|
||||
final override string getAlgorithmName() { result = "HKDF" }
|
||||
|
||||
private NodeBase getHashAlgorithmOrUnknown() {
|
||||
if exists(this.getHashAlgorithm())
|
||||
then result = this.getHashAlgorithm()
|
||||
else result instanceof UnknownNode
|
||||
}
|
||||
|
||||
abstract HashAlgorithm getHashAlgorithm();
|
||||
|
||||
/**
|
||||
* digest:HashAlgorithm
|
||||
*/
|
||||
override NodeBase getChild(string edgeName) {
|
||||
result = super.getChild(edgeName)
|
||||
or
|
||||
edgeName = "digest" and result = this.getHashAlgorithmOrUnknown()
|
||||
edgeName = "digest" and result = this.getHashAlgorithm()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PKCS12KDF extends KeyDerivationAlgorithm {
|
||||
final override string getAlgorithmName() { result = "PKCS12KDF" }
|
||||
|
||||
abstract HashAlgorithm getHashAlgorithm();
|
||||
|
||||
override NodeBase getChild(string edgeName) {
|
||||
result = super.getChild(edgeName)
|
||||
or
|
||||
edgeName = "digest" and result = this.getHashAlgorithm()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
125
cpp/ql/lib/experimental/Quantum/BaseBackup.qll
Normal file
125
cpp/ql/lib/experimental/Quantum/BaseBackup.qll
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* A language-independent library for reasoning about cryptography.
|
||||
*/
|
||||
|
||||
import codeql.util.Location
|
||||
import codeql.util.Option
|
||||
|
||||
signature module InputSig<LocationSig Location> {
|
||||
class KnownUnknownLocation extends Location;
|
||||
|
||||
class LocatableElement {
|
||||
Location getLocation();
|
||||
}
|
||||
}
|
||||
|
||||
// An operation = a specific loc in code
|
||||
// An algorithm
|
||||
// Properties
|
||||
// Node -> Operation -> Algorithm -> Symmetric -> SpecificSymmetricAlgo
|
||||
// -[Language-Specific]-> LibrarySymmetricAlgo -> Properties
|
||||
// For example (nsted newtypes):
|
||||
/*
|
||||
* newtype for each algo, and each one of those would have params for their properties
|
||||
* implementation: optional/range for example
|
||||
*
|
||||
*
|
||||
*
|
||||
* /**
|
||||
* Constructs an `Option` type that is a disjoint union of the given type and an
|
||||
* additional singleton element.
|
||||
*/
|
||||
|
||||
module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
newtype TNode =
|
||||
TNodeUnknown() or
|
||||
TNodeAlgorithm() or
|
||||
TNodeOperation()
|
||||
|
||||
/*
|
||||
* A cryptographic asset in code, i.e., an algorithm, operation, property, or known unknown.
|
||||
*/
|
||||
|
||||
abstract class Node extends TNode {
|
||||
// this would then extend LanguageNode
|
||||
abstract Location getLocation();
|
||||
|
||||
abstract string toString();
|
||||
|
||||
abstract Node getChild(int childIndex);
|
||||
|
||||
final Node getAChild() { result = this.getChild(_) }
|
||||
|
||||
final Node getAParent() { result.getAChild() = this }
|
||||
}
|
||||
|
||||
final class KnownUnknown extends Node, TNodeUnknown {
|
||||
override string toString() { result = "unknown" }
|
||||
|
||||
override Node getChild(int childIndex) { none() }
|
||||
|
||||
override Location getLocation() { result instanceof Input::KnownUnknownLocation }
|
||||
}
|
||||
|
||||
abstract class Operation extends Node, TNodeOperation {
|
||||
/**
|
||||
* Gets the algorithm associated with this operation.
|
||||
*/
|
||||
abstract Node getAlgorithm();
|
||||
|
||||
/**
|
||||
* Gets the name of this operation, e.g., "hash" or "encrypt".
|
||||
*/
|
||||
abstract string getOperationName();
|
||||
|
||||
final override Node getChild(int childIndex) { childIndex = 0 and result = this.getAlgorithm() }
|
||||
|
||||
final override string toString() { result = this.getOperationName() }
|
||||
}
|
||||
|
||||
abstract class Algorithm extends Node, TNodeAlgorithm {
|
||||
/**
|
||||
* Gets the name of this algorithm, e.g., "AES" or "SHA".
|
||||
*/
|
||||
abstract string getAlgorithmName();
|
||||
}
|
||||
|
||||
/**
|
||||
* A hashing operation that processes data to generate a hash value.
|
||||
* This operation takes an input message of arbitrary content and length and produces a fixed-size
|
||||
* hash value as the output using a specified hashing algorithm.
|
||||
*/
|
||||
abstract class HashOperation extends Operation {
|
||||
abstract override HashAlgorithm getAlgorithm();
|
||||
|
||||
override string getOperationName() { result = "hash" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A hashing algorithm that transforms variable-length input into a fixed-size hash value.
|
||||
*/
|
||||
abstract class HashAlgorithm extends Algorithm { }
|
||||
|
||||
/**
|
||||
* An operation that derives one or more keys from an input value.
|
||||
*/
|
||||
abstract class KeyDerivationOperation extends Operation {
|
||||
override string getOperationName() { result = "key derivation" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An algorithm that derives one or more keys from an input value.
|
||||
*/
|
||||
abstract class KeyDerivationAlgorithm extends Algorithm {
|
||||
abstract override string getAlgorithmName();
|
||||
}
|
||||
|
||||
/**
|
||||
* HKDF Extract+Expand key derivation function.
|
||||
*/
|
||||
abstract class HKDFAlgorithm extends KeyDerivationAlgorithm {
|
||||
final override string getAlgorithmName() { result = "HKDF" }
|
||||
|
||||
abstract Node getDigestAlgorithm();
|
||||
}
|
||||
}
|
||||
10
cpp/ql/lib/experimental/Quantum/Language.qll
Normal file
10
cpp/ql/lib/experimental/Quantum/Language.qll
Normal file
@@ -0,0 +1,10 @@
|
||||
private import Base
|
||||
private import cpp as Lang
|
||||
|
||||
module CryptoInput implements InputSig<Lang::Location> {
|
||||
class LocatableElement = Lang::Locatable;
|
||||
}
|
||||
|
||||
module Crypto = CryptographyBase<Lang::Location, CryptoInput>;
|
||||
|
||||
import OpenSSL
|
||||
100
cpp/ql/lib/experimental/Quantum/OpenSSL.qll
Normal file
100
cpp/ql/lib/experimental/Quantum/OpenSSL.qll
Normal file
@@ -0,0 +1,100 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
module OpenSSLModel {
|
||||
import Language
|
||||
|
||||
abstract class KeyDerivationOperation extends Crypto::KeyDerivationOperation { }
|
||||
|
||||
class SHA1Algo extends Crypto::SHA1 instanceof MacroAccess {
|
||||
SHA1Algo() { this.getMacro().getName() = "SN_sha1" }
|
||||
}
|
||||
|
||||
module AlgorithmToEVPKeyDeriveConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof KeyDerivationAlgorithm }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(EVP_KDF_derive kdo | sink.asExpr() = kdo.getAlgorithmArg())
|
||||
}
|
||||
}
|
||||
|
||||
module AlgorithmToEVPKeyDeriveFlow = DataFlow::Global<AlgorithmToEVPKeyDeriveConfig>;
|
||||
|
||||
predicate algorithm_to_EVP_KDF_derive(Crypto::Algorithm algo, EVP_KDF_derive derive) {
|
||||
algo.(Expr).getEnclosingFunction() = derive.(Expr).getEnclosingFunction()
|
||||
}
|
||||
|
||||
class EVP_KDF_derive extends KeyDerivationOperation instanceof FunctionCall {
|
||||
EVP_KDF_derive() { this.getTarget().getName() = "EVP_KDF_derive" }
|
||||
|
||||
override Crypto::Algorithm getAlgorithm() { algorithm_to_EVP_KDF_derive(result, this) }
|
||||
|
||||
Expr getAlgorithmArg() { result = this.(FunctionCall).getArgument(3) }
|
||||
}
|
||||
|
||||
abstract class KeyDerivationAlgorithm extends Crypto::KeyDerivationAlgorithm { }
|
||||
|
||||
class EVP_KDF_fetch_Call extends FunctionCall {
|
||||
EVP_KDF_fetch_Call() { this.getTarget().getName() = "EVP_KDF_fetch" }
|
||||
|
||||
Expr getAlgorithmArg() { result = this.getArgument(1) }
|
||||
}
|
||||
|
||||
predicate kdf_names(string algo) { algo = ["HKDF", "PKCS12KDF"] }
|
||||
|
||||
class KDFAlgorithmStringLiteral extends Crypto::NodeBase instanceof StringLiteral {
|
||||
KDFAlgorithmStringLiteral() { kdf_names(this.getValue().toUpperCase()) }
|
||||
|
||||
override string toString() { result = this.(StringLiteral).toString() }
|
||||
|
||||
string getValue() { result = this.(StringLiteral).getValue() }
|
||||
}
|
||||
|
||||
private module AlgorithmStringToFetchConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof KDFAlgorithmStringLiteral }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(EVP_KDF_fetch_Call call | sink.asExpr() = call.getAlgorithmArg())
|
||||
}
|
||||
}
|
||||
|
||||
module AlgorithmStringToFetchFlow = DataFlow::Global<AlgorithmStringToFetchConfig>;
|
||||
|
||||
predicate algorithmStringToKDFFetchArgFlow(string name, KDFAlgorithmStringLiteral origin, Expr arg) {
|
||||
exists(EVP_KDF_fetch_Call sinkCall |
|
||||
origin.getValue().toUpperCase() = name and
|
||||
arg = sinkCall.getAlgorithmArg() and
|
||||
AlgorithmStringToFetchFlow::flow(DataFlow::exprNode(origin), DataFlow::exprNode(arg))
|
||||
)
|
||||
}
|
||||
|
||||
class HKDF extends KeyDerivationAlgorithm, Crypto::HKDF instanceof Expr {
|
||||
KDFAlgorithmStringLiteral origin;
|
||||
|
||||
HKDF() { algorithmStringToKDFFetchArgFlow("HKDF", origin, this) }
|
||||
|
||||
override Crypto::HashAlgorithm getHashAlgorithm() { none() }
|
||||
|
||||
override Crypto::NodeBase getOrigin() { result = origin }
|
||||
}
|
||||
|
||||
class TestKeyDerivationOperationHacky extends KeyDerivationOperation instanceof FunctionCall {
|
||||
HKDF hkdf;
|
||||
|
||||
TestKeyDerivationOperationHacky() {
|
||||
this.getEnclosingFunction() = hkdf.(Expr).getEnclosingFunction()
|
||||
}
|
||||
|
||||
override Crypto::KeyDerivationAlgorithm getAlgorithm() { result = hkdf }
|
||||
}
|
||||
|
||||
class PKCS12KDF extends KeyDerivationAlgorithm, Crypto::PKCS12KDF instanceof Expr {
|
||||
KDFAlgorithmStringLiteral origin;
|
||||
|
||||
PKCS12KDF() { algorithmStringToKDFFetchArgFlow("PKCS12KDF", origin, this) }
|
||||
|
||||
override Crypto::HashAlgorithm getHashAlgorithm() { none() }
|
||||
|
||||
override Crypto::NodeBase getOrigin() { result = origin }
|
||||
}
|
||||
}
|
||||
17
cpp/ql/src/experimental/Quantum/Test.ql
Normal file
17
cpp/ql/src/experimental/Quantum/Test.ql
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @name "PQC Test"
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import experimental.Quantum.Language
|
||||
|
||||
query predicate nodes(Crypto::NodeBase node) { any() }
|
||||
|
||||
query predicate edges(Crypto::NodeBase source, Crypto::NodeBase target, string key, string value) {
|
||||
target = source.getChild(value) and
|
||||
key = "semmle.label"
|
||||
}
|
||||
|
||||
query predicate graphProperties(string key, string value) {
|
||||
key = "semmle.graphKind" and value = "tree"
|
||||
}
|
||||
8
cpp/ql/src/experimental/Quantum/Test2.ql
Normal file
8
cpp/ql/src/experimental/Quantum/Test2.ql
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @name "PQC Test"
|
||||
*/
|
||||
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::KeyDerivationAlgorithm n
|
||||
select n
|
||||
Reference in New Issue
Block a user