Skip to content

Commit bac0a63

Browse files
committed
Initial hash models for openssl.
1 parent cf72fde commit bac0a63

8 files changed

Lines changed: 303 additions & 97 deletions

File tree

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

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -22,82 +22,82 @@ abstract class AdditionalFlowInputStep extends DataFlow::Node {
2222
}
2323

2424

25-
/**
26-
* Generic data source to node input configuration
27-
*/
28-
module GenericDataSourceUniversalFlowConfig implements DataFlow::ConfigSig {
29-
predicate isSource(DataFlow::Node source) {
30-
source = any(Crypto::GenericDataSourceInstance i).getOutputNode()
31-
}
25+
// /**
26+
// * Generic data source to node input configuration
27+
// */
28+
// module GenericDataSourceUniversalFlowConfig implements DataFlow::ConfigSig {
29+
// predicate isSource(DataFlow::Node source) {
30+
// source = any(Crypto::GenericDataSourceInstance i).getOutputNode()
31+
// }
3232

33-
predicate isSink(DataFlow::Node sink) {
34-
sink = any(Crypto::FlowAwareElement other).getInputNode()
35-
}
33+
// predicate isSink(DataFlow::Node sink) {
34+
// sink = any(Crypto::FlowAwareElement other).getInputNode()
35+
// }
3636

37-
predicate isBarrierOut(DataFlow::Node node) {
38-
node = any(Crypto::FlowAwareElement element).getInputNode()
39-
}
37+
// predicate isBarrierOut(DataFlow::Node node) {
38+
// node = any(Crypto::FlowAwareElement element).getInputNode()
39+
// }
4040

41-
predicate isBarrierIn(DataFlow::Node node) {
42-
node = any(Crypto::FlowAwareElement element).getOutputNode()
43-
}
41+
// predicate isBarrierIn(DataFlow::Node node) {
42+
// node = any(Crypto::FlowAwareElement element).getOutputNode()
43+
// }
4444

45-
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
46-
node1.(AdditionalFlowInputStep).getOutput() = node2
47-
}
48-
}
45+
// predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
46+
// node1.(AdditionalFlowInputStep).getOutput() = node2
47+
// }
48+
// }
4949

5050

5151

52-
// // TODO: I think this will be inefficient, no?
53-
// class ConstantDataSource extends Crypto::GenericConstantOrAllocationSource instanceof Literal {
54-
// override DataFlow::Node getOutputNode() {
55-
// result.asExpr() = this
56-
// }
52+
// // // TODO: I think this will be inefficient, no?
53+
// // class ConstantDataSource extends Crypto::GenericConstantOrAllocationSource instanceof Literal {
54+
// // override DataFlow::Node getOutputNode() {
55+
// // result.asExpr() = this
56+
// // }
5757

58-
// override predicate flowsTo(Crypto::FlowAwareElement other) {
59-
// // TODO: separate config to avoid blowing up data-flow analysis
60-
// GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
61-
// }
58+
// // override predicate flowsTo(Crypto::FlowAwareElement other) {
59+
// // // TODO: separate config to avoid blowing up data-flow analysis
60+
// // GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
61+
// // }
6262

63-
// override string getAdditionalDescription() { result = this.toString() }
64-
// }
63+
// // override string getAdditionalDescription() { result = this.toString() }
64+
// // }
6565

66-
/**
67-
* Definitions of various generic data sources
68-
*/
69-
// final class DefaultFlowSource = SourceNode;
66+
// /**
67+
// * Definitions of various generic data sources
68+
// */
69+
// // final class DefaultFlowSource = SourceNode;
7070

71-
// final class DefaultRemoteFlowSource = RemoteFlowSource;
71+
// // final class DefaultRemoteFlowSource = RemoteFlowSource;
7272

73-
// class GenericLocalDataSource extends Crypto::GenericLocalDataSource {
74-
// GenericLocalDataSource() {
75-
// any(DefaultFlowSource src | not src instanceof DefaultRemoteFlowSource).asExpr() = this
76-
// }
73+
// // class GenericLocalDataSource extends Crypto::GenericLocalDataSource {
74+
// // GenericLocalDataSource() {
75+
// // any(DefaultFlowSource src | not src instanceof DefaultRemoteFlowSource).asExpr() = this
76+
// // }
7777

