Skip to content

Commit 83617e0

Browse files
authored
Merge pull request #2 from nicolaswill/knewbury01/JCA-sample
Implement first stage cryptography modelling and queries
2 parents 27c7bf3 + 2b1b90c commit 83617e0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+8888
-302
lines changed
Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,121 @@
11
private import codeql.cryptography.Model
2+
import semmle.code.cpp.ir.IR
3+
import semmle.code.cpp.security.FlowSources as FlowSources
24
private import cpp as Lang
35

46
module CryptoInput implements InputSig<Lang::Location> {
7+
class DataFlowNode = DataFlow::Node;
8+
59
class LocatableElement = Lang::Locatable;
610

711
class UnknownLocation = Lang::UnknownDefaultLocation;
12+
13+
LocatableElement dfn_to_element(DataFlow::Node node) {
14+
result = node.asExpr() or
15+
result = node.asParameter() or
16+
result = node.asVariable()
17+
}
818
}
919

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

12-
import OpenSSL
22+
/**
23+
* Artifact output to node input configuration
24+
*/
25+
abstract class AdditionalFlowInputStep extends DataFlow::Node {
26+
abstract DataFlow::Node getOutput();
27+
28+
final DataFlow::Node getInput() { result = this }
29+
}
30+
31+
/**
32+
* Generic data source to node input configuration
33+
*/
34+
module GenericDataSourceUniversalFlowConfig implements DataFlow::ConfigSig {
35+
predicate isSource(DataFlow::Node source) {
36+
source = any(Crypto::GenericDataSourceInstance i).getOutputNode()
37+
}
38+
39+
predicate isSink(DataFlow::Node sink) {
40+
sink = any(Crypto::FlowAwareElement other).getInputNode()
41+
}
42+
43+
predicate isBarrierOut(DataFlow::Node node) {
44+
node = any(Crypto::FlowAwareElement element).getInputNode()
45+
}
46+
47+
predicate isBarrierIn(DataFlow::Node node) {
48+
node = any(Crypto::FlowAwareElement element).getOutputNode()
49+
}
50+
51+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
52+
node1.(AdditionalFlowInputStep).getOutput() = node2
53+
}
54+
}
55+
56+
// // // TODO: I think this will be inefficient, no?
57+
// // class ConstantDataSource extends Crypto::GenericConstantOrAllocationSource instanceof Literal {
58+
// // override DataFlow::Node getOutputNode() {
59+
// // result.asExpr() = this
60+
// // }
61+
// // override predicate flowsTo(Crypto::FlowAwareElement other) {
62+
// // // TODO: separate config to avoid blowing up data-flow analysis
63+
// // GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
64+
// // }
65+
// // override string getAdditionalDescription() { result = this.toString() }
66+
// // }
67+
// /**
68+
// * Definitions of various generic data sources
69+
// */
70+
// // final class DefaultFlowSource = SourceNode;
71+
// // final class DefaultRemoteFlowSource = RemoteFlowSource;
72+
// // class GenericLocalDataSource extends Crypto::GenericLocalDataSource {
73+
// // GenericLocalDataSource() {
74+
// // any(DefaultFlowSource src | not src instanceof DefaultRemoteFlowSource).asExpr() = this
75+
// // }
76+
// // override DataFlow::Node getOutputNode() { result.asExpr() = this }
77+
// // override predicate flowsTo(Crypto::FlowAwareElement other) {
78+
// // GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
79+
// // }
80+
// // override string getAdditionalDescription() { result = this.toString() }
81+
// // }
82+
// // class GenericRemoteDataSource extends Crypto::GenericRemoteDataSource {
83+
// // GenericRemoteDataSource() { any(DefaultRemoteFlowSource src).asExpr() = this }
84+
// // override DataFlow::Node getOutputNode() { result.asExpr() = this }
85+
// // override predicate flowsTo(Crypto::FlowAwareElement other) {
86+
// // GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
87+
// // }
88+
// // override string getAdditionalDescription() { result = this.toString() }
89+
// // }
90+
// module GenericDataSourceUniversalFlow = DataFlow::Global<GenericDataSourceUniversalFlowConfig>;
91+
module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
92+
predicate isSource(DataFlow::Node source) {
93+
source = any(Crypto::ArtifactInstance artifact).getOutputNode()
94+
}
95+
96+
predicate isSink(DataFlow::Node sink) {
97+
sink = any(Crypto::FlowAwareElement other).getInputNode()
98+
}
99+
100+
predicate isBarrierOut(DataFlow::Node node) {
101+
node = any(Crypto::FlowAwareElement element).getInputNode()
102+
}
103+
104+
predicate isBarrierIn(DataFlow::Node node) {
105+
node = any(Crypto::FlowAwareElement element).getOutputNode()
106+
}
107+
108+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
109+
node1.(AdditionalFlowInputStep).getOutput() = node2
110+
}
111+
}
112+
113+
module ArtifactUniversalFlow = DataFlow::Global<ArtifactUniversalFlowConfig>;
114+
115+
abstract class CipherOutputArtifact extends Crypto::KeyOperationOutputArtifactInstance {
116+
override predicate flowsTo(Crypto::FlowAwareElement other) {
117+
ArtifactUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
118+
}
119+
}
120+
121+
import OpenSSL.OpenSSL

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

