From 34f5e4e0c8b4f1ff9bb9ac2ab2cd63c813038a94 Mon Sep 17 00:00:00 2001
From: "REDMOND\\brodes" <brodes@microsoft.com>
Date: Fri, 16 May 2025 11:23:19 -0400
Subject: [PATCH 1/2] Adding cipher update modeling (model flow through update
 to final)

---
 .../OpenSSL/Operations/EVPCipherOperation.qll | 45 ++++++++++---------
 1 file changed, 25 insertions(+), 20 deletions(-)

diff --git a/cpp/ql/lib/experimental/quantum/OpenSSL/Operations/EVPCipherOperation.qll b/cpp/ql/lib/experimental/quantum/OpenSSL/Operations/EVPCipherOperation.qll
index b544079579af..f22bcae69275 100644
--- a/cpp/ql/lib/experimental/quantum/OpenSSL/Operations/EVPCipherOperation.qll
+++ b/cpp/ql/lib/experimental/quantum/OpenSSL/Operations/EVPCipherOperation.qll
@@ -67,37 +67,42 @@ abstract class EVP_Cipher_Operation extends OpenSSLOperation, Crypto::KeyOperati
   }
 }
 
-// abstract class EVP_Update_Call extends EVP_Cipher_Operation { }
-abstract class EVP_Final_Call extends EVP_Cipher_Operation {
-  override Expr getInputArg() { none() }
-}
-
-// TODO: only model Final (model final as operation and model update but not as an operation)
-// Updates are multiple input consumers (most important)
-// TODO: assuming update doesn't ouput, otherwise it outputs artifacts, but is not an operation
 class EVP_Cipher_Call extends EVP_Cipher_Operation {
   EVP_Cipher_Call() { this.(Call).getTarget().getName() = "EVP_Cipher" }
 
   override Expr getInputArg() { result = this.(Call).getArgument(2) }
 }
 
-// ******* TODO: model UPDATE but not as the core operation, rather a step towards final
-// see the JCA
-// class EVP_Encrypt_Decrypt_or_Cipher_Update_Call extends EVP_Update_Call {
-//   EVP_Encrypt_Decrypt_or_Cipher_Update_Call() {
-//     this.(Call).getTarget().getName() in [
-//         "EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"
-//       ]
-//   }
-//   override Expr getInputArg() { result = this.(Call).getArgument(3) }
-// }
-class EVP_Encrypt_Decrypt_or_Cipher_Final_Call extends EVP_Final_Call {
-  EVP_Encrypt_Decrypt_or_Cipher_Final_Call() {
+// NOTE: not modeled as cipher operations, these are intermediate calls
+class EVP_Update_Call extends Call {
+  EVP_Update_Call() {
+    this.(Call).getTarget().getName() in [
+        "EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"
+      ]
+  }
+
+  Expr getInputArg() { result = this.(Call).getArgument(3) }
+
+  DataFlow::Node getInputNode() { result.asExpr() = this.getInputArg() }
+
+  Expr getContextArg() { result = this.(Call).getArgument(0) }
+}
+
+class EVP_Final_Call extends EVP_Cipher_Operation {
+  EVP_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() {
+    CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
+  }
+
+  override Expr getInputArg() { result = this.getUpdateCalls().getInputArg() }
+
+  override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }
 }
 
 class EVP_PKEY_Operation extends EVP_Cipher_Operation {

From dbd66e64c6d1d7722b94c2edae432b3b74237721 Mon Sep 17 00:00:00 2001
From: "REDMOND\\brodes" <brodes@microsoft.com>
Date: Fri, 16 May 2025 11:23:42 -0400
Subject: [PATCH 2/2] Fixing bug in JCA cipher modeling. intermediate
 operations should not be key operations.

---
 java/ql/lib/experimental/quantum/JCA.qll | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/java/ql/lib/experimental/quantum/JCA.qll b/java/ql/lib/experimental/quantum/JCA.qll
index ceca0e45464b..867d6f2c9b8f 100644
--- a/java/ql/lib/experimental/quantum/JCA.qll
+++ b/java/ql/lib/experimental/quantum/JCA.qll
@@ -611,6 +611,8 @@ module JCAModel {
   }
 
   class CipherOperationInstance extends Crypto::KeyOperationInstance instanceof CipherOperationCall {
+    CipherOperationInstance() { not this.isIntermediate() }
+
     override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
       if CipherFlowAnalysisImpl::hasInit(this)
       then result = CipherFlowAnalysisImpl::getInitFromUse(this, _, _).getCipherOperationModeType()