78-
// override DataFlow::Node getOutputNode() { result.asExpr() = this }
78+
// // override DataFlow::Node getOutputNode() { result.asExpr() = this }
7979

80-
// override predicate flowsTo(Crypto::FlowAwareElement other) {
81-
// GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
82-
// }
80+
// // override predicate flowsTo(Crypto::FlowAwareElement other) {
81+
// // GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
82+
// // }
8383

84-
// override string getAdditionalDescription() { result = this.toString() }
85-
// }
84+
// // override string getAdditionalDescription() { result = this.toString() }
85+
// // }
8686

87-
// class GenericRemoteDataSource extends Crypto::GenericRemoteDataSource {
88-
// GenericRemoteDataSource() { any(DefaultRemoteFlowSource src).asExpr() = this }
87+
// // class GenericRemoteDataSource extends Crypto::GenericRemoteDataSource {
88+
// // GenericRemoteDataSource() { any(DefaultRemoteFlowSource src).asExpr() = this }
8989

90-
// override DataFlow::Node getOutputNode() { result.asExpr() = this }
90+
// // override DataFlow::Node getOutputNode() { result.asExpr() = this }
9191

92-
// override predicate flowsTo(Crypto::FlowAwareElement other) {
93-
// GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
94-
// }
92+
// // override predicate flowsTo(Crypto::FlowAwareElement other) {
93+
// // GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
94+
// // }
9595

96-
// override string getAdditionalDescription() { result = this.toString() }
97-
// }
96+
// // override string getAdditionalDescription() { result = this.toString() }
97+
// // }
9898

9999

100-
module GenericDataSourceUniversalFlow = DataFlow::Global<GenericDataSourceUniversalFlowConfig>;
100+
// module GenericDataSourceUniversalFlow = DataFlow::Global<GenericDataSourceUniversalFlowConfig>;
101101

