Merge pull request #19814 from bdrodes/codescanning_fixes_cpp

Crypto: Fix QL-for-QL alerts and refactor type standardization
This commit is contained in:
Nicolas Will
2025-06-26 16:33:19 +02:00
committed by GitHub
20 changed files with 746 additions and 679 deletions

View File

@@ -56,7 +56,7 @@ module ArtifactFlowConfig implements DataFlow::ConfigSig {
module ArtifactFlow = DataFlow::Global<ArtifactFlowConfig>;
/**
* Artifact output to node input configuration
* An artifact output to node input configuration
*/
abstract class AdditionalFlowInputStep extends DataFlow::Node {
abstract DataFlow::Node getOutput();
@@ -91,9 +91,8 @@ module GenericDataSourceFlowConfig implements DataFlow::ConfigSig {
module GenericDataSourceFlow = TaintTracking::Global<GenericDataSourceFlowConfig>;
private class ConstantDataSource extends Crypto::GenericConstantSourceInstance instanceof Literal {
ConstantDataSource() { this instanceof OpenSslGenericSourceCandidateLiteral }
private class ConstantDataSource extends Crypto::GenericConstantSourceInstance instanceof OpenSslGenericSourceCandidateLiteral
{
override DataFlow::Node getOutputNode() { result.asExpr() = this }
override predicate flowsTo(Crypto::FlowAwareElement other) {

View File

@@ -48,7 +48,7 @@ module KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig implements DataFlow::
module KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow =
DataFlow::Global<KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig>;
module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof OpenSslPaddingLiteral }
predicate isSink(DataFlow::Node sink) {
@@ -60,8 +60,8 @@ module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataF
}
}
module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow =
DataFlow::Global<RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow =
DataFlow::Global<RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
class OpenSslAlgorithmAdditionalFlowStep extends AdditionalFlowInputStep {
OpenSslAlgorithmAdditionalFlowStep() { exists(AlgorithmPassthroughCall c | c.getInNode() = this) }
@@ -114,11 +114,11 @@ class CopyAndDupAlgorithmPassthroughCall extends AlgorithmPassthroughCall {
override DataFlow::Node getOutNode() { result = outNode }
}
class NIDToPointerPassthroughCall extends AlgorithmPassthroughCall {
class NidToPointerPassthroughCall extends AlgorithmPassthroughCall {
DataFlow::Node inNode;
DataFlow::Node outNode;
NIDToPointerPassthroughCall() {
NidToPointerPassthroughCall() {
this.getTarget().getName() in ["OBJ_nid2obj", "OBJ_nid2ln", "OBJ_nid2sn"] and
inNode.asExpr() = this.getArgument(0) and
outNode.asExpr() = this
@@ -150,11 +150,11 @@ class PointerToPointerPassthroughCall extends AlgorithmPassthroughCall {
override DataFlow::Node getOutNode() { result = outNode }
}
class PointerToNIDPassthroughCall extends AlgorithmPassthroughCall {
class PointerToNidPassthroughCall extends AlgorithmPassthroughCall {
DataFlow::Node inNode;
DataFlow::Node outNode;
PointerToNIDPassthroughCall() {
PointerToNidPassthroughCall() {
this.getTarget().getName() in ["OBJ_obj2nid", "OBJ_ln2nid", "OBJ_sn2nid", "OBJ_txt2nid"] and
(
inNode.asIndirectExpr() = this.getArgument(0)

View File

@@ -5,36 +5,35 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
private import AlgToAVCFlow
private import codeql.quantum.experimental.Standardization::Types::KeyOpAlg as KeyOpAlg
/**
* Given a `KnownOpenSslBlockModeAlgorithmExpr`, converts this to a block family type.
* Does not bind if there is no mapping (no mapping to 'unknown' or 'other').
*/
predicate knownOpenSslConstantToBlockModeFamilyType(
KnownOpenSslBlockModeAlgorithmExpr e, Crypto::TBlockCipherModeOfOperationType type
KnownOpenSslBlockModeAlgorithmExpr e, KeyOpAlg::ModeOfOperationType type
) {
exists(string name |
name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
(
name.matches("CBC") and type instanceof Crypto::CBC
name = "CBC" and type instanceof KeyOpAlg::CBC
or
name.matches("CFB%") and type instanceof Crypto::CFB
name = "CFB%" and type instanceof KeyOpAlg::CFB
or
name.matches("CTR") and type instanceof Crypto::CTR
name = "CTR" and type instanceof KeyOpAlg::CTR
or
name.matches("GCM") and type instanceof Crypto::GCM
name = "GCM" and type instanceof KeyOpAlg::GCM
or
name.matches("OFB") and type instanceof Crypto::OFB
name = "OFB" and type instanceof KeyOpAlg::OFB
or
name.matches("XTS") and type instanceof Crypto::XTS
name = "XTS" and type instanceof KeyOpAlg::XTS
or
name.matches("CCM") and type instanceof Crypto::CCM
name = "CCM" and type instanceof KeyOpAlg::CCM
or
name.matches("GCM") and type instanceof Crypto::GCM
name = "CCM" and type instanceof KeyOpAlg::CCM
or
name.matches("CCM") and type instanceof Crypto::CCM
or
name.matches("ECB") and type instanceof Crypto::ECB
name = "ECB" and type instanceof KeyOpAlg::ECB
)
)
}
@@ -64,10 +63,10 @@ class KnownOpenSslBlockModeConstantAlgorithmInstance extends OpenSslAlgorithmIns
getterCall = this
}
override Crypto::TBlockCipherModeOfOperationType getModeType() {
override KeyOpAlg::ModeOfOperationType getModeType() {
knownOpenSslConstantToBlockModeFamilyType(this, result)
or
not knownOpenSslConstantToBlockModeFamilyType(this, _) and result = Crypto::OtherMode()
not knownOpenSslConstantToBlockModeFamilyType(this, _) and result = KeyOpAlg::OtherMode()
}
// NOTE: I'm not going to attempt to parse out the mode specific part, so returning

View File

@@ -33,9 +33,9 @@ predicate knownOpenSslConstantToCipherFamilyType(
or
name.matches("CAST5%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::CAST5())
or
name.matches("2DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DoubleDES())
name.matches("2DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DOUBLE_DES())
or
name.matches("3DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::TripleDES())
name.matches("3DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::TRIPLE_DES())
or
name.matches("DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DES())
or
@@ -113,7 +113,7 @@ class KnownOpenSslCipherConstantAlgorithmInstance extends OpenSslAlgorithmInstan
this.(KnownOpenSslCipherAlgorithmExpr).getExplicitKeySize() = result
}
override Crypto::KeyOpAlg::Algorithm getAlgorithmType() {
override KeyOpAlg::AlgorithmType getAlgorithmType() {
knownOpenSslConstantToCipherFamilyType(this, result)
or
not knownOpenSslConstantToCipherFamilyType(this, _) and

View File

@@ -39,8 +39,14 @@ class KnownOpenSslEllipticCurveConstantAlgorithmInstance extends OpenSslAlgorith
result = this.(Call).getTarget().getName()
}
override Crypto::TEllipticCurveType getEllipticCurveType() {
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _, result)
override Crypto::EllipticCurveFamilyType getEllipticCurveFamilyType() {
if
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _,
_)
then
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _,
result)
else result = Crypto::OtherEllipticCurveType()
}
override string getParsedEllipticCurveName() {
@@ -48,7 +54,7 @@ class KnownOpenSslEllipticCurveConstantAlgorithmInstance extends OpenSslAlgorith
}
override int getKeySize() {
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.(KnownOpenSslAlgorithmExpr)
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.(KnownOpenSslAlgorithmExpr)
.getNormalizedName(), result, _)
}
}

View File

@@ -11,21 +11,21 @@ predicate knownOpenSslConstantToHashFamilyType(
exists(string name |
name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
(
name.matches("BLAKE2B") and type instanceof Crypto::BLAKE2B
name = "BLAKE2B" and type instanceof Crypto::BLAKE2B
or
name.matches("BLAKE2S") and type instanceof Crypto::BLAKE2S
name = "BLAKE2S" and type instanceof Crypto::BLAKE2S
or
name.matches("GOST%") and type instanceof Crypto::GOSTHash
name.matches("GOST%") and type instanceof Crypto::GOST_HASH
or
name.matches("MD2") and type instanceof Crypto::MD2
name = "MD2" and type instanceof Crypto::MD2
or
name.matches("MD4") and type instanceof Crypto::MD4
name = "MD4" and type instanceof Crypto::MD4
or
name.matches("MD5") and type instanceof Crypto::MD5
name = "MD5" and type instanceof Crypto::MD5
or
name.matches("MDC2") and type instanceof Crypto::MDC2
name = "MDC2" and type instanceof Crypto::MDC2
or
name.matches("POLY1305") and type instanceof Crypto::POLY1305
name = "POLY1305" and type instanceof Crypto::POLY1305
or
name.matches(["SHA", "SHA1"]) and type instanceof Crypto::SHA1
or
@@ -33,13 +33,13 @@ predicate knownOpenSslConstantToHashFamilyType(
or
name.matches("SHA3-%") and type instanceof Crypto::SHA3
or
name.matches(["SHAKE"]) and type instanceof Crypto::SHAKE
name = "SHAKE" and type instanceof Crypto::SHAKE
or
name.matches("SM3") and type instanceof Crypto::SM3
name = "SM3" and type instanceof Crypto::SM3
or
name.matches("RIPEMD160") and type instanceof Crypto::RIPEMD160
name = "RIPEMD160" and type instanceof Crypto::RIPEMD160
or
name.matches("WHIRLPOOL") and type instanceof Crypto::WHIRLPOOL
name = "WHIRLPOOL" and type instanceof Crypto::WHIRLPOOL
)
)
}

View File

@@ -210,7 +210,8 @@ string getAlgorithmAlias(string alias) {
}
/**
* Finds aliases of known alagorithms defined by users (through obj_name_add and various macros pointing to this function)
* Holds for aliases of known algorithms defined by users
* (through obj_name_add and various macros pointing to this function).
*
* The `target` and `alias` are converted to lowercase to be of a standard form.
*/
@@ -222,7 +223,7 @@ predicate customAliases(string target, string alias) {
}
/**
* A hard-coded mapping of known algorithm aliases in OpenSsl.
* Holds for a hard-coded mapping of known algorithm aliases in OpenSsl.
* This was derived by applying the same kind of logic foun din `customAliases` to the
* OpenSsl code base directly.
*

View File

@@ -7,7 +7,7 @@ private import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
private import AlgToAVCFlow
class KnownOpenSslMacConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
Crypto::MACAlgorithmInstance instanceof KnownOpenSslMacAlgorithmExpr
Crypto::MacAlgorithmInstance instanceof KnownOpenSslMacAlgorithmExpr
{
OpenSslAlgorithmValueConsumer getterCall;
@@ -39,14 +39,14 @@ class KnownOpenSslMacConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
result = this.(Call).getTarget().getName()
}
override Crypto::TMACType getMacType() {
this instanceof KnownOpenSslHMacAlgorithmExpr and result instanceof Crypto::THMAC
override Crypto::MacType getMacType() {
this instanceof KnownOpenSslHMacAlgorithmExpr and result = Crypto::HMAC()
or
this instanceof KnownOpenSslCMacAlgorithmExpr and result instanceof Crypto::TCMAC
this instanceof KnownOpenSslCMacAlgorithmExpr and result = Crypto::CMAC()
}
}
class KnownOpenSslHMacConstantAlgorithmInstance extends Crypto::HMACAlgorithmInstance,
class KnownOpenSslHMacConstantAlgorithmInstance extends Crypto::HmacAlgorithmInstance,
KnownOpenSslMacConstantAlgorithmInstance
{
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {

View File

@@ -5,6 +5,7 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
private import AlgToAVCFlow
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
private import codeql.quantum.experimental.Standardization::Types::KeyOpAlg as KeyOpAlg
/**
* A class to define padding specific integer values.
@@ -28,18 +29,18 @@ class OpenSslPaddingLiteral extends Literal {
* Does not bind if there is no mapping (no mapping to 'unknown' or 'other').
*/
predicate knownOpenSslConstantToPaddingFamilyType(
KnownOpenSslPaddingAlgorithmExpr e, Crypto::TPaddingType type
KnownOpenSslPaddingAlgorithmExpr e, KeyOpAlg::PaddingSchemeType type
) {
exists(string name |
name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
(
name.matches("OAEP") and type = Crypto::OAEP()
name = "OAEP" and type = KeyOpAlg::OAEP()
or
name.matches("PSS") and type = Crypto::PSS()
name = "PSS" and type = KeyOpAlg::PSS()
or
name.matches("PKCS7") and type = Crypto::PKCS7()
name = "PKCS7" and type = KeyOpAlg::PKCS7()
or
name.matches("PKCS1V15") and type = Crypto::PKCS1_v1_5()
name = "PKCS1V15" and type = KeyOpAlg::PKCS1_V1_5()
)
)
}
@@ -85,7 +86,7 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
// Source is `this`
src.asExpr() = this and
// This traces to a padding-specific consumer
RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow::flow(src, sink)
RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow::flow(src, sink)
) and
isPaddingSpecificConsumer = true
}
@@ -98,24 +99,24 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
Crypto::TPaddingType getKnownPaddingType() {
this.(Literal).getValue().toInt() in [1, 7, 8] and result = Crypto::PKCS1_v1_5()
KeyOpAlg::PaddingSchemeType getKnownPaddingType() {
this.(Literal).getValue().toInt() in [1, 7, 8] and result = KeyOpAlg::PKCS1_V1_5()
or
this.(Literal).getValue().toInt() = 3 and result = Crypto::NoPadding()
this.(Literal).getValue().toInt() = 3 and result = KeyOpAlg::NoPadding()
or
this.(Literal).getValue().toInt() = 4 and result = Crypto::OAEP()
this.(Literal).getValue().toInt() = 4 and result = KeyOpAlg::OAEP()
or
this.(Literal).getValue().toInt() = 5 and result = Crypto::ANSI_X9_23()
this.(Literal).getValue().toInt() = 5 and result = KeyOpAlg::ANSI_X9_23()
or
this.(Literal).getValue().toInt() = 6 and result = Crypto::PSS()
this.(Literal).getValue().toInt() = 6 and result = KeyOpAlg::PSS()
}
override Crypto::TPaddingType getPaddingType() {
override KeyOpAlg::PaddingSchemeType getPaddingType() {
isPaddingSpecificConsumer = true and
(
result = this.getKnownPaddingType()
or
not exists(this.getKnownPaddingType()) and result = Crypto::OtherPadding()
not exists(this.getKnownPaddingType()) and result = KeyOpAlg::OtherPadding()
)
or
isPaddingSpecificConsumer = false and
@@ -143,7 +144,7 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
// this instanceof Literal and
// this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8]
// // TODO: trace to padding-specific consumers
// RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow
// RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow
// }
// override string getRawPaddingAlgorithmName() { result = this.(Literal).getValue().toString() }
// override Crypto::TPaddingType getPaddingType() {
@@ -161,18 +162,18 @@ class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInsta
// else result = Crypto::OtherPadding()
// }
// }
class OAEPPaddingAlgorithmInstance extends Crypto::OAEPPaddingAlgorithmInstance,
class OaepPaddingAlgorithmInstance extends Crypto::OaepPaddingAlgorithmInstance,
KnownOpenSslPaddingConstantAlgorithmInstance
{
OAEPPaddingAlgorithmInstance() {
this.(Crypto::PaddingAlgorithmInstance).getPaddingType() = Crypto::OAEP()
OaepPaddingAlgorithmInstance() {
this.(Crypto::PaddingAlgorithmInstance).getPaddingType() = KeyOpAlg::OAEP()
}
override Crypto::HashAlgorithmInstance getOAEPEncodingHashAlgorithm() {
override Crypto::HashAlgorithmInstance getOaepEncodingHashAlgorithm() {
none() //TODO
}
override Crypto::HashAlgorithmInstance getMGF1HashAlgorithm() {
override Crypto::HashAlgorithmInstance getMgf1HashAlgorithm() {
none() //TODO
}
}

View File

@@ -73,7 +73,7 @@ class KnownOpenSslSignatureConstantAlgorithmInstance extends OpenSslAlgorithmIns
none()
}
override KeyOpAlg::Algorithm getAlgorithmType() {
override KeyOpAlg::AlgorithmType getAlgorithmType() {
knownOpenSslConstantToSignatureFamilyType(this, result)
or
not knownOpenSslConstantToSignatureFamilyType(this, _) and

View File

@@ -4,10 +4,10 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
/**
* Cases like EVP_MD5(),
* there is no input, rather it directly gets an algorithm
* and returns it.
* Also includes operations directly using an algorithm
* A call that is considered to inherently 'consume' an algorithm value.
* E.g., cases like EVP_MD5(),
* where there is no input, rather it directly gets an algorithm
* and returns it. Also includes operations directly using an algorithm
* like AES_encrypt().
*/
class DirectAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer instanceof OpenSslAlgorithmCall

View File

@@ -7,7 +7,7 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmI
abstract class HashAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer { }
/**
* EVP_Q_Digest directly consumes algorithm constant values
* An EVP_Q_Digest directly consumes algorithm constant values
*/
class Evp_Q_Digest_Algorithm_Consumer extends HashAlgorithmValueConsumer {
Evp_Q_Digest_Algorithm_Consumer() { this.(Call).getTarget().getName() = "EVP_Q_digest" }

View File

@@ -91,7 +91,8 @@ class Evp_Cipher_Update_Call extends EvpUpdate {
}
/**
* see: https://docs.openssl.org/master/man3/EVP_EncryptInit/#synopsis
* The EVP Cipher operations.
* See: https://docs.openssl.org/master/man3/EVP_EncryptInit/#synopsis
* Base configuration for all EVP cipher operations.
*/
abstract class Evp_Cipher_Operation extends EvpOperation, Crypto::KeyOperationInstance {
@@ -163,6 +164,7 @@ class Evp_Cipher_Final_Call extends EvpFinal, Evp_Cipher_Operation {
}
/**
* The EVP encryption/decryption operations.
* https://docs.openssl.org/3.2/man3/EVP_PKEY_decrypt/
* https://docs.openssl.org/3.2/man3/EVP_PKEY_encrypt
*/

View File

@@ -5,7 +5,7 @@ import semmle.code.java.controlflow.Dominance
module JCAModel {
import Language
import Crypto::KeyOpAlg as KeyOpAlg
import codeql.quantum.experimental.Standardization::Types::KeyOpAlg as KeyOpAlg
abstract class CipherAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer { }
@@ -115,7 +115,7 @@ module JCAModel {
}
bindingset[name]
Crypto::THashType hash_name_to_type_known(string name, int digestLength) {
Crypto::HashType hash_name_to_type_known(string name, int digestLength) {
name = "SHA-1" and result instanceof Crypto::SHA1 and digestLength = 160
or
name = ["SHA-256", "SHA-384", "SHA-512"] and
@@ -152,24 +152,22 @@ module JCAModel {
}
bindingset[name]
private predicate mode_name_to_type_known(
Crypto::TBlockCipherModeOfOperationType type, string name
) {
type = Crypto::ECB() and name = "ECB"
private predicate mode_name_to_type_known(KeyOpAlg::ModeOfOperationType type, string name) {
type = KeyOpAlg::ECB() and name = "ECB"
or
type = Crypto::CBC() and name = "CBC"
type = KeyOpAlg::CBC() and name = "CBC"
or
type = Crypto::GCM() and name = "GCM"
type = KeyOpAlg::GCM() and name = "GCM"
or
type = Crypto::CTR() and name = "CTR"
type = KeyOpAlg::CTR() and name = "CTR"
or
type = Crypto::XTS() and name = "XTS"
type = KeyOpAlg::XTS() and name = "XTS"
or
type = Crypto::CCM() and name = "CCM"
type = KeyOpAlg::CCM() and name = "CCM"
or
type = Crypto::SIV() and name = "SIV"
type = KeyOpAlg::SIV() and name = "SIV"
or
type = Crypto::OCB() and name = "OCB"
type = KeyOpAlg::OCB() and name = "OCB"
}
bindingset[name]
@@ -182,7 +180,7 @@ module JCAModel {
type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DES())
or
upper = "TRIPLEDES" and
type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::TripleDES())
type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::TRIPLE_DES())
or
upper = "IDEA" and
type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::IDEA())
@@ -205,8 +203,8 @@ module JCAModel {
}
bindingset[name]
predicate mac_name_to_mac_type_known(Crypto::TMACType type, string name) {
type = Crypto::THMAC() and
predicate mac_name_to_mac_type_known(Crypto::TMacType type, string name) {
type = Crypto::HMAC() and
name.toUpperCase().matches("HMAC%")
}
@@ -298,18 +296,18 @@ module JCAModel {
override string getRawPaddingAlgorithmName() { result = super.getPadding() }
bindingset[name]
private predicate paddingToNameMappingKnown(Crypto::TPaddingType type, string name) {
type instanceof Crypto::NoPadding and name = "NOPADDING"
private predicate paddingToNameMappingKnown(KeyOpAlg::PaddingSchemeType type, string name) {
type instanceof KeyOpAlg::NoPadding and name = "NOPADDING"
or
type instanceof Crypto::PKCS7 and name = ["PKCS5Padding", "PKCS7Padding"] // TODO: misnomer in the JCA?
type instanceof KeyOpAlg::PKCS7 and name = ["PKCS5Padding", "PKCS7Padding"] // TODO: misnomer in the JCA?
or
type instanceof Crypto::OAEP and name.matches("OAEP%") // TODO: handle OAEPWith%
type instanceof KeyOpAlg::OAEP and name.matches("OAEP%") // TODO: handle OAEPWith%
}
override Crypto::TPaddingType getPaddingType() {
override KeyOpAlg::PaddingSchemeType getPaddingType() {
if this.paddingToNameMappingKnown(_, super.getPadding())
then this.paddingToNameMappingKnown(result, super.getPadding())
else result instanceof Crypto::OtherPadding
else result instanceof KeyOpAlg::OtherPadding
}
}
@@ -320,10 +318,10 @@ module JCAModel {
override string getRawModeAlgorithmName() { result = super.getMode() }
override Crypto::TBlockCipherModeOfOperationType getModeType() {
override KeyOpAlg::ModeOfOperationType getModeType() {
if mode_name_to_type_known(_, super.getMode())
then mode_name_to_type_known(result, super.getMode())
else result instanceof Crypto::OtherMode
else result instanceof KeyOpAlg::OtherMode
}
}
@@ -347,7 +345,7 @@ module JCAModel {
override string getRawAlgorithmName() { result = super.getValue() }
override KeyOpAlg::Algorithm getAlgorithmType() {
override KeyOpAlg::AlgorithmType getAlgorithmType() {
if cipher_name_to_type_known(_, super.getAlgorithmName())
then cipher_name_to_type_known(result, super.getAlgorithmName())
else result instanceof KeyOpAlg::TUnknownKeyOperationAlgorithmType
@@ -373,12 +371,12 @@ module JCAModel {
oaep_padding_string_components(any(CipherStringLiteral s).getPadding(), hash, mfg)
}
class OAEPPaddingHashAlgorithmInstance extends OAEPPaddingAlgorithmInstance,
class OaepPaddingHashAlgorithmInstance extends OaepPaddingAlgorithmInstance,
Crypto::HashAlgorithmInstance instanceof CipherStringLiteral
{
string hashName;
OAEPPaddingHashAlgorithmInstance() {
OaepPaddingHashAlgorithmInstance() {
oaep_padding_string_components(super.getPadding(), hashName, _)
}
@@ -389,12 +387,12 @@ module JCAModel {
override int getFixedDigestLength() { exists(hash_name_to_type_known(hashName, result)) }
}
class OAEPPaddingAlgorithmInstance extends Crypto::OAEPPaddingAlgorithmInstance,
class OaepPaddingAlgorithmInstance extends Crypto::OaepPaddingAlgorithmInstance,
CipherStringLiteralPaddingAlgorithmInstance
{
override Crypto::HashAlgorithmInstance getOAEPEncodingHashAlgorithm() { result = this }
override Crypto::HashAlgorithmInstance getOaepEncodingHashAlgorithm() { result = this }
override Crypto::HashAlgorithmInstance getMGF1HashAlgorithm() { none() } // TODO
override Crypto::HashAlgorithmInstance getMgf1HashAlgorithm() { none() } // TODO
}
/**
@@ -1156,9 +1154,7 @@ module JCAModel {
}
module KeySpecInstantiationToGenerateSecretFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) {
exists(KeySpecInstantiation call | src.asExpr() = call)
}
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof KeySpecInstantiation }
predicate isSink(DataFlow::Node sink) {
exists(SecretKeyFactoryGenerateSecretCall call | sink.asExpr() = call.getKeySpecArg())
@@ -1207,29 +1203,29 @@ module JCAModel {
predicate isIntermediate() { none() }
}
class KDFAlgorithmStringLiteral extends Crypto::KeyDerivationAlgorithmInstance instanceof StringLiteral
class KdfAlgorithmStringLiteral extends Crypto::KeyDerivationAlgorithmInstance instanceof StringLiteral
{
SecretKeyFactoryKDFAlgorithmValueConsumer consumer;
KDFAlgorithmStringLiteral() {
KdfAlgorithmStringLiteral() {
kdf_names(this.getValue()) and
KDFAlgorithmStringToGetInstanceFlow::flow(DataFlow::exprNode(this), consumer.getInputNode())
}
override string getRawKDFAlgorithmName() { result = super.getValue() }
override string getRawKdfAlgorithmName() { result = super.getValue() }
override Crypto::TKeyDerivationType getKDFType() {
override Crypto::TKeyDerivationType getKdfType() {
result = kdf_name_to_kdf_type(super.getValue(), _)
}
SecretKeyFactoryKDFAlgorithmValueConsumer getConsumer() { result = consumer }
}
class PBKDF2AlgorithmStringLiteral extends KDFAlgorithmStringLiteral,
Crypto::PBKDF2AlgorithmInstance, Crypto::HMACAlgorithmInstance, Crypto::HashAlgorithmInstance,
class Pbkdf2AlgorithmStringLiteral extends KdfAlgorithmStringLiteral,
Crypto::Pbkdf2AlgorithmInstance, Crypto::HmacAlgorithmInstance, Crypto::HashAlgorithmInstance,
Crypto::AlgorithmValueConsumer
{
PBKDF2AlgorithmStringLiteral() { super.getKDFType() instanceof Crypto::PBKDF2 }
Pbkdf2AlgorithmStringLiteral() { super.getKdfType() instanceof Crypto::PBKDF2 }
override Crypto::ConsumerInputDataFlowNode getInputNode() { none() }
@@ -1244,16 +1240,16 @@ module JCAModel {
}
override string getRawMacAlgorithmName() {
result = super.getRawKDFAlgorithmName().splitAt("PBKDF2With", 1)
result = super.getRawKdfAlgorithmName().splitAt("PBKDF2With", 1)
}
override string getRawHashAlgorithmName() {
result = super.getRawKDFAlgorithmName().splitAt("WithHmac", 1)
result = super.getRawKdfAlgorithmName().splitAt("WithHmac", 1)
}
override Crypto::TMACType getMacType() { result instanceof Crypto::THMAC }
override Crypto::MacType getMacType() { result = Crypto::HMAC() }
override Crypto::AlgorithmValueConsumer getHMACAlgorithmValueConsumer() { result = this }
override Crypto::AlgorithmValueConsumer getHmacAlgorithmValueConsumer() { result = this }
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() { result = this }
}
@@ -1267,7 +1263,7 @@ module JCAModel {
override Crypto::ConsumerInputDataFlowNode getInputNode() { result.asExpr() = this }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(KDFAlgorithmStringLiteral l | l.getConsumer() = this and result = l)
exists(KdfAlgorithmStringLiteral l | l.getConsumer() = this and result = l)
}
SecretKeyFactoryGetInstanceCall getInstantiation() { result = call }
@@ -1442,105 +1438,103 @@ module JCAModel {
* MACs
*/
module MACKnownAlgorithmToConsumerConfig implements DataFlow::ConfigSig {
module MacKnownAlgorithmToConsumerConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { mac_names(src.asExpr().(StringLiteral).getValue()) }
predicate isSink(DataFlow::Node sink) {
exists(MACGetInstanceCall call | sink.asExpr() = call.getAlgorithmArg())
exists(MacGetInstanceCall call | sink.asExpr() = call.getAlgorithmArg())
}
}
module MACKnownAlgorithmToConsumerFlow = DataFlow::Global<MACKnownAlgorithmToConsumerConfig>;
module MacKnownAlgorithmToConsumerFlow = DataFlow::Global<MacKnownAlgorithmToConsumerConfig>;
module MACGetInstanceToMACOperationFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof MACGetInstanceCall }
module MacGetInstanceToMacOperationFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof MacGetInstanceCall }
predicate isSink(DataFlow::Node sink) {
exists(MACOperationCall call | sink.asExpr() = call.(MethodCall).getQualifier()) or
exists(MACInitCall call | sink.asExpr() = call.(MethodCall).getQualifier())
exists(MacOperationCall call | sink.asExpr() = call.(MethodCall).getQualifier()) or
exists(MacInitCall call | sink.asExpr() = call.(MethodCall).getQualifier())
}
}
module MACGetInstanceToMACOperationFlow =
DataFlow::Global<MACGetInstanceToMACOperationFlowConfig>;
module MacGetInstanceToMacOperationFlow =
DataFlow::Global<MacGetInstanceToMacOperationFlowConfig>;
module MACInitCallToMACOperationFlowConfig implements DataFlow::ConfigSig {
module MacInitCallToMacOperationFlowConfig implements DataFlow::ConfigSig {
// TODO: use flow state with one config
predicate isSource(DataFlow::Node src) {
exists(MACInitCall init | src.asExpr() = init.getQualifier())
exists(MacInitCall init | src.asExpr() = init.getQualifier())
}
predicate isSink(DataFlow::Node sink) {
exists(MACOperationCall call | sink.asExpr() = call.(MethodCall).getQualifier())
exists(MacOperationCall call | sink.asExpr() = call.(MethodCall).getQualifier())
}
}
module MACInitCallToMACOperationFlow = DataFlow::Global<MACInitCallToMACOperationFlowConfig>;
module MacInitCallToMacOperationFlow = DataFlow::Global<MacInitCallToMacOperationFlowConfig>;
class KnownMACAlgorithm extends Crypto::MACAlgorithmInstance instanceof StringLiteral {
MACGetInstanceAlgorithmValueConsumer consumer;
class KnownMacAlgorithm extends Crypto::MacAlgorithmInstance instanceof StringLiteral {
MacGetInstanceAlgorithmValueConsumer consumer;
KnownMACAlgorithm() {
KnownMacAlgorithm() {
mac_names(this.getValue()) and
MACKnownAlgorithmToConsumerFlow::flow(DataFlow::exprNode(this), consumer.getInputNode())
MacKnownAlgorithmToConsumerFlow::flow(DataFlow::exprNode(this), consumer.getInputNode())
}
MACGetInstanceAlgorithmValueConsumer getConsumer() { result = consumer }
MacGetInstanceAlgorithmValueConsumer getConsumer() { result = consumer }
override string getRawMacAlgorithmName() { result = super.getValue() }
override Crypto::TMACType getMacType() {
override Crypto::MacType getMacType() {
if mac_name_to_mac_type_known(_, super.getValue())
then mac_name_to_mac_type_known(result, super.getValue())
else result instanceof Crypto::TOtherMACType
else result = Crypto::OtherMacType()
}
}
class MACGetInstanceCall extends MethodCall {
MACGetInstanceCall() { this.getCallee().hasQualifiedName("javax.crypto", "Mac", "getInstance") }
class MacGetInstanceCall extends MethodCall {
MacGetInstanceCall() { this.getCallee().hasQualifiedName("javax.crypto", "Mac", "getInstance") }
Expr getAlgorithmArg() { result = this.getArgument(0) }
MACOperationCall getOperation() {
MACGetInstanceToMACOperationFlow::flow(DataFlow::exprNode(this),
MacOperationCall getOperation() {
MacGetInstanceToMacOperationFlow::flow(DataFlow::exprNode(this),
DataFlow::exprNode(result.(MethodCall).getQualifier()))
}
MACInitCall getInitCall() {
MACGetInstanceToMACOperationFlow::flow(DataFlow::exprNode(this),
MacInitCall getInitCall() {
MacGetInstanceToMacOperationFlow::flow(DataFlow::exprNode(this),
DataFlow::exprNode(result.getQualifier()))
}
}
class MACInitCall extends MethodCall {
MACInitCall() { this.getCallee().hasQualifiedName("javax.crypto", "Mac", "init") }
class MacInitCall extends MethodCall {
MacInitCall() { this.getCallee().hasQualifiedName("javax.crypto", "Mac", "init") }
Expr getKeyArg() {
result = this.getArgument(0) and this.getMethod().getParameterType(0).hasName("Key")
}
MACOperationCall getOperation() {
MACInitCallToMACOperationFlow::flow(DataFlow::exprNode(this.getQualifier()),
MacOperationCall getOperation() {
MacInitCallToMacOperationFlow::flow(DataFlow::exprNode(this.getQualifier()),
DataFlow::exprNode(result.(MethodCall).getQualifier()))
}
}
class MACGetInstanceAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer {
MACGetInstanceCall call;
MACGetInstanceAlgorithmValueConsumer() { this = call.getAlgorithmArg() }
class MacGetInstanceAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer {
MacGetInstanceAlgorithmValueConsumer() { this = any(MacGetInstanceCall c).getAlgorithmArg() }
override Crypto::ConsumerInputDataFlowNode getInputNode() { result.asExpr() = this }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(KnownMACAlgorithm l | l.getConsumer() = this and result = l)
exists(KnownMacAlgorithm l | l.getConsumer() = this and result = l)
}
}
class MACOperationCall extends Crypto::MACOperationInstance instanceof MethodCall {
class MacOperationCall extends Crypto::MacOperationInstance instanceof MethodCall {
Expr output;
MACOperationCall() {
MacOperationCall() {
super.getMethod().getDeclaringType().hasQualifiedName("javax.crypto", "Mac") and
(
super.getMethod().hasStringSignature(["doFinal()", "doFinal(byte[])"]) and this = output
@@ -1551,13 +1545,13 @@ module JCAModel {
}
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
exists(MACGetInstanceCall instantiation |
exists(MacGetInstanceCall instantiation |
instantiation.getOperation() = this and result = instantiation.getAlgorithmArg()
)
}
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
exists(MACGetInstanceCall instantiation, MACInitCall initCall |
exists(MacGetInstanceCall instantiation, MacInitCall initCall |
instantiation.getOperation() = this and
initCall.getOperation() = this and
instantiation.getInitCall() = initCall and
@@ -1599,15 +1593,18 @@ module JCAModel {
override string getRawEllipticCurveName() { result = super.getValue() }
override Crypto::TEllipticCurveType getEllipticCurveType() {
if Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.getRawEllipticCurveName(), _, _)
override Crypto::EllipticCurveFamilyType getEllipticCurveFamilyType() {
if
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getRawEllipticCurveName(), _, _)
then
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.getRawEllipticCurveName(), _, result)
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getRawEllipticCurveName(), _,
result)
else result = Crypto::OtherEllipticCurveType()
}
override int getKeySize() {
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.getRawEllipticCurveName(), result, _)
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getRawEllipticCurveName(),
result, _)
}
EllipticCurveAlgorithmValueConsumer getConsumer() { result = consumer }

View File

@@ -7,7 +7,7 @@ import experimental.quantum.Language
class AESGCMAlgorithmNode extends Crypto::KeyOperationAlgorithmNode {
AESGCMAlgorithmNode() {
this.getAlgorithmType() = Crypto::KeyOpAlg::TSymmetricCipher(Crypto::KeyOpAlg::AES()) and
this.getModeOfOperation().getModeType() = Crypto::GCM()
this.getModeOfOperation().getModeType() = Crypto::KeyOpAlg::GCM()
}
}

View File

@@ -11,5 +11,5 @@ import java
import experimental.quantum.Language
from Crypto::KeyOperationAlgorithmNode a
where a.getAlgorithmType() instanceof Crypto::KeyOpAlg::AsymmetricCipherAlgorithm
where a.getAlgorithmType() instanceof Crypto::KeyOpAlg::AsymmetricCipherAlgorithmType
select a, a.getAlgorithmName()

View File

@@ -13,6 +13,6 @@ 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
a.getAlgorithmType() instanceof Crypto::KeyOpAlg::AsymmetricCipherAlgorithmType or
a.getAlgorithmType() instanceof Crypto::KeyOpAlg::SymmetricCipherAlgorithmType
select a, a.getAlgorithmName()

View File

@@ -11,5 +11,5 @@ import java
import experimental.quantum.Language
from Crypto::KeyOperationAlgorithmNode a
where a.getAlgorithmType() instanceof Crypto::KeyOpAlg::SymmetricCipherAlgorithm
where a.getAlgorithmType() instanceof Crypto::KeyOpAlg::SymmetricCipherAlgorithmType
select a, a.getAlgorithmName()

View File

@@ -29,6 +29,8 @@ signature module InputSig<LocationSig Location> {
}
module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
import Standardization::Types
final class LocatableElement = Input::LocatableElement;
final class UnknownLocation = Input::UnknownLocation;
@@ -355,7 +357,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
* * An artifact's properties (such as being a nonce) are not necessarily inherent; they are determined by the context in which the artifact is consumed.
* The consumer node is therefore essential in defining these properties for inputs.
* * This approach reduces ambiguity by avoiding separate notions of "artifact source" and "consumer", as the node itself encapsulates both roles.
* * Instances of nodes do not necessarily have to come from a consumer, allowing additional modelling of an artifact to occur outside of the consumer.
* * Instances of nodes do not necessarily have to come from a consumer, allowing additional modeling of an artifact to occur outside of the consumer.
*/
abstract class ArtifactConsumer extends ConsumerElement {
/**
@@ -403,7 +405,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
or
exists(KeyDerivationOperationInstance op | inputNode = op.getInputConsumer())
or
exists(MACOperationInstance op | inputNode = op.getMessageConsumer())
exists(MacOperationInstance op | inputNode = op.getMessageConsumer())
or
exists(HashOperationInstance op | inputNode = op.getInputConsumer())
) and
@@ -537,7 +539,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
(
exists(KeyOperationInstance op | inputNode = op.getKeyConsumer())
or
exists(MACOperationInstance op | inputNode = op.getKeyConsumer())
exists(MacOperationInstance op | inputNode = op.getKeyConsumer())
or
exists(KeyAgreementSecretGenerationOperationInstance op |
inputNode = op.getServerKeyConsumer() or
@@ -552,192 +554,6 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
final override ConsumerInputDataFlowNode getInputNode() { result = inputNode }
}
/**
* The `KeyOpAlg` module defines key operation algorithms types (e.g., symmetric ciphers, signatures, etc.)
* and provides mapping of those types to string names and structural properties.
*/
module KeyOpAlg {
/**
* An algorithm used in key operations.
*/
newtype TAlgorithm =
TSymmetricCipher(TSymmetricCipherType t) or
TAsymmetricCipher(TAsymmetricCipherType t) or
TSignature(TSignatureAlgorithmType t) or
TKeyEncapsulation(TKEMAlgorithmType t) or
TUnknownKeyOperationAlgorithmType()
// Parameterized algorithm types
newtype TSymmetricCipherType =
AES() or
ARIA() or
BLOWFISH() or
CAMELLIA() or
CAST5() or
CHACHA20() or
DES() or
DESX() or
GOST() or
IDEA() or
KUZNYECHIK() or
MAGMA() or
TripleDES() or
DoubleDES() or
RC2() or
RC4() or
RC5() or
SEED() or
SM4() or
OtherSymmetricCipherType()
newtype TAsymmetricCipherType =
RSA() or
OtherAsymmetricCipherType()
newtype TSignatureAlgorithmType =
DSA() or
ECDSA() or
EDDSA() or // e.g., ED25519 or ED448
OtherSignatureAlgorithmType()
newtype TKEMAlgorithmType =
Kyber() or
FrodoKEM() or
OtherKEMAlgorithmType()
newtype TCipherStructureType =
Block() or
Stream() or
UnknownCipherStructureType()
class CipherStructureType extends TCipherStructureType {
string toString() {
result = "Block" and this = Block()
or
result = "Stream" and this = Stream()
or
result = "Unknown" and this = UnknownCipherStructureType()
}
}
predicate fixedImplicitCipherKeySize(TAlgorithm type, int size) {
type = TSymmetricCipher(DES()) and size = 56
or
type = TSymmetricCipher(DESX()) and size = 184
or
type = TSymmetricCipher(DoubleDES()) and size = 112
or
type = TSymmetricCipher(TripleDES()) and size = 168
or
type = TSymmetricCipher(CHACHA20()) and size = 256
or
type = TSymmetricCipher(IDEA()) and size = 128
or
type = TSymmetricCipher(KUZNYECHIK()) and size = 256
or
type = TSymmetricCipher(MAGMA()) and size = 256
or
type = TSymmetricCipher(SM4()) and size = 128
or
type = TSymmetricCipher(SEED()) and size = 128
}
predicate symmetric_cipher_to_name_and_structure(
TSymmetricCipherType type, string name, CipherStructureType s
) {
type = AES() and name = "AES" and s = Block()
or
type = ARIA() and name = "ARIA" and s = Block()
or
type = BLOWFISH() and name = "Blowfish" and s = Block()
or
type = CAMELLIA() and name = "Camellia" and s = Block()
or
type = CAST5() and name = "CAST5" and s = Block()
or
type = CHACHA20() and name = "ChaCha20" and s = Stream()
or
type = DES() and name = "DES" and s = Block()
or
type = DESX() and name = "DESX" and s = Block()
or
type = GOST() and name = "GOST" and s = Block()
or
type = IDEA() and name = "IDEA" and s = Block()
or
type = KUZNYECHIK() and name = "Kuznyechik" and s = Block()
or
type = MAGMA() and name = "Magma" and s = Block()
or
type = TripleDES() and name = "TripleDES" and s = Block()
or
type = DoubleDES() and name = "DoubleDES" and s = Block()
or
type = RC2() and name = "RC2" and s = Block()
or
type = RC4() and name = "RC4" and s = Stream()
or
type = RC5() and name = "RC5" and s = Block()
or
type = SEED() and name = "SEED" and s = Block()
or
type = SM4() and name = "SM4" and s = Block()
or
type = OtherSymmetricCipherType() and
name = "UnknownSymmetricCipher" and
s = UnknownCipherStructureType()
}
predicate type_to_name(Algorithm type, string name) {
// Symmetric cipher algorithm
symmetric_cipher_to_name_and_structure(type.(SymmetricCipherAlgorithm).getType(), name, _)
or
// Asymmetric cipher algorithms
type = TAsymmetricCipher(RSA()) and name = "RSA"
or
type = TAsymmetricCipher(OtherAsymmetricCipherType()) and name = "UnknownAsymmetricCipher"
or
// Signature algorithms
type = TSignature(DSA()) and name = "DSA"
or
type = TSignature(ECDSA()) and name = "ECDSA"
or
type = TSignature(EDDSA()) and name = "EDSA"
or
type = TSignature(OtherSignatureAlgorithmType()) and name = "UnknownSignature"
or
// Key Encapsulation Mechanisms
type = TKeyEncapsulation(Kyber()) and name = "Kyber"
or
type = TKeyEncapsulation(FrodoKEM()) and name = "FrodoKEM"
or
type = TKeyEncapsulation(OtherKEMAlgorithmType()) and name = "UnknownKEM"
or
// Unknown
type = TUnknownKeyOperationAlgorithmType() and name = "Unknown"
}
class Algorithm extends TAlgorithm {
string toString() { type_to_name(this, result) }
}
class SymmetricCipherAlgorithm extends Algorithm, TSymmetricCipher {
TSymmetricCipherType type;
SymmetricCipherAlgorithm() { this = TSymmetricCipher(type) }
TSymmetricCipherType getType() { result = type }
}
class AsymmetricCipherAlgorithm extends Algorithm, TAsymmetricCipher {
TAsymmetricCipherType type;
AsymmetricCipherAlgorithm() { this = TAsymmetricCipher(type) }
TAsymmetricCipherType getType() { result = type }
}
}
/**
* A key-based cryptographic operation instance, encompassing:
* 1. **Ciphers**: Encryption and decryption, both symmetric and asymmetric
@@ -836,7 +652,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
*
* This predicate should always hold.
*/
abstract KeyOpAlg::Algorithm getAlgorithmType();
abstract KeyOpAlg::AlgorithmType getAlgorithmType();
/**
* Gets the mode of operation, such as "CBC", "GCM", or "ECB".
@@ -888,19 +704,6 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
predicate shouldHavePaddingScheme() { any() }
}
newtype TBlockCipherModeOfOperationType =
ECB() or // Not secure, widely used
CBC() or // Vulnerable to padding oracle attacks
CFB() or
GCM() or // Widely used AEAD mode (TLS 1.3, SSH, IPsec)
CTR() or // Fast stream-like encryption (SSH, disk encryption)
XTS() or // Standard for full-disk encryption (BitLocker, LUKS, FileVault)
CCM() or // Used in lightweight cryptography (IoT, WPA2)
SIV() or // Misuse-resistant encryption, used in secure storage
OCB() or // Efficient AEAD mode
OFB() or
OtherMode()
abstract class ModeOfOperationAlgorithmInstance extends AlgorithmInstance {
/**
* Gets the type of this mode of operation, e.g., "ECB" or "CBC".
@@ -909,7 +712,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
*
* If a type cannot be determined, the result is `OtherMode`.
*/
abstract TBlockCipherModeOfOperationType getModeType();
abstract KeyOpAlg::ModeOfOperationType getModeType();
/**
* Gets the isolated name as it appears in source, e.g., "CBC" in "AES/CBC/PKCS7Padding".
@@ -934,33 +737,28 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
*
* If a type cannot be determined, the result is `OtherPadding`.
*/
abstract TPaddingType getPaddingType();
abstract KeyOpAlg::PaddingSchemeType getPaddingType();
}
abstract class OAEPPaddingAlgorithmInstance extends PaddingAlgorithmInstance {
OAEPPaddingAlgorithmInstance() { this.getPaddingType() instanceof OAEP }
abstract class OaepPaddingAlgorithmInstance extends PaddingAlgorithmInstance {
OaepPaddingAlgorithmInstance() { this.getPaddingType() instanceof KeyOpAlg::OAEP }
/**
* Gets the hash algorithm used in this padding scheme.
*/
abstract HashAlgorithmInstance getOAEPEncodingHashAlgorithm();
abstract HashAlgorithmInstance getOaepEncodingHashAlgorithm();
/**
* Gets the hash algorithm used by MGF1 (assumption: MGF1 is the only MGF used by OAEP)
*/
abstract HashAlgorithmInstance getMGF1HashAlgorithm();
abstract HashAlgorithmInstance getMgf1HashAlgorithm();
}
newtype TMACType =
THMAC() or
TCMAC() or
TOtherMACType()
abstract class MACAlgorithmInstance extends AlgorithmInstance {
abstract class MacAlgorithmInstance extends AlgorithmInstance {
/**
* Gets the type of this MAC algorithm, e.g., "HMAC" or "CMAC".
*/
abstract TMACType getMacType();
abstract MacType getMacType();
/**
* Gets the isolated name as it appears in source, e.g., "HMAC-SHA256" in "HMAC-SHA256/UnrelatedInformation".
@@ -970,7 +768,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
abstract string getRawMacAlgorithmName();
}
abstract class MACOperationInstance extends OperationInstance {
abstract class MacOperationInstance extends OperationInstance {
/**
* Gets the message input used in this operation.
*/
@@ -982,8 +780,8 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
abstract ConsumerInputDataFlowNode getKeyConsumer();
}
abstract class HMACAlgorithmInstance extends MACAlgorithmInstance {
HMACAlgorithmInstance() { this.getMacType() instanceof THMAC }
abstract class HmacAlgorithmInstance extends MacAlgorithmInstance {
HmacAlgorithmInstance() { this.getMacType() = HMAC() }
/**
* Gets the hash algorithm used by this HMAC algorithm.
@@ -999,7 +797,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
*/
abstract string getRawEllipticCurveName();
abstract TEllipticCurveType getEllipticCurveType();
abstract TEllipticCurveFamilyType getEllipticCurveFamilyType();
abstract int getKeySize();
@@ -1060,8 +858,10 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
}
/**
* Users should not extend this class directly, but instead use
* `KeyCreationOperationInstance` or `KeyDerivationOperationInstance`.
* An operation that generates, derives, or loads a cryptographic key.
*
* Library modeling should not extend this class directly but rather extend
* `KeyGenerationOperationInstance`, `KeyDerivationOperationInstance`, or `KeyLoadOperationInstance`.
*/
abstract class KeyCreationOperationInstance extends OperationInstance {
abstract string getKeyCreationTypeDescription();
@@ -1087,6 +887,9 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
}
}
/**
* An operation that derives a key from an input password or other data.
*/
abstract class KeyDerivationOperationInstance extends KeyCreationOperationInstance {
final override KeyArtifactType getOutputKeyType() { result instanceof TSymmetricKeyType }
@@ -1120,16 +923,16 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
/**
* Gets the type of this key derivation algorithm, e.g., "PBKDF2" or "HKDF".
*/
abstract TKeyDerivationType getKDFType();
abstract TKeyDerivationType getKdfType();
/**
* Gets the isolated name as it appears in source, e.g., "PBKDF2WithHmacSHA256" in "PBKDF2WithHmacSHA256/UnrelatedInformation".
*/
abstract string getRawKDFAlgorithmName();
abstract string getRawKdfAlgorithmName();
}
abstract class PBKDF2AlgorithmInstance extends KeyDerivationAlgorithmInstance {
PBKDF2AlgorithmInstance() { this.getKDFType() instanceof PBKDF2 }
abstract class Pbkdf2AlgorithmInstance extends KeyDerivationAlgorithmInstance {
Pbkdf2AlgorithmInstance() { this.getKdfType() instanceof PBKDF2 }
/**
* Gets the HMAC algorithm used by this PBKDF2 algorithm.
@@ -1137,11 +940,11 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
* Note: Other PRFs are not supported, as most cryptographic libraries
* only support HMAC for PBKDF2's PRF input.
*/
abstract AlgorithmValueConsumer getHMACAlgorithmValueConsumer();
abstract AlgorithmValueConsumer getHmacAlgorithmValueConsumer();
}
abstract class ScryptAlgorithmInstance extends KeyDerivationAlgorithmInstance {
ScryptAlgorithmInstance() { this.getKDFType() instanceof SCRYPT }
ScryptAlgorithmInstance() { this.getKdfType() instanceof SCRYPT }
/**
* Gets the HMAC algorithm used by this PBKDF2 algorithm.
@@ -1149,7 +952,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
* Note: Other PRFs are not supported, as most cryptographic libraries
* only support HMAC for PBKDF2's PRF input.
*/
abstract AlgorithmValueConsumer getHMACAlgorithmValueConsumer();
abstract AlgorithmValueConsumer getHmacAlgorithmValueConsumer();
}
abstract class KeyGenerationOperationInstance extends KeyCreationOperationInstance {
@@ -1160,24 +963,14 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
final override string getKeyCreationTypeDescription() { result = "KeyLoad" }
}
// Key agreement algorithms
newtype TKeyAgreementType =
DH() or // Diffie-Hellman
EDH() or // Ephemeral Diffie-Hellman
ECDH() or // Elliptic Curve Diffie-Hellman
// NOTE: for now ESDH is considered simply EDH
//ESDH() or // Ephemeral-Static Diffie-Hellman
// Note: x25519 and x448 are applications of ECDH
OtherKeyAgreementType()
abstract class KeyAgreementAlgorithmInstance extends AlgorithmInstance {
abstract TKeyAgreementType getKeyAgreementType();
abstract string getRawKeyAgreementAlgorithmName();
}
abstract class ECDHKeyAgreementAlgorithmInstance extends KeyAgreementAlgorithmInstance {
ECDHKeyAgreementAlgorithmInstance() { this.getKeyAgreementType() instanceof ECDH }
abstract class EcdhKeyAgreementAlgorithmInstance extends KeyAgreementAlgorithmInstance {
EcdhKeyAgreementAlgorithmInstance() { this.getKeyAgreementType() instanceof ECDH }
/**
* Gets the consumer for the elliptic curve used in the key agreement operation.
@@ -1216,7 +1009,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
* This concept is used to model consumers that have no known source as an algorithm node.
*
* The `isCandidateAVCSig` predicate is used to restrict the set of consumers that expect inputs of `AlgorithmInstanceType`.
* These "total unknown" algorithm nodes would otherwise not exist if not modelled as a consumer node.
* These "total unknown" algorithm nodes would otherwise not exist if not modeled as a consumer node.
*/
module AlgorithmInstanceOrValueConsumer<
AlgorithmInstanceType Alg, isCandidateAVCSig/1 isCandidateAVC>
@@ -1237,58 +1030,58 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
Alg asAlg() { result = this }
AlgorithmValueConsumer asAVC() { result = this and not this instanceof Alg }
AlgorithmValueConsumer asAvc() { result = this and not this instanceof Alg }
}
}
private predicate isHashAVC(AlgorithmValueConsumer avc) {
private predicate isHashAvc(AlgorithmValueConsumer avc) {
exists(HashOperationInstance op | op.getAnAlgorithmValueConsumer() = avc) or
exists(HMACAlgorithmInstance alg | avc = alg.getAConsumer())
exists(HmacAlgorithmInstance alg | avc = alg.getAConsumer())
}
private predicate isKeyOperationAlgorithmAVC(AlgorithmValueConsumer avc) {
private predicate isKeyOperationAlgorithmAvc(AlgorithmValueConsumer avc) {
exists(KeyOperationInstance op | op.getAnAlgorithmValueConsumer() = avc)
}
private predicate isMACAVC(AlgorithmValueConsumer avc) {
exists(MACOperationInstance op | op.getAnAlgorithmValueConsumer() = avc) or
exists(PBKDF2AlgorithmInstance alg | avc = alg.getHMACAlgorithmValueConsumer())
private predicate isMacAvc(AlgorithmValueConsumer avc) {
exists(MacOperationInstance op | op.getAnAlgorithmValueConsumer() = avc) or
exists(Pbkdf2AlgorithmInstance alg | avc = alg.getHmacAlgorithmValueConsumer())
}
private predicate isKeyDerivationAVC(AlgorithmValueConsumer avc) {
private predicate isKeyDerivationAvc(AlgorithmValueConsumer avc) {
exists(KeyDerivationOperationInstance op | op.getAnAlgorithmValueConsumer() = avc)
}
private predicate isEllipticCurveAVC(AlgorithmValueConsumer avc) {
exists(ECDHKeyAgreementAlgorithmInstance alg |
private predicate isEllipticCurveAvc(AlgorithmValueConsumer avc) {
exists(EcdhKeyAgreementAlgorithmInstance alg |
avc = alg.getEllipticCurveAlgorithmValueConsumer()
) or
exists(KeyGenerationOperationInstance op | op.getAnAlgorithmValueConsumer() = avc)
}
private predicate isKeyAgreementAVC(AlgorithmValueConsumer avc) {
private predicate isKeyAgreementAvc(AlgorithmValueConsumer avc) {
exists(KeyAgreementSecretGenerationOperationInstance op |
op.getAnAlgorithmValueConsumer() = avc
)
}
final private class KeyOperationAlgorithmInstanceOrValueConsumer =
AlgorithmInstanceOrValueConsumer<KeyOperationAlgorithmInstance, isKeyOperationAlgorithmAVC/1>::Union;
AlgorithmInstanceOrValueConsumer<KeyOperationAlgorithmInstance, isKeyOperationAlgorithmAvc/1>::Union;
final private class HashAlgorithmInstanceOrValueConsumer =
AlgorithmInstanceOrValueConsumer<HashAlgorithmInstance, isHashAVC/1>::Union;
AlgorithmInstanceOrValueConsumer<HashAlgorithmInstance, isHashAvc/1>::Union;
final private class MACAlgorithmInstanceOrValueConsumer =
AlgorithmInstanceOrValueConsumer<MACAlgorithmInstance, isMACAVC/1>::Union;
final private class MacAlgorithmInstanceOrValueConsumer =
AlgorithmInstanceOrValueConsumer<MacAlgorithmInstance, isMacAvc/1>::Union;
final private class KeyDerivationAlgorithmInstanceOrValueConsumer =
AlgorithmInstanceOrValueConsumer<KeyDerivationAlgorithmInstance, isKeyDerivationAVC/1>::Union;
AlgorithmInstanceOrValueConsumer<KeyDerivationAlgorithmInstance, isKeyDerivationAvc/1>::Union;
final private class EllipticCurveInstanceOrValueConsumer =
AlgorithmInstanceOrValueConsumer<EllipticCurveInstance, isEllipticCurveAVC/1>::Union;
AlgorithmInstanceOrValueConsumer<EllipticCurveInstance, isEllipticCurveAvc/1>::Union;
final private class KeyAgreementAlgorithmInstanceOrValueConsumer =
AlgorithmInstanceOrValueConsumer<KeyAgreementAlgorithmInstance, isKeyAgreementAVC/1>::Union;
AlgorithmInstanceOrValueConsumer<KeyAgreementAlgorithmInstance, isKeyAgreementAvc/1>::Union;
private newtype TNode =
// Output artifacts (data that is not an operation or algorithm, e.g., a key)
@@ -1315,17 +1108,17 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
TPaddingAlgorithm(PaddingAlgorithmInstance e) or
// All other operations
THashOperation(HashOperationInstance e) or
TMACOperation(MACOperationInstance e) or
TMacOperation(MacOperationInstance e) or
TKeyAgreementOperation(KeyAgreementSecretGenerationOperationInstance e) or
// All other algorithms
TEllipticCurve(EllipticCurveInstanceOrValueConsumer e) or
THashAlgorithm(HashAlgorithmInstanceOrValueConsumer e) or
TKeyDerivationAlgorithm(KeyDerivationAlgorithmInstanceOrValueConsumer e) or
TMACAlgorithm(MACAlgorithmInstanceOrValueConsumer e) or
TMacAlgorithm(MacAlgorithmInstanceOrValueConsumer e) or
TKeyAgreementAlgorithm(KeyAgreementAlgorithmInstanceOrValueConsumer e) or
// Generic source nodes, i.e., sources of data that are not resolvable to a specific known asset.
TGenericSourceNode(GenericSourceInstance e) {
// An element modelled as a `GenericSourceInstance` can also be modelled as a `KnownElement`
// An element modeled as a `GenericSourceInstance` can also be modeled as a `KnownElement`
// For example, a string literal "AES" could be a generic constant but also an algorithm instance.
//
// Therefore, only create generic nodes tied to instances which are not also a `KnownElement`...
@@ -1769,17 +1562,17 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
/**
* A MAC operation that produces a MAC value.
*/
final class MACOperationNode extends OperationNode, TMACOperation {
MACOperationInstance instance;
final class MacOperationNode extends OperationNode, TMacOperation {
MacOperationInstance instance;
MACOperationNode() { this = TMACOperation(instance) }
MacOperationNode() { this = TMacOperation(instance) }
final override string getInternalType() { result = "MACOperation" }
override LocatableElement asElement() { result = instance }
override predicate isCandidateAlgorithmNode(AlgorithmNode node) {
node instanceof MACAlgorithmNode
node instanceof MacAlgorithmNode
}
MessageArtifactNode getAMessage() {
@@ -1804,10 +1597,10 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
/**
* A MAC algorithm, such as HMAC or CMAC.
*/
class MACAlgorithmNode extends AlgorithmNode, TMACAlgorithm {
MACAlgorithmInstanceOrValueConsumer instance;
class MacAlgorithmNode extends AlgorithmNode, TMacAlgorithm {
MacAlgorithmInstanceOrValueConsumer instance;
MACAlgorithmNode() { this = TMACAlgorithm(instance) }
MacAlgorithmNode() { this = TMacAlgorithm(instance) }
final override string getInternalType() { result = "MACAlgorithm" }
@@ -1817,20 +1610,15 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
result = instance.asAlg().getRawMacAlgorithmName()
}
TMACType getMacType() { result = instance.asAlg().getMacType() }
MacType getMacType() { result = instance.asAlg().getMacType() }
final private predicate macToNameMapping(TMACType type, string name) {
type instanceof THMAC and
name = "HMAC"
}
override string getAlgorithmName() { this.macToNameMapping(this.getMacType(), result) }
override string getAlgorithmName() { result = this.getMacType().toString() }
}
final class HMACAlgorithmNode extends MACAlgorithmNode {
HMACAlgorithmInstance hmacInstance;
final class HmacAlgorithmNode extends MacAlgorithmNode {
HmacAlgorithmInstance hmacInstance;
HMACAlgorithmNode() { hmacInstance = instance.asAlg() }
HmacAlgorithmNode() { hmacInstance = instance.asAlg() }
NodeBase getHashAlgorithmOrUnknown() {
result.asElement() = hmacInstance.getHashAlgorithmValueConsumer().getASource()
@@ -1993,22 +1781,22 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
override LocatableElement asElement() { result = instance }
final override string getRawAlgorithmName() {
result = instance.asAlg().getRawKDFAlgorithmName()
result = instance.asAlg().getRawKdfAlgorithmName()
}
override string getAlgorithmName() { result = this.getRawAlgorithmName() } // TODO: standardize?
}
/**
* PBKDF2 key derivation function
* A PBKDF2 (key derivation function) algorithm node.
*/
class PBKDF2AlgorithmNode extends KeyDerivationAlgorithmNode {
PBKDF2AlgorithmInstance pbkdf2Instance;
class Pbkdf2AlgorithmNode extends KeyDerivationAlgorithmNode {
Pbkdf2AlgorithmInstance pbkdf2Instance;
PBKDF2AlgorithmNode() { pbkdf2Instance = instance.asAlg() }
Pbkdf2AlgorithmNode() { pbkdf2Instance = instance.asAlg() }
HMACAlgorithmNode getHMACAlgorithm() {
result.asElement() = pbkdf2Instance.getHMACAlgorithmValueConsumer().getASource()
HmacAlgorithmNode getHmacAlgorithm() {
result.asElement() = pbkdf2Instance.getHmacAlgorithmValueConsumer().getASource()
}
override NodeBase getChild(string key) {
@@ -2016,12 +1804,12 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
or
// [KNOWN_OR_UNKNOWN]
key = "PRF" and
if exists(this.getHMACAlgorithm()) then result = this.getHMACAlgorithm() else result = this
if exists(this.getHmacAlgorithm()) then result = this.getHmacAlgorithm() else result = this
}
}
/**
* scrypt key derivation function
* An SCRYPT key derivation algorithm node.
*/
class ScryptAlgorithmNode extends KeyDerivationAlgorithmNode {
ScryptAlgorithmInstance scryptInstance;
@@ -2223,7 +2011,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
}
/**
* Block cipher modes of operation algorithms
* A block cipher mode of operation algorithm node.
*/
class ModeOfOperationAlgorithmNode extends AlgorithmNode, TModeOfOperationAlgorithm {
ModeOfOperationAlgorithmInstance instance;
@@ -2243,42 +2031,11 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
*
* If a type cannot be determined, the result is `OtherMode`.
*/
TBlockCipherModeOfOperationType getModeType() { result = instance.getModeType() }
KeyOpAlg::ModeOfOperationType getModeType() { result = instance.getModeType() }
final private predicate modeToNameMapping(TBlockCipherModeOfOperationType type, string name) {
type = ECB() and name = "ECB"
or
type = CBC() and name = "CBC"
or
type = GCM() and name = "GCM"
or
type = CTR() and name = "CTR"
or
type = XTS() and name = "XTS"
or
type = CCM() and name = "CCM"
or
type = SIV() and name = "SIV"
or
type = OCB() and name = "OCB"
or
type = CFB() and name = "CFB"
or
type = OFB() and name = "OFB"
}
override string getAlgorithmName() { this.modeToNameMapping(this.getModeType(), result) }
override string getAlgorithmName() { result = this.getModeType().toString() }
}
newtype TPaddingType =
PKCS1_v1_5() or // RSA encryption/signing padding
PSS() or
PKCS7() or // Standard block cipher padding (PKCS5 for 8-byte blocks)
ANSI_X9_23() or // Zero-padding except last byte = padding length
NoPadding() or // Explicit no-padding
OAEP() or // RSA OAEP padding
OtherPadding()
class PaddingAlgorithmNode extends AlgorithmNode, TPaddingAlgorithm {
PaddingAlgorithmInstance instance;
@@ -2288,38 +2045,24 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
override LocatableElement asElement() { result = instance }
TPaddingType getPaddingType() { result = instance.getPaddingType() }
KeyOpAlg::PaddingSchemeType getPaddingType() { result = instance.getPaddingType() }
final private predicate paddingToNameMapping(TPaddingType type, string name) {
type = ANSI_X9_23() and name = "ANSI_X9_23"
or
type = NoPadding() and name = "NoPadding"
or
type = OAEP() and name = "OAEP"
or
type = PKCS1_v1_5() and name = "PKCS1_v1_5"
or
type = PKCS7() and name = "PKCS7"
or
type = PSS() and name = "PSS"
}
override string getAlgorithmName() { this.paddingToNameMapping(this.getPaddingType(), result) }
override string getAlgorithmName() { result = this.getPaddingType().toString() }
override string getRawAlgorithmName() { result = instance.getRawPaddingAlgorithmName() }
}
class OAEPPaddingAlgorithmNode extends PaddingAlgorithmNode {
override OAEPPaddingAlgorithmInstance instance;
override OaepPaddingAlgorithmInstance instance;
OAEPPaddingAlgorithmNode() { this = TPaddingAlgorithm(instance) }
HashAlgorithmNode getOAEPEncodingHashAlgorithm() {
result.asElement() = instance.getOAEPEncodingHashAlgorithm()
result.asElement() = instance.getOaepEncodingHashAlgorithm()
}
HashAlgorithmNode getMGF1HashAlgorithm() {
result.asElement() = instance.getMGF1HashAlgorithm()
result.asElement() = instance.getMgf1HashAlgorithm()
}
override NodeBase getChild(string edgeName) {
@@ -2349,14 +2092,10 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
override string getInternalType() { result = "KeyOperationAlgorithm" }
final KeyOpAlg::CipherStructureType getSymmetricCipherStructure() {
KeyOpAlg::symmetric_cipher_to_name_and_structure(this.getAlgorithmType()
.(KeyOpAlg::SymmetricCipherAlgorithm)
.getType(), _, result)
result = this.getAlgorithmType().(KeyOpAlg::SymmetricCipherAlgorithmType).getStructureType()
}
final override string getAlgorithmName() {
KeyOpAlg::type_to_name(this.getAlgorithmType(), result)
}
final override string getAlgorithmName() { result = this.getAlgorithmType().toString() }
final override string getRawAlgorithmName() { result = instance.asAlg().getRawAlgorithmName() }
@@ -2366,7 +2105,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
int getKeySizeFixed() {
result = instance.asAlg().getKeySizeFixed()
or
KeyOpAlg::fixedImplicitCipherKeySize(instance.asAlg().getAlgorithmType(), result)
result = instance.asAlg().getAlgorithmType().getImplicitKeySize()
}
/**
@@ -2379,7 +2118,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
/**
* Gets the type of this key operation algorithm, e.g., "SymmetricEncryption(_)" or ""
*/
KeyOpAlg::Algorithm getAlgorithmType() { result = instance.asAlg().getAlgorithmType() }
KeyOpAlg::AlgorithmType getAlgorithmType() { result = instance.asAlg().getAlgorithmType() }
predicate isAsymmetric() {
this.getAlgorithmType() instanceof KeyOpAlg::TAsymmetricCipher
@@ -2485,24 +2224,6 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
}
}
newtype THashType =
BLAKE2B() or
BLAKE2S() or
GOSTHash() or
MD2() or
MD4() or
MD5() or
MDC2() or
POLY1305() or
SHA1() or
SHA2() or
SHA3() or
SHAKE() or
SM3() or
RIPEMD160() or
WHIRLPOOL() or
OtherHashType()
/**
* A hashing algorithm that transforms variable-length input into a fixed-size hash value.
*/
@@ -2517,42 +2238,14 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
override string getRawAlgorithmName() { result = instance.asAlg().getRawHashAlgorithmName() }
final private predicate hashTypeToNameMapping(THashType type, string name) {
type = BLAKE2B() and name = "BLAKE2B"
or
type = BLAKE2S() and name = "BLAKE2S"
or
type = RIPEMD160() and name = "RIPEMD160"
or
type = MD2() and name = "MD2"
or
type = MD4() and name = "MD4"
or
type = MD5() and name = "MD5"
or
type = POLY1305() and name = "POLY1305"
or
type = SHA1() and name = "SHA1"
or
type = SHA2() and name = "SHA2"
or
type = SHA3() and name = "SHA3"
or
type = SHAKE() and name = "SHAKE"
or
type = SM3() and name = "SM3"
or
type = WHIRLPOOL() and name = "WHIRLPOOL"
}
/**
* Gets the type of this hashing algorithm, e.g., MD5 or SHA.
*
* When modeling a new hashing algorithm, use this predicate to specify the type of the algorithm.
*/
THashType getHashFamily() { result = instance.asAlg().getHashFamily() }
HashType getHashFamily() { result = instance.asAlg().getHashFamily() }
override string getAlgorithmName() { this.hashTypeToNameMapping(this.getHashFamily(), result) }
override string getAlgorithmName() { result = this.getHashFamily().toString() }
int getDigestLength() {
result = instance.asAlg().getFixedDigestLength() or
@@ -2572,116 +2265,6 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
}
}
/**
* Elliptic curve algorithms
*/
newtype TEllipticCurveType =
NIST() or
SEC() or
NUMS() or
PRIME() or
BRAINPOOL() or
CURVE25519() or
CURVE448() or
C2() or
SM2() or
ES() or
OtherEllipticCurveType()
private predicate isBrainpoolCurve(string curveName, int keySize) {
// ALL BRAINPOOL CURVES
keySize in [160, 192, 224, 256, 320, 384, 512] and
(
curveName = "BRAINPOOLP" + keySize + "R1"
or
curveName = "BRAINPOOLP" + keySize + "T1"
)
}
private predicate isSecCurve(string curveName, int keySize) {
// ALL SEC CURVES
keySize in [112, 113, 128, 131, 160, 163, 192, 193, 224, 233, 239, 256, 283, 384, 409, 521, 571] and
exists(string suff | suff in ["R1", "R2", "K1"] |
curveName = "SECT" + keySize + suff or
curveName = "SECP" + keySize + suff
)
}
private predicate isC2Curve(string curveName, int keySize) {
// ALL C2 CURVES
keySize in [163, 176, 191, 208, 239, 272, 304, 359, 368, 431] and
exists(string pre, string suff |
pre in ["PNB", "ONB", "TNB"] and suff in ["V1", "V2", "V3", "V4", "V5", "W1", "R1"]
|
curveName = "C2" + pre + keySize + suff
)
}
private predicate isPrimeCurve(string curveName, int keySize) {
// ALL PRIME CURVES
keySize in [192, 239, 256] and
exists(string suff | suff in ["V1", "V2", "V3"] | curveName = "PRIME" + keySize + suff)
}
private predicate isNumsCurve(string curveName, int keySize) {
// ALL NUMS CURVES
keySize in [256, 384, 512] and
exists(string suff | suff = "T1" | curveName = "NUMSP" + keySize + suff)
}
/**
* Holds if `name` corresponds to a known elliptic curve.
*
* Note: As an exception, this predicate may be used for library modelling, as curve names are largely standardized.
*
* When modelling, verify that this predicate offers sufficient coverage for the library and handle edge-cases.
*/
bindingset[curveName]
predicate isEllipticCurveAlgorithmName(string curveName) {
ellipticCurveNameToKeySizeAndFamilyMapping(curveName, _, _)
}
/**
* Relates elliptic curve names to their key size and family.
*
* Note: As an exception, this predicate may be used for library modelling, as curve names are largely standardized.
*
* When modelling, verify that this predicate offers sufficient coverage for the library and handle edge-cases.
*/
bindingset[rawName]
predicate ellipticCurveNameToKeySizeAndFamilyMapping(
string rawName, int keySize, TEllipticCurveType curveFamily
) {
exists(string curveName | curveName = rawName.toUpperCase() |
isSecCurve(curveName, keySize) and curveFamily = SEC()
or
isBrainpoolCurve(curveName, keySize) and curveFamily = BRAINPOOL()
or
isC2Curve(curveName, keySize) and curveFamily = C2()
or
isPrimeCurve(curveName, keySize) and curveFamily = PRIME()
or
isNumsCurve(curveName, keySize) and curveFamily = NUMS()
or
curveName = "ES256" and keySize = 256 and curveFamily = ES()
or
curveName = "CURVE25519" and keySize = 255 and curveFamily = CURVE25519()
or
curveName = "CURVE448" and keySize = 448 and curveFamily = CURVE448()
or
// TODO: separate these into key agreement logic or sign/verify (ECDSA / ECDH)
// or
// curveName = "X25519" and keySize = 255 and curveFamily = CURVE25519()
// or
// curveName = "ED25519" and keySize = 255 and curveFamily = CURVE25519()
// or
// curveName = "ED448" and keySize = 448 and curveFamily = CURVE448()
// or
// curveName = "X448" and keySize = 448 and curveFamily = CURVE448()
curveName = "SM2" and keySize in [256, 512] and curveFamily = SM2()
)
}
final class EllipticCurveNode extends AlgorithmNode, TEllipticCurve {
EllipticCurveInstanceOrValueConsumer instance;
@@ -2707,7 +2290,9 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
override string getAlgorithmName() { result = this.getRawAlgorithmName() }
TEllipticCurveType getEllipticCurveType() { result = instance.asAlg().getEllipticCurveType() }
EllipticCurveFamilyType getEllipticCurveFamilyType() {
result = instance.asAlg().getEllipticCurveFamilyType()
}
override predicate properties(string key, string value, Location location) {
super.properties(key, value, location)

View File

@@ -0,0 +1,477 @@
/**
* The `KeyOpAlg` module defines key operation algorithms types (e.g., symmetric ciphers, signatures, etc.)
* and provides mapping of those types to string names and structural properties.
*/
module Types {
module KeyOpAlg {
/**
* An algorithm used in key operations.
*/
newtype TAlgorithm =
TSymmetricCipher(TSymmetricCipherType t) or
TAsymmetricCipher(TAsymmetricCipherType t) or
TSignature(TSignatureAlgorithmType t) or
TKeyEncapsulation(TKemAlgorithmType t) or
TUnknownKeyOperationAlgorithmType()
// Parameterized algorithm types
newtype TSymmetricCipherType =
AES() or
ARIA() or
BLOWFISH() or
CAMELLIA() or
CAST5() or
CHACHA20() or
DES() or
DESX() or
GOST() or
IDEA() or
KUZNYECHIK() or
MAGMA() or
TRIPLE_DES() or
DOUBLE_DES() or
RC2() or
RC4() or
RC5() or
SEED() or
SM4() or
OtherSymmetricCipherType()
newtype TAsymmetricCipherType =
RSA() or
OtherAsymmetricCipherType()
newtype TSignatureAlgorithmType =
DSA() or
ECDSA() or
EDDSA() or // e.g., ED25519 or ED448
OtherSignatureAlgorithmType()
newtype TKemAlgorithmType =
KYBER() or
FRODO_KEM() or
OtherKemAlgorithmType()
newtype TCipherStructureType =
Block() or
Stream() or
UnknownCipherStructureType()
class CipherStructureType extends TCipherStructureType {
string toString() {
result = "Block" and this = Block()
or
result = "Stream" and this = Stream()
or
result = "Unknown" and this = UnknownCipherStructureType()
}
}
private predicate symmetric_cipher_to_name_and_structure(
TSymmetricCipherType type, string name, CipherStructureType s
) {
type = AES() and name = "AES" and s = Block()
or
type = ARIA() and name = "ARIA" and s = Block()
or
type = BLOWFISH() and name = "Blowfish" and s = Block()
or
type = CAMELLIA() and name = "Camellia" and s = Block()
or
type = CAST5() and name = "CAST5" and s = Block()
or
type = CHACHA20() and name = "ChaCha20" and s = Stream()
or
type = DES() and name = "DES" and s = Block()
or
type = DESX() and name = "DESX" and s = Block()
or
type = GOST() and name = "GOST" and s = Block()
or
type = IDEA() and name = "IDEA" and s = Block()
or
type = KUZNYECHIK() and name = "Kuznyechik" and s = Block()
or
type = MAGMA() and name = "Magma" and s = Block()
or
type = TRIPLE_DES() and name = "TripleDES" and s = Block()
or
type = DOUBLE_DES() and name = "DoubleDES" and s = Block()
or
type = RC2() and name = "RC2" and s = Block()
or
type = RC4() and name = "RC4" and s = Stream()
or
type = RC5() and name = "RC5" and s = Block()
or
type = SEED() and name = "SEED" and s = Block()
or
type = SM4() and name = "SM4" and s = Block()
or
type = OtherSymmetricCipherType() and
name = "UnknownSymmetricCipher" and
s = UnknownCipherStructureType()
}
class AlgorithmType extends TAlgorithm {
string toString() {
// Symmetric cipher algorithm
symmetric_cipher_to_name_and_structure(this.(SymmetricCipherAlgorithmType).getType(),
result, _)
or
// Asymmetric cipher algorithms
this = TAsymmetricCipher(RSA()) and result = "RSA"
or
this = TAsymmetricCipher(OtherAsymmetricCipherType()) and result = "UnknownAsymmetricCipher"
or
// Signature algorithms
this = TSignature(DSA()) and result = "DSA"
or
this = TSignature(ECDSA()) and result = "ECDSA"
or
this = TSignature(EDDSA()) and result = "EDSA"
or
this = TSignature(OtherSignatureAlgorithmType()) and result = "UnknownSignature"
or
// Key Encapsulation Mechanisms
this = TKeyEncapsulation(KYBER()) and result = "Kyber"
or
this = TKeyEncapsulation(FRODO_KEM()) and result = "FrodoKEM"
or
this = TKeyEncapsulation(OtherKemAlgorithmType()) and result = "UnknownKEM"
or
// Unknown
this = TUnknownKeyOperationAlgorithmType() and result = "Unknown"
}
int getImplicitKeySize() {
this = TSymmetricCipher(DES()) and result = 56
or
this = TSymmetricCipher(DESX()) and result = 184
or
this = TSymmetricCipher(DOUBLE_DES()) and result = 112
or
this = TSymmetricCipher(TRIPLE_DES()) and result = 168
or
this = TSymmetricCipher(CHACHA20()) and result = 256
or
this = TSymmetricCipher(IDEA()) and result = 128
or
this = TSymmetricCipher(KUZNYECHIK()) and result = 256
or
this = TSymmetricCipher(MAGMA()) and result = 256
or
this = TSymmetricCipher(SM4()) and result = 128
or
this = TSymmetricCipher(SEED()) and result = 128
}
}
class SymmetricCipherAlgorithmType extends AlgorithmType, TSymmetricCipher {
TSymmetricCipherType type;
SymmetricCipherAlgorithmType() { this = TSymmetricCipher(type) }
TSymmetricCipherType getType() { result = type }
TCipherStructureType getStructureType() {
symmetric_cipher_to_name_and_structure(type, _, result)
}
}
class AsymmetricCipherAlgorithmType extends AlgorithmType, TAsymmetricCipher {
TAsymmetricCipherType type;
AsymmetricCipherAlgorithmType() { this = TAsymmetricCipher(type) }
TAsymmetricCipherType getType() { result = type }
}
newtype TModeOfOperationType =
ECB() or // Not secure, widely used
CBC() or // Vulnerable to padding oracle attacks
CFB() or
GCM() or // Widely used AEAD mode (TLS 1.3, SSH, IPsec)
CTR() or // Fast stream-like encryption (SSH, disk encryption)
XTS() or // Standard for full-disk encryption (BitLocker, LUKS, FileVault)
CCM() or // Used in lightweight cryptography (IoT, WPA2)
SIV() or // Misuse-resistant encryption, used in secure storage
OCB() or // Efficient AEAD mode
OFB() or
OtherMode()
class ModeOfOperationType extends TModeOfOperationType {
string toString() {
this = ECB() and result = "ECB"
or
this = CBC() and result = "CBC"
or
this = GCM() and result = "GCM"
or
this = CTR() and result = "CTR"
or
this = XTS() and result = "XTS"
or
this = CCM() and result = "CCM"
or
this = SIV() and result = "SIV"
or
this = OCB() and result = "OCB"
or
this = CFB() and result = "CFB"
or
this = OFB() and result = "OFB"
}
}
newtype TPaddingSchemeType =
PKCS1_V1_5() or // RSA encryption/signing padding
PSS() or
PKCS7() or // Standard block cipher padding (PKCS5 for 8-byte blocks)
ANSI_X9_23() or // Zero-padding except last byte = padding length
NoPadding() or // Explicit no-padding
OAEP() or // RSA OAEP padding
OtherPadding()
class PaddingSchemeType extends TPaddingSchemeType {
string toString() {
this = ANSI_X9_23() and result = "ANSI_X9_23"
or
this = NoPadding() and result = "NoPadding"
or
this = OAEP() and result = "OAEP"
or
this = PKCS1_V1_5() and result = "PKCS1_v1_5"
or
this = PKCS7() and result = "PKCS7"
or
this = PSS() and result = "PSS"
or
this = OtherPadding() and result = "UnknownPadding"
}
}
}
newtype THashType =
BLAKE2B() or
BLAKE2S() or
GOST_HASH() or
MD2() or
MD4() or
MD5() or
MDC2() or
POLY1305() or
SHA1() or
SHA2() or
SHA3() or
SHAKE() or
SM3() or
RIPEMD160() or
WHIRLPOOL() or
OtherHashType()
class HashType extends THashType {
final string toString() {
this = BLAKE2B() and result = "BLAKE2B"
or
this = BLAKE2S() and result = "BLAKE2S"
or
this = RIPEMD160() and result = "RIPEMD160"
or
this = MD2() and result = "MD2"
or
this = MD4() and result = "MD4"
or
this = MD5() and result = "MD5"
or
this = POLY1305() and result = "POLY1305"
or
this = SHA1() and result = "SHA1"
or
this = SHA2() and result = "SHA2"
or
this = SHA3() and result = "SHA3"
or
this = SHAKE() and result = "SHAKE"
or
this = SM3() and result = "SM3"
or
this = WHIRLPOOL() and result = "WHIRLPOOL"
or
this = OtherHashType() and result = "UnknownHash"
}
}
newtype TMacType =
HMAC() or
CMAC() or
OtherMacType()
class MacType extends TMacType {
string toString() {
this = HMAC() and result = "HMAC"
or
this = CMAC() and result = "CMAC"
or
this = OtherMacType() and result = "UnknownMacType"
}
}
// Key agreement algorithms
newtype TKeyAgreementType =
DH() or // Diffie-Hellman
EDH() or // Ephemeral Diffie-Hellman
ECDH() or // Elliptic Curve Diffie-Hellman
// NOTE: for now ESDH is considered simply EDH
//ESDH() or // Ephemeral-Static Diffie-Hellman
// Note: x25519 and x448 are applications of ECDH
OtherKeyAgreementType()
class KeyAgreementType extends TKeyAgreementType {
string toString() {
this = DH() and result = "DH"
or
this = EDH() and result = "EDH"
or
this = ECDH() and result = "ECDH"
or
this = OtherKeyAgreementType() and result = "UnknownKeyAgreementType"
}
}
/**
* Elliptic curve algorithms
*/
newtype TEllipticCurveFamilyType =
NIST() or
SEC() or
NUMS() or
PRIME() or
BRAINPOOL() or
CURVE25519() or
CURVE448() or
C2() or
SM2() or
ES() or
OtherEllipticCurveType()
class EllipticCurveFamilyType extends TEllipticCurveFamilyType {
string toString() {
this = NIST() and result = "NIST"
or
this = SEC() and result = "SEC"
or
this = NUMS() and result = "NUMS"
or
this = PRIME() and result = "PRIME"
or
this = BRAINPOOL() and result = "BRAINPOOL"
or
this = CURVE25519() and result = "CURVE25519"
or
this = CURVE448() and result = "CURVE448"
or
this = C2() and result = "C2"
or
this = SM2() and result = "SM2"
or
this = ES() and result = "ES"
or
this = OtherEllipticCurveType() and result = "UnknownEllipticCurveType"
}
}
private predicate isBrainpoolCurve(string curveName, int keySize) {
// ALL BRAINPOOL CURVES
keySize in [160, 192, 224, 256, 320, 384, 512] and
(
curveName = "BRAINPOOLP" + keySize + "R1"
or
curveName = "BRAINPOOLP" + keySize + "T1"
)
}
private predicate isSecCurve(string curveName, int keySize) {
// ALL SEC CURVES
keySize in [112, 113, 128, 131, 160, 163, 192, 193, 224, 233, 239, 256, 283, 384, 409, 521, 571] and
exists(string suff | suff in ["R1", "R2", "K1"] |
curveName = "SECT" + keySize + suff or
curveName = "SECP" + keySize + suff
)
}
private predicate isC2Curve(string curveName, int keySize) {
// ALL C2 CURVES
keySize in [163, 176, 191, 208, 239, 272, 304, 359, 368, 431] and
exists(string pre, string suff |
pre in ["PNB", "ONB", "TNB"] and suff in ["V1", "V2", "V3", "V4", "V5", "W1", "R1"]
|
curveName = "C2" + pre + keySize + suff
)
}
private predicate isPrimeCurve(string curveName, int keySize) {
// ALL PRIME CURVES
keySize in [192, 239, 256] and
exists(string suff | suff in ["V1", "V2", "V3"] | curveName = "PRIME" + keySize + suff)
}
private predicate isNumsCurve(string curveName, int keySize) {
// ALL NUMS CURVES
keySize in [256, 384, 512] and
exists(string suff | suff = "T1" | curveName = "NUMSP" + keySize + suff)
}
/**
* Holds if `name` corresponds to a known elliptic curve.
*
* Note: As an exception, this predicate may be used for library modeling, as curve names are largely standardized.
*
* When modeling, verify that this predicate offers sufficient coverage for the library and handle edge-cases.
*/
bindingset[curveName]
predicate isEllipticCurveAlgorithmName(string curveName) {
ellipticCurveNameToKnownKeySizeAndFamilyMapping(curveName, _, _)
}
/**
* Relates elliptic curve names to their key size and family.
*
* Note: As an exception, this predicate may be used for library modeling, as curve names are largely standardized.
*
* When modeling, verify that this predicate offers sufficient coverage for the library and handle edge-cases.
*/
bindingset[rawName]
predicate ellipticCurveNameToKnownKeySizeAndFamilyMapping(
string rawName, int keySize, TEllipticCurveFamilyType curveFamily
) {
exists(string curveName | curveName = rawName.toUpperCase() |
isSecCurve(curveName, keySize) and curveFamily = SEC()
or
isBrainpoolCurve(curveName, keySize) and curveFamily = BRAINPOOL()
or
isC2Curve(curveName, keySize) and curveFamily = C2()
or
isPrimeCurve(curveName, keySize) and curveFamily = PRIME()
or
isNumsCurve(curveName, keySize) and curveFamily = NUMS()
or
curveName = "ES256" and keySize = 256 and curveFamily = ES()
or
curveName = "CURVE25519" and keySize = 255 and curveFamily = CURVE25519()
or
curveName = "CURVE448" and keySize = 448 and curveFamily = CURVE448()
or
// TODO: separate these into key agreement logic or sign/verify (ECDSA / ECDH)
// or
// curveName = "X25519" and keySize = 255 and curveFamily = CURVE25519()
// or
// curveName = "ED25519" and keySize = 255 and curveFamily = CURVE25519()
// or
// curveName = "ED448" and keySize = 448 and curveFamily = CURVE448()
// or
// curveName = "X448" and keySize = 448 and curveFamily = CURVE448()
curveName = "SM2" and keySize in [256, 512] and curveFamily = SM2()
)
}
}