Skip to content

Crypto: Model OpenSSL intermediate digest operations #19521

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
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions cpp/ql/lib/experimental/quantum/OpenSSL/OpenSSL.qll
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ module OpenSSLModel {
import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
import experimental.quantum.OpenSSL.Random
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ class EVP_Cipher_Call extends EVP_Cipher_Operation {
}

// NOTE: not modeled as cipher operations, these are intermediate calls
class EVP_Update_Call extends Call {
EVP_Update_Call() {
class EVP_Cipher_Update_Call extends Call {
EVP_Cipher_Update_Call() {
this.(Call).getTarget().getName() in [
"EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"
]
Expand All @@ -88,15 +88,15 @@ class EVP_Update_Call extends Call {
Expr getContextArg() { result = this.(Call).getArgument(0) }
}

class EVP_Final_Call extends EVP_Cipher_Operation {
EVP_Final_Call() {
class EVP_Cipher_Final_Call extends EVP_Cipher_Operation {
EVP_Cipher_Final_Call() {
this.(Call).getTarget().getName() in [
"EVP_EncryptFinal_ex", "EVP_DecryptFinal_ex", "EVP_CipherFinal_ex", "EVP_EncryptFinal",
"EVP_DecryptFinal", "EVP_CipherFinal"
]
}

EVP_Update_Call getUpdateCalls() {
EVP_Cipher_Update_Call getUpdateCalls() {
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
EVP_Hash_Initializer getInitCall() {
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
}

/**
* By default, the algorithm value comes from the init call.
* There are variants where this isn't true, in which case the
* subclass should override this method.
*/
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
DataFlow::exprNode(this.getInitCall().getAlgorithmArg()))
}
}

private module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig {
Expand Down Expand Up @@ -88,30 +98,34 @@

override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }
}
// // override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
// // AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
// // DataFlow::exprNode(this.getInitCall().getAlgorithmArg()))
// // }
// // ***** TODO *** complete modelinlg for hash operations, but have consideration for terminal and non-terminal (non intermedaite) steps
// // see the JCA. May need to update the cipher operations similarly
// // ALSO SEE cipher for how we currently model initialization of the algorithm through an init call
// class EVP_DigestUpdate_Operation extends EVP_Hash_Operation {
// EVP_DigestUpdate_Operation() {
// this.(Call).getTarget().getName() = "EVP_DigestUpdate" and
// isPossibleOpenSSLFunction(this.(Call).getTarget())
// }
// override Crypto::AlgorithmConsumer getAlgorithmConsumer() {
// this.getInitCall().getAlgorithmArg() = result
// }
// }
// class EVP_DigestFinal_Variants_Operation extends EVP_Hash_Operation {
// EVP_DigestFinal_Variants_Operation() {
// this.(Call).getTarget().getName() in [
// "EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"
// ] and
// isPossibleOpenSSLFunction(this.(Call).getTarget())
// }
// override Crypto::AlgorithmConsumer getAlgorithmConsumer() {
// this.getInitCall().getAlgorithmArg() = result
// }
// }

// NOTE: not modeled as hash operations, these are intermediate calls
Copy link
Preview

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 concise doc comment above the EVP_Digest_Update_Call and EVP_Digest_Final_Call classes to explain their intended data‐flow role.

Suggested change
// NOTE: not modeled as hash operations, these are intermediate calls
/**
* Represents an intermediate call to `EVP_DigestUpdate`, which processes
* additional input data for a digest operation. This class models the
* data flow of the input and context arguments used in the update step.
*/

Copilot uses AI. Check for mistakes.

class EVP_Digest_Update_Call extends Call {
EVP_Digest_Update_Call() { this.(Call).getTarget().getName() in ["EVP_DigestUpdate"] }

Check warning

Code scanning / CodeQL

Singleton set literal Warning

Singleton set literal can be replaced by its member.

Expr getInputArg() { result = this.(Call).getArgument(1) }

DataFlow::Node getInputNode() { result.asExpr() = this.getInputArg() }

Expr getContextArg() { result = this.(Call).getArgument(0) }
}

class EVP_Digest_Final_Call extends EVP_Hash_Operation {
EVP_Digest_Final_Call() {
this.(Call).getTarget().getName() in [
"EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"
]
}

EVP_Digest_Update_Call getUpdateCalls() {
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
}

override Expr getInputArg() { result = this.getUpdateCalls().getInputArg() }

override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }

override Expr getOutputArg() { result = this.(Call).getArgument(1) }

override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() { result = this.getOutputNode() }
}