mirror of
https://github.com/github/codeql.git
synced 2026-02-03 16:51:07 +01:00
341 lines
13 KiB
Plaintext
341 lines
13 KiB
Plaintext
/**
|
|
* Provides classes modeling security-relevant aspects of the `cryptography` PyPI package.
|
|
* See https://cryptography.io/en/latest/.
|
|
*/
|
|
|
|
private import python
|
|
private import semmle.python.dataflow.new.DataFlow
|
|
private import semmle.python.Concepts
|
|
private import semmle.python.ApiGraphs
|
|
|
|
/**
|
|
* Provides models for the `cryptography` PyPI package.
|
|
* See https://cryptography.io/en/latest/.
|
|
*/
|
|
private module CryptographyModel {
|
|
/**
|
|
* Provides helper predicates for the eliptic curve cryptography parts in
|
|
* `cryptography.hazmat.primitives.asymmetric.ec`.
|
|
*/
|
|
module Ecc {
|
|
/**
|
|
* Gets a predefined curve class from
|
|
* `cryptography.hazmat.primitives.asymmetric.ec` with a specific key size (in bits).
|
|
*/
|
|
private API::Node predefinedCurveClass(int keySize) {
|
|
exists(string curveName |
|
|
result =
|
|
API::moduleImport("cryptography")
|
|
.getMember("hazmat")
|
|
.getMember("primitives")
|
|
.getMember("asymmetric")
|
|
.getMember("ec")
|
|
.getMember(curveName)
|
|
|
|
|
// obtained by manually looking at source code in
|
|
// https://github.com/pyca/cryptography/blob/cba69f1922803f4f29a3fde01741890d88b8e217/src/cryptography/hazmat/primitives/asymmetric/ec.py#L208-L300
|
|
curveName = "SECT571R1" and keySize = 570 // Indeed the numbers do not match.
|
|
or
|
|
curveName = "SECT409R1" and keySize = 409
|
|
or
|
|
curveName = "SECT283R1" and keySize = 283
|
|
or
|
|
curveName = "SECT233R1" and keySize = 233
|
|
or
|
|
curveName = "SECT163R2" and keySize = 163
|
|
or
|
|
curveName = "SECT571K1" and keySize = 571
|
|
or
|
|
curveName = "SECT409K1" and keySize = 409
|
|
or
|
|
curveName = "SECT283K1" and keySize = 283
|
|
or
|
|
curveName = "SECT233K1" and keySize = 233
|
|
or
|
|
curveName = "SECT163K1" and keySize = 163
|
|
or
|
|
curveName = "SECP521R1" and keySize = 521
|
|
or
|
|
curveName = "SECP384R1" and keySize = 384
|
|
or
|
|
curveName = "SECP256R1" and keySize = 256
|
|
or
|
|
curveName = "SECP256K1" and keySize = 256
|
|
or
|
|
curveName = "SECP224R1" and keySize = 224
|
|
or
|
|
curveName = "SECP192R1" and keySize = 192
|
|
or
|
|
curveName = "BrainpoolP256R1" and keySize = 256
|
|
or
|
|
curveName = "BrainpoolP384R1" and keySize = 384
|
|
or
|
|
curveName = "BrainpoolP512R1" and keySize = 512
|
|
)
|
|
}
|
|
|
|
/** Gets a reference to a predefined curve class with a specific key size (in bits), as well as the origin of the class. */
|
|
private DataFlow::TypeTrackingNode curveClassWithKeySize(
|
|
DataFlow::TypeTracker t, int keySize, DataFlow::Node origin
|
|
) {
|
|
t.start() and
|
|
result = predefinedCurveClass(keySize).getAnImmediateUse() and
|
|
origin = result
|
|
or
|
|
exists(DataFlow::TypeTracker t2 |
|
|
result = curveClassWithKeySize(t2, keySize, origin).track(t2, t)
|
|
)
|
|
}
|
|
|
|
/** Gets a reference to a predefined curve class with a specific key size (in bits), as well as the origin of the class. */
|
|
DataFlow::Node curveClassWithKeySize(int keySize, DataFlow::Node origin) {
|
|
curveClassWithKeySize(DataFlow::TypeTracker::end(), keySize, origin).flowsTo(result)
|
|
}
|
|
|
|
/** Gets a reference to a predefined curve class instance with a specific key size (in bits), as well as the origin of the class. */
|
|
private DataFlow::TypeTrackingNode curveClassInstanceWithKeySize(
|
|
DataFlow::TypeTracker t, int keySize, DataFlow::Node origin
|
|
) {
|
|
t.start() and
|
|
result.(DataFlow::CallCfgNode).getFunction() = curveClassWithKeySize(keySize, origin)
|
|
or
|
|
exists(DataFlow::TypeTracker t2 |
|
|
result = curveClassInstanceWithKeySize(t2, keySize, origin).track(t2, t)
|
|
)
|
|
}
|
|
|
|
/** Gets a reference to a predefined curve class instance with a specific key size (in bits), as well as the origin of the class. */
|
|
DataFlow::Node curveClassInstanceWithKeySize(int keySize, DataFlow::Node origin) {
|
|
curveClassInstanceWithKeySize(DataFlow::TypeTracker::end(), keySize, origin).flowsTo(result)
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
/**
|
|
* A call to `cryptography.hazmat.primitives.asymmetric.rsa.generate_private_key`
|
|
*
|
|
* See https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa.html#cryptography.hazmat.primitives.asymmetric.rsa.generate_private_key
|
|
*/
|
|
class CryptographyRsaGeneratePrivateKeyCall extends Cryptography::PublicKey::KeyGeneration::RsaRange,
|
|
DataFlow::CallCfgNode {
|
|
CryptographyRsaGeneratePrivateKeyCall() {
|
|
this =
|
|
API::moduleImport("cryptography")
|
|
.getMember("hazmat")
|
|
.getMember("primitives")
|
|
.getMember("asymmetric")
|
|
.getMember("rsa")
|
|
.getMember("generate_private_key")
|
|
.getACall()
|
|
}
|
|
|
|
override DataFlow::Node getKeySizeArg() {
|
|
result in [this.getArg(1), this.getArgByName("key_size")]
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A call to `cryptography.hazmat.primitives.asymmetric.dsa.generate_private_key`
|
|
*
|
|
* See https://cryptography.io/en/latest/hazmat/primitives/asymmetric/dsa.html#cryptography.hazmat.primitives.asymmetric.dsa.generate_private_key
|
|
*/
|
|
class CryptographyDsaGeneratePrivateKeyCall extends Cryptography::PublicKey::KeyGeneration::DsaRange,
|
|
DataFlow::CallCfgNode {
|
|
CryptographyDsaGeneratePrivateKeyCall() {
|
|
this =
|
|
API::moduleImport("cryptography")
|
|
.getMember("hazmat")
|
|
.getMember("primitives")
|
|
.getMember("asymmetric")
|
|
.getMember("dsa")
|
|
.getMember("generate_private_key")
|
|
.getACall()
|
|
}
|
|
|
|
override DataFlow::Node getKeySizeArg() {
|
|
result in [this.getArg(0), this.getArgByName("key_size")]
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A call to `cryptography.hazmat.primitives.asymmetric.ec.generate_private_key`
|
|
*
|
|
* See https://cryptography.io/en/latest/hazmat/primitives/asymmetric/ec.html#cryptography.hazmat.primitives.asymmetric.ec.generate_private_key
|
|
*/
|
|
class CryptographyEcGeneratePrivateKeyCall extends Cryptography::PublicKey::KeyGeneration::EccRange,
|
|
DataFlow::CallCfgNode {
|
|
CryptographyEcGeneratePrivateKeyCall() {
|
|
this =
|
|
API::moduleImport("cryptography")
|
|
.getMember("hazmat")
|
|
.getMember("primitives")
|
|
.getMember("asymmetric")
|
|
.getMember("ec")
|
|
.getMember("generate_private_key")
|
|
.getACall()
|
|
}
|
|
|
|
/** Gets the argument that specifies the curve to use. */
|
|
DataFlow::Node getCurveArg() { result in [this.getArg(0), this.getArgByName("curve")] }
|
|
|
|
override int getKeySizeWithOrigin(DataFlow::Node origin) {
|
|
this.getCurveArg() = Ecc::curveClassInstanceWithKeySize(result, origin)
|
|
or
|
|
this.getCurveArg() = Ecc::curveClassWithKeySize(result, origin)
|
|
}
|
|
|
|
// Note: There is not really a key-size argument, since it's always specified by the curve.
|
|
override DataFlow::Node getKeySizeArg() { none() }
|
|
}
|
|
|
|
/** Provides models for the `cryptography.hazmat.primitives.ciphers` package */
|
|
private module Ciphers {
|
|
/** Gets a reference to a `cryptography.hazmat.primitives.ciphers.algorithms` Class */
|
|
API::Node algorithmClassRef(string algorithmName) {
|
|
result =
|
|
API::moduleImport("cryptography")
|
|
.getMember("hazmat")
|
|
.getMember("primitives")
|
|
.getMember("ciphers")
|
|
.getMember("algorithms")
|
|
.getMember(algorithmName)
|
|
}
|
|
|
|
/** Gets a reference to a Cipher instance using algorithm with `algorithmName`. */
|
|
DataFlow::TypeTrackingNode cipherInstance(DataFlow::TypeTracker t, string algorithmName) {
|
|
t.start() and
|
|
exists(DataFlow::CallCfgNode call | result = call |
|
|
call =
|
|
API::moduleImport("cryptography")
|
|
.getMember("hazmat")
|
|
.getMember("primitives")
|
|
.getMember("ciphers")
|
|
.getMember("Cipher")
|
|
.getACall() and
|
|
algorithmClassRef(algorithmName).getReturn().getAUse() in [
|
|
call.getArg(0), call.getArgByName("algorithm")
|
|
]
|
|
)
|
|
or
|
|
exists(DataFlow::TypeTracker t2 | result = cipherInstance(t2, algorithmName).track(t2, t))
|
|
}
|
|
|
|
/** Gets a reference to a Cipher instance using algorithm with `algorithmName`. */
|
|
DataFlow::Node cipherInstance(string algorithmName) {
|
|
cipherInstance(DataFlow::TypeTracker::end(), algorithmName).flowsTo(result)
|
|
}
|
|
|
|
/** Gets a reference to the encryptor of a Cipher instance using algorithm with `algorithmName`. */
|
|
DataFlow::TypeTrackingNode cipherEncryptor(DataFlow::TypeTracker t, string algorithmName) {
|
|
t.start() and
|
|
result.(DataFlow::MethodCallNode).calls(cipherInstance(algorithmName), "encryptor")
|
|
or
|
|
exists(DataFlow::TypeTracker t2 | result = cipherEncryptor(t2, algorithmName).track(t2, t))
|
|
}
|
|
|
|
/**
|
|
* Gets a reference to the encryptor of a Cipher instance using algorithm with `algorithmName`.
|
|
*
|
|
* You obtain an encryptor by using the `encryptor()` method on a Cipher instance.
|
|
*/
|
|
DataFlow::Node cipherEncryptor(string algorithmName) {
|
|
cipherEncryptor(DataFlow::TypeTracker::end(), algorithmName).flowsTo(result)
|
|
}
|
|
|
|
/** Gets a reference to the dncryptor of a Cipher instance using algorithm with `algorithmName`. */
|
|
DataFlow::TypeTrackingNode cipherDecryptor(DataFlow::TypeTracker t, string algorithmName) {
|
|
t.start() and
|
|
result.(DataFlow::MethodCallNode).calls(cipherInstance(algorithmName), "decryptor")
|
|
or
|
|
exists(DataFlow::TypeTracker t2 | result = cipherDecryptor(t2, algorithmName).track(t2, t))
|
|
}
|
|
|
|
/**
|
|
* Gets a reference to the decryptor of a Cipher instance using algorithm with `algorithmName`.
|
|
*
|
|
* You obtain an decryptor by using the `decryptor()` method on a Cipher instance.
|
|
*/
|
|
DataFlow::Node cipherDecryptor(string algorithmName) {
|
|
cipherDecryptor(DataFlow::TypeTracker::end(), algorithmName).flowsTo(result)
|
|
}
|
|
|
|
/**
|
|
* An encrypt or decrypt operation from `cryptography.hazmat.primitives.ciphers`.
|
|
*/
|
|
class CryptographyGenericCipherOperation extends Cryptography::CryptographicOperation::Range,
|
|
DataFlow::MethodCallNode {
|
|
string algorithmName;
|
|
|
|
CryptographyGenericCipherOperation() {
|
|
exists(DataFlow::Node object, string method |
|
|
object in [cipherEncryptor(algorithmName), cipherDecryptor(algorithmName)] and
|
|
method in ["update", "update_into"] and
|
|
this.calls(object, method)
|
|
)
|
|
}
|
|
|
|
override Cryptography::CryptographicAlgorithm getAlgorithm() {
|
|
result.matchesName(algorithmName)
|
|
}
|
|
|
|
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] }
|
|
}
|
|
}
|
|
|
|
/** Provides models for the `cryptography.hazmat.primitives.hashes` package */
|
|
private module Hashes {
|
|
/**
|
|
* Gets a reference to a `cryptography.hazmat.primitives.hashes` class, representing
|
|
* a hashing algorithm.
|
|
*/
|
|
API::Node algorithmClassRef(string algorithmName) {
|
|
result =
|
|
API::moduleImport("cryptography")
|
|
.getMember("hazmat")
|
|
.getMember("primitives")
|
|
.getMember("hashes")
|
|
.getMember(algorithmName)
|
|
}
|
|
|
|
/** Gets a reference to a Hash instance using algorithm with `algorithmName`. */
|
|
private DataFlow::TypeTrackingNode hashInstance(DataFlow::TypeTracker t, string algorithmName) {
|
|
t.start() and
|
|
exists(DataFlow::CallCfgNode call | result = call |
|
|
call =
|
|
API::moduleImport("cryptography")
|
|
.getMember("hazmat")
|
|
.getMember("primitives")
|
|
.getMember("hashes")
|
|
.getMember("Hash")
|
|
.getACall() and
|
|
algorithmClassRef(algorithmName).getReturn().getAUse() in [
|
|
call.getArg(0), call.getArgByName("algorithm")
|
|
]
|
|
)
|
|
or
|
|
exists(DataFlow::TypeTracker t2 | result = hashInstance(t2, algorithmName).track(t2, t))
|
|
}
|
|
|
|
/** Gets a reference to a Hash instance using algorithm with `algorithmName`. */
|
|
DataFlow::Node hashInstance(string algorithmName) {
|
|
hashInstance(DataFlow::TypeTracker::end(), algorithmName).flowsTo(result)
|
|
}
|
|
|
|
/**
|
|
* An hashing operation from `cryptography.hazmat.primitives.hashes`.
|
|
*/
|
|
class CryptographyGenericHashOperation extends Cryptography::CryptographicOperation::Range,
|
|
DataFlow::MethodCallNode {
|
|
string algorithmName;
|
|
|
|
CryptographyGenericHashOperation() { this.calls(hashInstance(algorithmName), "update") }
|
|
|
|
override Cryptography::CryptographicAlgorithm getAlgorithm() {
|
|
result.matchesName(algorithmName)
|
|
}
|
|
|
|
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] }
|
|
}
|
|
}
|
|
}
|