102102
module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
103103
predicate isSource(DataFlow::Node source) {

cpp/ql/lib/experimental/Quantum/OpenSSL/EVPDigestAlgorithmSource.qll

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ predicate literalToHashFamilyType(Literal e, Crypto::THashType type) {
3939

4040
class HashKnownAlgorithmLiteralAlgorithmInstance extends Crypto::HashAlgorithmInstance instanceof Literal
4141
{
42-
OpenSSLAlgorithmGetterCall cipherGetterCall;
42+
OpenSSLAlgorithmGetterCall getterCall;
4343

4444
HashKnownAlgorithmLiteralAlgorithmInstance() {
4545
exists(DataFlow::Node src, DataFlow::Node sink |
46-
sink = cipherGetterCall.getValueArgNode() and
46+
sink = getterCall.getValueArgNode() and
4747
src.asExpr() = this and
4848
KnownAlgorithmLiteralToAlgorithmGetterFlow::flow(src, sink) and
4949
// Not just any known value, but specifically a known cipher operation
@@ -56,10 +56,12 @@ class HashKnownAlgorithmLiteralAlgorithmInstance extends Crypto::HashAlgorithmIn
5656

5757
// TODO: should this not be part of the abstract algorithm definition?
5858
Crypto::AlgorithmConsumer getConsumer() {
59-
AlgGetterToAlgConsumerFlow::flow(cipherGetterCall.getResultNode(), DataFlow::exprNode(result))
59+
AlgGetterToAlgConsumerFlow::flow(getterCall.getResultNode(), DataFlow::exprNode(result))
6060
}
6161

6262
override Crypto::THashType getHashFamily() { literalToHashFamilyType(this, result) }
6363

64+
override int getHashSize() { none() } //TODO
65+
6466
override string getRawAlgorithmName() { result = this.(Literal).getValue().toString() }
6567
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import cpp
2+
import experimental.Quantum.Language
3+
import EVPHashConsumers
4+
import OpenSSLAlgorithmGetter
5+
6+
predicate literalToHashFamilyType(Literal e, Crypto::THashType type) {
7+
exists(string name, string algType | algType.toLowerCase().matches("hash") |
8+
resolveAlgorithmFromLiteral(e, name, algType) and
9+
(
10+
name.matches("BLAKE2B") and type instanceof Crypto::BLAKE2B
11+
or
12+
name.matches("BLAKE2S") and type instanceof Crypto::BLAKE2S
13+
or
14+
name.matches("MD2") and type instanceof Crypto::MD2
15+
or
16+
name.matches("MD4") and type instanceof Crypto::MD4
17+
or
18+
name.matches("MD5") and type instanceof Crypto::MD5
19+
or
20+
name.matches("POLY1305") and type instanceof Crypto::POLY1305
21+
or
22+
name.matches(["SHA", "SHA1"]) and type instanceof Crypto::SHA1
23+
or
24+
name.matches("SHA+%") and not name.matches(["SHA1", "SHA3-"]) and type instanceof Crypto::SHA2
25+
or
26+
name.matches("SHA3-%") and type instanceof Crypto::SHA3
27+
or
28+
name.matches(["SHAKE"]) and type instanceof Crypto::SHAKE
29+
or
30+
name.matches("SM3") and type instanceof Crypto::SM3
31+
or
32+
name.matches("RIPEMD160") and type instanceof Crypto::RIPEMD160
33+
or
34+
//or
35+
//TODO: need to handle MACs differently, including md_GOST94
36+
// name.matches("%GOST%") and type instanceof Crypto::GOST
37+
name.matches("WHIRLPOOL") and type instanceof Crypto::WHIRLPOOL
38+
)
39+
)
40+
}
41+
42+
class HashKnownAlgorithmLiteralAlgorithmInstance extends Crypto::HashAlgorithmInstance instanceof Literal
43+
{
44+
OpenSSLAlgorithmGetterCall cipherGetterCall;
45+
46+
HashKnownAlgorithmLiteralAlgorithmInstance() {
47+
exists(DataFlow::Node src, DataFlow::Node sink |
48+
sink = cipherGetterCall.getValueArgNode() and
49+
src.asExpr() = this and
50+
KnownAlgorithmLiteralToAlgorithmGetterFlow::flow(src, sink) and
51+
// Not just any known value, but specifically a known cipher operation
52+
exists(string algType |
53+
resolveAlgorithmFromLiteral(src.asExpr(), _, algType) and
54+
algType.toLowerCase().matches("hash")
55+
)
56+
)
57+
}
58+
59+
Crypto::AlgorithmConsumer getConsumer() {
60+
AlgGetterToAlgConsumerFlow::flow(cipherGetterCall.getResultNode(), DataFlow::exprNode(result))
61+
}
62+
63+
override Crypto::THashType getHashFamily() {
64+
literalToHashFamilyType(this, result)
65+
}
66+
67+
override string getRawAlgorithmName() { result = this.(Literal).getValue().toString() }
68+
69+
override int getHashSize() {none() }//TODO
70+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import EVPHashInitializer
2+
import EVPHashOperation
3+
import EVPHashAlgorithmSource
4+
5+
class EVP_Digest_Initializer_Algorithm_Consumer extends Crypto::AlgorithmConsumer instanceof EVPDigestInitializerAlgorithmArgument{
6+
override DataFlow::Node getInputNode() { result.asExpr() = this }
7+
8+
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
9+
result.(HashKnownAlgorithmLiteralAlgorithmInstance).getConsumer() = this
10+
}
11+
}
12+
13+
class EVP_Q_Digest_Algorithm_Consumer extends Crypto::AlgorithmConsumer instanceof EVP_Q_Digest_Algorithm_Argument{
14+
override DataFlow::Node getInputNode() { result.asExpr() = this }
15+
16+
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
17+
result.(HashKnownAlgorithmLiteralAlgorithmInstance).getConsumer() = this
18+
}
19+
}
20+
21+
class EVP_Digest_Algorithm_Consumer extends Crypto::AlgorithmConsumer instanceof EVP_Digest_Algorithm_Argument{
22+
override DataFlow::Node getInputNode() { result.asExpr() = this }
23+
24+
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
25+
result.(HashKnownAlgorithmLiteralAlgorithmInstance).getConsumer() = this
26+
}
27+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import cpp
2+
3+
abstract class EVP_Hash_Inititalizer extends Call {
4+
Expr getContextArg() { result = this.(Call).getArgument(0) }
5+
6+
abstract Expr getAlgorithmArg();
7+
}
8+
9+
class EVP_DigestInit_Variant_Calls extends EVP_Hash_Inititalizer {
10+
EVP_DigestInit_Variant_Calls() {
11+
this.(Call).getTarget().getName() in [
12+
"EVP_DigestInit", "EVP_DigestInit_ex", "EVP_DigestInit_ex2"
13+
]
14+
}
15+
16+
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
17+
18+
}
19+
20+
21+
class EVPDigestInitializerAlgorithmArgument extends Expr {
22+
EVPDigestInitializerAlgorithmArgument() {
23+
exists(EVP_Hash_Inititalizer initCall | this = initCall.getAlgorithmArg())
24+
}
25+
}
Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,83 @@
11
import experimental.Quantum.Language
22
import CtxFlow as CTXFlow
3+
import LibraryDetector
4+
import EVPHashInitializer
5+
import EVPHashConsumers
36

7+
abstract class EVP_Hash_Operation extends Crypto::HashOperationInstance instanceof Call {
8+
Expr getContextArg() { result = this.(Call).getArgument(0) }
49

5-
//https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
10+
EVP_Hash_Inititalizer getInitCall() {
11+
CTXFlow::ctxFlowsTo(result.getContextArg(), this.getContextArg())
12+
}
13+
}
14+
15+
//https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
16+
class EVP_Q_Digest_Operation extends EVP_Hash_Operation {
17+
EVP_Q_Digest_Operation() {
18+
this.(Call).getTarget().getName() = "EVP_Q_digest" and
19+
isPossibleOpenSSLFunction(this.(Call).getTarget())
20+
}
21+
22+
override Crypto::AlgorithmConsumer getAlgorithmConsumer() { this.(Call).getArgument(1) = result }
23+
24+
override EVP_Hash_Inititalizer getInitCall() {
25+
// This variant of digest does not use an init
26+
// and even if it were used, the init would be ignored/undefined
27+
none()
28+
}
29+
}
30+
31+
class EVP_Q_Digest_Algorithm_Argument extends Expr {
32+
EVP_Q_Digest_Algorithm_Argument() {
33+
exists(EVP_Q_Digest_Operation op | this = op.(Call).getArgument(1))
34+
}
35+
}
36+
37+
class EVP_Digest_Operation extends EVP_Hash_Operation {
38+
EVP_Digest_Operation() {
39+
this.(Call).getTarget().getName() = "EVP_Digest" and
40+
isPossibleOpenSSLFunction(this.(Call).getTarget())
41+
}
42+
43+
// There is no context argument for this function
44+
override Expr getContextArg() { none() }
45+
46+
override Crypto::AlgorithmConsumer getAlgorithmConsumer() { this.(Call).getArgument(4) = result }
47+
48+
override EVP_Hash_Inititalizer getInitCall() {
49+
// This variant of digest does not use an init
50+
// and even if it were used, the init would be ignored/undefined
51+
none()
52+
}
53+
}
54+
55+
class EVP_Digest_Algorithm_Argument extends Expr {
56+
EVP_Digest_Algorithm_Argument() {
57+
exists(EVP_Digest_Operation op | this = op.(Call).getArgument(4))
58+
}
59+
}
60+
61+
class EVP_DigestUpdate_Operation extends EVP_Hash_Operation {
62+
EVP_DigestUpdate_Operation() {
63+
this.(Call).getTarget().getName() = "EVP_DigestUpdate" and
64+
isPossibleOpenSSLFunction(this.(Call).getTarget())
65+
}
66+
67+
override Crypto::AlgorithmConsumer getAlgorithmConsumer() {
68+
this.getInitCall().getAlgorithmArg() = result
69+
}
70+
}
71+
72+
class EVP_DigestFinal_Variants_Operation extends EVP_Hash_Operation {
73+
EVP_DigestFinal_Variants_Operation() {
74+
this.(Call).getTarget().getName() in [
75+
"EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"
76+
] and
77+
isPossibleOpenSSLFunction(this.(Call).getTarget())
78+
}
79+
80+
override Crypto::AlgorithmConsumer getAlgorithmConsumer() {
81+
this.getInitCall().getAlgorithmArg() = result
82+
}
83+
}

0 commit comments

Comments
 (0)