Skip to content

Commit 1a7d8cb

Browse files
committed
WIP
1 parent 395d54b commit 1a7d8cb

File tree

6 files changed

+288
-52
lines changed

6 files changed

+288
-52
lines changed

cpp/ql/lib/experimental/Quantum/Base.qll

Lines changed: 28 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import codeql.util.Location
66
import codeql.util.Option
77

88
signature module InputSig<LocationSig Location> {
9-
class KnownUnknownLocation extends Location;
10-
119
class LocatableElement {
1210
Location getLocation();
1311
}
@@ -16,14 +14,7 @@ signature module InputSig<LocationSig Location> {
1614
module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
1715
final class LocatableElement = Input::LocatableElement;
1816

19-
newtype TNode =
20-
TNodeUnknown() or
21-
TNodeAsset() or
22-
TNodeValue() // currently unused
23-
24-
class KnownNode = TNodeAsset or TNodeValue;
25-
26-
abstract class NodeBase extends TNode {
17+
abstract class NodeBase instanceof LocatableElement {
2718
/**
2819
* Returns a string representation of this node, usually the name of the operation/algorithm/property.
2920
*/
@@ -32,45 +23,27 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
3223
/**
3324
* Returns the location of this node in the code.
3425
*/
35-
abstract Location getLocation();
26+
Location getLocation() { result = super.getLocation() }
3627

3728
/**
3829
* Returns the child of this node with the given edge name.
3930
*
4031
* This predicate is used by derived classes to construct the graph of cryptographic operations.
4132
*/
42-
NodeBase getChild(string edgeName) { none() }
33+
NodeBase getChild(string edgeName) { edgeName = "origin" and result = this.getOrigin() }
34+
35+
/**
36+
* Gets the origin of this node, e.g., a string literal in source describing it.
37+
*/
38+
NodeBase getOrigin() { none() }
4339

4440
/**
4541
* Returns the parent of this node.
4642
*/
4743
final NodeBase getAParent() { result.getChild(_) = this }
4844
}
4945

50-
/**
51-
* A node representing an unknown value.
52-
*
53-
* If a property should have a value but that value is unknown, `UnknownNode` to represent that value.
54-
*/
55-
final class UnknownNode extends NodeBase, TNodeUnknown {
56-
override string toString() { result = "unknown" }
57-
58-
override Location getLocation() { result instanceof Input::KnownUnknownLocation }
59-
}
60-
61-
/**
62-
* A node with a known location in the code.
63-
*/
64-
abstract class LocatableNode extends NodeBase, TNodeAsset {
65-
abstract LocatableElement toElement();
66-
67-
override Location getLocation() { result = this.toElement().getLocation() }
68-
}
69-
70-
/**
71-
* A node representing a known asset, i.e., an algorithm, operation, or property.
72-
*/
73-
class Asset = LocatableNode;
46+
class Asset = NodeBase;
7447

7548
/**
7649
* A cryptographic operation, such as hashing or encryption.
@@ -79,12 +52,6 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
7952
/**
8053
* Gets the algorithm associated with this operation.
8154
*/
82-
private NodeBase getAlgorithmOrUnknown() {
83-
if exists(this.getAlgorithm())
84-
then result = this.getAlgorithm()
85-
else result instanceof UnknownNode
86-
}
87-
8855
abstract Algorithm getAlgorithm();
8956

9057
/**
@@ -95,8 +62,10 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
9562
final override string toString() { result = this.getOperationName() }
9663

9764
override NodeBase getChild(string edgeName) {
65+
result = super.getChild(edgeName)
66+
or
9867
edgeName = "algorithm" and
99-
this.getAlgorithmOrUnknown() = result
68+
if exists(this.getAlgorithm()) then result = this.getAlgorithm() else result = this
10069
}
10170
}
10271

@@ -125,6 +94,10 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
12594
*/
12695
abstract class HashAlgorithm extends Algorithm { }
12796

97+
abstract class SHA1 extends HashAlgorithm {
98+
override string getAlgorithmName() { result = "SHA1" }
99+
}
100+
128101
/**
129102
* An operation that derives one or more keys from an input value.
130103
*/
@@ -142,24 +115,27 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
142115
/**
143116
* HKDF Extract+Expand key derivation function.
144117
*/
145-
abstract class HKDFAlgorithm extends KeyDerivationAlgorithm {
118+
abstract class HKDF extends KeyDerivationAlgorithm {
146119
final override string getAlgorithmName() { result = "HKDF" }
147120

148-
private NodeBase getHashAlgorithmOrUnknown() {
149-
if exists(this.getHashAlgorithm())
150-
then result = this.getHashAlgorithm()
151-
else result instanceof UnknownNode
121+
abstract HashAlgorithm getHashAlgorithm();
122+
123+
override NodeBase getChild(string edgeName) {
124+
result = super.getChild(edgeName)
125+
or
126+
edgeName = "digest" and result = this.getHashAlgorithm()
152127
}
128+
}
129+
130+
abstract class PKCS12KDF extends KeyDerivationAlgorithm {
131+
final override string getAlgorithmName() { result = "PKCS12KDF" }
153132

154133
abstract HashAlgorithm getHashAlgorithm();
155134

156-
/**
157-
* digest:HashAlgorithm
158-
*/
159135
override NodeBase getChild(string edgeName) {
160136
result = super.getChild(edgeName)
161137
or
162-
edgeName = "digest" and result = this.getHashAlgorithmOrUnknown()
138+
edgeName = "digest" and result = this.getHashAlgorithm()
163139
}
164140
}
165141
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* A language-independent library for reasoning about cryptography.
3+
*/
4+
5+
import codeql.util.Location
6+
import codeql.util.Option
7+
8+
signature module InputSig<LocationSig Location> {
9+
class KnownUnknownLocation extends Location;
10+
11+
class LocatableElement {
12+
Location getLocation();
13+
}
14+
}
15+
16+
// An operation = a specific loc in code
17+
// An algorithm
18+
// Properties
19+
// Node -> Operation -> Algorithm -> Symmetric -> SpecificSymmetricAlgo
20+
// -[Language-Specific]-> LibrarySymmetricAlgo -> Properties
21+
// For example (nsted newtypes):
22+
/*
23+
* newtype for each algo, and each one of those would have params for their properties
24+
* implementation: optional/range for example
25+
*
26+
*
27+
*
28+
* /**
29+
* Constructs an `Option` type that is a disjoint union of the given type and an
30+
* additional singleton element.
31+
*/
32+
33+
module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
34+
newtype TNode =
35+
TNodeUnknown() or
36+
TNodeAlgorithm() or
37+
TNodeOperation()
38+
39+
/*
40+
* A cryptographic asset in code, i.e., an algorithm, operation, property, or known unknown.
41+
*/
42+
43+
abstract class Node extends TNode {
44+
// this would then extend LanguageNode
45+
abstract Location getLocation();
46+
47+
abstract string toString();
48+
49+
abstract Node getChild(int childIndex);
50+
51+
final Node getAChild() { result = this.getChild(_) }
52+
53+
final Node getAParent() { result.getAChild() = this }
54+
}
55+
56+
final class KnownUnknown extends Node, TNodeUnknown {
57+
override string toString() { result = "unknown" }
58+
59+
override Node getChild(int childIndex) { none() }
60+
61+
override Location getLocation() { result instanceof Input::KnownUnknownLocation }
62+
}
63+
64+
abstract class Operation extends Node, TNodeOperation {
65+
/**
66+
* Gets the algorithm associated with this operation.
67+
*/
68+
abstract Node getAlgorithm();
69+
70+
/**
71+
* Gets the name of this operation, e.g., "hash" or "encrypt".
72+
*/
73+
abstract string getOperationName();
74+
75+
final override Node getChild(int childIndex) { childIndex = 0 and result = this.getAlgorithm() }
76+
77+
final override string toString() { result = this.getOperationName() }
78+
}
79+
80+
abstract class Algorithm extends Node, TNodeAlgorithm {
81+
/**
82+
* Gets the name of this algorithm, e.g., "AES" or "SHA".
83+
*/
84+
abstract string getAlgorithmName();
85+
}
86+
87+
/**
88+
* A hashing operation that processes data to generate a hash value.
89+
* This operation takes an input message of arbitrary content and length and produces a fixed-size
90+
* hash value as the output using a specified hashing algorithm.
91+
*/
92+
abstract class HashOperation extends Operation {
93+
abstract override HashAlgorithm getAlgorithm();
94+
95+
override string getOperationName() { result = "hash" }
96+
}
97+
98+
/**
99+
* A hashing algorithm that transforms variable-length input into a fixed-size hash value.
100+
*/
101+
abstract class HashAlgorithm extends Algorithm { }
102+
103+
/**
104+
* An operation that derives one or more keys from an input value.
105+
*/
106+
abstract class KeyDerivationOperation extends Operation {
107+
override string getOperationName() { result = "key derivation" }
108+
}
109+
110+
/**
111+
* An algorithm that derives one or more keys from an input value.
112+
*/
113+
abstract class KeyDerivationAlgorithm extends Algorithm {
114+
abstract override string getAlgorithmName();
115+
}
116+
117+
/**
118+
* HKDF Extract+Expand key derivation function.
119+
*/
120+
abstract class HKDFAlgorithm extends KeyDerivationAlgorithm {
121+
final override string getAlgorithmName() { result = "HKDF" }
122+
123+
abstract Node getDigestAlgorithm();
124+
}
125+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
private import Base
2+
private import cpp as Lang
3+
4+
module CryptoInput implements InputSig<Lang::Location> {
5+
class LocatableElement = Lang::Locatable;
6+
}
7+
8+
module Crypto = CryptographyBase<Lang::Location, CryptoInput>;
9+
10+
import OpenSSL
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import cpp
2+
import semmle.code.cpp.dataflow.new.DataFlow
3+
4+
module OpenSSLModel {
5+
import Language
6+
7+
abstract class KeyDerivationOperation extends Crypto::KeyDerivationOperation { }
8+
9+
class SHA1Algo extends Crypto::SHA1 instanceof MacroAccess {
10+
SHA1Algo() { this.getMacro().getName() = "SN_sha1" }
11+
}
12+
13+
module AlgorithmToEVPKeyDeriveConfig implements DataFlow::ConfigSig {
14+
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof KeyDerivationAlgorithm }
15+
16+
predicate isSink(DataFlow::Node sink) {
17+
exists(EVP_KDF_derive kdo | sink.asExpr() = kdo.getAlgorithmArg())
18+
}
19+
}
20+
21+
module AlgorithmToEVPKeyDeriveFlow = DataFlow::Global<AlgorithmToEVPKeyDeriveConfig>;
22+
23+
predicate algorithm_to_EVP_KDF_derive(Crypto::Algorithm algo, EVP_KDF_derive derive) {
24+
algo.(Expr).getEnclosingFunction() = derive.(Expr).getEnclosingFunction()
25+
}
26+
27+
class EVP_KDF_derive extends KeyDerivationOperation instanceof FunctionCall {
28+
EVP_KDF_derive() { this.getTarget().getName() = "EVP_KDF_derive" }
29+
30+
override Crypto::Algorithm getAlgorithm() { algorithm_to_EVP_KDF_derive(result, this) }
31+
32+
Expr getAlgorithmArg() { result = this.(FunctionCall).getArgument(3) }
33+
}
34+
35+
abstract class KeyDerivationAlgorithm extends Crypto::KeyDerivationAlgorithm { }
36+
37+
class EVP_KDF_fetch_Call extends FunctionCall {
38+
EVP_KDF_fetch_Call() { this.getTarget().getName() = "EVP_KDF_fetch" }
39+
40+
Expr getAlgorithmArg() { result = this.getArgument(1) }
41+
}
42+
43+
predicate kdf_names(string algo) { algo = ["HKDF", "PKCS12KDF"] }
44+
45+
class KDFAlgorithmStringLiteral extends Crypto::NodeBase instanceof StringLiteral {
46+
KDFAlgorithmStringLiteral() { kdf_names(this.getValue().toUpperCase()) }
47+
48+
override string toString() { result = this.(StringLiteral).toString() }
49+
50+
string getValue() { result = this.(StringLiteral).getValue() }
51+
}
52+
53+
private module AlgorithmStringToFetchConfig implements DataFlow::ConfigSig {
54+
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof KDFAlgorithmStringLiteral }
55+
56+
predicate isSink(DataFlow::Node sink) {
57+
exists(EVP_KDF_fetch_Call call | sink.asExpr() = call.getAlgorithmArg())
58+
}
59+
}
60+
61+
module AlgorithmStringToFetchFlow = DataFlow::Global<AlgorithmStringToFetchConfig>;
62+
63+
predicate algorithmStringToKDFFetchArgFlow(string name, KDFAlgorithmStringLiteral origin, Expr arg) {
64+
exists(EVP_KDF_fetch_Call sinkCall |
65+
origin.getValue().toUpperCase() = name and
66+
arg = sinkCall.getAlgorithmArg() and
67+
AlgorithmStringToFetchFlow::flow(DataFlow::exprNode(origin), DataFlow::exprNode(arg))
68+
)
69+
}
70+
71+
class HKDF extends KeyDerivationAlgorithm, Crypto::HKDF instanceof Expr {
72+
KDFAlgorithmStringLiteral origin;
73+
74+
HKDF() { algorithmStringToKDFFetchArgFlow("HKDF", origin, this) }
75+
76+
override Crypto::HashAlgorithm getHashAlgorithm() { none() }
77+
78+
override Crypto::NodeBase getOrigin() { result = origin }
79+
}
80+
81+
class TestKeyDerivationOperationHacky extends KeyDerivationOperation instanceof FunctionCall {
82+
HKDF hkdf;
83+
84+
TestKeyDerivationOperationHacky() {
85+
this.getEnclosingFunction() = hkdf.(Expr).getEnclosingFunction()
86+
}
87+
88+
override Crypto::KeyDerivationAlgorithm getAlgorithm() { result = hkdf }
89+
}
90+
91+
class PKCS12KDF extends KeyDerivationAlgorithm, Crypto::PKCS12KDF instanceof Expr {
92+
KDFAlgorithmStringLiteral origin;
93+
94+
PKCS12KDF() { algorithmStringToKDFFetchArgFlow("PKCS12KDF", origin, this) }
95+
96+
override Crypto::HashAlgorithm getHashAlgorithm() { none() }
97+
98+
override Crypto::NodeBase getOrigin() { result = origin }
99+
}
100+
}

0 commit comments

Comments
 (0)