mirror of
https://github.com/github/codeql.git
synced 2025-12-18 01:33:15 +01:00
Merge pull request #7021 from erik-krogh/cwe326
JS: Add insufficient key size query
This commit is contained in:
@@ -25,6 +25,26 @@ abstract class CryptographicOperation extends Expr {
|
||||
*/
|
||||
abstract class CryptographicKey extends DataFlow::ValueNode { }
|
||||
|
||||
/**
|
||||
* The creation of a cryptographic key.
|
||||
*/
|
||||
abstract class CryptographicKeyCreation extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the algorithm used to create the key.
|
||||
*/
|
||||
abstract CryptographicAlgorithm getAlgorithm();
|
||||
|
||||
/**
|
||||
* Gets the size of the key.
|
||||
*/
|
||||
abstract int getSize();
|
||||
|
||||
/**
|
||||
* Gets whether the key is symmetric.
|
||||
*/
|
||||
abstract predicate isSymmetricKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* A key used in a cryptographic algorithm, viewed as a `CredentialsExpr`.
|
||||
*/
|
||||
@@ -141,14 +161,9 @@ private module NodeJSCrypto {
|
||||
* Also matches `createHash`, `createHmac`, `createSign` instead of `createCipher`.
|
||||
*/
|
||||
|
||||
exists(DataFlow::SourceNode mod, string createSuffix |
|
||||
createSuffix = "Hash" or
|
||||
createSuffix = "Hmac" or
|
||||
createSuffix = "Sign" or
|
||||
createSuffix = "Cipher"
|
||||
|
|
||||
exists(DataFlow::SourceNode mod |
|
||||
mod = DataFlow::moduleImport("crypto") and
|
||||
this = mod.getAMemberCall("create" + createSuffix) and
|
||||
this = mod.getAMemberCall("create" + ["Hash", "Hmac", "Sign", "Cipher"]) and
|
||||
algorithm.matchesName(getArgument(0).getStringValue())
|
||||
)
|
||||
}
|
||||
@@ -156,6 +171,52 @@ private module NodeJSCrypto {
|
||||
CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
}
|
||||
|
||||
private class CreateKey extends CryptographicKeyCreation, DataFlow::CallNode {
|
||||
boolean symmetric;
|
||||
|
||||
CreateKey() {
|
||||
// crypto.generateKey(type, options, callback)
|
||||
// crypto.generateKeyPair(type, options, callback)
|
||||
// crypto.generateKeyPairSync(type, options)
|
||||
// crypto.generateKeySync(type, options)
|
||||
exists(DataFlow::SourceNode mod, string keyType |
|
||||
keyType = "Key" and symmetric = true
|
||||
or
|
||||
keyType = "KeyPair" and symmetric = false
|
||||
|
|
||||
mod = DataFlow::moduleImport("crypto") and
|
||||
this = mod.getAMemberCall("generate" + keyType + ["", "Sync"])
|
||||
)
|
||||
}
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() {
|
||||
result.matchesName(getArgument(0).getStringValue())
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
symmetric = true and
|
||||
result = getOptionArgument(1, "length").getIntValue()
|
||||
or
|
||||
symmetric = false and
|
||||
result = getOptionArgument(1, "modulusLength").getIntValue()
|
||||
}
|
||||
|
||||
override predicate isSymmetricKey() { symmetric = true }
|
||||
}
|
||||
|
||||
private class CreateDiffieHellmanKey extends CryptographicKeyCreation, DataFlow::CallNode {
|
||||
// require("crypto").createDiffieHellman(prime_length);
|
||||
CreateDiffieHellmanKey() {
|
||||
this = DataFlow::moduleMember("crypto", "createDiffieHellman").getACall()
|
||||
}
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { none() }
|
||||
|
||||
override int getSize() { result = getArgument(0).getIntValue() }
|
||||
|
||||
override predicate isSymmetricKey() { none() }
|
||||
}
|
||||
|
||||
private class Apply extends CryptographicOperation, MethodCallExpr {
|
||||
InstantiatedAlgorithm instantiation;
|
||||
|
||||
@@ -282,6 +343,35 @@ private module CryptoJS {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class CreateKey extends CryptographicKeyCreation, DataFlow::CallNode {
|
||||
string algorithm;
|
||||
int optionArg;
|
||||
|
||||
CreateKey() {
|
||||
// var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 });
|
||||
this =
|
||||
getAlgorithmExpr(any(CryptographicAlgorithm algo | algo.getName() = algorithm)).getACall() and
|
||||
optionArg = 2
|
||||
or
|
||||
// var key = CryptoJS.algo.PBKDF2.create({ keySize: 8 });
|
||||
this =
|
||||
DataFlow::moduleMember("crypto-js", "algo")
|
||||
.getAPropertyRead(algorithm)
|
||||
.getAMethodCall("create") and
|
||||
optionArg = 0
|
||||
}
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result.matchesName(algorithm) }
|
||||
|
||||
override int getSize() {
|
||||
result = getOptionArgument(optionArg, "keySize").getIntValue() * 32 // size is in words
|
||||
or
|
||||
result = getArgument(optionArg).getIntValue() * 32 // size is in words
|
||||
}
|
||||
|
||||
override predicate isSymmetricKey() { any() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -467,6 +557,39 @@ private module Forge {
|
||||
private class Key extends CryptographicKey {
|
||||
Key() { this = any(KeyCipher cipher).getKey() }
|
||||
}
|
||||
|
||||
private class CreateKey extends CryptographicKeyCreation, DataFlow::CallNode {
|
||||
CryptographicAlgorithm algorithm;
|
||||
|
||||
CreateKey() {
|
||||
// var cipher = forge.rc2.createEncryptionCipher(key, 128);
|
||||
this =
|
||||
getAnImportNode()
|
||||
.getAPropertyRead(any(string s | algorithm.matchesName(s)))
|
||||
.getAMemberCall("createEncryptionCipher")
|
||||
or
|
||||
// var key = forge.random.getBytesSync(16);
|
||||
// var cipher = forge.cipher.createCipher('AES-CBC', key);
|
||||
this =
|
||||
getAnImportNode()
|
||||
.getAPropertyRead("cipher")
|
||||
.getAMemberCall(["createCipher", "createDecipher"]) and
|
||||
algorithm.matchesName(this.getArgument(0).getStringValue())
|
||||
}
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
|
||||
override int getSize() {
|
||||
result = this.getArgument(1).getIntValue()
|
||||
or
|
||||
exists(DataFlow::CallNode call | call.getCalleeName() = ["getBytes", "getBytesSync"] |
|
||||
getArgument(1).getALocalSource() = call and
|
||||
result = call.getArgument(0).getIntValue() * 8 // bytes to bits
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSymmetricKey() { any() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -556,13 +679,38 @@ private module Hasha {
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides classes for working with the `express-jwt` package (https://github.com/auth0/express-jwt);
|
||||
*/
|
||||
module ExpressJwt {
|
||||
private class Key extends CryptographicKey {
|
||||
Key() { this = DataFlow::moduleMember("express-jwt", "sign").getACall().getArgument(1) }
|
||||
}
|
||||
/**
|
||||
* Provides classes for working with the `express-jwt` package (https://github.com/auth0/express-jwt);
|
||||
*/
|
||||
private module ExpressJwt {
|
||||
private class Key extends CryptographicKey {
|
||||
Key() { this = DataFlow::moduleMember("express-jwt", "sign").getACall().getArgument(1) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides classes for working with the `node-rsa` package (https://www.npmjs.com/package/node-rsa)
|
||||
*/
|
||||
private module NodeRsa {
|
||||
private class CreateKey extends CryptographicKeyCreation, API::InvokeNode {
|
||||
CryptographicAlgorithm algorithm;
|
||||
|
||||
CreateKey() {
|
||||
this = API::moduleImport("node-rsa").getAnInstantiation()
|
||||
or
|
||||
this = API::moduleImport("node-rsa").getInstance().getMember("generateKeyPair").getACall()
|
||||
}
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result.matchesName("rsa") }
|
||||
|
||||
override int getSize() {
|
||||
result = this.getArgument(0).getIntValue()
|
||||
or
|
||||
result = this.getOptionArgument(0, "b").getIntValue()
|
||||
}
|
||||
|
||||
override predicate isSymmetricKey() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ private module AlgorithmNames {
|
||||
name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"]
|
||||
}
|
||||
|
||||
predicate isWeakPasswordHashingAlgorithm(string name) { none() }
|
||||
predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" }
|
||||
}
|
||||
|
||||
private import AlgorithmNames
|
||||
@@ -85,11 +85,13 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm {
|
||||
|
||||
/**
|
||||
* Holds if the name of this algorithm matches `name` modulo case,
|
||||
* white space, dashes, and underscores.
|
||||
* white space, dashes, underscores, and anything after a dash in the name
|
||||
* (to ignore modes of operation, such as CBC or ECB).
|
||||
*/
|
||||
bindingset[name]
|
||||
predicate matchesName(string name) {
|
||||
name.toUpperCase().regexpReplaceAll("[-_ ]", "") = getName()
|
||||
[name.toUpperCase(), name.toUpperCase().regexpCapture("^(\\w+)(?:-.*)?$", 1)]
|
||||
.regexpReplaceAll("[-_ ]", "") = getName()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user