#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;
}
} 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 ¤tRequest,
+ 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 ¤tRequest)
+{
+ 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();) {
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;
}
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 */
{
}
-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,
{
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)