Skip to content

Commit 9637aec

Browse files
authored
Merge pull request #19547 from bdrodes/openssl_pkey_alg_value_consumers
Quantum: Add OpenSSL PKEY algorithm value consumers.
2 parents 1828d40 + 48e484b commit 9637aec

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
private import cpp as Language
2-
import semmle.code.cpp.dataflow.new.DataFlow
2+
import semmle.code.cpp.dataflow.new.TaintTracking
33
import codeql.quantum.experimental.Model
44

55
module CryptoInput implements InputSig<Language::Location> {
@@ -86,6 +86,27 @@ module GenericDataSourceFlowConfig implements DataFlow::ConfigSig {
8686
}
8787
}
8888

89+
module GenericDataSourceFlow = TaintTracking::Global<GenericDataSourceFlowConfig>;
90+
91+
private class ConstantDataSource extends Crypto::GenericConstantSourceInstance instanceof Literal {
92+
ConstantDataSource() {
93+
// TODO: this is an API specific workaround for OpenSSL, as 'EC' is a constant that may be used
94+
// where typical algorithms are specified, but EC specifically means set up a
95+
// default curve container, that will later be specified explicitly (or if not a default)
96+
// curve is used.
97+
this.getValue() != "EC"
98+
}
99+
100+
override DataFlow::Node getOutputNode() { result.asExpr() = this }
101+
102+
override predicate flowsTo(Crypto::FlowAwareElement other) {
103+
// TODO: separate config to avoid blowing up data-flow analysis
104+
GenericDataSourceFlow::flow(this.getOutputNode(), other.getInputNode())
105+
}
106+
107+
override string getAdditionalDescription() { result = this.toString() }
108+
}
109+
89110
module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
90111
predicate isSource(DataFlow::Node source) {
91112
source = any(Crypto::ArtifactInstance artifact).getOutputNode()

cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmValueConsumers/OpenSSLAlgorithmValueConsumers.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ import DirectAlgorithmValueConsumer
44
import PaddingAlgorithmValueConsumer
55
import HashAlgorithmValueConsumer
66
import EllipticCurveAlgorithmValueConsumer
7+
import PKeyAlgorithmValueConsumer
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import cpp
2+
private import experimental.quantum.Language
3+
private import experimental.quantum.OpenSSL.LibraryDetector
4+
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
5+
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
6+
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
7+
8+
abstract class PKeyValueConsumer extends OpenSSLAlgorithmValueConsumer { }
9+
10+
class EVPPKeyAlgorithmConsumer extends PKeyValueConsumer {
11+
DataFlow::Node valueArgNode;
12+
DataFlow::Node resultNode;
13+
14+
EVPPKeyAlgorithmConsumer() {
15+
resultNode.asExpr() = this.(Call) and // in all cases the result is the return
16+
isPossibleOpenSSLFunction(this.(Call).getTarget()) and
17+
(
18+
// NOTE: some of these consumers are themselves key gen operations,
19+
// in these cases, the operation will be created separately for the same function.
20+
this.(Call).getTarget().getName() in [
21+
"EVP_PKEY_CTX_new_id", "EVP_PKEY_new_raw_private_key", "EVP_PKEY_new_raw_public_key",
22+
"EVP_PKEY_new_mac_key"
23+
] and
24+
valueArgNode.asExpr() = this.(Call).getArgument(0)
25+
or
26+
this.(Call).getTarget().getName() in [
27+
"EVP_PKEY_CTX_new_from_name", "EVP_PKEY_new_raw_private_key_ex",
28+
"EVP_PKEY_new_raw_public_key_ex", "EVP_PKEY_CTX_ctrl", "EVP_PKEY_CTX_set_group_name"
29+
] and
30+
valueArgNode.asExpr() = this.(Call).getArgument(1)
31+
or
32+
// argInd 2 is 'type' which can be RSA, or EC
33+
// if RSA argInd 3 is the key size, else if EC argInd 3 is the curve name
34+
// In all other cases there is no argInd 3, and argInd 2 is the algorithm.
35+
// Since this is a key gen operation, handling the key size should be handled
36+
// when the operation is again modeled as a key gen operation.
37+
this.(Call).getTarget().getName() = "EVP_PKEY_Q_keygen" and
38+
(
39+
// Elliptic curve case
40+
// If the argInd 3 is a derived type (pointer or array) then assume it is a curve name
41+
if this.(Call).getArgument(3).getType().getUnderlyingType() instanceof DerivedType
42+
then valueArgNode.asExpr() = this.(Call).getArgument(3)
43+
else
44+
// All other cases
45+
valueArgNode.asExpr() = this.(Call).getArgument(2)
46+
)
47+
)
48+
}
49+
50+
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
51+
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i)
52+
}
53+
54+
override DataFlow::Node getResultNode() { result = resultNode }
55+
56+
override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
57+
}

0 commit comments

Comments
 (0)