Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import cpp
import experimental.quantum.Language
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
import KnownAlgorithmConstants
Comment thread Fixed
Comment thread Fixed
import OpenSSLAlgorithmInstanceBase
import AlgToAVCFlow

class KnownOpenSSLEllipticCurveConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
Crypto::EllipticCurveInstance instanceof KnownOpenSSLEllipticCurveAlgorithmConstant

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in KnownOpenSSLEllipticCurveConstantAlgorithmInstance should be PascalCase/camelCase.
{
OpenSSLAlgorithmValueConsumer getterCall;

KnownOpenSSLEllipticCurveConstantAlgorithmInstance() {
// Two possibilities:
// 1) The source is a literal and flows to a getter, then we know we have an instance
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that
// Possibility 1:
this instanceof Literal and
exists(DataFlow::Node src, DataFlow::Node sink |
// Sink is an argument to a CipherGetterCall
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
// Source is `this`
src.asExpr() = this and
// This traces to a getter
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
)
or
// Possibility 2:
this instanceof DirectAlgorithmValueConsumer and getterCall = this
}

override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall }

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in getAVC should be PascalCase/camelCase.

override string getRawEllipticCurveName() { result = this.(Literal).getValue().toString() }

override Crypto::TEllipticCurveType getEllipticCurveType() {
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.(KnownOpenSSLEllipticCurveAlgorithmConstant)
.getNormalizedName(), _, result)
}

override int getKeySize() {
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.(KnownOpenSSLEllipticCurveAlgorithmConstant)
.getNormalizedName(), result, _)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@
}
}

class KnownOpenSSLEllipticCurveAlgorithmConstant extends KnownOpenSSLAlgorithmConstant {
Comment thread Fixed

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in KnownOpenSSLEllipticCurveAlgorithmConstant should be PascalCase/camelCase.
KnownOpenSSLEllipticCurveAlgorithmConstant() {
exists(string algType |
resolveAlgorithmFromExpr(this, _, algType) and
algType.toLowerCase().matches("elliptic_curve")
)
}
}

/**
* Resolves a call to a 'direct algorithm getter', e.g., EVP_MD5()
* This approach to fetching algorithms was used in OpenSSL 1.0.2.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import OpenSSLAlgorithmInstanceBase

Check warning

Code scanning / CodeQL

Redundant import Warning

Redundant import, the module is already imported inside
CipherAlgorithmInstance
.
Redundant import, the module is already imported inside
PaddingAlgorithmInstance
.
Redundant import, the module is already imported inside
BlockAlgorithmInstance
.
import CipherAlgorithmInstance
import PaddingAlgorithmInstance
import BlockAlgorithmInstance
import HashAlgorithmInstance
import EllipticCurveAlgorithmInstance
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend going through all of these and doing a private import of OpenSSLAlgorithmInstanceBase (and other modules where possible).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import cpp
import experimental.quantum.Language
Comment thread Fixed
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances

Copy link

Copilot AI May 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Add a doc comment explaining the purpose and usage of EllipticCurveValueConsumer to improve maintainability.

Suggested change
/**
* An abstract base class for consumers of elliptic curve algorithm values.
*
* This class is designed to be extended by specific implementations that
* handle elliptic curve-related cryptographic operations in OpenSSL.
* It provides a common interface and shared functionality for such consumers.
*
* Subclasses should implement the necessary methods to process elliptic curve
* algorithm values and integrate with the OpenSSL cryptographic library.
*/

Copilot uses AI. Check for mistakes.
abstract class EllipticCurveValueConsumer extends OpenSSLAlgorithmValueConsumer { }

//https://docs.openssl.org/3.0/man3/EC_KEY_new/#name
class EVPEllipticCurveAlgorithmConsumer extends EllipticCurveValueConsumer {

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in EVPEllipticCurveAlgorithmConsumer should be PascalCase/camelCase.
DataFlow::Node valueArgNode;
DataFlow::Node resultNode;

EVPEllipticCurveAlgorithmConsumer() {
resultNode.asExpr() = this.(Call) and // in all cases the result is the return
isPossibleOpenSSLFunction(this.(Call).getTarget()) and
(
this.(Call).getTarget().getName() in ["EVP_EC_gen", "EC_KEY_new_by_curve_name"] and
valueArgNode.asExpr() = this.(Call).getArgument(0)
or
this.(Call).getTarget().getName() in [
"EC_KEY_new_by_curve_name_ex", "EVP_PKEY_CTX_set_ec_paramgen_curve_nid"
] and
valueArgNode.asExpr() = this.(Call).getArgument(2)
)
}

override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there a generic algorithm class here, and why does the algorithm itself bind itself to the AVC as opposed to what is actually using/related to the algorithm consumed?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I correct in my reasoning below?

"An algorithm instance exists if and only if it is a string literal that flows to a consumer. Consequently, the definition of an algorithm instance is inherently constrained by the consumer to which it flows, establishing a dependent relationship between the instance and its consuming context."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

basically a literal must flow to something that consumes it, if not, we aren't calling it an algorithm.

There is a flip side, the direct algorithms (functions like AES()), these... well we could say are algorithms in their own right, but I didn't model it that way. So if these don't flow to something, they also don't exist as an algorithm. We may need to re-address that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are indeed algorithms -- the instance where you define them would be be modeled by extending an algorithm, operation, and AVC (assuming AES() also performs some sort of operation using AES).

}

override DataFlow::Node getResultNode() { result = resultNode }

override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import OpenSSLAlgorithmValueConsumerBase

Check warning

Code scanning / CodeQL

Redundant import Warning

Redundant import, the module is already imported inside
CipherAlgorithmValueConsumer
.
Redundant import, the module is already imported inside
DirectAlgorithmValueConsumer
.
Redundant import, the module is already imported inside
PaddingAlgorithmValueConsumer
.
Redundant import, the module is already imported inside
HashAlgorithmValueConsumer
.
import CipherAlgorithmValueConsumer
import DirectAlgorithmValueConsumer
import PaddingAlgorithmValueConsumer
import HashAlgorithmValueConsumer
import EllipticCurveAlgorithmValueConsumer
9 changes: 2 additions & 7 deletions java/ql/lib/experimental/quantum/JCA.qll
Original file line number Diff line number Diff line change
Expand Up @@ -1606,13 +1606,8 @@ module JCAModel {
else result = Crypto::OtherEllipticCurveType()
}

override string getKeySize() {
exists(int keySize |
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.getRawEllipticCurveName(), keySize,
_)
|
result = keySize.toString()
)
override int getKeySize() {
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.getRawEllipticCurveName(), result, _)
}

EllipticCurveAlgorithmValueConsumer getConsumer() { result = consumer }
Expand Down
4 changes: 2 additions & 2 deletions shared/quantum/codeql/quantum/experimental/Model.qll
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {

abstract TEllipticCurveType getEllipticCurveType();

abstract string getKeySize();
abstract int getKeySize();

/**
* The 'parsed' curve name, e.g., "P-256" or "secp256r1"
Expand Down Expand Up @@ -2613,7 +2613,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
or
// [ONLY_KNOWN]
key = "KeySize" and
value = instance.asAlg().getKeySize() and
value = instance.asAlg().getKeySize().toString() and
location = this.getLocation()
or
// [KNOWN_OR_UNKNOWN]
Expand Down
Loading