Cipher API implementation (server part) 45/292645/9
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Fri, 5 May 2023 08:37:23 +0000 (10:37 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Mon, 5 Jun 2023 14:05:26 +0000 (16:05 +0200)
Change-Id: Ie4a9c50378d461e659401829863bbe32cf67f305

src/manager/service/crypto-request.h
src/manager/service/encryption-logic.cpp
src/manager/service/encryption-logic.h
src/manager/service/encryption-service.cpp
src/manager/service/encryption-service.h
src/manager/service/iencryption-service.h

index 467c9c7..ecdbc78 100644 (file)
 #include <generic-socket-manager.h>
 #include <protocols.h>
 #include <ckm/ckm-type.h>
+#include <generic-backend/gctx.h>
 
 namespace CKM {
 
 struct CryptoRequest {
-       ConnectionID conn;
-       Credentials cred;
-       EncryptionCommand command;
-       int msgId;
-       CryptoAlgorithmSerializable cas;
-       Name name;
-       ClientId explicitOwner;
-       Password password;
-       RawBuffer input;
+       ConnectionID conn;               // identifies the connection with the client
+       Credentials cred;                // client's credentials
+       EncryptionCommand command;       // requested command identifier
+       int msgId;                       // unique identifier of a message from given client
+       CryptoAlgorithmSerializable cas; // bundle of encryption/decryption parameters
+       Name name;                       // name of the key used for crypto operation
+       ClientId explicitOwner;          // owner of the key used for crypto operation
+       Password password;               // password needed to decrypt the key used for crypto operation
+       RawBuffer input;                 // input data of given command passed from client
+       Crypto::GCtxShPtr context;       // encryption context used in multi-stage encryption/decryption
+       bool onward;                     // true for encryption, false for decryption
 };
 
 } /* namespace CKM */
index 6698317..3038e90 100644 (file)
 #include <encryption-logic.h>
 #include <ckm/ckm-error.h>
 #include <dpl/log/log.h>
+#include <generic-backend/gctx.h>
 
 namespace CKM {
 
+namespace {
+constexpr unsigned NO_ID = 0;
+}
+
+void EncryptionLogic::BumpCounter()
+{
+       m_counter++;
+       if (m_counter == NO_ID)
+               m_counter++;
+}
+
+void EncryptionLogic::RespondWithError(const CryptoRequest &request, int errorCode)
+{
+       if (request.command == EncryptionCommand::INITIALIZE_CIPHER)
+               m_service.RespondWithInt(request, errorCode);
+       else
+               m_service.RespondWithBuffer(request, errorCode);
+}
+
 void EncryptionLogic::Crypt(const CryptoRequest &request)
 {
        // check arguments
        if (request.input.empty()) {
                LogError("No input data");
-               m_service.RespondToClient(request, CKM_API_ERROR_INPUT_PARAM);
+               RespondWithError(request, CKM_API_ERROR_INPUT_PARAM);
                return;
        }
-       m_counter++;
+       BumpCounter();
 
        // store request in the map
        auto ret = m_requestsMap.insert(std::make_pair(m_counter, request));
 
        if (!ret.second) {
                LogError("Request with id = " << m_counter << " already exists");
-               m_service.RespondToClient(request, CKM_API_ERROR_SERVER_ERROR);
+               RespondWithError(request, CKM_API_ERROR_SERVER_ERROR);
                return;
        }
 
@@ -50,10 +70,86 @@ void EncryptionLogic::Crypt(const CryptoRequest &request)
        } catch (...) {
                LogError("Key request failed");
                m_requestsMap.erase(m_counter);
-               m_service.RespondToClient(request, CKM_API_ERROR_SERVER_ERROR);
+               RespondWithError(request, CKM_API_ERROR_SERVER_ERROR);
        }
 }
 
+template <typename T>
+void EncryptionLogic::FindAndExecute(int initReqId,
+                                     const CryptoRequest &currentRequest,
+                                     T&& func,
+                                     bool erase)
+{
+       auto ret = m_requestsMap.find(initReqId);
+       if (ret == m_requestsMap.end()) {
+               // no such request
+               RespondWithError(currentRequest, CKM_API_ERROR_INPUT_PARAM);
+               return;
+       }
+
+       try {
+               func(ret->second.context);
+       } catch (const Exc::Exception &ex) {
+               RespondWithError(currentRequest, ex.error());
+       } catch (...) {
+               LogError("Uncaught exception from encrypt/decrypt.");
+               RespondWithError(currentRequest, CKM_API_ERROR_SERVER_ERROR);
+       }
+
+       if (erase)
+               m_requestsMap.erase(ret);
+}
+
+void EncryptionLogic::Initialize(int initReqId, const CryptoRequest &currentRequest)
+{
+       if (initReqId == NO_ID) {
+               BumpCounter();
+
+               // store request in the map
+               auto ret = m_requestsMap.insert(std::make_pair(m_counter, currentRequest));
+
+               if (!ret.second) {
+                       LogError("Request with id = " << m_counter << " already exists");
+                       RespondWithError(currentRequest, CKM_API_ERROR_SERVER_ERROR);
+                       return;
+               }
+
+               // request key
+               try {
+                       m_service.RequestKey(m_counter, currentRequest);
+               } catch (...) {
+                       LogError("Key request failed");
+                       m_requestsMap.erase(m_counter);
+                       RespondWithError(currentRequest, CKM_API_ERROR_SERVER_ERROR);
+               }
+       } else {
+               FindAndExecute(initReqId, currentRequest, [&](auto &context){
+                       context->customize(currentRequest.cas);
+                       m_service.RespondWithInt(currentRequest, CKM_API_SUCCESS, initReqId);
+               });
+       }
+}
+
+void EncryptionLogic::Update(int initReqId, const CryptoRequest& currentRequest)
+{
+       FindAndExecute(initReqId, currentRequest, [&](Crypto::GCtxShPtr &context){
+               auto output = context->update(currentRequest.input);
+               m_service.RespondWithBuffer(currentRequest, CKM_API_SUCCESS, output);
+       });
+}
+
+void EncryptionLogic::Finalize(int initReqId, const CryptoRequest& currentRequest)
+{
+       FindAndExecute(
+               initReqId,
+               currentRequest,
+               [&](Crypto::GCtxShPtr &context){
+                       auto output = context->finalize(currentRequest.input);
+                       m_service.RespondWithBuffer(currentRequest, CKM_API_SUCCESS, output);
+               },
+               true); // Drop the request in finalize. If reinitialization is necessary it can be modified.
+}
+
 void EncryptionLogic::DropRequests(const ConnectionID& connectionID)
 {
        for (auto it = m_requestsMap.begin(); it != m_requestsMap.end();) {
@@ -72,19 +168,17 @@ void EncryptionLogic::KeyRetrieved(MsgKeyResponse response)
                LogError("No matching request found"); // nothing we can do
                return;
        }
-
-       CryptoRequest req = std::move(it->second);
-       m_requestsMap.erase(it);
+       auto& req = it->second;
 
        if (response.error != CKM_API_SUCCESS) {
                LogError("Attempt to retrieve key failed with error: " << response.error);
-               m_service.RespondToClient(req, response.error);
+               RespondWithError(req, response.error);
                return;
        }
 
        if (!response.key) {
                LogError("Retrieved key is empty");
-               m_service.RespondToClient(req, CKM_API_ERROR_SERVER_ERROR);
+               RespondWithError(req, CKM_API_ERROR_SERVER_ERROR);
                return;
        }
 
@@ -92,18 +186,29 @@ void EncryptionLogic::KeyRetrieved(MsgKeyResponse response)
        try {
                RawBuffer output;
 
-               if (req.command == EncryptionCommand::ENCRYPT)
+               switch (req.command) {
+               case EncryptionCommand::ENCRYPT:
                        output = response.key->encrypt(req.cas, req.input);
-               else
+                       break;
+               case EncryptionCommand::DECRYPT:
                        output = response.key->decrypt(req.cas, req.input);
-
-               m_service.RespondToClient(req, CKM_API_SUCCESS, output);
+                       break;
+               case EncryptionCommand::INITIALIZE_CIPHER:
+                       req.context = response.key->initContext(req.cas, req.onward);
+                       m_service.RespondWithInt(req, CKM_API_SUCCESS, response.id);
+                       return;
+               default:
+                       ThrowErr(Exc::InternalError, "Unexpected command type.");
+               }
+
+               m_service.RespondWithBuffer(req, CKM_API_SUCCESS, output);
        } catch (const Exc::Exception &ex) {
-               m_service.RespondToClient(req, ex.error());
+               RespondWithError(req, ex.error());
        } catch (...) {
                LogError("Uncaught exception from encrypt/decrypt.");
-               m_service.RespondToClient(req, CKM_API_ERROR_SERVER_ERROR);
+               RespondWithError(req, CKM_API_ERROR_SERVER_ERROR);
        }
+       m_requestsMap.erase(it);
 }
 
 } /* namespace CKM */
