mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
Merge branch 'brodes/key_agreement' of https://github.com/nicolaswill/codeql into brodes/key_agreement
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import experimental.Quantum.Language
|
||||
|
||||
/**
|
||||
* Flow from any function that appears to return a value
|
||||
* to an artifact node.
|
||||
* NOTE: TODO: need to handle call by refernece for now. Need to re-evaluate (see notes below)
|
||||
* Such functions may be 'wrappers' for some derived value.
|
||||
*/
|
||||
private module WrapperConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(Call c |
|
||||
c = source.asExpr()
|
||||
// not handling references yet, I think we want to flat say references are only ok
|
||||
// if I know the source, otherwise, it has to be through an additional flow step, which
|
||||
// we filter as a source, i.e., references are only allowed as sources only,
|
||||
// no inferrece? Not sure if that would work
|
||||
//or
|
||||
// source.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = c.getAnArgument()
|
||||
) and
|
||||
// Filter out sources that are known additional flow steps, as these are likely not the
|
||||
// kind of wrapper source we are looking for.
|
||||
not exists(AdditionalFlowInputStep s | s.getOutput() = source)
|
||||
}
|
||||
|
||||
// Flow through additional flow steps
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
node1.(AdditionalFlowInputStep).getOutput() = node2
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(Crypto::ArtifactNode i).asElement() }
|
||||
}
|
||||
|
||||
module WrapperFlow = DataFlow::Global<WrapperConfig>;
|
||||
|
||||
/**
|
||||
* Using a set approach to determine if reuse of an artifact exists.
|
||||
* This predicate produces a set of 'wrappers' that flow to the artifact node.
|
||||
* This set can be compared with the set to another artifact node to determine if they are the same.
|
||||
*/
|
||||
private DataFlow::Node getWrapperSet(Crypto::NonceArtifactNode a) {
|
||||
WrapperFlow::flow(result, DataFlow::exprNode(a.asElement()))
|
||||
or
|
||||
result.asExpr() = a.getSourceElement()
|
||||
}
|
||||
|
||||
/**
|
||||
* Two different artifact nodes are considered reuse if any of the following conditions are met:
|
||||
* 1. The source for artifact `a` and artifact `b` are the same and the source is a literal.
|
||||
* 2. The source for artifact `a` and artifact `b` are not the same and the source is a literal of the same value.
|
||||
* 3. For all 'wrappers' that return the source of artifact `a`, and that wrapper also exists for artifact `b`.
|
||||
* 4. For all 'wrappers' that return the source of artifact `b`, and that wrapper also exists for artifact `a`.
|
||||
*/
|
||||
predicate isArtifactReuse(Crypto::ArtifactNode a, Crypto::ArtifactNode b) {
|
||||
a != b and
|
||||
(
|
||||
a.getSourceElement() = b.getSourceElement() and a.getSourceElement() instanceof Literal
|
||||
or
|
||||
a.getSourceElement().(Literal).getValue() = b.getSourceElement().(Literal).getValue()
|
||||
or
|
||||
forex(DataFlow::Node e | e = getWrapperSet(a) |
|
||||
exists(DataFlow::Node e2 | e2 = getWrapperSet(b) | e = e2)
|
||||
)
|
||||
or
|
||||
forex(DataFlow::Node e | e = getWrapperSet(b) |
|
||||
exists(DataFlow::Node e2 | e2 = getWrapperSet(a) | e = e2)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @name Detects known weak KDf iteration counts (less than 100k and the count is statically known)
|
||||
* @id java/crypto_inventory_filters/known_weak_kdf_iteration_count
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
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()
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @name Detects reuse of the same nonce in multiple operations
|
||||
* @id java/crypto_inventory_filter/nonce_reuse
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import ArtifactReuse
|
||||
|
||||
from Crypto::NonceArtifactNode nonce1, Crypto::NonceArtifactNode nonce2
|
||||
where isArtifactReuse(nonce1, nonce2)
|
||||
select nonce1, "Reuse with nonce $@", nonce2, nonce2.toString()
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @name Detects unknown KDf iteration counts
|
||||
* @id java/crypto_inventory_filters/unknown_kdf_iteration_count
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::KeyDerivationOperationNode op, Element e, string msg
|
||||
where
|
||||
e = op.getIterationCount().asElement() and
|
||||
not e instanceof Literal and
|
||||
msg = "Key derivation operation with unknown iteration: $@"
|
||||
or
|
||||
not exists(op.getIterationCount()) and
|
||||
e = op.asElement() and
|
||||
msg = "Key derivation operation with no iteration configuration."
|
||||
select op, msg, e, e.toString()
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @name Detects known asymmetric algorithms
|
||||
* @id java/crypto_inventory_slices/known_asymmetric_algorithm
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::AlgorithmNode a
|
||||
where Crypto::isKnownAsymmetricAlgorithm(a)
|
||||
select a, "Instance of asymmetric algorithm " + a.getAlgorithmName()
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @name Detects known asymmetric cipher algorithms
|
||||
* @id java/crypto_inventory_slices/known_symmetric_cipher_algorithm
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::KeyOperationAlgorithmNode a
|
||||
where a.getAlgorithmType() instanceof Crypto::KeyOpAlg::AsymmetricCipherAlgorithm
|
||||
select a, "Instance of asymmetric cipher algorithm " + a.getAlgorithmName()
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @name Detects operations where the algorithm applied is a known asymmetric algorithms
|
||||
* @id java/crypto_inventory_slices/known_asymmetric_operation_algorithm
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::OperationNode op, Crypto::AlgorithmNode a
|
||||
where a = op.getAKnownAlgorithm() and Crypto::isKnownAsymmetricAlgorithm(a)
|
||||
select op, "Operation using asymmetric algorithm $@", a, a.getAlgorithmName()
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @name Detects known cipher algorithms
|
||||
* @id java/crypto_inventory_slices/known_cipher_algorithm
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
// TODO: should there be a cipher algorithm node?
|
||||
from Crypto::KeyOperationAlgorithmNode a
|
||||
where
|
||||
a.getAlgorithmType() instanceof Crypto::KeyOpAlg::AsymmetricCipherAlgorithm or
|
||||
a.getAlgorithmType() instanceof Crypto::KeyOpAlg::SymmetricCipherAlgorithm
|
||||
select a, "Instance of cipher algorithm " + a.getAlgorithmName()
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @name Detects known elliptic curve algorithms
|
||||
* @id java/crypto_inventory_slices/known_elliptic_curve_algorithm
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::EllipticCurveNode a
|
||||
select a, "Instance of elliptic curve algorithm " + a.getAlgorithmName()
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @name Detects algorithms that are known hashing algorithms
|
||||
* @id java/crypto_inventory_slices/known_hashing_algorithm
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::HashAlgorithmNode a
|
||||
select a, "Instance of hashing algorithm " + a.getAlgorithmName()
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @name Detects uses of hashing operations (operations exlicitly for hashing only, irrespective of the algorithm used)
|
||||
* @id java/crypto_inventory_slices/known_hashing_operation
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::HashOperationNode op
|
||||
select op, "Known hashing operation"
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @name Detects operations where the algorithm applied is a known hashing algorithm
|
||||
* @id java/crypto_inventory_slices/operation_with_known_hashing_algorithm
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::OperationNode op, Crypto::HashAlgorithmNode a
|
||||
where a = op.getAKnownAlgorithm()
|
||||
select op, "Operation using hashing algorithm $@", a, a.getAlgorithmName()
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @name Detects known key derivation algorithms
|
||||
* @id java/crypto_inventory_slices/known_key_derivation_algorithm
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::KeyDerivationAlgorithmNode alg
|
||||
select alg, "Known key derivation algorithm " + alg.getAlgorithmName()
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @name Detects uses of key derivation operations (operations exlicitly for key derivation only, irrespective of the algorithm used)
|
||||
* @id java/crypto_inventory_slices/known_key_derivation_operation
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::KeyDerivationOperationNode op
|
||||
select op, "Known key derivation operation"
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @name Detects operations where the algorithm applied is a known key derivation algorithm
|
||||
* @id java/crypto_inventory_slices/operation_with_known_key_derivation_algorithm
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::OperationNode op, Crypto::KeyDerivationAlgorithmNode a
|
||||
where a = op.getAKnownAlgorithm()
|
||||
select op, "Operation using key derivation algorithm $@", a, a.getAlgorithmName()
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Detects functions that take in crypto configuration parameters but calls are not detected in source.
|
||||
* @id java/crypto_inventory_slices/likely_crypto_api_function
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Callable f, Parameter p, Crypto::OperationNode op
|
||||
where
|
||||
op.asElement().(Expr).getEnclosingCallable() = f and
|
||||
op.getAnAlgorithmOrGenericSource().asElement() = p
|
||||
select f,
|
||||
"Likely crypto API function: Operation $@ configured by parameter $@ with no known configuring call",
|
||||
op, op.toString(), p, p.toString()
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @name Detects operations where the algorithm applied is unknown
|
||||
* @id java/crypto_inventory_slices/unknown_operation_algorithm
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import experimental.Quantum.Language
|
||||
|
||||
//TODO: can we have an unknown node concept?
|
||||
from Crypto::OperationNode op, Element e, string msg
|
||||
where
|
||||
not exists(op.getAnAlgorithmOrGenericSource()) and
|
||||
e = op.asElement() and
|
||||
msg = "Operation with unconfigured algorithm (no known sources)."
|
||||
or
|
||||
exists(Crypto::GenericSourceNode n |
|
||||
n = op.getAnAlgorithmOrGenericSource() and
|
||||
e = n.asElement()
|
||||
) and
|
||||
msg = "Operation with unknown algorithm source: $@"
|
||||
select op, msg, e, e.toString()
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* @name Possible Nonce Reuse: Produces false positives if reuse occurs in a source that is a re-entry point.
|
||||
* @id java/possible-nonce-reuse
|
||||
* @kind problem
|
||||
*/
|
||||
|
||||
import experimental.Quantum.Language
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
from
|
||||
Crypto::KeyOperationNode op1, Crypto::KeyOperationNode op2, Crypto::NonceArtifactNode nonce1,
|
||||
Crypto::NonceArtifactNode nonce2, Crypto::FlowAwareElement src1, Crypto::FlowAwareElement src2
|
||||
where
|
||||
// NOTE: not looking at value of the nonce, if we knew value, it would be insecure (hard coded)
|
||||
// Instead trying to find nonce sources that trace to multiple operations.
|
||||
// Only looking for encryption operations, presumably if reuse for decryption either wouldn't be observable
|
||||
// (the encryption happened else where) or we are able to see the encryption and decryption operation and
|
||||
// reuse for encryption is the concern)
|
||||
(
|
||||
op1.getKeyOperationSubtype() instanceof Crypto::EncryptionSubtype or
|
||||
op1.getKeyOperationSubtype() instanceof Crypto::WrapSubtype or
|
||||
op1.getKeyOperationSubtype() instanceof Crypto::UnknownCipherOperationSubtype
|
||||
) and
|
||||
(
|
||||
op2.getKeyOperationSubtype() instanceof Crypto::EncryptionSubtype or
|
||||
op2.getKeyOperationSubtype() instanceof Crypto::WrapSubtype or
|
||||
op2.getKeyOperationSubtype() instanceof Crypto::UnknownCipherOperationSubtype
|
||||
) and
|
||||
nonce1 = op1.getANonce() and
|
||||
nonce2 = op2.getANonce() and
|
||||
op1 != op2 and
|
||||
nonce1.getSourceElement() = src1 and
|
||||
nonce2.getSourceElement() = src2 and
|
||||
src1 = src2
|
||||
// TODO: need to clarify that a reuse in a non-finalize is ok, need to check if 'finalize' through a modeled predicate
|
||||
select op1, "Operation has a possible reused nonce with source $@", src1, src1.toString()
|
||||
Reference in New Issue
Block a user