Lines changed: 0 additions & 102 deletions
This file was deleted.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/**
2+
* In OpenSSL, flow between 'context' parameters is often used to
3+
* store state/config of how an operation will eventually be performed.
4+
* Tracing algorithms and configurations to operations therefore
5+
* requires tracing context parameters for many OpenSSL apis.
6+
*
7+
* This library provides a dataflow analysis to track context parameters
8+
* between any two functions accepting openssl context parameters.
9+
* The dataflow takes into consideration flowing through duplication and copy calls
10+
* as well as flow through flow killers (free/reset calls).
11+
*
12+
* TODO: we may need to revisit 'free' as a dataflow killer, depending on how
13+
* we want to model use after frees.
14+
*
15+
* This library also provides classes to represent context Types and relevant
16+
* arguments/expressions.
17+
*/
18+
19+
import semmle.code.cpp.dataflow.new.DataFlow
20+
21+
class CTXType extends Type {
22+
CTXType() {
23+
// TODO: should we limit this to an openssl path?
24+
this.getUnspecifiedType().stripType().getName().matches("evp_%ctx_%st")
25+
}
26+
}
27+
28+
class CTXPointerExpr extends Expr {
29+
CTXPointerExpr() {
30+
this.getType() instanceof CTXType and
31+
this.getType() instanceof PointerType
32+
}
33+
}
34+
35+
class CTXPointerArgument extends CTXPointerExpr {
36+
CTXPointerArgument() { exists(Call c | c.getAnArgument() = this) }
37+
38+
Call getCall() { result.getAnArgument() = this }
39+
}
40+
41+
class CTXClearCall extends Call {
42+
CTXClearCall() {
43+
this.getTarget().getName().toLowerCase().matches(["%free%", "%reset%"]) and
44+
this.getAnArgument() instanceof CTXPointerArgument
45+
}
46+
}
47+
48+
class CTXCopyOutArgCall extends Call {
49+
CTXCopyOutArgCall() {
50+
this.getTarget().getName().toLowerCase().matches(["%copy%"]) and
51+
this.getAnArgument() instanceof CTXPointerArgument
52+
}
53+
}
54+
55+
class CTXCopyReturnCall extends Call {
56+
CTXCopyReturnCall() {
57+
this.getTarget().getName().toLowerCase().matches(["%dup%"]) and
58+
this.getAnArgument() instanceof CTXPointerArgument and
59+
this instanceof CTXPointerExpr
60+
}
61+
}
62+
63+
module OpenSSLCTXArgumentFlowConfig implements DataFlow::ConfigSig {
64+
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CTXPointerArgument }
65+
66+
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof CTXPointerArgument }
67+
68+
predicate isBarrier(DataFlow::Node node) {
69+
exists(CTXClearCall c | c.getAnArgument() = node.asExpr())
70+
}
71+
72+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
73+
exists(CTXCopyOutArgCall c |
74+
c.getAnArgument() = node1.asExpr() and
75+
c.getAnArgument() = node2.asExpr() and
76+
node1.asExpr() != node2.asExpr() and
77+
node2.asExpr().getType() instanceof CTXType
78+
)
79+
or
80+
exists(CTXCopyReturnCall c |
81+
c.getAnArgument() = node1.asExpr() and
82+
c = node2.asExpr() and
83+
node1.asExpr() != node2.asExpr() and
84+
node2.asExpr().getType() instanceof CTXType
85+
)
86+
}
87+
}
88+
89+
module OpenSSLCTXArgumentFlow = DataFlow::Global<OpenSSLCTXArgumentFlowConfig>;
90+
91+
predicate ctxFlowsTo(CTXPointerArgument source, CTXPointerArgument sink) {
92+
exists(DataFlow::Node a, DataFlow::Node b |
93+
OpenSSLCTXArgumentFlow::flow(a, b) and
94+
a.asExpr() = source and
95+
b.asExpr() = sink
96+
)
97+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import EVPCipherInitializer
2+
import EVPCipherOperation
3+
import EVPCipherAlgorithmSource
4+
5+
class EVP_Cipher_Initializer_Algorithm_Consumer extends Crypto::AlgorithmConsumer instanceof EVPCipherInitializerAlgorithmArgument
6+
{
7+
override DataFlow::Node getInputNode() { result.asExpr() = this }
8+
9+
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
10+
result.(KnownOpenSSLCipherConstantAlgorithmInstance).getConsumer() = this
11+
}
12+
}
13+
14+
// //TODO: need a key consumer
15+
// class EVP_Initializer_Key_Consumer extends Crypto::KeyConsumer instanceof EVP_Cipher_Inititalizer isntanceof InitializerKeyArgument{
16+
// }
17+
class EVP_Cipher_Initializer_IV_Consumer extends Crypto::NonceArtifactConsumer instanceof EVPCipherInitializerIVArgument
18+
{
19+
override DataFlow::Node getInputNode() { result.asExpr() = this }
20+
}
21+
22+
class EVP_Cipher_Input_Consumer extends Crypto::CipherInputConsumer instanceof EVPCipherInputArgument
23+
{
24+
override DataFlow::Node getInputNode() { result.asExpr() = this }
25+
}

0 commit comments

Comments
 (0)