index 65c9d0d..945af7b 100644 (file)
@@ -37,8 +37,20 @@ public:
 
        void Crypt(const CryptoRequest &request);
        void KeyRetrieved(MsgKeyResponse response);
+       void Initialize(int initReqId, const CryptoRequest &request);
+       void Update(int initReqId, const CryptoRequest &updateRquest);
+       void Finalize(int initReqId, const CryptoRequest &finalizeRequest);
        void DropRequests(const ConnectionID& connectionID);
 private:
+       void BumpCounter();
+       void RespondWithError(const CryptoRequest &request, int errorCode);
+
+       template <typename T>
+       void FindAndExecute(int initReqId,
+                           const CryptoRequest &currentRequest,
+                           T&& func,
+                           bool erase = false);
+
        IEncryptionService &m_service;
 
        std::unordered_map<unsigned, CryptoRequest> m_requestsMap;
index d254be4..599149d 100644 (file)
@@ -42,18 +42,31 @@ EncryptionService::~EncryptionService()
 {
 }
 
-void EncryptionService::RespondToClient(const CryptoRequest &request,
-                                                                               int retCode,
-                                                                               const RawBuffer &data)
+template <class...Args>
+void EncryptionService::RespondToClient(const CryptoRequest &request, int retCode, Args&&...args)
 {
        try {
-               RawBuffer response = SerializeMessage(request.msgId, retCode, data);
+               RawBuffer response = SerializeMessage(request.msgId, retCode, std::forward<Args>(args)...);
                m_serviceManager->Write(request.conn, response);
        } catch (...) {
                LogError("Failed to send response to the client");
        }
 }
 
