mirror of
https://github.com/github/codeql.git
synced 2025-12-16 08:43:11 +01:00
317 lines
12 KiB
Plaintext
317 lines
12 KiB
Plaintext
import cpp
|
|
private import experimental.cryptography.CryptoAlgorithmNames
|
|
import semmle.code.cpp.ir.dataflow.TaintTracking
|
|
|
|
/*
|
|
* A cryptographic artifact is a DataFlow::Node associated with some
|
|
* operation, algorithm, or any other aspect of cryptography.
|
|
*/
|
|
|
|
abstract class CryptographicArtifact extends Expr { }
|
|
|
|
// /**
|
|
// * Associates a symmetric encryption algorithm with a block mode.
|
|
// * The DataFlow::Node representing this association should be the
|
|
// * point where the algorithm and block mode are combined.
|
|
// * This may be at the call to encryption or in the construction
|
|
// * of an object prior to encryption.
|
|
// */
|
|
// abstract class SymmetricCipher extends CryptographicArtifact{
|
|
// abstract SymmetricEncryptionAlgorithm getEncryptionAlgorithm();
|
|
// abstract BlockMode getBlockMode();
|
|
// final predicate hasBlockMode(){
|
|
// exists(this.getBlockMode())
|
|
// }
|
|
// }
|
|
// /**
|
|
// * A cryptographic operation is a method call that invokes a cryptographic
|
|
// * algorithm (encrypt/decrypt) or a function in support of a cryptographic algorithm
|
|
// * (key generation).
|
|
// *
|
|
// * Since operations are related to or in support of algorithms, operations must
|
|
// * provide a reference to their associated algorithm. Often operataions themselves
|
|
// * encapsulate algorithms, so operations can also extend CryptographicAlgorithm
|
|
// * and refer to themselves as the target algorithm.
|
|
// */
|
|
// abstract class CryptographicOperation extends CryptographicArtifact, Call{
|
|
// // bindingset[paramName, ind]
|
|
// // final DataFlow::Node getParameterSource(int ind, string paramName){
|
|
// // result = Utils::getUltimateSrcFromApiNode(this.(API::CallNode).getParameter(ind, paramName))
|
|
// // }
|
|
// final string getAlgorithmName(){
|
|
// if exists(this.getAlgorithm().getName())
|
|
// then result = this.getAlgorithm().getName()
|
|
// else result = unknownAlgorithm()
|
|
// }
|
|
// final predicate hasAlgorithm(){
|
|
// exists(this.getAlgorithm())
|
|
// }
|
|
// final predicate isUnknownAlgorithm(){
|
|
// this.getAlgorithmName() = unknownAlgorithm()
|
|
// or
|
|
// not this.hasAlgorithm()
|
|
// }
|
|
// // TODO: this might have to be parameterized by a configuration source for
|
|
// // situations where an operation is passed an algorithm
|
|
// abstract CryptographicAlgorithm getAlgorithm();
|
|
// }
|
|
// /** A key generation operation for asymmetric keys */
|
|
// abstract class KeyGen extends CryptographicOperation{
|
|
// int getAKeySizeInBits(){
|
|
// result = getKeySizeInBits(_)
|
|
// }
|
|
// final predicate hasKeySize(Expr configSrc){
|
|
// exists(this.getKeySizeInBits(configSrc))
|
|
// }
|
|
// final predicate hasKeySize(){
|
|
// exists(this.getAKeySizeInBits())
|
|
// }
|
|
// abstract Expr getKeyConfigSrc();
|
|
// abstract int getKeySizeInBits(Expr configSrc);
|
|
// }
|
|
abstract class CryptographicOperation extends CryptographicArtifact, Call { }
|
|
|
|
abstract class KeyGeneration extends CryptographicOperation {
|
|
// TODO: what if the algorithm is UNKNOWN?
|
|
abstract Expr getKeyConfigurationSource(CryptographicAlgorithm alg);
|
|
|
|
abstract CryptographicAlgorithm getAlgorithm();
|
|
|
|
int getKeySizeInBits(CryptographicAlgorithm alg) {
|
|
result = this.getKeyConfigurationSource(alg).(Literal).getValue().toInt()
|
|
}
|
|
|
|
predicate hasConstantKeySize(CryptographicAlgorithm alg) { exists(this.getKeySizeInBits(alg)) }
|
|
|
|
predicate hasKeyConfigurationSource(CryptographicAlgorithm alg) {
|
|
exists(this.getKeyConfigurationSource(alg))
|
|
}
|
|
|
|
Expr getAKeyConfigurationSource() { result = this.getKeyConfigurationSource(_) }
|
|
}
|
|
|
|
abstract class AsymmetricKeyGeneration extends KeyGeneration { }
|
|
|
|
abstract class SymmetricKeyGeneration extends KeyGeneration { }
|
|
|
|
/**
|
|
* A cryptographic algorithm is a `CryptographicArtifact`
|
|
* representing a cryptographic algorithm (see `CryptoAlgorithmNames.qll`).
|
|
* Cryptographic algorithms can be functions referencing common crypto algorithms (e.g., hashlib.md5)
|
|
* or strings that are used in cryptographic operation configurations (e.g., hashlib.new("md5")).
|
|
* Cryptogrpahic algorithms may also be operations that wrap or abstract one or
|
|
* more algorithms (e.g., cyrptography.fernet.Fernet and AES, CBC and PKCS7).
|
|
*
|
|
* In principle, this class should model the location where an algorithm enters the program, not
|
|
* necessarily where it is used.
|
|
*/
|
|
abstract class CryptographicAlgorithm extends CryptographicArtifact {
|
|
abstract string getName();
|
|
|
|
abstract string getAlgType();
|
|
|
|
// string getAlgType(){
|
|
// if this instanceof HashAlgorithm then result = getHashType()
|
|
// else if this instanceof KeyDerivationAlgorithm then result = getKeyDerivationType()
|
|
// else if this instanceof SymmetricEncryptionAlgorithm then result = getSymmetricEncryptionType()
|
|
// else if this instanceof AsymmetricEncryptionAlgorithm then result = getAsymmetricEncryptionType()
|
|
// else if this instanceof SymmetricEncryptionAlgorithm then result = getSymmetricPaddingType()
|
|
// else if this instanceof AsymmetricEncryptionAlgorithm then result = getAsymmetricPaddingType()
|
|
// else if this instanceof EllipticCurveAlgorithm then result = getEllipticCurveType()
|
|
// else if this instanceof BlockMode then result = getCipherBlockModeType()
|
|
// else if this instanceof KeyExchangeAlgorithm then result = getKeyExchangeType()
|
|
// else if this instanceof SigningAlgorithm then result = getSignatureType()
|
|
// else result = unknownAlgorithm()
|
|
// }
|
|
// TODO: handle case where name isn't known, not just unknown?
|
|
/**
|
|
* Normalizes a raw name into a normalized name as found in `CryptoAlgorithmNames.qll`.
|
|
* Subclassess should override for more api-specific normalization.
|
|
* By default, converts a raw name to upper-case with no hyphen, underscore, hash, or space.
|
|
*/
|
|
bindingset[s]
|
|
string normalizeName(string s) {
|
|
exists(string normStr | normStr = s.toUpperCase().regexpReplaceAll("[-_ ]|/", "") |
|
|
result = normStr and isKnownAlgorithm(result)
|
|
or
|
|
result = unknownAlgorithm() and not isKnownAlgorithm(normStr)
|
|
)
|
|
}
|
|
|
|
abstract Expr configurationSink();
|
|
|
|
predicate hasConfigurationSink() { exists(this.configurationSink()) }
|
|
}
|
|
|
|
abstract class HashAlgorithm extends CryptographicAlgorithm {
|
|
final string getHashName() {
|
|
if exists(string n | n = this.getName() and isHashingAlgorithm(n))
|
|
then isHashingAlgorithm(result) and result = this.getName()
|
|
else result = unknownAlgorithm()
|
|
}
|
|
|
|
override string getAlgType() { result = getHashType() }
|
|
}
|
|
|
|
abstract class KeyDerivationAlgorithm extends CryptographicAlgorithm {
|
|
final string getKDFName() {
|
|
if exists(string n | n = this.getName() and isKeyDerivationAlgorithm(n))
|
|
then isKeyDerivationAlgorithm(result) and result = this.getName()
|
|
else result = unknownAlgorithm()
|
|
}
|
|
|
|
override string getAlgType() { result = getKeyDerivationType() }
|
|
}
|
|
|
|
// abstract class KeyDerivationOperation extends CryptographicOperation{
|
|
// DataFlow::Node getIterationSizeSrc(){
|
|
// none()
|
|
// }
|
|
// DataFlow::Node getSaltConfigSrc(){
|
|
// none()
|
|
// }
|
|
// DataFlow::Node getHashConfigSrc(){
|
|
// none()
|
|
// }
|
|
// // TODO: get encryption algorithm for CBC-based KDF?
|
|
// DataFlow::Node getDerivedKeySizeSrc(){
|
|
// none()
|
|
// }
|
|
// DataFlow::Node getModeSrc(){
|
|
// none()
|
|
// }
|
|
// // TODO: add more to cover all the parameters of most KDF operations? Perhaps subclass for each type?
|
|
// abstract predicate requiresIteration();
|
|
// abstract predicate requiresSalt();
|
|
// abstract predicate requiresHash();
|
|
// //abstract predicate requiresKeySize(); // Going to assume all requires a size
|
|
// abstract predicate requiresMode();
|
|
// }
|
|
abstract class EncryptionAlgorithm extends CryptographicAlgorithm {
|
|
final predicate isAsymmetric() { this instanceof AsymmetricEncryptionAlgorithm }
|
|
|
|
final predicate isSymmetric() { not this.isAsymmetric() }
|
|
// NOTE: DO_NOT add getEncryptionName here, we rely on the fact the parent
|
|
// class does not have this common predicate.
|
|
}
|
|
|
|
/**
|
|
* A parent class to represent any algorithm for which
|
|
* asymmetric cryptography is involved.
|
|
* Intended to be distinct from AsymmetricEncryptionAlgorithm
|
|
* which is intended only for asymmetric algorithms that specifically encrypt.
|
|
*/
|
|
abstract class AsymmetricAlgorithm extends CryptographicAlgorithm { }
|
|
|
|
/**
|
|
* Algorithms directly or indirectly related to asymmetric encryption,
|
|
* e.g., RSA, DSA, but also RSA padding algorithms
|
|
*/
|
|
abstract class AsymmetricEncryptionAlgorithm extends AsymmetricAlgorithm, EncryptionAlgorithm {
|
|
final string getEncryptionName() {
|
|
if exists(string n | n = this.getName() and isAsymmetricEncryptionAlgorithm(n))
|
|
then isAsymmetricEncryptionAlgorithm(result) and result = this.getName()
|
|
else result = unknownAlgorithm()
|
|
}
|
|
|
|
override string getAlgType() { result = getAsymmetricEncryptionType() }
|
|
}
|
|
|
|
/**
|
|
* Algorithms directly or indirectly related to symmetric encryption,
|
|
* e.g., AES, DES, but also block modes and padding
|
|
*/
|
|
abstract class SymmetricEncryptionAlgorithm extends EncryptionAlgorithm {
|
|
final string getEncryptionName() {
|
|
if exists(string n | n = this.getName() and isSymmetricEncryptionAlgorithm(n))
|
|
then isSymmetricEncryptionAlgorithm(result) and result = this.getName()
|
|
else result = unknownAlgorithm()
|
|
}
|
|
|
|
// TODO: add a stream cipher predicate?
|
|
override string getAlgType() { result = getSymmetricEncryptionType() }
|
|
}
|
|
|
|
// Used only to categorize all padding into a single object,
|
|
// DO_NOT add predicates here. Only for categorization purposes.
|
|
abstract class PaddingAlgorithm extends CryptographicAlgorithm { }
|
|
|
|
abstract class SymmetricPadding extends PaddingAlgorithm {
|
|
final string getPaddingName() {
|
|
if exists(string n | n = this.getName() and isSymmetricPaddingAlgorithm(n))
|
|
then isSymmetricPaddingAlgorithm(result) and result = this.getName()
|
|
else result = unknownAlgorithm()
|
|
}
|
|
|
|
override string getAlgType() { result = getSymmetricPaddingType() }
|
|
}
|
|
|
|
abstract class AsymmetricPadding extends PaddingAlgorithm {
|
|
final string getPaddingName() {
|
|
if exists(string n | n = this.getName() and isAsymmetricPaddingAlgorithm(n))
|
|
then isAsymmetricPaddingAlgorithm(result) and result = this.getName()
|
|
else result = unknownAlgorithm()
|
|
}
|
|
|
|
override string getAlgType() { result = getAsymmetricPaddingType() }
|
|
}
|
|
|
|
abstract class EllipticCurveAlgorithm extends AsymmetricAlgorithm {
|
|
final string getCurveName() {
|
|
if exists(string n | n = this.getName() and isEllipticCurveAlgorithm(n))
|
|
then isEllipticCurveAlgorithm(result) and result = this.getName()
|
|
else result = unknownAlgorithm()
|
|
}
|
|
|
|
final int getCurveBitSize() { isEllipticCurveAlgorithm(this.getCurveName(), result) }
|
|
|
|
override string getAlgType() { result = getEllipticCurveType() }
|
|
}
|
|
|
|
abstract class BlockModeAlgorithm extends CryptographicAlgorithm {
|
|
final string getBlockModeName() {
|
|
if exists(string n | n = this.getName() and isCipherBlockModeAlgorithm(n))
|
|
then isCipherBlockModeAlgorithm(result) and result = this.getName()
|
|
else result = unknownAlgorithm()
|
|
}
|
|
|
|
/**
|
|
* Gets the source of the IV configuration.
|
|
*/
|
|
abstract Expr getIVorNonce();
|
|
|
|
final predicate hasIVorNonce() { exists(this.getIVorNonce()) }
|
|
|
|
override string getAlgType() { result = getCipherBlockModeType() }
|
|
}
|
|
|
|
// abstract class KeyWrapOperation extends CryptographicOperation{
|
|
// }
|
|
abstract class AuthenticatedEncryptionAlgorithm extends SymmetricEncryptionAlgorithm {
|
|
final string getAuthticatedEncryptionName() {
|
|
if exists(string n | n = this.getName() and isSymmetricEncryptionAlgorithm(n))
|
|
then isSymmetricEncryptionAlgorithm(result) and result = this.getName()
|
|
else result = unknownAlgorithm()
|
|
}
|
|
}
|
|
|
|
abstract class KeyExchangeAlgorithm extends AsymmetricAlgorithm {
|
|
final string getKeyExchangeName() {
|
|
if exists(string n | n = this.getName() and isKeyExchangeAlgorithm(n))
|
|
then isKeyExchangeAlgorithm(result) and result = this.getName()
|
|
else result = unknownAlgorithm()
|
|
}
|
|
|
|
override string getAlgType() { result = getKeyExchangeType() }
|
|
}
|
|
|
|
abstract class SigningAlgorithm extends AsymmetricAlgorithm {
|
|
final string getSigningName() {
|
|
if exists(string n | n = this.getName() and isSignatureAlgorithm(n))
|
|
then isSignatureAlgorithm(result) and result = this.getName()
|
|
else result = unknownAlgorithm()
|
|
}
|
|
|
|
override string getAlgType() { result = getSignatureType() }
|
|
}
|