Files
codeql/cpp/ql/lib/experimental/quantum/OpenSSL/Operations/KeyGenOperation.qll

210 lines
7.0 KiB
Plaintext

private import experimental.quantum.Language
private import OpenSSLOperationBase
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
/**
* A call to EC_KEY_generate_key, which is used to generate an EC key pair.
* Note: this is an operation, though the input parameter is a "EC_KEY*".
* EC_KEY is really an empty context for a key that hasn't been generated, hence
* we consider this an operation generating a key and not accepting a key input.
*/
class ECKeyGen extends OperationStep instanceof Call {
//, Crypto::KeyGenerationOperationInstance {
ECKeyGen() { this.(Call).getTarget().getName() = "EC_KEY_generate_key" }
override DataFlow::Node getInput(IOType type) {
result.asIndirectExpr() = this.(Call).getArgument(0) and type = ContextIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asDefiningArgument() = this and type = KeyIO()
}
override OperationStepType getStepType() { result = ContextCreationStep() }
}
/**
* A call to EVP_PKEY_keygen_init or EVP_PKEY_paramgen_init.
*/
class EvpKeyGenInitialize extends OperationStep {
EvpKeyGenInitialize() {
this.getTarget().getName() in [
"EVP_PKEY_keygen_init",
"EVP_PKEY_paramgen_init"
]
}
override DataFlow::Node getInput(IOType type) {
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
}
override OperationStepType getStepType() { result = InitializerStep() }
}
/**
* A base class for final key generation operation steps.
*/
abstract class KeyGenFinalOperationStep extends OperationStep {
override OperationStepType getStepType() { result = FinalStep() }
}
/**
* A call to `EVP_PKEY_Q_keygen`
*/
class EvpPKeyQKeyGen extends KeyGenFinalOperationStep instanceof Call {
EvpPKeyQKeyGen() { this.getTarget().getName() = "EVP_PKEY_Q_keygen" }
override DataFlow::Node getOutput(IOType type) {
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
or
result.asDefiningArgument() = this and type = KeyIO()
}
override DataFlow::Node getInput(IOType type) {
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
or
// When arg 3 is a derived type, it is a curve name, otherwise it is a key size for RSA if provided
// and arg 2 is the algorithm type
this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
result.asIndirectExpr() = this.getArgument(3) and
type = PrimaryAlgorithmIO()
or
not this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
result.asIndirectExpr() = this.getArgument(2) and
type = PrimaryAlgorithmIO()
or
not this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
result.asIndirectExpr() = this.getArgument(3) and
type = KeySizeIO()
}
}
/**
* A call to `EVP_RSA_gen`
*/
class EvpRsaGen extends KeyGenFinalOperationStep instanceof Call {
EvpRsaGen() { this.getTarget().getName() = "EVP_RSA_gen" }
override DataFlow::Node getOutput(IOType type) {
result.asDefiningArgument() = this and type = KeyIO()
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = KeySizeIO()
}
}
/**
* A call to RSA_generate_key
*/
class RsaGenerateKey extends KeyGenFinalOperationStep instanceof Call {
RsaGenerateKey() { this.getTarget().getName() = "RSA_generate_key" }
override DataFlow::Node getOutput(IOType type) {
result.asDefiningArgument() = this and type = KeyIO()
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = KeySizeIO()
}
}
/**
* A call to RSA_generate_key_ex
*/
class RsaGenerateKeyEx extends KeyGenFinalOperationStep instanceof Call {
RsaGenerateKeyEx() { this.getTarget().getName() = "RSA_generate_key_ex" }
override DataFlow::Node getOutput(IOType type) {
result.asDefiningArgument() = this.getArgument(0) and type = KeyIO()
}
override DataFlow::Node getInput(IOType type) {
// arg 0 comes in as a blank RSA key, which we consider a context,
// on output it is considered a key
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
}
}
/**
* A call to `EVP_PKEY_generate` or `EVP_PKEY_keygen`.
*/
class EvpPkeyGen extends KeyGenFinalOperationStep instanceof Call {
EvpPkeyGen() { this.getTarget().getName() in ["EVP_PKEY_generate", "EVP_PKEY_keygen"] }
override DataFlow::Node getInput(IOType type) {
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asDefiningArgument() = this.getArgument(1) and type = KeyIO()
or
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
}
}
/**
* A call to `EVP_PKEY_new_mac_key` that creates a new generic MAC key.
* - EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e, const unsigned char *key, int keylen);
*/
class EvpNewMacKey extends KeyGenFinalOperationStep {
EvpNewMacKey() { this.getTarget().getName() = "EVP_PKEY_new_mac_key" }
override DataFlow::Node getInput(IOType type) {
// the raw key that is configured into the output key
result.asIndirectExpr() = this.getArgument(2) and type = KeyIO()
or
result.asExpr() = this.getArgument(3) and type = KeySizeIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asIndirectExpr() = this and type = KeyIO()
}
}
/// TODO: https://docs.openssl.org/3.0/man3/EVP_PKEY_new/#synopsis
/**
* An `KeyGenerationOperationInstance` for the for all key gen final operation steps.
*/
class OpenSslKeyGenOperationInstance extends Crypto::KeyGenerationOperationInstance instanceof KeyGenFinalOperationStep
{
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
super.getPrimaryAlgorithmValueConsumer() = result
}
override Crypto::KeyArtifactType getOutputKeyType() { result = Crypto::TAsymmetricKeyType() }
override Crypto::ArtifactOutputDataFlowNode getOutputKeyArtifact() {
super.getOutputStepFlowingToStep(KeyIO()).getOutput(KeyIO()) = result
}
override predicate hasKeyValueConsumer() {
exists(OperationStep s | s.flowsToOperationStep(this) and s.setsValue(KeyIO()))
}
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
super.getDominatingInitializersToStep(KeySizeIO()).getInput(KeySizeIO()) = result
}
override int getKeySizeFixed() {
none()
// TODO: marked as none as the operation itself has no key size, it
// comes from the algorithm source, but note we could grab the
// algorithm source and get the key size (see below).
// We may need to reconsider what is the best approach here.
// result =
// this.getAnAlgorithmValueConsumer()
// .getAKnownAlgorithmSource()
// .(Crypto::EllipticCurveInstance)
// .getKeySize()
}
override Crypto::ConsumerInputDataFlowNode getKeyValueConsumer() {
super.getDominatingInitializersToStep(KeyIO()).getInput(KeyIO()) = result
}
}