Skip to content

Quantum: Add OpenSSL signature models #19705

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Jun 18, 2025

Conversation

bdrodes
Copy link
Contributor

@bdrodes bdrodes commented Jun 9, 2025

No description provided.

bdrodes added 6 commits June 4, 2025 15:41
…calls that return a known algorithm and calls that operate on a known algorithm. update KnownAlgorithmConstants to correct algType for signature algorithms. Update all instances and prior uses of the old mechanic to KnownAlgorithmConstants.
…dd initial signature tests (no expected files yet). Add new openssl .h stubs. Clean up of OperationBase and associated uses. Update test case stubs to be closer to the actual stubs. Fix unncessary instanceof check in signatures.
…tep to handle paramgen. Remove redundant test. Overhaul of EVP update/initializer/final mechanics. Misc. updates for new API and refactoring EVPKeyGenOperation. Clean up of keygen_operaitons.ql.
@github-actions github-actions bot added the C++ label Jun 9, 2025
Copy link

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

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

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

@nicolaswill nicolaswill changed the title Pawel signatures conversion Quantum: Add OpenSSL signature models (Pawel Platek) Jun 10, 2025
bdrodes added 8 commits June 10, 2025 13:37
…del update. Remove setting RSA bits as an RSA algorithm. Fix bug in hash algorithm. Add missing PKey encryption to cipher ops. Consolidate ctx initializers. Add unit tests, and alter unit test directory structure to allow for application to other APIs. Update expected files for unit tests (not all updated yet, a work in progress).
…properties that configure downstream operations. Add key size tests
…to disallow null key and IV on initializers (typically do not represent an actual key or IV).
…. Update model to account for MAC algorithms.
… for now and noting the issue for a future PR.
@bdrodes bdrodes marked this pull request as ready for review June 13, 2025 16:13
@bdrodes bdrodes requested review from a team as code owners June 13, 2025 16:13
@bdrodes bdrodes changed the title Quantum: Add OpenSSL signature models (Pawel Platek) Quantum: Add OpenSSL signature models Jun 13, 2025
Copy link
Contributor

@nicolaswill nicolaswill left a comment

Choose a reason for hiding this comment

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

Did a brief review -- nothing semantic other than verifying that results look reasonable. There are other instances of the same code pattern issues I left some example comments for and open QL-for-QL alerts.

