Python: Port cryptodome models to use API graphs

This commit is contained in:
Rasmus Wriedt Larsen
2021-02-17 14:31:33 +01:00
parent 1eabfbd0e4
commit 2a8f720bc6

View File

@@ -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