mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Python: Model rsa
This commit is contained in:
2
python/change-notes/2021-06-09-rsa-add-modeling.md
Normal file
2
python/change-notes/2021-06-09-rsa-add-modeling.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Added modeling of the PyPI package `rsa`.
|
||||
@@ -16,6 +16,7 @@ private import semmle.python.frameworks.MysqlConnectorPython
|
||||
private import semmle.python.frameworks.MySQLdb
|
||||
private import semmle.python.frameworks.Psycopg2
|
||||
private import semmle.python.frameworks.PyMySQL
|
||||
private import semmle.python.frameworks.Rsa
|
||||
private import semmle.python.frameworks.Simplejson
|
||||
private import semmle.python.frameworks.Stdlib
|
||||
private import semmle.python.frameworks.Tornado
|
||||
|
||||
141
python/ql/src/semmle/python/frameworks/Rsa.qll
Normal file
141
python/ql/src/semmle/python/frameworks/Rsa.qll
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of the `rsa` PyPI package.
|
||||
* See https://stuvel.eu/python-rsa-doc/.
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.dataflow.new.TaintTracking
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
/**
|
||||
* Provides models for the `rsa` PyPI package.
|
||||
* See https://stuvel.eu/python-rsa-doc/.
|
||||
*/
|
||||
private module Rsa {
|
||||
/**
|
||||
* A call to `rsa.newkeys`
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.newkeys
|
||||
*/
|
||||
class RsaNewkeysCall extends Cryptography::PublicKey::KeyGeneration::RsaRange,
|
||||
DataFlow::CallCfgNode {
|
||||
RsaNewkeysCall() { this = API::moduleImport("rsa").getMember("newkeys").getACall() }
|
||||
|
||||
override DataFlow::Node getKeySizeArg() {
|
||||
result in [this.getArg(0), this.getArgByName("nbits")]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `rsa.encrypt`
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.encrypt
|
||||
*/
|
||||
class RsaEncryptCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode {
|
||||
RsaEncryptCall() { this = API::moduleImport("rsa").getMember("encrypt").getACall() }
|
||||
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() { result.getName() = "RSA" }
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [this.getArg(0), this.getArgByName("message")]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `rsa.decrypt`
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.decrypt
|
||||
*/
|
||||
class RsaDecryptCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode {
|
||||
RsaDecryptCall() { this = API::moduleImport("rsa").getMember("decrypt").getACall() }
|
||||
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() { result.getName() = "RSA" }
|
||||
|
||||
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("crypto")] }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `rsa.sign`, which both hashes and signs in the input message.
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.sign
|
||||
*/
|
||||
class RsaSignCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode {
|
||||
RsaSignCall() { this = API::moduleImport("rsa").getMember("sign").getACall() }
|
||||
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() {
|
||||
// signature part
|
||||
result.getName() = "RSA"
|
||||
or
|
||||
// hashing part
|
||||
exists(StrConst str, DataFlow::Node hashNameArg |
|
||||
hashNameArg in [this.getArg(2), this.getArgByName("hash_method")] and
|
||||
DataFlow::exprNode(str).(DataFlow::LocalSourceNode).flowsTo(hashNameArg) and
|
||||
result.matchesName(str.getText())
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [this.getArg(0), this.getArgByName("message")]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `rsa.verify`
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.verify
|
||||
*/
|
||||
class RsaVerifyCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode {
|
||||
RsaVerifyCall() { this = API::moduleImport("rsa").getMember("verify").getACall() }
|
||||
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() {
|
||||
// note that technically there is also a hashing operation going on but we don't
|
||||
// know what algorithm is used up front, since it is encoded in the signature
|
||||
result.getName() = "RSA"
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [this.getArg(0), this.getArgByName("message")]
|
||||
or
|
||||
result in [this.getArg(1), this.getArgByName("signature")]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `rsa.compute_hash`
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.compute_hash
|
||||
*/
|
||||
class RsaComputeHashCall extends Cryptography::CryptographicOperation::Range,
|
||||
DataFlow::CallCfgNode {
|
||||
RsaComputeHashCall() { this = API::moduleImport("rsa").getMember("compute_hash").getACall() }
|
||||
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() {
|
||||
exists(StrConst str, DataFlow::Node hashNameArg |
|
||||
hashNameArg in [this.getArg(1), this.getArgByName("method_name")] and
|
||||
DataFlow::exprNode(str).(DataFlow::LocalSourceNode).flowsTo(hashNameArg) and
|
||||
result.matchesName(str.getText())
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [this.getArg(0), this.getArgByName("message")]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `rsa.sign_hash`
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.sign_hash
|
||||
*/
|
||||
class RsaSignHashCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode {
|
||||
RsaSignHashCall() { this = API::moduleImport("rsa").getMember("sign_hash").getACall() }
|
||||
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() { result.getName() = "RSA" }
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [this.getArg(0), this.getArgByName("hash_value")]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
import rsa
|
||||
|
||||
# using a rather low keysize, since otherwise it takes quite long to run.
|
||||
(public_key, private_key) = rsa.newkeys(512) # $ MISSING: PublicKeyGeneration keySize=2048
|
||||
(public_key, private_key) = rsa.newkeys(nbits=512) # $ MISSING: PublicKeyGeneration keySize=2048
|
||||
(public_key, private_key) = rsa.newkeys(512) # $ PublicKeyGeneration keySize=512
|
||||
(public_key, private_key) = rsa.newkeys(nbits=512) # $ PublicKeyGeneration keySize=512
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -16,15 +16,15 @@ print("encrypt/decrypt")
|
||||
|
||||
secret_message = b"secret message"
|
||||
|
||||
encrypted = rsa.encrypt(secret_message, public_key) # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=secret_message
|
||||
encrypted = rsa.encrypt(message=secret_message, pub_key=public_key) # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=secret_message
|
||||
encrypted = rsa.encrypt(secret_message, public_key) # $ CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=secret_message
|
||||
encrypted = rsa.encrypt(message=secret_message, pub_key=public_key) # $ CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=secret_message
|
||||
|
||||
print("encrypted={}".format(encrypted))
|
||||
|
||||
print()
|
||||
|
||||
decrypted = rsa.decrypt(encrypted, private_key) # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=encrypted
|
||||
decrypted = rsa.decrypt(crypto=encrypted, priv_key=private_key) # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=encrypted
|
||||
decrypted = rsa.decrypt(encrypted, private_key) # $ CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=encrypted
|
||||
decrypted = rsa.decrypt(crypto=encrypted, priv_key=private_key) # $ CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=encrypted
|
||||
|
||||
print("decrypted={}".format(decrypted))
|
||||
assert decrypted == secret_message
|
||||
@@ -42,13 +42,13 @@ print("sign/verify")
|
||||
message = b"message"
|
||||
other_message = b"other message"
|
||||
|
||||
hash = rsa.compute_hash(message, "SHA-256") # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=SHA256 CryptographicOperationInput=message
|
||||
hash = rsa.compute_hash(message=message, method_name="SHA-256") # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=SHA256 CryptographicOperationInput=message
|
||||
signature_from_hash = rsa.sign_hash(hash, private_key, "SHA-256") # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=hash
|
||||
signature_from_hash = rsa.sign_hash(hash_value=hash, priv_key=private_key, hash_method="SHA-256") # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=hash
|
||||
hash = rsa.compute_hash(message, "SHA-256") # $ CryptographicOperation CryptographicOperationAlgorithm=SHA256 CryptographicOperationInput=message
|
||||
hash = rsa.compute_hash(message=message, method_name="SHA-256") # $ CryptographicOperation CryptographicOperationAlgorithm=SHA256 CryptographicOperationInput=message
|
||||
signature_from_hash = rsa.sign_hash(hash, private_key, "SHA-256") # $ CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=hash
|
||||
signature_from_hash = rsa.sign_hash(hash_value=hash, priv_key=private_key, hash_method="SHA-256") # $ CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=hash
|
||||
|
||||
signature = rsa.sign(message, private_key, "SHA-256") # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationAlgorithm=SHA256 CryptographicOperationInput=message
|
||||
signature = rsa.sign(message=message, priv_key=private_key, hash_method="SHA-256") # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationAlgorithm=SHA256 CryptographicOperationInput=message
|
||||
signature = rsa.sign(message, private_key, "SHA-256") # $ CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationAlgorithm=SHA256 CryptographicOperationInput=message
|
||||
signature = rsa.sign(message=message, priv_key=private_key, hash_method="SHA-256") # $ CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationAlgorithm=SHA256 CryptographicOperationInput=message
|
||||
|
||||
assert signature == signature_from_hash
|
||||
|
||||
@@ -56,13 +56,13 @@ print("signature={}".format(signature))
|
||||
|
||||
print()
|
||||
|
||||
rsa.verify(message, signature, public_key) # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=message CryptographicOperationInput=signature
|
||||
rsa.verify(message=message, signature=signature, pub_key=public_key) # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=message CryptographicOperationInput=signature
|
||||
rsa.verify(message, signature, public_key) # $ CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=message CryptographicOperationInput=signature
|
||||
rsa.verify(message=message, signature=signature, pub_key=public_key) # $ CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=message CryptographicOperationInput=signature
|
||||
|
||||
print("Signature verified (as expected)")
|
||||
|
||||
try:
|
||||
rsa.verify(other_message, signature, public_key) # $ MISSING: CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=other_message CryptographicOperationInput=signature
|
||||
rsa.verify(other_message, signature, public_key) # $ CryptographicOperation CryptographicOperationAlgorithm=RSA CryptographicOperationInput=other_message CryptographicOperationInput=signature
|
||||
raise Exception("Signature verified (unexpected)")
|
||||
except rsa.VerificationError:
|
||||
print("Signature mismatch (as expected)")
|
||||
|
||||
Reference in New Issue
Block a user