@@ -29,7 +29,7 @@ predicate knownOpenSSLConstantToHashFamilyType(
or
name.matches(["SHA", "SHA1"]) and type instanceof Crypto::SHA1
or
name.matches("SHA+%") and not name.matches(["SHA1", "SHA3-"]) and type instanceof Crypto::SHA2
name.matches("SHA_%") and not name.matches(["SHA1", "SHA3-"]) and type instanceof Crypto::SHA2
Copy link
Contributor

Choose a reason for hiding this comment

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

This is redundant. SHA_ cannot match SHA1 or SHA3.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The _ in matches means match one character, not any character (+ vs *), so it isn't redundant. The issue was I accidentally used the '+' syntax previously.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah! Four years of writing CodeQL, and I just learned that now...

Holds when the receiver matches the pattern. Patterns are matched by case sensitive string matching, and there are two wildcards: _ matches a single character, and % matches any sequence of characters.

Anyway, isn't _% redundant then? Just % should do the same thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I basically didn't want to match just "sha" and call it sha2. I wrote this awhile back so there is probably a better way, but basically it would not be correct to just use % because of that.

this instanceof DirectAlgorithmValueConsumer and getterCall = this
this instanceof OpenSSLAlgorithmCall and
this instanceof DirectAlgorithmValueConsumer and
getterCall = this
Copy link
Contributor

Choose a reason for hiding this comment

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

Will this ever hold? This class does not extend OpenSSLAlgorithmValueConsumer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy Pasta? I'll fix this.

//ASSUMPTION: these cases will have operands for the call
not exists(this.(Call).getAnArgument()) and
exists(string name, string parsedTargetName |
parsedTargetName =
Copy link
Contributor

Choose a reason for hiding this comment

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

Seeing name normalization done outside of the model raises red flags for me. Does OpenSSL have the same algorithm specified in various places with either underscores or dashes? If so, that makes sense I guess.

Copy link
Contributor

Choose a reason for hiding this comment

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

However, why not change the matching logic for the OpenSSL-modelling-to-model-type mapping to have a wildcard on underscores or dashes rather than normalize it at the instance-modelling stage?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

From prior investigations, it appeared openssl direct algorithm fetches use underscores, whereas the constants OpenSSL uses for algorithms uses dashes. The constants (the strings) are mapped to NID with dashes, so this normalization attempts to take function names and normalize them to the other kinds of constant strings. I'm open to other suggestions here but it is probably best suited for a separate PR.

//TODO: this set will have to be exhaustive, and for each operation
//further modeling will be necessary for each case to map the APIs operands
//ASSUMPTION: these cases must have operands for the call
exists(this.(Call).getAnArgument()) and
Copy link
Contributor

Choose a reason for hiding this comment

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

Why does it need to have an argument? What would those arguments be? Quick evaluating doesn't really answer my question at first glance either, so could you please clarify the documentation?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me preface this by saying how we handle direct operation calls is something that will need some work.

But, what I've done so far is to distinguish direct fetching calls (e.g., something like AES_256(), which would return an algorithm container of some kind), from operation calls (e.g., AES_256_encrypt(....)). In the former, we never see arguments passed in because you are just getting an algorithm directly. For the latter, it is an assumed operation, meaning you have to pass a parameter somehow to operate on data.

Does that answer your question?

exists(this.(Call).getAnArgument()) and
//TODO: Each case would be enumerated here. Will likely need an exhaustive mapping much like
// for known constants.
knownOpenSSLAlgorithmOperationCall(this, normalizedName, algType)
Copy link
Contributor

Choose a reason for hiding this comment

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

If there is no normalized name or algorithm type identified for this, the instance will simply not exist. We want to report known unknowns as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Per my comment above. How we handle direct operations needs a general revision. What we currently have is a POC for some of the work done with signatures, and even then it was partial. In the prior work (the PR we started from) example signatures were occurring using some direct operations. I want to open an issue to entirely refactor this, but for now it is a breadcrumb.

private class CtxPointerReturn extends CtxPointerExpr {
CtxPointerReturn() { exists(Call c | c = this) }

Call getCall() { result = this.(Call) }
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Call getCall() { result = this.(Call) }
Call getCall() { result = this }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Check

}

predicate isSink(DataFlow::Node sink) {
exists(Call call | call.(Call).getAnArgument() = sink.asExpr())
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
exists(Call call | call.(Call).getAnArgument() = sink.asExpr())
exists(Call call | call.getAnArgument() = sink.asExpr())

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Check

}
}

class EVP_CipherInit_SKEY_Call extends EVP_EX2_Initializer {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
class EVP_CipherInit_SKEY_Call extends EVP_EX2_Initializer {
class EVP_CipherInit_SKEY_Call extends EVP_EX2_Initializer instanceof Call {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If you follow the inheritance back up, it is already an instanceof call.

}

class EVP_CipherInit_SKEY_Call extends EVP_EX2_Initializer {
EVP_CipherInit_SKEY_Call() { this.(Call).getTarget().getName() in ["EVP_CipherInit_SKEY"] }
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
EVP_CipherInit_SKEY_Call() { this.(Call).getTarget().getName() in ["EVP_CipherInit_SKEY"] }
EVP_CipherInit_SKEY_Call() { super.getTarget().hasName("EVP_CipherInit_SKEY") }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could do this with the extends call you mentioned above I suppose but it already does extend a call so it's all very odd I have to restate it. If you prefer that though I can do it, but I just wanted to bring to your attention it is already explicitly instanceof call.

class EVP_CipherInit_SKEY_Call extends EVP_EX2_Initializer {
EVP_CipherInit_SKEY_Call() { this.(Call).getTarget().getName() in ["EVP_CipherInit_SKEY"] }

override Expr getKeyOperationSubtypeArg() { result = this.(Call).getArgument(5) }
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
override Expr getKeyOperationSubtypeArg() { result = this.(Call).getArgument(5) }
override Expr getKeyOperationSubtypeArg() { result = super.getArgument(5) }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See comments above.

@github-actions github-actions bot added the Java label Jun 17, 2025
@nicolaswill nicolaswill self-requested a review June 18, 2025 13:31
@nicolaswill nicolaswill merged commit 16c6411 into github:main Jun 18, 2025
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants