mirror of
https://github.com/github/codeql.git
synced 2026-04-26 09:15:12 +02:00
Refactor instances and consumers + add JCA hashes
This commit is contained in:
@@ -3,10 +3,11 @@ import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.security.FlowSources as FlowSources
|
||||
private import cpp as Lang
|
||||
|
||||
|
||||
module CryptoInput implements InputSig<Lang::Location> {
|
||||
class DataFlowNode = DataFlow::Node;
|
||||
|
||||
class LocatableElement = Lang::Locatable;
|
||||
|
||||
class UnknownLocation = Lang::UnknownDefaultLocation;
|
||||
}
|
||||
|
||||
@@ -21,7 +22,6 @@ abstract class AdditionalFlowInputStep extends DataFlow::Node {
|
||||
final DataFlow::Node getInput() { result = this }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generic data source to node input configuration
|
||||
*/
|
||||
@@ -47,61 +47,44 @@ module GenericDataSourceUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// // // TODO: I think this will be inefficient, no?
|
||||
// // class ConstantDataSource extends Crypto::GenericConstantOrAllocationSource instanceof Literal {
|
||||
// // override DataFlow::Node getOutputNode() {
|
||||
// // result.asExpr() = this
|
||||
// // override DataFlow::Node getOutputNode() {
|
||||
// // result.asExpr() = this
|
||||
// // }
|
||||
|
||||
// // override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
// // // TODO: separate config to avoid blowing up data-flow analysis
|
||||
// // GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
// // }
|
||||
|
||||
// // override string getAdditionalDescription() { result = this.toString() }
|
||||
// // }
|
||||
|
||||
// /**
|
||||
// * Definitions of various generic data sources
|
||||
// */
|
||||
// // final class DefaultFlowSource = SourceNode;
|
||||
|
||||
// // final class DefaultRemoteFlowSource = RemoteFlowSource;
|
||||
|
||||
// // class GenericLocalDataSource extends Crypto::GenericLocalDataSource {
|
||||
// // GenericLocalDataSource() {
|
||||
// // any(DefaultFlowSource src | not src instanceof DefaultRemoteFlowSource).asExpr() = this
|
||||
// // }
|
||||
|
||||
// // override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
|
||||
// // override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
// // GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
// // }
|
||||
|
||||
// // override string getAdditionalDescription() { result = this.toString() }
|
||||
// // }
|
||||
|
||||
// // class GenericRemoteDataSource extends Crypto::GenericRemoteDataSource {
|
||||
// // GenericRemoteDataSource() { any(DefaultRemoteFlowSource src).asExpr() = this }
|
||||
|
||||
// // override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
|
||||
// // override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
// // GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
// // }
|
||||
|
||||
// // override string getAdditionalDescription() { result = this.toString() }
|
||||
// // }
|
||||
|
||||
|
||||
// module GenericDataSourceUniversalFlow = DataFlow::Global<GenericDataSourceUniversalFlowConfig>;
|
||||
|
||||
module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source = any(Crypto::ArtifactElement artifact).getOutputNode()
|
||||
source = any(Crypto::ArtifactInstance artifact).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
@@ -120,12 +103,13 @@ module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
node1.(AdditionalFlowInputStep).getOutput() = node2
|
||||
}
|
||||
}
|
||||
|
||||
module ArtifactUniversalFlow = DataFlow::Global<ArtifactUniversalFlowConfig>;
|
||||
|
||||
abstract class CipherOutputArtifact extends Crypto::CipherOutputArtifactInstance {
|
||||
override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
ArtifactUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
import OpenSSL.OpenSSL
|
||||
|
||||
@@ -6,7 +6,7 @@ class EVP_Cipher_Initializer_Algorithm_Consumer extends Crypto::AlgorithmConsume
|
||||
{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
|
||||
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
result.(KnownOpenSSLCipherConstantAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,26 +2,29 @@ import EVPHashInitializer
|
||||
import EVPHashOperation
|
||||
import EVPHashAlgorithmSource
|
||||
|
||||
class EVP_Digest_Initializer_Algorithm_Consumer extends Crypto::AlgorithmConsumer instanceof EVPDigestInitializerAlgorithmArgument{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
class EVP_Digest_Initializer_Algorithm_Consumer extends Crypto::AlgorithmValueConsumer instanceof EVPDigestInitializerAlgorithmArgument
|
||||
{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
|
||||
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
|
||||
result.(KnownOpenSSLHashConstantAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
result.(KnownOpenSSLHashConstantAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_Q_Digest_Algorithm_Consumer extends Crypto::AlgorithmConsumer instanceof EVP_Q_Digest_Algorithm_Argument{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
class EVP_Q_Digest_Algorithm_Consumer extends Crypto::AlgorithmValueConsumer instanceof EVP_Q_Digest_Algorithm_Argument
|
||||
{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
|
||||
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
|
||||
result.(KnownOpenSSLHashConstantAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
result.(KnownOpenSSLHashConstantAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_Digest_Algorithm_Consumer extends Crypto::AlgorithmConsumer instanceof EVP_Digest_Algorithm_Argument{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
class EVP_Digest_Algorithm_Consumer extends Crypto::AlgorithmValueConsumer instanceof EVP_Digest_Algorithm_Argument
|
||||
{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
|
||||
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
|
||||
result.(KnownOpenSSLHashConstantAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
result.(KnownOpenSSLHashConstantAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ module JCAModel {
|
||||
*
|
||||
* For example, in `Cipher.getInstance(algorithm)`, this class represents `algorithm`.
|
||||
*/
|
||||
class CipherGetInstanceAlgorithmArg extends Crypto::AlgorithmConsumer instanceof Expr {
|
||||
class CipherGetInstanceAlgorithmArg extends Crypto::AlgorithmValueConsumer instanceof Expr {
|
||||
CipherGetInstanceCall call;
|
||||
|
||||
CipherGetInstanceAlgorithmArg() { this = call.getAlgorithmArg() }
|
||||
@@ -218,7 +218,7 @@ module JCAModel {
|
||||
value = result.getValue()
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
result.(CipherStringLiteralAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
@@ -354,15 +354,17 @@ module JCAModel {
|
||||
|
||||
override Crypto::CipherOperationSubtype getCipherOperationSubtype() { result = mode }
|
||||
|
||||
override Crypto::NonceArtifactConsumer getNonceConsumer() {
|
||||
result = sink.getState().(InitializedCipherModeFlowState).getInitCall().getNonceArg()
|
||||
override DataFlow::Node getNonceConsumer() {
|
||||
result.asExpr() = sink.getState().(InitializedCipherModeFlowState).getInitCall().getNonceArg()
|
||||
}
|
||||
|
||||
override Crypto::CipherInputConsumer getInputConsumer() {
|
||||
result = doFinalize.getMessageArg().asExpr()
|
||||
override DataFlow::Node getInputConsumer() { result = doFinalize.getMessageArg() }
|
||||
|
||||
override DataFlow::Node getKeyConsumer() {
|
||||
result.asExpr() = sink.getState().(InitializedCipherModeFlowState).getInitCall().getKeyArg()
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmConsumer getAlgorithmConsumer() { result = consumer }
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() { result = consumer }
|
||||
|
||||
override Crypto::CipherOutputArtifactInstance getOutputArtifact() {
|
||||
result = doFinalize.getOutput()
|
||||
@@ -493,27 +495,114 @@ module JCAModel {
|
||||
}
|
||||
}
|
||||
|
||||
class CipherInitCallNonceArgConsumer extends Crypto::NonceArtifactConsumer instanceof Expr {
|
||||
CipherInitCallNonceArgConsumer() { this = any(CipherInitCall call).getNonceArg() }
|
||||
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
class CipherInitCallKeyConsumer extends Crypto::ArtifactConsumer {
|
||||
CipherInitCallKeyConsumer() { this = any(CipherInitCall call).getKeyArg() }
|
||||
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
class CipherMessageInputConsumer extends Crypto::CipherInputConsumer {
|
||||
CipherMessageInputConsumer() { this = any(CipherOperationCall call).getMessageArg().asExpr() }
|
||||
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
class CipherOperationCallOutput extends CipherOutputArtifact {
|
||||
CipherOperationCallOutput() { this = any(CipherOperationCall call).getOutput() }
|
||||
|
||||
override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
bindingset[hash]
|
||||
predicate hash_names(string hash) {
|
||||
hash.toUpperCase()
|
||||
.matches([
|
||||
"SHA-1", "SHA-256", "SHA-384", "SHA-512", "SHA3-224", "SHA3-256", "SHA3-384",
|
||||
"SHA3-512", "BLAKE2b", "BLAKE2s"
|
||||
].toUpperCase())
|
||||
}
|
||||
|
||||
// flow config from a known hash algorithm literal to MessageDigest.getInstance
|
||||
module KnownHashAlgorithmLiteralToMessageDigestConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { hash_names(src.asExpr().(StringLiteral).getValue()) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MessageDigestGetInstanceCall call | sink.asExpr() = call.getAlgorithmArg())
|
||||
}
|
||||
}
|
||||
|
||||
module KnownHashAlgorithmLiteralToMessageDigestFlow =
|
||||
DataFlow::Global<KnownHashAlgorithmLiteralToMessageDigestConfig>;
|
||||
|
||||
class KnownHashAlgorithm extends Crypto::HashAlgorithmInstance instanceof StringLiteral {
|
||||
MessageDigestAlgorithmValueConsumer consumer;
|
||||
|
||||
KnownHashAlgorithm() {
|
||||
hash_names(this.getValue()) and
|
||||
KnownHashAlgorithmLiteralToMessageDigestFlow::flow(DataFlow::exprNode(this),
|
||||
consumer.getInputNode())
|
||||
}
|
||||
|
||||
MessageDigestAlgorithmValueConsumer getConsumer() { result = consumer }
|
||||
|
||||
override string getRawAlgorithmName() { result = this.(StringLiteral).getValue() }
|
||||
|
||||
override Crypto::THashType getHashFamily() {
|
||||
result = Crypto::OtherHashType() // TODO
|
||||
}
|
||||
}
|
||||
|
||||
class MessageDigestAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer {
|
||||
MessageDigestGetInstanceCall call;
|
||||
|
||||
MessageDigestAlgorithmValueConsumer() { this = call.getAlgorithmArg() }
|
||||
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
exists(KnownHashAlgorithm l | l.getConsumer() = this and result = l)
|
||||
}
|
||||
}
|
||||
|
||||
class MessageDigestGetInstanceCall extends MethodCall {
|
||||
MessageDigestGetInstanceCall() {
|
||||
this.getCallee().hasQualifiedName("java.security", "MessageDigest", "getInstance")
|
||||
}
|
||||
|
||||
Expr getAlgorithmArg() { result = this.getArgument(0) }
|
||||
|
||||
DigestHashOperation getDigestCall() {
|
||||
DigestGetInstanceToDigestFlow::flow(DataFlow::exprNode(this),
|
||||
DataFlow::exprNode(result.(DigestCall).getQualifier()))
|
||||
}
|
||||
}
|
||||
|
||||
class DigestCall extends MethodCall {
|
||||
DigestCall() { this.getCallee().hasQualifiedName("java.security", "MessageDigest", "digest") }
|
||||
|
||||
Expr getDigestArtifactOutput() { result = this }
|
||||
}
|
||||
|
||||
// flow config from MessageDigest.getInstance to MessageDigest.digest
|
||||
module DigestGetInstanceToDigestConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof MessageDigestGetInstanceCall }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(DigestCall c | c.getQualifier() = sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
module DigestGetInstanceToDigestFlow = DataFlow::Global<DigestGetInstanceToDigestConfig>;
|
||||
|
||||
class DigestArtifact extends DigestArtifactInstance {
|
||||
DigestArtifact() { this = any(DigestCall call).getDigestArtifactOutput() }
|
||||
|
||||
override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
class DigestHashOperation extends Crypto::HashOperationInstance instanceof DigestCall {
|
||||
override Crypto::DigestArtifactInstance getDigestArtifact() {
|
||||
result = this.(DigestCall).getDigestArtifactOutput()
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
exists(MessageDigestGetInstanceCall call |
|
||||
call.getDigestCall() = this and result = call.getAlgorithmArg()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,11 @@ module CryptoInput implements InputSig<Language::Location> {
|
||||
class LocatableElement = Language::Element;
|
||||
|
||||
class UnknownLocation = UnknownDefaultLocation;
|
||||
|
||||
LocatableElement dfn_to_element(DataFlow::Node node) {
|
||||
result = node.asExpr() or
|
||||
result = node.asParameter()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,6 +105,17 @@ class InsecureRandomnessInstance extends RandomnessInstance {
|
||||
InsecureRandomnessInstance() { exists(InsecureRandomnessSource node | this = node.asExpr()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Output artifact flow logic
|
||||
*/
|
||||
abstract class DigestArtifactInstance extends Crypto::DigestArtifactInstance {
|
||||
override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
ArtifactUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
}
|
||||
|
||||
override predicate isConsumerArtifact() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Artifact output to node input configuration
|
||||
*/
|
||||
@@ -115,6 +131,8 @@ abstract class CipherOutputArtifact extends Crypto::CipherOutputArtifactInstance
|
||||
override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
ArtifactUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
}
|
||||
|
||||
override predicate isConsumerArtifact() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,7 +162,7 @@ module GenericDataSourceUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
|
||||
module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source = any(Crypto::ArtifactElement artifact).getOutputNode()
|
||||
source = any(Crypto::ArtifactInstance artifact).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
|
||||
@@ -6,17 +6,19 @@
|
||||
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::NonceNode n, Crypto::CipherOperationNode op, Crypto::FlowAwareElement src, string msg
|
||||
from
|
||||
Crypto::NonceArtifactNode n, Crypto::CipherOperationNode op, Crypto::FlowAwareElement src,
|
||||
string msg
|
||||
where
|
||||
op.getANonce() = n and
|
||||
// Only encryption mode is relevant for insecure nonces, consder any 'unknown' subtype
|
||||
// as possibly encryption.
|
||||
// as possibly encryption.
|
||||
(
|
||||
op.getCipherOperationSubtype() instanceof Crypto::EncryptionSubtype
|
||||
or
|
||||
op.getCipherOperationSubtype() instanceof Crypto::WrapSubtype
|
||||
or
|
||||
op.getCipherOperationSubtype() instanceof Crypto::UnwrapSubtype
|
||||
op.getCipherOperationSubtype() instanceof Crypto::UnwrapSubtype
|
||||
) and
|
||||
(
|
||||
// Known sources cases that are not secure
|
||||
@@ -30,7 +32,6 @@ where
|
||||
src = n.asElement()
|
||||
)
|
||||
select n, msg, src, src.toString()
|
||||
|
||||
// variant using instances, does not yield the same results
|
||||
// from Crypto::NonceArtifactConsumer n, Crypto::CipherOperationInstance op, Crypto::FlowAwareElement src, string msg
|
||||
// where
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
/**
|
||||
* @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::CipherOperationNode op1, Crypto::CipherOperationNode op2, Crypto::NonceNode nonce1,
|
||||
Crypto::NonceNode nonce2, Crypto::FlowAwareElement src1, Crypto::FlowAwareElement src2
|
||||
Crypto::CipherOperationNode op1, Crypto::CipherOperationNode 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.
|
||||
|
||||
@@ -6,7 +6,8 @@ import experimental.Quantum.Language
|
||||
|
||||
from
|
||||
Crypto::CipherOperationNode op, Crypto::CipherAlgorithmNode a,
|
||||
Crypto::ModeOfOperationAlgorithmNode m, Crypto::PaddingAlgorithmNode p, Crypto::NonceNode nonce
|
||||
Crypto::ModeOfOperationAlgorithmNode m, Crypto::PaddingAlgorithmNode p,
|
||||
Crypto::NonceArtifactNode nonce
|
||||
where
|
||||
a = op.getAKnownCipherAlgorithm() and
|
||||
m = a.getModeOfOperation() and
|
||||
|
||||
9
java/ql/src/experimental/Quantum/TestHash.ql
Normal file
9
java/ql/src/experimental/Quantum/TestHash.ql
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @name TestHashOperations
|
||||
*/
|
||||
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::HashOperationNode op, Crypto::HashAlgorithmNode alg
|
||||
where alg = op.getAKnownHashAlgorithm()
|
||||
select op, op.getDigest(), alg, alg.getRawAlgorithmName()
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import codeql.util.Location
|
||||
import codeql.util.Option
|
||||
import codeql.util.Either
|
||||
|
||||
signature module InputSig<LocationSig Location> {
|
||||
class LocatableElement {
|
||||
@@ -19,6 +20,8 @@ signature module InputSig<LocationSig Location> {
|
||||
}
|
||||
|
||||
class UnknownLocation instanceof Location;
|
||||
|
||||
LocatableElement dfn_to_element(DataFlowNode node);
|
||||
}
|
||||
|
||||
module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
@@ -50,12 +53,12 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
|
||||
NodeBase getPassthroughNodeChild(NodeBase node) {
|
||||
result = node.(CipherInputNode).getChild(_) or
|
||||
result = node.(NonceNode).getChild(_)
|
||||
result = node.(NonceArtifactNode).getChild(_)
|
||||
}
|
||||
|
||||
predicate isPassthroughNode(NodeBase node) {
|
||||
node instanceof CipherInputNode or
|
||||
node instanceof NonceNode
|
||||
node instanceof NonceArtifactNode
|
||||
}
|
||||
|
||||
predicate nodes_graph_impl(NodeBase node, string key, string value) {
|
||||
@@ -121,7 +124,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
}
|
||||
|
||||
/**
|
||||
* An element that represents a _known_ cryptographic asset.
|
||||
* An element that represents a _known_ cryptographic asset with a determinable value OR an artifact.
|
||||
*
|
||||
* CROSS PRODUCT WARNING: Do not model any *other* element that is a `FlowAwareElement` to the same
|
||||
* instance in the database, as every other `KnownElement` will share that output artifact's flow.
|
||||
@@ -133,17 +136,17 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
/**
|
||||
* An element that represents a _known_ cryptographic operation.
|
||||
*/
|
||||
abstract class OperationElement extends KnownElement {
|
||||
abstract class OperationInstance extends KnownElement {
|
||||
/**
|
||||
* Gets the consumer of algorithms associated with this operation.
|
||||
* Gets the consumers of algorithm values associated with this operation.
|
||||
*/
|
||||
abstract AlgorithmConsumer getAlgorithmConsumer();
|
||||
abstract AlgorithmValueConsumer getAnAlgorithmValueConsumer();
|
||||
}
|
||||
|
||||
/**
|
||||
* An element that represents a _known_ cryptographic algorithm.
|
||||
*/
|
||||
abstract class AlgorithmElement extends KnownElement {
|
||||
abstract class AlgorithmInstance extends KnownElement {
|
||||
/**
|
||||
* Gets the raw name as it appears in source, e.g., "AES/CBC/PKCS7Padding".
|
||||
* This name is not parsed or formatted.
|
||||
@@ -151,11 +154,6 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
abstract string getRawAlgorithmName();
|
||||
}
|
||||
|
||||
/**
|
||||
* An element that represents a _known_ cryptographic artifact.
|
||||
*/
|
||||
abstract class ArtifactElement extends KnownElement, FlowAwareElement { }
|
||||
|
||||
/**
|
||||
* An element that represents an _unknown_ data-source with a non-statically determinable value.
|
||||
*/
|
||||
@@ -198,6 +196,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
|
||||
override DataFlowNode getOutputNode() { none() }
|
||||
|
||||
// for internal use only
|
||||
final GenericDataSourceInstance getAnUnknownSource() {
|
||||
result.flowsTo(this) and not result = this.getAKnownSource()
|
||||
}
|
||||
@@ -207,23 +206,31 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
}
|
||||
|
||||
final NodeBase getAKnownSourceNode() { result.asElement() = this.getAKnownSource() }
|
||||
|
||||
final LocatableElement getASource() {
|
||||
result = this.getAnUnknownSource() or
|
||||
result = this.getAKnownSource()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AlgorithmValueConsumer extends ConsumerElement {
|
||||
/**
|
||||
* DO NOT USE.
|
||||
* Model `getAKnownAlgorithmSource()` instead, which is equivalent but correctly typed.
|
||||
*/
|
||||
final override KnownElement getAKnownSource() { result = this.getAKnownAlgorithmSource() }
|
||||
|
||||
/**
|
||||
* Gets a known algorithm value that is equivalent to or consumed by this element.
|
||||
*/
|
||||
abstract AlgorithmInstance getAKnownAlgorithmSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* An element that consumes _known_ and _unknown_ values.
|
||||
*
|
||||
* A value consumer can consume multiple values and multiple value sources at once.
|
||||
* An element that represents a _known_ cryptographic artifact.
|
||||
*/
|
||||
abstract class ValueConsumer extends ConsumerElement {
|
||||
final override KnownElement getAKnownSource() { none() }
|
||||
|
||||
abstract string getAKnownValue(Location location);
|
||||
}
|
||||
|
||||
abstract class AlgorithmConsumer extends ConsumerElement {
|
||||
final override KnownElement getAKnownSource() { result = this.getAKnownAlgorithmSource() }
|
||||
|
||||
abstract AlgorithmElement getAKnownAlgorithmSource();
|
||||
abstract class ArtifactInstance extends KnownElement, FlowAwareElement {
|
||||
abstract predicate isConsumerArtifact(); // whether this is an input artifact defined by its consumer
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,15 +239,6 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
* The concept of "`ArtifactConsumer` = `ArtifactNode`" should be used for inputs, as a consumer can be directly tied
|
||||
* to the artifact it receives, thereby becoming the definitive contextual source for that artifact.
|
||||
*
|
||||
* For example, consider a nonce artifact consumer:
|
||||
*
|
||||
* A `NonceArtifactConsumer` is always the `NonceArtifactInstance` itself, since data only becomes (i.e., is determined to be)
|
||||
* a `NonceArtifactInstance` when it is consumed in a context that expects a nonce (e.g., an argument expecting nonce data).
|
||||
* In this case, the artifact (nonce) is fully defined by the context in which it is consumed, and the consumer embodies
|
||||
* that identity without the need for additional differentiation. Without the context a consumer provides, that data could
|
||||
* otherwise be any other type of artifact or even simply random data.
|
||||
*
|
||||
*
|
||||
* Architectural Implications:
|
||||
* * By directly coupling a consumer with the node that receives an artifact,
|
||||
* the data flow is fully transparent with the consumer itself serving only as a transparent node.
|
||||
@@ -251,24 +249,114 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
*/
|
||||
abstract class ArtifactConsumer extends ConsumerElement {
|
||||
/**
|
||||
* DO NOT USE:
|
||||
* Use `getAKnownArtifactSource() instead. The behaviour of these two predicates is equivalent.
|
||||
*/
|
||||
final override KnownElement getAKnownSource() { result = this.getAKnownArtifactSource() }
|
||||
|
||||
final ArtifactElement getAKnownArtifactSource() { result.flowsTo(this) }
|
||||
final ArtifactInstance getAKnownArtifactSource() { result.flowsTo(this) }
|
||||
}
|
||||
|
||||
abstract class ArtifactConsumerAndInstance extends ArtifactConsumer {
|
||||
final override DataFlowNode getOutputNode() { none() }
|
||||
|
||||
final override predicate flowsTo(FlowAwareElement other) { none() }
|
||||
/**
|
||||
* An `ArtifactConsumer` that is also an `ArtifactInstance`.
|
||||
*
|
||||
* For example:
|
||||
* A `NonceArtifactConsumer` is always the `NonceArtifactInstance` itself, since data only becomes (i.e., is determined to be)
|
||||
* a `NonceArtifactInstance` when it is consumed in a context that expects a nonce (e.g., an argument expecting nonce data).
|
||||
* In this case, the artifact (nonce) is fully defined by the context in which it is consumed, and the consumer embodies
|
||||
* that identity without the need for additional differentiation. Without the context a consumer provides, that data could
|
||||
* otherwise be any other type of artifact or even simply random data.
|
||||
*
|
||||
* TODO: what if a Nonce from hypothetical func `generateNonce()` flows to this instance which is also a Nonce?
|
||||
* TODO: potential solution is creating another artifact type called NonceData or treating it as a generic source.
|
||||
*
|
||||
* TODO: An alternative is simply having a predicate DataFlowNode getNonceInputNode() on (for example) operations.
|
||||
* Under the hood, in Model.qll, we would create the instance for the modeller, thus avoiding the need for the modeller
|
||||
* to create a separate consumer class / instance themselves using this class.
|
||||
*/
|
||||
abstract private class ArtifactConsumerAndInstance extends ArtifactConsumer, ArtifactInstance {
|
||||
override predicate isConsumerArtifact() { any() }
|
||||
}
|
||||
|
||||
abstract class CipherOutputArtifactInstance extends ArtifactElement {
|
||||
final private class NonceArtifactConsumer extends ArtifactConsumerAndInstance {
|
||||
DataFlowNode inputNode;
|
||||
|
||||
NonceArtifactConsumer() {
|
||||
exists(CipherOperationInstance op | inputNode = op.getNonceConsumer()) and
|
||||
this = Input::dfn_to_element(inputNode)
|
||||
}
|
||||
|
||||
final override DataFlowNode getInputNode() { result = inputNode }
|
||||
}
|
||||
|
||||
final private class CipherInputArtifactConsumer extends ArtifactConsumerAndInstance {
|
||||
DataFlowNode inputNode;
|
||||
|
||||
CipherInputArtifactConsumer() {
|
||||
exists(CipherOperationInstance op | inputNode = op.getInputConsumer()) and
|
||||
this = Input::dfn_to_element(inputNode)
|
||||
}
|
||||
|
||||
final override DataFlowNode getInputNode() { result = inputNode }
|
||||
}
|
||||
|
||||
// Output artifacts are determined solely by the element that produces them.
|
||||
// Implementation guidance: these *do* need to be defined generically at the language-level
|
||||
// in order for a flowsTo to be defined. At the per-modeling-instance level, extend that language-level class!
|
||||
abstract class OutputArtifactInstance extends ArtifactInstance {
|
||||
override predicate isConsumerArtifact() { none() }
|
||||
}
|
||||
|
||||
abstract class DigestArtifactInstance extends OutputArtifactInstance {
|
||||
final override DataFlowNode getInputNode() { none() }
|
||||
}
|
||||
|
||||
abstract class CipherOperationInstance extends OperationElement {
|
||||
abstract class RandomNumberGenerationInstance extends OutputArtifactInstance {
|
||||
// TODO: input seed?
|
||||
final override DataFlowNode getInputNode() { none() }
|
||||
}
|
||||
|
||||
abstract class CipherOutputArtifactInstance extends ArtifactInstance {
|
||||
final override DataFlowNode getInputNode() { none() }
|
||||
}
|
||||
|
||||
// Artifacts that may be outputs or inputs
|
||||
newtype TKeyArtifactType =
|
||||
TSymmetricKeyType() or
|
||||
TAsymmetricKeyType() or
|
||||
TUnknownKeyType()
|
||||
|
||||
class KeyArtifactType extends TKeyArtifactType {
|
||||
string toString() {
|
||||
this = TSymmetricKeyType() and result = "Symmetric"
|
||||
or
|
||||
this = TAsymmetricKeyType() and result = "Asymmetric"
|
||||
or
|
||||
this = TUnknownKeyType() and result = "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
abstract class KeyArtifactInstance extends ArtifactInstance {
|
||||
abstract KeyArtifactType getKeyType();
|
||||
}
|
||||
|
||||
final class KeyArtifactConsumer extends ArtifactConsumerAndInstance, KeyArtifactInstance {
|
||||
DataFlowNode inputNode;
|
||||
|
||||
KeyArtifactConsumer() {
|
||||
exists(CipherOperationInstance op | inputNode = op.getKeyConsumer()) and
|
||||
this = Input::dfn_to_element(inputNode)
|
||||
}
|
||||
|
||||
override KeyArtifactType getKeyType() { result instanceof TUnknownKeyType }
|
||||
|
||||
final override DataFlowNode getInputNode() { result = inputNode }
|
||||
}
|
||||
|
||||
/**
|
||||
* A cipher operation instance, such as encryption or decryption.
|
||||
*/
|
||||
abstract class CipherOperationInstance extends OperationInstance {
|
||||
/**
|
||||
* Gets the subtype of this cipher operation, distinguishing encryption, decryption, key wrapping, and key unwrapping.
|
||||
*/
|
||||
@@ -277,12 +365,17 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
/**
|
||||
* Gets the consumer of nonces/IVs associated with this cipher operation.
|
||||
*/
|
||||
abstract NonceArtifactConsumer getNonceConsumer();
|
||||
abstract DataFlowNode getNonceConsumer();
|
||||
|
||||
/**
|
||||
* Gets the consumer of plaintext or ciphertext input associated with this cipher operation.
|
||||
*/
|
||||
abstract CipherInputConsumer getInputConsumer();
|
||||
abstract DataFlowNode getInputConsumer();
|
||||
|
||||
/**
|
||||
* Gets the consumer of a key.
|
||||
*/
|
||||
abstract DataFlowNode getKeyConsumer();
|
||||
|
||||
/**
|
||||
* Gets the output artifact of this cipher operation.
|
||||
@@ -294,7 +387,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
abstract CipherOutputArtifactInstance getOutputArtifact();
|
||||
}
|
||||
|
||||
abstract class CipherAlgorithmInstance extends AlgorithmElement {
|
||||
abstract class CipherAlgorithmInstance extends AlgorithmInstance {
|
||||
/**
|
||||
* Gets the type of this cipher, e.g., "AES" or "ChaCha20".
|
||||
*/
|
||||
@@ -303,7 +396,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
/**
|
||||
* Gets the mode of operation of this cipher, e.g., "GCM" or "CBC".
|
||||
*
|
||||
* IMPLEMENTATION NOTE: as a trade-off, this is not a consumer but always either an instance or unknown.
|
||||
* IMPLEMENTATION NOTE: as a tradeoff, this is not a consumer but always either an instance or unknown.
|
||||
* A mode of operation is therefore assumed to always be part of the cipher algorithm itself.
|
||||
*/
|
||||
abstract ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm();
|
||||
@@ -311,13 +404,13 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
/**
|
||||
* Gets the padding scheme of this cipher, e.g., "PKCS7" or "NoPadding".
|
||||
*
|
||||
* IMPLEMENTATION NOTE: as a trade-off, this is not a consumer but always either an instance or unknown.
|
||||
* IMPLEMENTATION NOTE: as a tradeoff, this is not a consumer but always either an instance or unknown.
|
||||
* A padding algorithm is therefore assumed to always be defined as part of the cipher algorithm itself.
|
||||
*/
|
||||
abstract PaddingAlgorithmInstance getPaddingAlgorithm();
|
||||
}
|
||||
|
||||
abstract class ModeOfOperationAlgorithmInstance extends AlgorithmElement {
|
||||
abstract class ModeOfOperationAlgorithmInstance extends AlgorithmInstance {
|
||||
/**
|
||||
* Gets the type of this mode of operation, e.g., "ECB" or "CBC".
|
||||
*
|
||||
@@ -335,7 +428,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
abstract string getRawModeAlgorithmName();
|
||||
}
|
||||
|
||||
abstract class PaddingAlgorithmInstance extends AlgorithmElement {
|
||||
abstract class PaddingAlgorithmInstance extends AlgorithmInstance {
|
||||
/**
|
||||
* Gets the isolated name as it appears in source, e.g., "PKCS7Padding" in "AES/CBC/PKCS7Padding".
|
||||
*
|
||||
@@ -353,56 +446,70 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
abstract TPaddingType getPaddingType();
|
||||
}
|
||||
|
||||
abstract class KeyEncapsulationOperationInstance extends LocatableElement { }
|
||||
abstract class OAEPPaddingAlgorithmInstance extends PaddingAlgorithmInstance {
|
||||
OAEPPaddingAlgorithmInstance() { this.getPaddingType() = OAEP() }
|
||||
|
||||
abstract class KeyEncapsulationAlgorithmInstance extends LocatableElement { }
|
||||
/**
|
||||
* Gets the hash algorithm used in this padding scheme.
|
||||
*/
|
||||
abstract HashAlgorithmInstance getHashAlgorithm();
|
||||
|
||||
abstract class EllipticCurveAlgorithmInstance extends LocatableElement { }
|
||||
|
||||
abstract class HashOperationInstance extends OperationElement {
|
||||
// TODO: need input and outputs, but this should be universal to all Operations
|
||||
/**
|
||||
* Gets the mask generation function used in this padding scheme.
|
||||
*/
|
||||
abstract HashAlgorithmInstance getMaskGenerationFunction();
|
||||
}
|
||||
|
||||
abstract class HashAlgorithmInstance extends AlgorithmElement {
|
||||
abstract class KeyEncapsulationOperationInstance extends OperationInstance { }
|
||||
|
||||
abstract class KeyEncapsulationAlgorithmInstance extends AlgorithmInstance { }
|
||||
|
||||
abstract class EllipticCurveAlgorithmInstance extends AlgorithmInstance { }
|
||||
|
||||
abstract class HashOperationInstance extends OperationInstance {
|
||||
abstract DigestArtifactInstance getDigestArtifact();
|
||||
}
|
||||
|
||||
abstract class HashAlgorithmInstance extends AlgorithmInstance {
|
||||
/**
|
||||
* Gets the type of this digest algorithm, e.g., "SHA1", "SHA2", "MD5" etc.
|
||||
*/
|
||||
abstract THashType getHashFamily();
|
||||
|
||||
// abstract int getHashSize();
|
||||
}
|
||||
|
||||
abstract class KeyDerivationOperationInstance extends KnownElement { }
|
||||
abstract class KeyDerivationOperationInstance extends OperationInstance { }
|
||||
|
||||
abstract class KeyDerivationAlgorithmInstance extends KnownElement { }
|
||||
abstract class KeyDerivationAlgorithmInstance extends AlgorithmInstance { }
|
||||
|
||||
// Artifacts determined solely by the element that produces them
|
||||
// Implementation guidance: these *do* need to be defined generically at the language-level
|
||||
// in order for a flowsTo to be defined. At the per-modeling-instance level, extend that language-level class!
|
||||
abstract class OutputArtifactElement extends ArtifactElement {
|
||||
final override DataFlowNode getInputNode() { none() }
|
||||
private signature class AlgorithmInstanceType instanceof AlgorithmInstance;
|
||||
|
||||
module AlgorithmInstanceOrValueConsumer<AlgorithmInstanceType Alg> {
|
||||
class Union extends LocatableElement {
|
||||
Union() {
|
||||
this instanceof Alg
|
||||
or
|
||||
this instanceof AlgorithmValueConsumer and
|
||||
not exists(this.(AlgorithmValueConsumer).getASource())
|
||||
}
|
||||
|
||||
Alg asAlg() { result = this }
|
||||
|
||||
AlgorithmValueConsumer asAVC() { result = this }
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DigestArtifactInstance extends OutputArtifactElement { }
|
||||
class CipherAlgorithmInstanceOrValueConsumer =
|
||||
AlgorithmInstanceOrValueConsumer<CipherAlgorithmInstance>::Union;
|
||||
|
||||
abstract class RandomNumberGenerationInstance extends OutputArtifactElement { } // TODO: is this an OutputArtifactElement if it takes a seed?
|
||||
|
||||
// Artifacts determined solely by the consumer that consumes them are defined as consumers
|
||||
// Implementation guidance: these do not need to be defined generically at the language-level
|
||||
// Only the sink node needs to be defined per-modeling-instance (e.g., in JCA.qll)
|
||||
abstract class NonceArtifactConsumer extends ArtifactConsumerAndInstance { }
|
||||
|
||||
abstract class CipherInputConsumer extends ArtifactConsumerAndInstance { }
|
||||
|
||||
// Other artifacts
|
||||
abstract class KeyArtifactInstance extends ArtifactElement { } // TODO: implement and categorize
|
||||
class HashAlgorithmInstanceOrValueConsumer =
|
||||
AlgorithmInstanceOrValueConsumer<HashAlgorithmInstance>::Union;
|
||||
|
||||
newtype TNode =
|
||||
// Artifacts (data that is not an operation or algorithm, e.g., a key)
|
||||
TDigest(DigestArtifactInstance e) or
|
||||
TKey(KeyArtifactInstance e) or
|
||||
TNonce(NonceArtifactConsumer e) or
|
||||
TCipherInput(CipherInputConsumer e) or
|
||||
TCipherInput(CipherInputArtifactConsumer e) or
|
||||
TCipherOutput(CipherOutputArtifactInstance e) or
|
||||
TRandomNumberGeneration(RandomNumberGenerationInstance e) { e.flowsTo(_) } or
|
||||
// Operations (e.g., hashing, encryption)
|
||||
@@ -411,9 +518,9 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
TCipherOperation(CipherOperationInstance e) or
|
||||
TKeyEncapsulationOperation(KeyEncapsulationOperationInstance e) or
|
||||
// Algorithms (e.g., SHA-256, AES)
|
||||
TCipherAlgorithm(CipherAlgorithmInstance e) or
|
||||
TCipherAlgorithm(CipherAlgorithmInstanceOrValueConsumer e) or
|
||||
TEllipticCurveAlgorithm(EllipticCurveAlgorithmInstance e) or
|
||||
THashAlgorithm(HashAlgorithmInstance e) or
|
||||
THashAlgorithm(HashAlgorithmInstanceOrValueConsumer e) or
|
||||
TKeyDerivationAlgorithm(KeyDerivationAlgorithmInstance e) or
|
||||
TKeyEncapsulationAlgorithm(KeyEncapsulationAlgorithmInstance e) or
|
||||
// Non-standalone Algorithms (e.g., Mode, Padding)
|
||||
@@ -567,10 +674,10 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
/**
|
||||
* A nonce or initialization vector
|
||||
*/
|
||||
final class NonceNode extends ArtifactNode, TNonce {
|
||||
final class NonceArtifactNode extends ArtifactNode, TNonce {
|
||||
NonceArtifactConsumer instance;
|
||||
|
||||
NonceNode() { this = TNonce(instance) }
|
||||
NonceArtifactNode() { this = TNonce(instance) }
|
||||
|
||||
final override string getInternalType() { result = "Nonce" }
|
||||
|
||||
@@ -594,7 +701,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
* Input text to a cipher operation
|
||||
*/
|
||||
final class CipherInputNode extends ArtifactNode, TCipherInput {
|
||||
CipherInputConsumer instance;
|
||||
CipherInputArtifactConsumer instance;
|
||||
|
||||
CipherInputNode() { this = TCipherInput(instance) }
|
||||
|
||||
@@ -616,6 +723,41 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
override LocatableElement asElement() { result = instance }
|
||||
}
|
||||
|
||||
/**
|
||||
* A cryptographic key, such as a symmetric key or asymmetric key pair.
|
||||
*/
|
||||
final class KeyArtifactNode extends ArtifactNode, TKey {
|
||||
KeyArtifactInstance instance;
|
||||
|
||||
KeyArtifactNode() { this = TKey(instance) }
|
||||
|
||||
final override string getInternalType() { result = "Key" }
|
||||
|
||||
override LocatableElement asElement() { result = instance }
|
||||
|
||||
override predicate properties(string key, string value, Location location) {
|
||||
super.properties(key, value, location)
|
||||
or
|
||||
// [ONLY_KNOWN]
|
||||
key = "KeyType" and
|
||||
value = instance.getKeyType().toString() and
|
||||
location = this.getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A digest produced by a hash operation.
|
||||
*/
|
||||
final class DigestArtifactNode extends ArtifactNode, TDigest {
|
||||
DigestArtifactInstance instance;
|
||||
|
||||
DigestArtifactNode() { this = TDigest(instance) }
|
||||
|
||||
final override string getInternalType() { result = "Digest" }
|
||||
|
||||
override LocatableElement asElement() { result = instance }
|
||||
}
|
||||
|
||||
/**
|
||||
* A cryptographic operation, such as hashing or encryption.
|
||||
*/
|
||||
@@ -693,26 +835,30 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
*/
|
||||
NodeBase getACipherAlgorithmOrUnknown() {
|
||||
result = this.getAKnownCipherAlgorithm() or
|
||||
result = this.asElement().(OperationElement).getAlgorithmConsumer().getAnUnknownSourceNode()
|
||||
result =
|
||||
this.asElement().(OperationInstance).getAnAlgorithmValueConsumer().getAnUnknownSourceNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a known algorithm associated with this operation
|
||||
*/
|
||||
CipherAlgorithmNode getAKnownCipherAlgorithm() {
|
||||
result = this.asElement().(OperationElement).getAlgorithmConsumer().getAKnownSourceNode()
|
||||
result =
|
||||
this.asElement().(OperationInstance).getAnAlgorithmValueConsumer().getAKnownSourceNode()
|
||||
}
|
||||
|
||||
CipherOperationSubtype getCipherOperationSubtype() {
|
||||
result = instance.getCipherOperationSubtype()
|
||||
}
|
||||
|
||||
NonceNode getANonce() {
|
||||
result.asElement() = this.asElement().(CipherOperationInstance).getNonceConsumer()
|
||||
NonceArtifactNode getANonce() {
|
||||
result.asElement() =
|
||||
Input::dfn_to_element(this.asElement().(CipherOperationInstance).getNonceConsumer())
|
||||
}
|
||||
|
||||
CipherInputNode getAnInputArtifact() {
|
||||
result.asElement() = this.asElement().(CipherOperationInstance).getInputConsumer()
|
||||
result.asElement() =
|
||||
Input::dfn_to_element(this.asElement().(CipherOperationInstance).getInputConsumer())
|
||||
}
|
||||
|
||||
CipherOutputNode getAnOutputArtifact() {
|
||||
@@ -858,6 +1004,32 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
override string getRawAlgorithmName() { result = instance.getRawPaddingAlgorithmName() }
|
||||
}
|
||||
|
||||
class OAEPPaddingAlgorithmNode extends PaddingAlgorithmNode {
|
||||
override OAEPPaddingAlgorithmInstance instance;
|
||||
|
||||
OAEPPaddingAlgorithmNode() { this = TPaddingAlgorithm(instance) }
|
||||
|
||||
HashAlgorithmNode getHashAlgorithm() { result.asElement() = instance.getHashAlgorithm() }
|
||||
|
||||
HashAlgorithmNode getMaskGenerationFunction() {
|
||||
result.asElement() = instance.getMaskGenerationFunction()
|
||||
}
|
||||
|
||||
override NodeBase getChild(string edgeName) {
|
||||
result = super.getChild(edgeName)
|
||||
or
|
||||
// [KNOWN_OR_UNKNOWN]
|
||||
edgeName = "MD" and
|
||||
if exists(this.getHashAlgorithm()) then result = this.getHashAlgorithm() else result = this
|
||||
or
|
||||
// [KNOWN_OR_UNKNOWN]
|
||||
edgeName = "MGF" and
|
||||
if exists(this.getMaskGenerationFunction())
|
||||
then result = this.getMaskGenerationFunction()
|
||||
else result = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper type for distinguishing between block and stream ciphers.
|
||||
*/
|
||||
@@ -904,7 +1076,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
OtherCipherType()
|
||||
|
||||
final class CipherAlgorithmNode extends AlgorithmNode, TCipherAlgorithm {
|
||||
CipherAlgorithmInstance instance;
|
||||
CipherAlgorithmInstanceOrValueConsumer instance;
|
||||
|
||||
CipherAlgorithmNode() { this = TCipherAlgorithm(instance) }
|
||||
|
||||
@@ -920,7 +1092,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
this.cipherFamilyToNameAndStructure(this.getCipherFamily(), result, _)
|
||||
}
|
||||
|
||||
final override string getRawAlgorithmName() { result = instance.getRawAlgorithmName() }
|
||||
final override string getRawAlgorithmName() { result = instance.asAlg().getRawAlgorithmName() }
|
||||
|
||||
/**
|
||||
* Gets the key size of this cipher, e.g., "128" or "256".
|
||||
@@ -930,20 +1102,20 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
/**
|
||||
* Gets the type of this cipher, e.g., "AES" or "ChaCha20".
|
||||
*/
|
||||
TCipherType getCipherFamily() { result = instance.getCipherFamily() }
|
||||
TCipherType getCipherFamily() { result = instance.asAlg().getCipherFamily() }
|
||||
|
||||
/**
|
||||
* Gets the mode of operation of this cipher, e.g., "GCM" or "CBC".
|
||||
*/
|
||||
ModeOfOperationAlgorithmNode getModeOfOperation() {
|
||||
result.asElement() = instance.getModeOfOperationAlgorithm()
|
||||
result.asElement() = instance.asAlg().getModeOfOperationAlgorithm()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the padding scheme of this cipher, e.g., "PKCS7" or "NoPadding".
|
||||
*/
|
||||
PaddingAlgorithmNode getPaddingAlgorithm() {
|
||||
result.asElement() = instance.getPaddingAlgorithm()
|
||||
result.asElement() = instance.asAlg().getPaddingAlgorithm()
|
||||
}
|
||||
|
||||
bindingset[type]
|
||||
@@ -1038,7 +1210,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
* hash value as the output using a specified hashing algorithm.
|
||||
*/
|
||||
class HashOperationNode extends OperationNode, THashOperation {
|
||||
HashAlgorithmInstance instance;
|
||||
HashOperationInstance instance;
|
||||
|
||||
HashOperationNode() { this = THashOperation(instance) }
|
||||
|
||||
@@ -1049,16 +1221,39 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
/**
|
||||
* Gets the algorithm or unknown source nodes consumed as an algorithm associated with this operation.
|
||||
*/
|
||||
NodeBase getACipherAlgorithmOrUnknown() {
|
||||
result = this.getAKnownCipherAlgorithm() or
|
||||
result = this.asElement().(OperationElement).getAlgorithmConsumer().getAnUnknownSourceNode()
|
||||
NodeBase getAHashAlgorithmOrUnknown() {
|
||||
result = this.getAKnownHashAlgorithm() or
|
||||
result =
|
||||
this.asElement().(OperationInstance).getAnAlgorithmValueConsumer().getAnUnknownSourceNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a known algorithm associated with this operation
|
||||
*/
|
||||
HashAlgorithmNode getAKnownCipherAlgorithm() {
|
||||
result = this.asElement().(OperationElement).getAlgorithmConsumer().getAKnownSourceNode()
|
||||
HashAlgorithmNode getAKnownHashAlgorithm() {
|
||||
result =
|
||||
this.asElement().(OperationInstance).getAnAlgorithmValueConsumer().getAKnownSourceNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the output digest node
|
||||
*/
|
||||
DigestArtifactNode getDigest() {
|
||||
result.asElement() = this.asElement().(HashOperationInstance).getDigestArtifact()
|
||||
}
|
||||
|
||||
override NodeBase getChild(string edgeName) {
|
||||
result = super.getChild(edgeName)
|
||||
or
|
||||
// [KNOWN_OR_UNKNOWN]
|
||||
edgeName = "Algorithm" and
|
||||
if exists(this.getAHashAlgorithmOrUnknown())
|
||||
then result = this.getAHashAlgorithmOrUnknown()
|
||||
else result = this
|
||||
or
|
||||
// [KNOWN_OR_UNKNOWN]
|
||||
edgeName = "Digest" and
|
||||
if exists(this.getDigest()) then result = this.getDigest() else result = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1083,11 +1278,17 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
/**
|
||||
* A hashing algorithm that transforms variable-length input into a fixed-size hash value.
|
||||
*/
|
||||
abstract class HashAlgorithmNode extends AlgorithmNode, THashAlgorithm {
|
||||
HashAlgorithmInstance instance;
|
||||
final class HashAlgorithmNode extends AlgorithmNode, THashAlgorithm {
|
||||
HashAlgorithmInstanceOrValueConsumer instance;
|
||||
|
||||
HashAlgorithmNode() { this = THashAlgorithm(instance) }
|
||||
|
||||
override string getInternalType() { result = "HashAlgorithm" }
|
||||
|
||||
override LocatableElement asElement() { result = instance }
|
||||
|
||||
override string getRawAlgorithmName() { result = instance.asAlg().getRawAlgorithmName() }
|
||||
|
||||
final predicate hashTypeToNameMapping(THashType type, string name) {
|
||||
type instanceof BLAKE2B and name = "BLAKE2B"
|
||||
or
|
||||
|
||||
Reference in New Issue
Block a user