Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c5cf0ff
added java cryptographic check queries
unprovable Oct 1, 2025
f38ab45
removed all @security.severity ratings to keep the main impartial
unprovable Oct 1, 2025
bba541c
Merge remote-tracking branch 'upstream/java-crypto-check' into santan…
bdrodes Oct 8, 2025
cf88e3f
Crypto: Standardize naming where use of "family" and "type" have been…
bdrodes Oct 8, 2025
1b1b333
Crypto: Modify suggested queries per misc. side conversations on stan…
bdrodes Oct 8, 2025
143be8c
Crypto: Remove redundant queries.
bdrodes Oct 8, 2025
bd34b6c
Crypto: Removing JCA model of random, need to reassess this as this i…
bdrodes Oct 8, 2025
83ff70b
Crypto: Adding tests for insecure iv or nonce. Updating generic liter…
bdrodes Oct 8, 2025
8e10e19
Crypto: Adding query for unknown IV initialization.
bdrodes Oct 8, 2025
75b5a9f
Crypto: Update general regression test results to account for removal…
bdrodes Oct 8, 2025
11e8139
Crypto: Updated default flows to use taint tracking (this is needed t…
bdrodes Oct 8, 2025
7a57496
Crypto: Missing test update.
bdrodes Oct 8, 2025
f524de4
Crypto: Updating insecure iv/nonce to consider if an operation is kno…
bdrodes Oct 8, 2025
fdba3ac
Crypto: Fix QL-for-QL alert and auto-format
nicolaswill Oct 9, 2025
c6cc4ff
Crypto: Minor fixes to WeakBlockModes, WeakHash to consider SHA3 ok, …
bdrodes Oct 9, 2025
3dedda4
Merge branch 'santander-java-crypto-check' of https://github.com/bdro…
bdrodes Oct 9, 2025
deb4373
Crypto: Minor fixes to WeakSymmetricCipher, change to a singular name…
bdrodes Oct 9, 2025
fba8087
Crypto: Example query reorg - moving queries of this PR into 'example…
bdrodes Oct 9, 2025
758759a
Crypto: Reused nonce query updates and test updates to address false …
bdrodes Oct 10, 2025
3667365
Crypto: Weak asymmetric key gen size fixes and test.
bdrodes Oct 10, 2025
ffd191d
Crypto: missing new endpoint to get the creating operation for a key …
bdrodes Oct 10, 2025
d68f3cf
Crypto: InsecureIVorNonceSource now ignored null to avoid being too n…
bdrodes Oct 10, 2025
e76ced1
Crypto: Updating weak asymmetric key gen to include key exchange.
bdrodes Oct 10, 2025
08abdb8
Crypto: Adding a "javaConstant" concept to handle config files.
bdrodes Oct 13, 2025
4b241d7
Crypto: adding initial weak hash query overhaul and tests, but no exp…
bdrodes Oct 13, 2025
bd068c2
Crypto: Updating expected file for weak asymmetric key gen size.
bdrodes Oct 13, 2025
76128ed
Crypto: Update InsecureIVorNonce to be a path problem.
bdrodes Oct 13, 2025
7847e92
Crypto: Update KDF iteration and count to be path problems
bdrodes Oct 13, 2025
8b5a423
Crypto: Convert ReusedNonce.ql into a path problem.
bdrodes Oct 13, 2025
7e8acd7
Crypto: Update WeakAsymmetricKeyGenSize to a path problem.
bdrodes Oct 13, 2025
55bbcee
Crypto: Make WeakAsymmetricKeyGenSize a path problem.
bdrodes Oct 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class KnownOpenSslEllipticCurveConstantAlgorithmInstance extends OpenSslAlgorith
result = this.(Call).getTarget().getName()
}

override Crypto::EllipticCurveFamilyType getEllipticCurveFamilyType() {
override Crypto::EllipticCurveType getEllipticCurveType() {
if
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _,
_)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class KnownOpenSslHashConstantAlgorithmInstance extends OpenSslAlgorithmInstance

override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }

override Crypto::THashType getHashFamily() {
override Crypto::THashType getHashType() {
knownOpenSslConstantToHashFamilyType(this, result)
or
not knownOpenSslConstantToHashFamilyType(this, _) and result = Crypto::OtherHashType()
Expand Down
141 changes: 64 additions & 77 deletions java/ql/lib/experimental/quantum/JCA.qll
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,7 @@ module JCAModel {
}

bindingset[hash]
predicate hash_names(string hash) {
hash.toUpperCase()
.matches(["SHA-%", "SHA3-%", "BLAKE2b%", "BLAKE2s%", "MD5", "RIPEMD160", "Whirlpool"]
.toUpperCase())
}
predicate hash_names(string hash) { exists(hash_name_to_type_known(hash, _)) }

bindingset[kdf]
predicate kdf_names(string kdf) {
Expand Down Expand Up @@ -110,7 +106,8 @@ module JCAModel {
predicate signature_names(string name) {
name.toUpperCase().splitAt("WITH", 1).matches(["RSA%", "ECDSA%", "DSA%"])
or
name.toUpperCase().matches(["RSASSA-PSS", "ED25519", "ED448", "EDDSA", "ML-DSA%", "HSS/LMS"])
name.toUpperCase()
.matches(["RSASSA-PSS", "ED25519", "ED448", "EDDSA", "ML-DSA%", "HSS/LMS", "DSA"])
}

bindingset[name]
Expand All @@ -131,41 +128,43 @@ module JCAModel {
// TODO: add additional
}

bindingset[name]
Crypto::HashType hash_name_to_type_known(string name, int digestLength) {
name in ["SHA-1", "SHA1"] and result instanceof Crypto::SHA1 and digestLength = 160
or
name in ["SHA-256", "SHA-384", "SHA-512", "SHA256", "SHA384", "SHA512"] and
result instanceof Crypto::SHA2 and
digestLength = name.replaceAll("-", "").splitAt("SHA", 1).toInt()
or
name in ["SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512", "SHA3256", "SHA3384", "SHA3512"] and
result instanceof Crypto::SHA3 and
digestLength = name.replaceAll("-", "").splitAt("SHA3", 1).toInt()
or
(
name.matches("BLAKE2b%") and
result instanceof Crypto::BLAKE2B
bindingset[nameRaw]
Crypto::HashType hash_name_to_type_known(string nameRaw, int digestLength) {
exists(string name | name = nameRaw.toUpperCase() |
name in ["SHA-1", "SHA1"] and result instanceof Crypto::SHA1 and digestLength = 160
or
name in ["SHA-256", "SHA-384", "SHA-512", "SHA256", "SHA384", "SHA512"] and
result instanceof Crypto::SHA2 and
digestLength = name.replaceAll("-", "").splitAt("SHA", 1).toInt()
or
name in ["SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512", "SHA3256", "SHA3384", "SHA3512"] and
result instanceof Crypto::SHA3 and
digestLength = name.replaceAll("-", "").splitAt("SHA3", 1).toInt()
or
(
name.toUpperCase().matches("BLAKE2B%") and
result instanceof Crypto::BLAKE2B
or
name.toUpperCase() = "BLAKE2S" and result instanceof Crypto::BLAKE2S
) and
(
if exists(name.indexOf("-"))
then name.splitAt("-", 1).toInt() = digestLength
else digestLength = 512
)
or
name = "BLAKE2s" and result instanceof Crypto::BLAKE2S
) and
(
if exists(name.indexOf("-"))
then name.splitAt("-", 1).toInt() = digestLength
else digestLength = 512
name = "MD5" and
result instanceof Crypto::MD5 and
digestLength = 128
or
name = "RIPEMD160" and
result instanceof Crypto::RIPEMD160 and
digestLength = 160
or
name = "WHIRLPOOL" and
result instanceof Crypto::WHIRLPOOL and
digestLength = 512 // TODO: verify
)
or
name = "MD5" and
result instanceof Crypto::MD5 and
digestLength = 128
or
name = "RIPEMD160" and
result instanceof Crypto::RIPEMD160 and
digestLength = 160
or
name = "Whirlpool" and
result instanceof Crypto::WHIRLPOOL and
digestLength = 512 // TODO: verify
}

bindingset[name]
Expand Down Expand Up @@ -257,6 +256,8 @@ module JCAModel {
name.toUpperCase().matches("ML-DSA%") and type = KeyOpAlg::TSignature(KeyOpAlg::DSA())
or
name.toUpperCase() = "HSS/LMS" and type = KeyOpAlg::TSignature(KeyOpAlg::HSS_LMS())
or
name.toUpperCase() = "DSA" and type = KeyOpAlg::TSignature(KeyOpAlg::DSA())
}

bindingset[name]
Expand All @@ -265,9 +266,9 @@ module JCAModel {
}

/**
* A `StringLiteral` in the `"ALG/MODE/PADDING"` or `"ALG"` format
* A `JavaConstant` in the `"ALG/MODE/PADDING"` or `"ALG"` format
*/
class CipherStringLiteral extends StringLiteral {
class CipherStringLiteral extends JavaConstant {
CipherStringLiteral() { cipher_names(this.getValue().splitAt("/")) }

string getAlgorithmName() { result = this.getValue().splitAt("/", 0) }
Expand Down Expand Up @@ -426,7 +427,7 @@ module JCAModel {

override string getRawHashAlgorithmName() { result = super.getPadding() }

override Crypto::THashType getHashFamily() { result = hash_name_to_type_known(hashName, _) }
override Crypto::THashType getHashType() { result = hash_name_to_type_known(hashName, _) }

override int getFixedDigestLength() { exists(hash_name_to_type_known(hashName, result)) }
}
Expand Down Expand Up @@ -836,7 +837,7 @@ module JCAModel {
* Flow from a known hash algorithm name to a `MessageDigest.getInstance(sink)` call.
*/
module KnownHashAlgorithmLiteralToMessageDigestConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { hash_names(src.asExpr().(StringLiteral).getValue()) }
predicate isSource(DataFlow::Node src) { hash_names(src.asExpr().(JavaConstant).getValue()) }

predicate isSink(DataFlow::Node sink) {
exists(HashAlgorithmValueConsumer consumer | sink = consumer.getInputNode())
Expand All @@ -846,7 +847,7 @@ module JCAModel {
module KnownHashAlgorithmLiteralToMessageDigestFlow =
DataFlow::Global<KnownHashAlgorithmLiteralToMessageDigestConfig>;

class KnownHashAlgorithm extends Crypto::HashAlgorithmInstance instanceof StringLiteral {
class KnownHashAlgorithm extends Crypto::HashAlgorithmInstance instanceof JavaConstant {
HashAlgorithmValueConsumer consumer;

KnownHashAlgorithm() {
Expand All @@ -859,7 +860,7 @@ module JCAModel {

override string getRawHashAlgorithmName() { result = super.getValue() }

override Crypto::THashType getHashFamily() {
override Crypto::THashType getHashType() {
result = hash_name_to_type_known(this.getRawHashAlgorithmName(), _)
}

Expand Down Expand Up @@ -1019,7 +1020,8 @@ module JCAModel {
}

class KeyGenerationAlgorithmValueConsumer extends CipherAlgorithmValueConsumer,
KeyAgreementAlgorithmValueConsumer, EllipticCurveAlgorithmValueConsumer instanceof Expr
KeyAgreementAlgorithmValueConsumer, EllipticCurveAlgorithmValueConsumer,
SignatureAlgorithmValueConsumer instanceof Expr
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is instanceof Expr necessary here?

{
KeyGeneratorGetInstanceCall instantiationCall;

Expand Down Expand Up @@ -1095,21 +1097,6 @@ module JCAModel {
}
}

/**
* An instance of `java.security.SecureRandom.nextBytes(byte[])` call.
* This is already generally modeled for Java in CodeQL, but
* we model it again as part of the crypto API model to have a cohesive model.
*/
class JavaSecuritySecureRandom extends Crypto::RandomNumberGenerationInstance instanceof Call {
JavaSecuritySecureRandom() {
this.getCallee().hasQualifiedName("java.security", "SecureRandom", "nextBytes")
}

override Crypto::DataFlowNode getOutputNode() { result.asExpr() = this.(Call).getArgument(0) }

override string getGeneratorName() { result = this.(Call).getCallee().getName() }
}

class KeyGeneratorGenerateCall extends Crypto::KeyGenerationOperationInstance instanceof MethodCall
{
Crypto::KeyArtifactType type;
Expand Down Expand Up @@ -1206,7 +1193,7 @@ module JCAModel {
}

module KDFAlgorithmStringToGetInstanceConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { kdf_names(src.asExpr().(StringLiteral).getValue()) }
predicate isSource(DataFlow::Node src) { kdf_names(src.asExpr().(JavaConstant).getValue()) }

predicate isSink(DataFlow::Node sink) {
exists(SecretKeyFactoryGetInstanceCall call | sink.asExpr() = call.getAlgorithmArg())
Expand Down Expand Up @@ -1247,7 +1234,7 @@ module JCAModel {
predicate isIntermediate() { none() }
}

class KdfAlgorithmStringLiteral extends Crypto::KeyDerivationAlgorithmInstance instanceof StringLiteral
class KdfAlgorithmStringLiteral extends Crypto::KeyDerivationAlgorithmInstance instanceof JavaConstant
{
SecretKeyFactoryKDFAlgorithmValueConsumer consumer;

Expand All @@ -1268,7 +1255,7 @@ module JCAModel {
class Pbkdf2WithHmac_KeyOperationAlgorithmStringLiteral extends Crypto::KeyOperationAlgorithmInstance instanceof KdfAlgorithmStringLiteral
{
Pbkdf2WithHmac_KeyOperationAlgorithmStringLiteral() {
this.(StringLiteral).getValue().toUpperCase().matches("PBKDF2WithHmac%".toUpperCase())
this.(JavaConstant).getValue().toUpperCase().matches("PBKDF2WithHmac%".toUpperCase())
}

override Crypto::KeyOpAlg::AlgorithmType getAlgorithmType() {
Expand All @@ -1289,20 +1276,20 @@ module JCAModel {

override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }

override string getRawAlgorithmName() { result = this.(StringLiteral).getValue() }
override string getRawAlgorithmName() { result = this.(JavaConstant).getValue() }
}

class Pbkdf2WithHmac_HashAlgorithmStringLiteral extends Crypto::HashAlgorithmInstance instanceof Pbkdf2WithHmac_KeyOperationAlgorithmStringLiteral
{
string hashName;

Pbkdf2WithHmac_HashAlgorithmStringLiteral() {
hashName = this.(StringLiteral).getValue().splitAt("WithHmac", 1)
hashName = this.(JavaConstant).getValue().splitAt("WithHmac", 1)
}

override string getRawHashAlgorithmName() { result = this.(StringLiteral).getValue() }
override string getRawHashAlgorithmName() { result = this.(JavaConstant).getValue() }

override Crypto::THashType getHashFamily() { result = hash_name_to_type_known(hashName, _) }
override Crypto::THashType getHashType() { result = hash_name_to_type_known(hashName, _) }

override int getFixedDigestLength() { exists(hash_name_to_type_known(hashName, result)) }
}
Expand Down Expand Up @@ -1414,7 +1401,7 @@ module JCAModel {
GetInstanceInitUseFlowAnalysis<KeyAgreementGetInstanceCall, KeyAgreementInitCall,
KeyAgreementCall>;

class KeyAgreementStringLiteral extends StringLiteral {
class KeyAgreementStringLiteral extends JavaConstant {
KeyAgreementStringLiteral() { key_agreement_names(this.getValue()) }
}

Expand Down Expand Up @@ -1532,7 +1519,7 @@ module JCAModel {
*/

module MacKnownAlgorithmToConsumerConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { mac_names(src.asExpr().(StringLiteral).getValue()) }
predicate isSource(DataFlow::Node src) { mac_names(src.asExpr().(JavaConstant).getValue()) }

predicate isSink(DataFlow::Node sink) {
exists(MacGetInstanceCall call | sink.asExpr() = call.getAlgorithmArg())
Expand Down Expand Up @@ -1566,7 +1553,7 @@ module JCAModel {

module MacInitCallToMacOperationFlow = DataFlow::Global<MacInitCallToMacOperationFlowConfig>;

class KnownMacAlgorithm extends Crypto::KeyOperationAlgorithmInstance instanceof StringLiteral {
class KnownMacAlgorithm extends Crypto::KeyOperationAlgorithmInstance instanceof JavaConstant {
MacGetInstanceAlgorithmValueConsumer consumer;

KnownMacAlgorithm() {
Expand Down Expand Up @@ -1722,7 +1709,7 @@ module JCAModel {
}
}

class SignatureStringLiteral extends StringLiteral {
class SignatureStringLiteral extends JavaConstant {
SignatureStringLiteral() { signature_names(this.getValue()) }
}

Expand Down Expand Up @@ -1765,12 +1752,12 @@ module JCAModel {
int digestLength;

SignatureHashAlgorithmInstance() {
hashType = signature_name_to_hash_type_known(this.(StringLiteral).getValue(), digestLength)
hashType = signature_name_to_hash_type_known(this.(JavaConstant).getValue(), digestLength)
}

override string getRawHashAlgorithmName() { result = this.(StringLiteral).getValue() }
override string getRawHashAlgorithmName() { result = this.(JavaConstant).getValue() }

override Crypto::THashType getHashFamily() { result = hashType }
override Crypto::THashType getHashType() { result = hashType }

override int getFixedDigestLength() { result = digestLength }
}
Expand Down Expand Up @@ -1891,7 +1878,7 @@ module JCAModel {

module EllipticCurveStringToConsumerFlow = DataFlow::Global<EllipticCurveStringToConsumerConfig>;

class EllipticCurveStringLiteral extends StringLiteral {
class EllipticCurveStringLiteral extends JavaConstant {
EllipticCurveStringLiteral() { elliptic_curve_names(this.getValue()) }
}

Expand All @@ -1905,7 +1892,7 @@ module JCAModel {

override string getRawEllipticCurveName() { result = super.getValue() }

override Crypto::EllipticCurveFamilyType getEllipticCurveFamilyType() {
override Crypto::EllipticCurveType getEllipticCurveType() {
if
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getRawEllipticCurveName(), _, _)
then
Expand Down
Loading
Loading