Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 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
10 changes: 5 additions & 5 deletions java/ql/lib/experimental/quantum/JCA.qll
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,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 @@ -859,7 +859,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 @@ -1302,7 +1302,7 @@ module JCAModel {

override string getRawHashAlgorithmName() { result = this.(StringLiteral).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 @@ -1770,7 +1770,7 @@ module JCAModel {

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

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

override int getFixedDigestLength() { result = digestLength }
}
Expand Down Expand Up @@ -1905,7 +1905,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
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* @name Insecure nonce at a cipher operation
* @id java/quantum/insecure-nonce
* @description A nonce is generated from a source that is not secure. This can lead to
* vulnerabilities such as replay attacks or key recovery.
* @kind problem
* @problem.severity error
* @precision high
* @tags quantum
* experimental
*/

import experimental.quantum.Language

predicate isInsecureNonceSource(Crypto::NonceArtifactNode n, Crypto::NodeBase src) {
src = n.getSourceNode() and
not src.asElement() instanceof SecureRandomnessInstance
}

from Crypto::KeyOperationNode op, Crypto::NodeBase src
where isInsecureNonceSource(op.getANonce(), src)
select op, "Operation uses insecure nonce source $@", src, src.toString()
24 changes: 24 additions & 0 deletions java/ql/src/experimental/quantum/Analysis/NonAESGCMCipher.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @name Cipher not AES-GCM mode
* @id java/quantum/non-aes-gcm
* @description An AES cipher is in use without GCM
* @kind problem
* @problem.severity error
* @precision high
* @tags quantum
* experimental
*/

import experimental.quantum.Language

class NonAESGCMAlgorithmNode extends Crypto::KeyOperationAlgorithmNode {
NonAESGCMAlgorithmNode() {
this.getAlgorithmType() = Crypto::KeyOpAlg::TSymmetricCipher(Crypto::KeyOpAlg::AES()) and
this.getModeOfOperation().getModeType() != Crypto::KeyOpAlg::GCM()
}
}

from Crypto::KeyOperationNode op, Crypto::KeyOperationOutputNode codeNode
where op.getAKnownAlgorithm() instanceof NonAESGCMAlgorithmNode and
codeNode = op.getAnOutputArtifact()
select op, "Non-AES-GCM instance."
2 changes: 1 addition & 1 deletion java/ql/src/experimental/quantum/Analysis/ReusedNonce.ql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @id java/quantum/reused-nonce
* @kind problem
* @problem.severity error
* @precision medium
* @precision high
* @tags quantum
* experimental
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* @id java/quantum/unknown-kdf-iteration-count
* @kind problem
* @precision medium
* @severity warning
* @tags quantum
* experimental
*/
Expand Down
24 changes: 24 additions & 0 deletions java/ql/src/experimental/quantum/Analysis/WeakAsymmetric.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @name Weak Asymmetric Key Size
* @id java/quantum/weak-asymmetric-key-size
* @description An asymmetric cipher with a short key size is in use
* @kind problem
* @problem.severity error
* @precision high
* @tags quantum
* experimental
*/

import java
import experimental.quantum.Language

from Crypto::KeyOperationAlgorithmNode op, DataFlow::Node configSrc, int keySize, string algName
where
keySize = op.getKeySizeFixed() and
keySize < 2048 and
algName = op.getAlgorithmName() and
// Can't be an elliptic curve
not Crypto::isEllipticCurveAlgorithmName(algName)
Copy link

Copilot AI Oct 8, 2025

Choose a reason for hiding this comment

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

The variable configSrc is declared in the from clause but never assigned a value in the where clause, which will cause the query to fail or produce no results. Either remove configSrc from the select statement or add a condition to assign it a value.

Suggested change
not Crypto::isEllipticCurveAlgorithmName(algName)
not Crypto::isEllipticCurveAlgorithmName(algName) and
configSrc = op.getConfigSource()

Copilot uses AI. Check for mistakes.

Copy link
Contributor

Choose a reason for hiding this comment

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

This comment does indeed point out an issue with the query. I would suggest a rewrite to something like the following (I have not tested this change... it's a draft revision):

/**
 * @name Weak Asymmetric Key Size
 * @id java/quantum/weak-asymmetric-key-size
 * @description An asymmetric cipher with a short key size is in use
 * @kind problem
 * @problem.severity error
 * @precision high
 * @tags quantum
 *       experimental
 */

import java
import experimental.quantum.Language

from
  Crypto::KeyOperationAlgorithmNode alg, Crypto::NodeBase configSrc, string configSrcDesc,
  int keySize, string algName
where
  algName = alg.getAlgorithmName() and
  // Can't be an elliptic curve
  not Crypto::isEllipticCurveAlgorithmName(algName) and
  (
    // Case 1: Key size from config source
    exists(Crypto::GenericSourceNode src |
      src = alg.getKeySize() and
      keySize = src.toString().toInt() and
      configSrc = src and
      configSrcDesc = src.toString()
    )
    or
    // Case 2: Fixed key size (no config source, or config source is fine)
    not exists(Crypto::GenericSourceNode src |
      src = alg.getKeySize() and
      src.toString().toInt() < 2048
    ) and
    keySize = alg.getKeySizeFixed() and
    configSrc = alg and
    configSrcDesc = "(implicit)"
  ) and
  keySize < 2048
select alg,
  "Use of weak asymmetric key size (" + keySize.toString() + " bits) for algorithm " + algName +
    " at config source $@.", configSrc, configSrcDesc

select op,
"Use of weak asymmetric key size (" + keySize.toString() + " bits) for algorithm " +
algName.toString() + " at config source $@", configSrc, configSrc.toString()
31 changes: 31 additions & 0 deletions java/ql/src/experimental/quantum/Analysis/WeakBlockModes.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @name Weak AES Block mode
* @id java/quantum/weak-block-modes
* @description An AES cipher is in use with an insecure block mode
* @kind problem
* @problem.severity error
* @precision high
* @tags quantum
* experimental
*/

import java
import experimental.quantum.Language

class WeakAESBlockModeAlgNode extends Crypto::KeyOperationAlgorithmNode {
WeakAESBlockModeAlgNode() {
this.getAlgorithmType() = Crypto::KeyOpAlg::TSymmetricCipher(Crypto::KeyOpAlg::AES()) and
(
this.getModeOfOperation().getModeType() = Crypto::KeyOpAlg::ECB() or
this.getModeOfOperation().getModeType() = Crypto::KeyOpAlg::CFB() or
this.getModeOfOperation().getModeType() = Crypto::KeyOpAlg::OFB() or
this.getModeOfOperation().getModeType() = Crypto::KeyOpAlg::CTR()
)
}
}

from Crypto::KeyOperationNode op, Crypto::KeyOperationOutputNode codeNode
where
op.getAKnownAlgorithm() instanceof WeakAESBlockModeAlgNode and
codeNode = op.getAnOutputArtifact()
select op, "Weak AES block mode instance."
34 changes: 34 additions & 0 deletions java/ql/src/experimental/quantum/Analysis/WeakHashing.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* @name Weak hashes
* @description Finds uses of cryptographic hashing algorithms that are unapproved or otherwise weak.
* @id java/quantum/weak-hashes
* @kind problem
* @problem.severity error
* @precision high
* @tags external/cwe/cwe-327
* quantum
* experimental
*/

import java
import experimental.quantum.Language

from Crypto::HashAlgorithmNode alg, Crypto::HashType htype, string msg
where
htype = alg.getHashType() and
(
htype != Crypto::SHA2() and
msg = "Use of unapproved hash algorithm or API " + htype.toString() + "."
or
htype = Crypto::SHA2() and
not exists(alg.getDigestLength()) and
msg =
"Use of approved hash algorithm or API type " + htype.toString() + " but unknown digest size."
or
htype = Crypto::SHA2() and
alg.getDigestLength() < 256 and
msg =
"Use of approved hash algorithm or API type " + htype.toString() + " but weak digest size (" +
alg.getDigestLength() + ")."
)
select alg, msg
20 changes: 20 additions & 0 deletions java/ql/src/experimental/quantum/Analysis/WeakKDFIterationCount.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @name Weak known key derivation function iteration count
* @description Detects key derivation operations with a known weak iteration count.
* @id java/quantum/weak-kdf-iteration-count
* @kind problem
* @problem.severity error
* @precision high
* @tags quantum
* experimental
*/

import java
import experimental.quantum.Language

from Crypto::KeyDerivationOperationNode op, Literal l
where
op.getIterationCount().asElement() = l and
l.getValue().toInt() < 100000
select op, "Key derivation operation configures iteration count below 100k: $@", l,
l.getValue().toString()
20 changes: 20 additions & 0 deletions java/ql/src/experimental/quantum/Analysis/WeakKDFKeySize.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @name Weak known key derivation function output length
* @description Detects key derivation operations with a known weak output length
* @id java/quantum/weak-kdf-key-size
* @kind problem
* @problem.severity error
* @precision high
* @tags quantum
* experimental
*/

import java
import experimental.quantum.Language

from Crypto::KeyDerivationOperationNode op, Literal l
where
op.getOutputKeySize().asElement() = l and
l.getValue().toInt() < 256
select op, "Key derivation operation configures output key length below 256: $@", l,
l.getValue().toString()
25 changes: 25 additions & 0 deletions java/ql/src/experimental/quantum/Analysis/WeakRSA.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* @name Cipher is Weak RSA Implementation
* @id java/quantum/weak-rsa
* @description RSA with a key length <2048 found
* @kind problem
* @problem.severity error
* @precision high
* @tags quantum
* experimental
*/

import experimental.quantum.Language

class WeakRsaAlgorithmNode extends Crypto::KeyOperationAlgorithmNode {
WeakRsaAlgorithmNode() {
this.getAlgorithmType() = Crypto::KeyOpAlg::TAsymmetricCipher(Crypto::KeyOpAlg::RSA()) and
this.getKeySizeFixed() < 2048
}
}

from Crypto::KeyOperationNode op, string message
where
op.getAKnownAlgorithm() instanceof WeakRsaAlgorithmNode and
message = "Weak RSA instance found with key length <2048"
select op, message
30 changes: 30 additions & 0 deletions java/ql/src/experimental/quantum/Analysis/WeakSymmetricCiphers.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @name Weak symmetric ciphers
* @description Finds uses of cryptographic symmetric cipher algorithms that are unapproved or otherwise weak.
* @id java/quantum/weak-ciphers
* @kind problem
* @problem.severity error
* @precision high
* @tags external/cwe/cwe-327
* quantum
* experimental
*/

import java
import experimental.quantum.Language
import Crypto::KeyOpAlg as KeyOpAlg

from Crypto::KeyOperationAlgorithmNode alg, KeyOpAlg::AlgorithmType algType, string msg
where
algType = alg.getAlgorithmType() and
(
algType = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DES()) or
algType = KeyOpAlg::TSymmetricCipher(KeyOpAlg::TRIPLE_DES()) or
algType = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DOUBLE_DES()) or
algType = KeyOpAlg::TSymmetricCipher(KeyOpAlg::RC2()) or
algType = KeyOpAlg::TSymmetricCipher(KeyOpAlg::RC4()) or
algType = KeyOpAlg::TSymmetricCipher(KeyOpAlg::IDEA()) or
algType = KeyOpAlg::TSymmetricCipher(KeyOpAlg::BLOWFISH())
) and
msg = "Use of unapproved symmetric cipher algorithm or API: " + algType.toString() + "."
select alg, msg
18 changes: 8 additions & 10 deletions shared/quantum/codeql/quantum/experimental/Model.qll
Original file line number Diff line number Diff line change
Expand Up @@ -825,20 +825,20 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
*/
abstract string getRawEllipticCurveName();

abstract TEllipticCurveFamilyType getEllipticCurveFamilyType();
abstract TEllipticCurveType getEllipticCurveType();

abstract int getKeySize();

/**
* The 'parsed' curve name, e.g., "P-256" or "secp256r1"
* The parsed name is full name of the curve, including the family, key size, and other
* The parsed name is full name of the curve, including the type, key size, and other
* typical parameters found on the name.
*
* In many cases this will be equivalent to `getRawEllipticCurveAlgorithmName()`,
* but not always (e.g., if the curve is specified through a raw NID).
*
* In cases like an NID, we want the standardized name so users can quickly
* understand what the curve is, while also parsing out the family and key size
* understand what the curve is, while also parsing out the type and key size
* separately.
*/
string getParsedEllipticCurveName() { result = this.getRawEllipticCurveName() }
Expand All @@ -854,7 +854,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
/**
* Gets the type of this digest algorithm, e.g., "SHA1", "SHA2", "MD5" etc.
*/
abstract THashType getHashFamily();
abstract THashType getHashType();

/**
* Gets the isolated name as it appears in source, e.g., "SHA-256" in "SHA-256/PKCS7Padding".
Expand Down Expand Up @@ -2293,13 +2293,13 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
*
* When modeling a new hashing algorithm, use this predicate to specify the type of the algorithm.
*/
HashType getHashFamily() { result = instance.asAlg().getHashFamily() }
HashType getHashType() { result = instance.asAlg().getHashType() }

override string getAlgorithmName() { result = this.getHashFamily().toString() }
override string getAlgorithmName() { result = this.getHashType().toString() }

int getDigestLength() {
result = instance.asAlg().getFixedDigestLength() or
fixedImplicitDigestLength(instance.asAlg().getHashFamily(), result)
fixedImplicitDigestLength(instance.asAlg().getHashType(), result)
}

final override predicate properties(string key, string value, Location location) {
Expand Down Expand Up @@ -2340,9 +2340,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {

override string getAlgorithmName() { result = this.getRawAlgorithmName() }

EllipticCurveFamilyType getEllipticCurveFamilyType() {
result = instance.asAlg().getEllipticCurveFamilyType()
}
EllipticCurveType getEllipticCurveType() { result = instance.asAlg().getEllipticCurveType() }

override predicate properties(string key, string value, Location location) {
super.properties(key, value, location)
Expand Down
Loading
Loading