+void EncryptionService::RespondWithBuffer(const CryptoRequest &request,
+                                                                                 int retCode,
+                                                                                 const RawBuffer &data)
+{
+       RespondToClient(request, retCode, data);
+}
+
+void EncryptionService::RespondWithInt(const CryptoRequest &request,
+                                                                          int retCode,
+                                                                          int value)
+{
+       RespondToClient(request, retCode, value);
+}
+
 void EncryptionService::RequestKey(unsigned id, const CryptoRequest &request)
 {
        MsgKeyRequest kReq(id, request.cred, request.name,
@@ -125,18 +138,34 @@ void EncryptionService::ProcessEncryption(const ConnectionID &conn,
 {
        int tmpCmd = 0;
        CryptoRequest req;
+       buffer.Deserialize(tmpCmd, req.msgId);
+       int reqId = 0;
 
-       buffer.Deserialize(tmpCmd, req.msgId, req.cas, req.name, req.explicitOwner,
-                                          req.password, req.input);
        req.command = static_cast<EncryptionCommand>(tmpCmd);
-
-       if (req.command != EncryptionCommand::ENCRYPT &&
-                       req.command != EncryptionCommand::DECRYPT)
-               throw std::runtime_error("Unsupported command: " + tmpCmd);
-
        req.conn = conn;
        req.cred = cred;
-       m_logic.Crypt(req);
+
+       switch (req.command) {
+       case EncryptionCommand::ENCRYPT:
+       case EncryptionCommand::DECRYPT:
+               buffer.Deserialize(req.cas, req.name, req.explicitOwner, req.password, req.input);
+               m_logic.Crypt(req);
+               break;
+       case EncryptionCommand::INITIALIZE_CIPHER:
+               buffer.Deserialize(reqId, req.cas, req.name, req.explicitOwner, req.password, req.onward);
+               m_logic.Initialize(reqId, req);
+               break;
+       case EncryptionCommand::UPDATE_CIPHER:
+               buffer.Deserialize(reqId, req.input);
+               m_logic.Update(reqId, req);
+               break;
+       case EncryptionCommand::FINALIZE_CIPHER:
+               buffer.Deserialize(reqId, req.input);
+               m_logic.Finalize(reqId, req);
+               break;
+       default:
+               throw std::runtime_error("Unsupported command: " + tmpCmd);
+       }
 }
 
 void EncryptionService::CustomHandle(const ReadEvent &event)
index 27a007f..e74b615 100644 (file)
@@ -80,11 +80,15 @@ private:
                                                   const Credentials &cred,
                                                   MessageBuffer &buffer);
 
+       template <class...Args>
+       void RespondToClient(const CryptoRequest &request, int retCode, Args&&...args);
+
        // from IEncryptionService
-       virtual void RespondToClient(const CryptoRequest &request,
-                                                                int retCode,
-                                                                const RawBuffer &data = RawBuffer());
-       virtual void RequestKey(unsigned id, const CryptoRequest &request);
+       void RespondWithBuffer(const CryptoRequest &request,
+                                                  int retCode,
+                                                  const RawBuffer &data = RawBuffer()) override;
+       void RespondWithInt(const CryptoRequest &request, int retCode, int value = 0) override;
+       void RequestKey(unsigned id, const CryptoRequest &request) override;
 
        EncryptionLogic m_logic;
 };
index 8aa3be5..cb9607e 100644 (file)
@@ -31,9 +31,12 @@ namespace CKM {
 
 class IEncryptionService {
 public:
-       virtual void RespondToClient(const CryptoRequest &request,
-                                                                int retCode,
-                                                                const RawBuffer &data = RawBuffer()) = 0;
+       virtual void RespondWithBuffer(const CryptoRequest &request,
+                                                                  int retCode,
+                                                                  const RawBuffer &data = RawBuffer()) = 0;
+       virtual void RespondWithInt(const CryptoRequest &request,
+                                                               int retCode,
+                                                               int value = 0) = 0;
        virtual void RequestKey(unsigned id, const CryptoRequest &request) = 0;
 protected:
        ~IEncryptionService() {}