diff --git a/cpp/ql/lib/experimental/quantum/Language.qll b/cpp/ql/lib/experimental/quantum/Language.qll index 168c25cdfaa0..26325b09f4c5 100644 --- a/cpp/ql/lib/experimental/quantum/Language.qll +++ b/cpp/ql/lib/experimental/quantum/Language.qll @@ -56,7 +56,7 @@ module ArtifactFlowConfig implements DataFlow::ConfigSig { module ArtifactFlow = DataFlow::Global; /** - * 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; -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) { diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/AlgToAVCFlow.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/AlgToAVCFlow.qll index d46c2f691916..f802e58d0a76 100644 --- a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/AlgToAVCFlow.qll +++ b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/AlgToAVCFlow.qll @@ -48,7 +48,7 @@ module KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig implements DataFlow:: module KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow = DataFlow::Global; -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; +module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow = + DataFlow::Global; 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) diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/BlockAlgorithmInstance.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/BlockAlgorithmInstance.qll index ba5f65a2203f..4bd4b4497660 100644 --- a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/BlockAlgorithmInstance.qll +++ b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/BlockAlgorithmInstance.qll @@ -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 diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/CipherAlgorithmInstance.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/CipherAlgorithmInstance.qll index 0fb8ecf95398..47ffd67924a6 100644 --- a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/CipherAlgorithmInstance.qll +++ b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/CipherAlgorithmInstance.qll @@ -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 diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/EllipticCurveAlgorithmInstance.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/EllipticCurveAlgorithmInstance.qll index 78cba4962864..82a2b1357f27 100644 --- a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/EllipticCurveAlgorithmInstance.qll +++ b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/EllipticCurveAlgorithmInstance.qll @@ -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, _) } } diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/HashAlgorithmInstance.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/HashAlgorithmInstance.qll index 0cc8e24f0a6c..2be84b68f616 100644 --- a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/HashAlgorithmInstance.qll +++ b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/HashAlgorithmInstance.qll @@ -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 ) ) } diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/KnownAlgorithmConstants.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/KnownAlgorithmConstants.qll index 9d60547a45ad..4328253f1a4f 100644 --- a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/KnownAlgorithmConstants.qll +++ b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/KnownAlgorithmConstants.qll @@ -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. * diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/MACAlgorithmInstance.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/MACAlgorithmInstance.qll index 2e476824316b..f12bad03d469 100644 --- a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/MACAlgorithmInstance.qll +++ b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/MACAlgorithmInstance.qll @@ -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() { diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/PaddingAlgorithmInstance.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/PaddingAlgorithmInstance.qll index 7a34b69ddf54..d487e05d0660 100644 --- a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/PaddingAlgorithmInstance.qll +++ b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/PaddingAlgorithmInstance.qll @@ -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 } } diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/SignatureAlgorithmInstance.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/SignatureAlgorithmInstance.qll index afd67410c0ad..cc2e5771ffc8 100644 --- a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/SignatureAlgorithmInstance.qll +++ b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/SignatureAlgorithmInstance.qll @@ -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 diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmValueConsumers/DirectAlgorithmValueConsumer.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmValueConsumers/DirectAlgorithmValueConsumer.qll index a4a65ead63d8..d200cf2a0961 100644 --- a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmValueConsumers/DirectAlgorithmValueConsumer.qll +++ b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmValueConsumers/DirectAlgorithmValueConsumer.qll @@ -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 diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmValueConsumers/HashAlgorithmValueConsumer.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmValueConsumers/HashAlgorithmValueConsumer.qll index a03114b276d2..114cf78a112e 100644 --- a/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmValueConsumers/HashAlgorithmValueConsumer.qll +++ b/cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmValueConsumers/HashAlgorithmValueConsumer.qll @@ -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" } diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/Operations/EVPCipherOperation.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/Operations/EVPCipherOperation.qll index 1f5bf9e442ca..2a2cf00b4622 100644 --- a/cpp/ql/lib/experimental/quantum/OpenSSL/Operations/EVPCipherOperation.qll +++ b/cpp/ql/lib/experimental/quantum/OpenSSL/Operations/EVPCipherOperation.qll @@ -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 */ diff --git a/java/ql/lib/experimental/quantum/JCA.qll b/java/ql/lib/experimental/quantum/JCA.qll index 16afa26347fe..9acb6b40e2cc 100644 --- a/java/ql/lib/experimental/quantum/JCA.qll +++ b/java/ql/lib/experimental/quantum/JCA.qll @@ -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; + module MacKnownAlgorithmToConsumerFlow = DataFlow::Global; - 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; + module MacGetInstanceToMacOperationFlow = + DataFlow::Global; - 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; + module MacInitCallToMacOperationFlow = DataFlow::Global; - 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 } diff --git a/java/ql/src/experimental/quantum/Examples/TestAESGCMNonce.ql b/java/ql/src/experimental/quantum/Examples/TestAESGCMNonce.ql index 096cfa822161..4c25f5d7beb8 100644 --- a/java/ql/src/experimental/quantum/Examples/TestAESGCMNonce.ql +++ b/java/ql/src/experimental/quantum/Examples/TestAESGCMNonce.ql @@ -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() } } diff --git a/java/ql/src/experimental/quantum/InventorySlices/KnownAsymmetricCipherAlgorithm.ql b/java/ql/src/experimental/quantum/InventorySlices/KnownAsymmetricCipherAlgorithm.ql index 69643d92cd24..ab4a2e72e5ac 100644 --- a/java/ql/src/experimental/quantum/InventorySlices/KnownAsymmetricCipherAlgorithm.ql +++ b/java/ql/src/experimental/quantum/InventorySlices/KnownAsymmetricCipherAlgorithm.ql @@ -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() diff --git a/java/ql/src/experimental/quantum/InventorySlices/KnownCipherAlgorithm.ql b/java/ql/src/experimental/quantum/InventorySlices/KnownCipherAlgorithm.ql index da3371a59b34..e8c839126177 100644 --- a/java/ql/src/experimental/quantum/InventorySlices/KnownCipherAlgorithm.ql +++ b/java/ql/src/experimental/quantum/InventorySlices/KnownCipherAlgorithm.ql @@ -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() diff --git a/java/ql/src/experimental/quantum/InventorySlices/KnownSymmetricCipherAlgorithm.ql b/java/ql/src/experimental/quantum/InventorySlices/KnownSymmetricCipherAlgorithm.ql index e4a8d3ff8679..7f2d550da74c 100644 --- a/java/ql/src/experimental/quantum/InventorySlices/KnownSymmetricCipherAlgorithm.ql +++ b/java/ql/src/experimental/quantum/InventorySlices/KnownSymmetricCipherAlgorithm.ql @@ -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() diff --git a/shared/quantum/codeql/quantum/experimental/Model.qll b/shared/quantum/codeql/quantum/experimental/Model.qll index d4a900f9bcac..d9fef2c4a19c 100644 --- a/shared/quantum/codeql/quantum/experimental/Model.qll +++ b/shared/quantum/codeql/quantum/experimental/Model.qll @@ -29,6 +29,8 @@ signature module InputSig { } module CryptographyBase Input> { + import Standardization::Types + final class LocatableElement = Input::LocatableElement; final class UnknownLocation = Input::UnknownLocation; @@ -355,7 +357,7 @@ module CryptographyBase 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 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 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 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 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 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 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 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 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 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 Input> { */ abstract string getRawEllipticCurveName(); - abstract TEllipticCurveType getEllipticCurveType(); + abstract TEllipticCurveFamilyType getEllipticCurveFamilyType(); abstract int getKeySize(); @@ -1060,8 +858,10 @@ module CryptographyBase 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 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 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 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 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 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 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 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::Union; + AlgorithmInstanceOrValueConsumer::Union; final private class HashAlgorithmInstanceOrValueConsumer = - AlgorithmInstanceOrValueConsumer::Union; + AlgorithmInstanceOrValueConsumer::Union; - final private class MACAlgorithmInstanceOrValueConsumer = - AlgorithmInstanceOrValueConsumer::Union; + final private class MacAlgorithmInstanceOrValueConsumer = + AlgorithmInstanceOrValueConsumer::Union; final private class KeyDerivationAlgorithmInstanceOrValueConsumer = - AlgorithmInstanceOrValueConsumer::Union; + AlgorithmInstanceOrValueConsumer::Union; final private class EllipticCurveInstanceOrValueConsumer = - AlgorithmInstanceOrValueConsumer::Union; + AlgorithmInstanceOrValueConsumer::Union; final private class KeyAgreementAlgorithmInstanceOrValueConsumer = - AlgorithmInstanceOrValueConsumer::Union; + AlgorithmInstanceOrValueConsumer::Union; private newtype TNode = // Output artifacts (data that is not an operation or algorithm, e.g., a key) @@ -1315,17 +1108,17 @@ module CryptographyBase 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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) diff --git a/shared/quantum/codeql/quantum/experimental/Standardization.qll b/shared/quantum/codeql/quantum/experimental/Standardization.qll new file mode 100644 index 000000000000..962f6458b395 --- /dev/null +++ b/shared/quantum/codeql/quantum/experimental/Standardization.qll @@ -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() + ) + } +}