mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
Python: Port cryptodome models to use API graphs
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
/**
|
||||
* Provides models for
|
||||
@@ -16,270 +17,6 @@ private import semmle.python.Concepts
|
||||
* See https://pycryptodome.readthedocs.io/en/latest/
|
||||
*/
|
||||
private module CryptodomeModel {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Cryptodome
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Gets a reference to the `Cryptodome`/`Crypto` module. */
|
||||
private DataFlow::Node cryptodome(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = DataFlow::importNode(["Cryptodome", "Crypto"])
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = cryptodome(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to the `Cryptodome`/`Crypto` module. */
|
||||
DataFlow::Node cryptodome() { result = cryptodome(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/** Provides models for the `Cryptodome`/`Crypto` module. */
|
||||
module Cryptodome {
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `Cryptodome`/`Crypto` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node cryptodome_attr(DataFlow::TypeTracker t, string attr_name) {
|
||||
attr_name in ["PublicKey"] and
|
||||
(
|
||||
t.start() and
|
||||
result = DataFlow::importNode(["Cryptodome", "Crypto"] + "." + attr_name)
|
||||
or
|
||||
t.startInAttr(attr_name) and
|
||||
result = cryptodome()
|
||||
)
|
||||
or
|
||||
// Due to bad performance when using normal setup with `cryptodome_attr(t2, attr_name).track(t2, t)`
|
||||
// we have inlined that code and forced a join
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
exists(DataFlow::StepSummary summary |
|
||||
cryptodome_attr_first_join(t2, attr_name, result, summary) and
|
||||
t = t2.append(summary)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate cryptodome_attr_first_join(
|
||||
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res, DataFlow::StepSummary summary
|
||||
) {
|
||||
DataFlow::StepSummary::step(cryptodome_attr(t2, attr_name), res, summary)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `Cryptodome`/`Crypto` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node cryptodome_attr(string attr_name) {
|
||||
result = cryptodome_attr(DataFlow::TypeTracker::end(), attr_name)
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Cryptodome.PublicKey
|
||||
// -------------------------------------------------------------------------
|
||||
/** Gets a reference to the `Cryptodome.PublicKey`/`Crypto.PublicKey` module. */
|
||||
DataFlow::Node publicKey() { result = cryptodome_attr("PublicKey") }
|
||||
|
||||
/** Provides models for the `Cryptodome.PublicKey`/`Crypto.PublicKey` module */
|
||||
module PublicKey {
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `Cryptodome.PublicKey`/`Crypto.PublicKey` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node publicKey_attr(DataFlow::TypeTracker t, string attr_name) {
|
||||
attr_name in ["RSA", "DSA", "ECC"] and
|
||||
(
|
||||
t.start() and
|
||||
result = DataFlow::importNode(["Cryptodome", "Crypto"] + ".PublicKey" + "." + attr_name)
|
||||
or
|
||||
t.startInAttr(attr_name) and
|
||||
result = publicKey()
|
||||
)
|
||||
or
|
||||
// Due to bad performance when using normal setup with `publicKey_attr(t2, attr_name).track(t2, t)`
|
||||
// we have inlined that code and forced a join
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
exists(DataFlow::StepSummary summary |
|
||||
publicKey_attr_first_join(t2, attr_name, result, summary) and
|
||||
t = t2.append(summary)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate publicKey_attr_first_join(
|
||||
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
|
||||
DataFlow::StepSummary summary
|
||||
) {
|
||||
DataFlow::StepSummary::step(publicKey_attr(t2, attr_name), res, summary)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `Cryptodome.PublicKey`/`Crypto.PublicKey` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node publicKey_attr(string attr_name) {
|
||||
result = publicKey_attr(DataFlow::TypeTracker::end(), attr_name)
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Cryptodome.PublicKey.RSA
|
||||
// -------------------------------------------------------------------------
|
||||
/** Gets a reference to the `Cryptodome.PublicKey.RSA`/`Crypto.PublicKey.RSA` module. */
|
||||
DataFlow::Node rsa() { result = publicKey_attr("RSA") }
|
||||
|
||||
/** Provides models for the `Cryptodome.PublicKey.RSA`/`Crypto.PublicKey.RSA` module */
|
||||
module RSA {
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `Cryptodome.PublicKey.RSA`/`Crypto.PublicKey.RSA` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node rsa_attr(DataFlow::TypeTracker t, string attr_name) {
|
||||
attr_name in ["generate"] and
|
||||
(
|
||||
t.start() and
|
||||
result =
|
||||
DataFlow::importNode(["Cryptodome", "Crypto"] + ".PublicKey.RSA" + "." + attr_name)
|
||||
or
|
||||
t.startInAttr(attr_name) and
|
||||
result = rsa()
|
||||
)
|
||||
or
|
||||
// Due to bad performance when using normal setup with `rsa_attr(t2, attr_name).track(t2, t)`
|
||||
// we have inlined that code and forced a join
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
exists(DataFlow::StepSummary summary |
|
||||
rsa_attr_first_join(t2, attr_name, result, summary) and
|
||||
t = t2.append(summary)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate rsa_attr_first_join(
|
||||
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
|
||||
DataFlow::StepSummary summary
|
||||
) {
|
||||
DataFlow::StepSummary::step(rsa_attr(t2, attr_name), res, summary)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `Cryptodome.PublicKey.RSA`/`Crypto.PublicKey.RSA` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node rsa_attr(string attr_name) {
|
||||
result = rsa_attr(DataFlow::TypeTracker::end(), attr_name)
|
||||
}
|
||||
|
||||
/** Gets a reference to the `Cryptodome.PublicKey.RSA.generate`/`Crypto.PublicKey.RSA.generate` function. */
|
||||
DataFlow::Node generate() { result = rsa_attr("generate") }
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Cryptodome.PublicKey.DSA
|
||||
// -------------------------------------------------------------------------
|
||||
/** Gets a reference to the `Cryptodome.PublicKey.DSA`/`Crypto.PublicKey.DSA` module. */
|
||||
DataFlow::Node dsa() { result = publicKey_attr("DSA") }
|
||||
|
||||
/** Provides models for the `Cryptodome.PublicKey.DSA`/`Crypto.PublicKey.DSA` module */
|
||||
module DSA {
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `Cryptodome.PublicKey.DSA`/`Crypto.PublicKey.DSA` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node dsa_attr(DataFlow::TypeTracker t, string attr_name) {
|
||||
attr_name in ["generate"] and
|
||||
(
|
||||
t.start() and
|
||||
result =
|
||||
DataFlow::importNode(["Cryptodome", "Crypto"] + ".PublicKey.DSA" + "." + attr_name)
|
||||
or
|
||||
t.startInAttr(attr_name) and
|
||||
result = dsa()
|
||||
)
|
||||
or
|
||||
// Due to bad performance when using normal setup with `dsa_attr(t2, attr_name).track(t2, t)`
|
||||
// we have inlined that code and forced a join
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
exists(DataFlow::StepSummary summary |
|
||||
dsa_attr_first_join(t2, attr_name, result, summary) and
|
||||
t = t2.append(summary)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate dsa_attr_first_join(
|
||||
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
|
||||
DataFlow::StepSummary summary
|
||||
) {
|
||||
DataFlow::StepSummary::step(dsa_attr(t2, attr_name), res, summary)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `Cryptodome.PublicKey.DSA`/`Crypto.PublicKey.DSA` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node dsa_attr(string attr_name) {
|
||||
result = dsa_attr(DataFlow::TypeTracker::end(), attr_name)
|
||||
}
|
||||
|
||||
/** Gets a reference to the `Cryptodome.PublicKey.DSA.generate`/`Crypto.PublicKey.DSA.generate` function. */
|
||||
DataFlow::Node generate() { result = dsa_attr("generate") }
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Cryptodome.PublicKey.ECC
|
||||
// -------------------------------------------------------------------------
|
||||
/** Gets a reference to the `Cryptodome.PublicKey.ECC`/`Crypto.PublicKey.ECC` module. */
|
||||
DataFlow::Node ecc() { result = publicKey_attr("ECC") }
|
||||
|
||||
/** Provides models for the `Cryptodome.PublicKey.ECC`/`Crypto.PublicKey.ECC` module */
|
||||
module ECC {
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `Cryptodome.PublicKey.ECC`/`Crypto.PublicKey.ECC` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node ecc_attr(DataFlow::TypeTracker t, string attr_name) {
|
||||
attr_name in ["generate"] and
|
||||
(
|
||||
t.start() and
|
||||
result =
|
||||
DataFlow::importNode(["Cryptodome", "Crypto"] + ".PublicKey.ECC" + "." + attr_name)
|
||||
or
|
||||
t.startInAttr(attr_name) and
|
||||
result = ecc()
|
||||
)
|
||||
or
|
||||
// Due to bad performance when using normal setup with `ecc_attr(t2, attr_name).track(t2, t)`
|
||||
// we have inlined that code and forced a join
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
exists(DataFlow::StepSummary summary |
|
||||
ecc_attr_first_join(t2, attr_name, result, summary) and
|
||||
t = t2.append(summary)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate ecc_attr_first_join(
|
||||
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
|
||||
DataFlow::StepSummary summary
|
||||
) {
|
||||
DataFlow::StepSummary::step(ecc_attr(t2, attr_name), res, summary)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `Cryptodome.PublicKey.ECC`/`Crypto.PublicKey.ECC` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node ecc_attr(string attr_name) {
|
||||
result = ecc_attr(DataFlow::TypeTracker::end(), attr_name)
|
||||
}
|
||||
|
||||
/** Gets a reference to the `Cryptodome.PublicKey.ECC.generate`/`Crypto.PublicKey.ECC.generate` function. */
|
||||
DataFlow::Node generate() { result = ecc_attr("generate") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/**
|
||||
* A call to `Cryptodome.PublicKey.RSA.generate`/`Crypto.PublicKey.RSA.generate`
|
||||
@@ -287,15 +24,18 @@ private module CryptodomeModel {
|
||||
* See https://pycryptodome.readthedocs.io/en/latest/src/public_key/rsa.html#Crypto.PublicKey.RSA.generate
|
||||
*/
|
||||
class CryptodomePublicKeyRsaGenerateCall extends Cryptography::PublicKey::KeyGeneration::RsaRange,
|
||||
DataFlow::CfgNode {
|
||||
override CallNode node;
|
||||
|
||||
DataFlow::CallCfgNode {
|
||||
CryptodomePublicKeyRsaGenerateCall() {
|
||||
node.getFunction() = Cryptodome::PublicKey::RSA::generate().asCfgNode()
|
||||
this =
|
||||
API::moduleImport(["Crypto", "Cryptodome"])
|
||||
.getMember("PublicKey")
|
||||
.getMember("RSA")
|
||||
.getMember("generate")
|
||||
.getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getKeySizeArg() {
|
||||
result.asCfgNode() in [node.getArg(0), node.getArgByName("bits")]
|
||||
result in [this.getArg(0), this.getArgByName("bits")]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,15 +45,18 @@ private module CryptodomeModel {
|
||||
* See https://pycryptodome.readthedocs.io/en/latest/src/public_key/dsa.html#Crypto.PublicKey.DSA.generate
|
||||
*/
|
||||
class CryptodomePublicKeyDsaGenerateCall extends Cryptography::PublicKey::KeyGeneration::DsaRange,
|
||||
DataFlow::CfgNode {
|
||||
override CallNode node;
|
||||
|
||||
DataFlow::CallCfgNode {
|
||||
CryptodomePublicKeyDsaGenerateCall() {
|
||||
node.getFunction() = Cryptodome::PublicKey::DSA::generate().asCfgNode()
|
||||
this =
|
||||
API::moduleImport(["Crypto", "Cryptodome"])
|
||||
.getMember("PublicKey")
|
||||
.getMember("DSA")
|
||||
.getMember("generate")
|
||||
.getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getKeySizeArg() {
|
||||
result.asCfgNode() in [node.getArg(0), node.getArgByName("bits")]
|
||||
result in [this.getArg(0), this.getArgByName("bits")]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,16 +66,20 @@ private module CryptodomeModel {
|
||||
* See https://pycryptodome.readthedocs.io/en/latest/src/public_key/ecc.html#Crypto.PublicKey.ECC.generate
|
||||
*/
|
||||
class CryptodomePublicKeyEccGenerateCall extends Cryptography::PublicKey::KeyGeneration::EccRange,
|
||||
DataFlow::CfgNode {
|
||||
override CallNode node;
|
||||
|
||||
DataFlow::CallCfgNode {
|
||||
CryptodomePublicKeyEccGenerateCall() {
|
||||
node.getFunction() = Cryptodome::PublicKey::ECC::generate().asCfgNode()
|
||||
this =
|
||||
API::moduleImport(["Crypto", "Cryptodome"])
|
||||
.getMember("PublicKey")
|
||||
.getMember("ECC")
|
||||
.getMember("generate")
|
||||
.getACall()
|
||||
}
|
||||
|
||||
/** Gets the argument that specifies the curve to use (a string). */
|
||||
DataFlow::Node getCurveArg() { result.asCfgNode() in [node.getArgByName("curve")] }
|
||||
DataFlow::Node getCurveArg() { result in [this.getArgByName("curve")] }
|
||||
|
||||
/** Gets the name of the curve to use, as well as the origin that explains how we obtained this name. */
|
||||
string getCurveWithOrigin(DataFlow::Node origin) {
|
||||
exists(StrConst str | origin = DataFlow::exprNode(str) |
|
||||
origin.(DataFlow::LocalSourceNode).flowsTo(this.getCurveArg()) and
|
||||
@@ -341,7 +88,7 @@ private module CryptodomeModel {
|
||||
}
|
||||
|
||||
override int getKeySizeWithOrigin(DataFlow::Node origin) {
|
||||
exists(string curve | curve = getCurveWithOrigin(origin) |
|
||||
exists(string curve | curve = this.getCurveWithOrigin(origin) |
|
||||
// using list from https://pycryptodome.readthedocs.io/en/latest/src/public_key/ecc.html
|
||||
curve in ["NIST P-256", "p256", "P-256", "prime256v1", "secp256r1"] and result = 256
|
||||
or
|
||||
|
||||
Reference in New Issue
Block a user