Cipher API implementation (backend part) 11/292711/8
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Thu, 11 May 2023 12:32:56 +0000 (14:32 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Mon, 5 Jun 2023 14:05:26 +0000 (16:05 +0200)
Change-Id: I7d2e5ef36a539a34f7e93a7fd9c16c90534d6aad

12 files changed:
misc/ckm_db_tool/CMakeLists.txt
src/CMakeLists.txt
src/manager/crypto/generic-backend/gctx.h [new file with mode: 0644]
src/manager/crypto/generic-backend/gobj.h
src/manager/crypto/sw-backend/crypto.h
src/manager/crypto/sw-backend/ctx.cpp [new file with mode: 0644]
src/manager/crypto/sw-backend/ctx.h [new file with mode: 0644]
src/manager/crypto/sw-backend/internals.cpp
src/manager/crypto/sw-backend/internals.h
src/manager/crypto/sw-backend/obj.cpp
src/manager/crypto/sw-backend/obj.h
unit-tests/CMakeLists.txt

index 4cf1b3e..00b800e 100644 (file)
@@ -29,6 +29,7 @@ SET(CKM_DB_TOOLS_SOURCES
     ${KEY_MANAGER_PATH}/crypto/sw-backend/obj.cpp
     ${KEY_MANAGER_PATH}/crypto/sw-backend/store.cpp
     ${KEY_MANAGER_PATH}/crypto/sw-backend/kbkdf.cpp
+    ${KEY_MANAGER_PATH}/crypto/sw-backend/ctx.cpp
     ${KEY_MANAGER_PATH}/dpl/core/src/colors.cpp
     ${KEY_MANAGER_PATH}/dpl/db/src/naive_synchronization_object.cpp
     ${KEY_MANAGER_PATH}/dpl/db/src/sql_connection.cpp
index 21946dd..a9b1f15 100644 (file)
@@ -49,6 +49,7 @@ SET(KEY_MANAGER_SOURCES
     ${KEY_MANAGER_PATH}/crypto/sw-backend/internals.cpp
     ${KEY_MANAGER_PATH}/crypto/sw-backend/store.cpp
     ${KEY_MANAGER_PATH}/crypto/sw-backend/kbkdf.cpp
+    ${KEY_MANAGER_PATH}/crypto/sw-backend/ctx.cpp
     ${KEY_MANAGER_PATH}/crypto/platform/decider.cpp
     ${SECURITY_MANAGER_WRAPPER_PATH}
     ${CYNARA_WRAPPER_PATH}
diff --git a/src/manager/crypto/generic-backend/gctx.h b/src/manager/crypto/generic-backend/gctx.h
new file mode 100644 (file)
index 0000000..bcee76f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *  Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+#pragma once
+
+#include <memory>
+#include <ckm/ckm-type.h>
+
+namespace CKM {
+namespace Crypto {
+
+class GCtx {
+public:
+       virtual void customize(const CryptoAlgorithm& algo) = 0;
+       virtual RawBuffer update(const RawBuffer& input) = 0;
+       virtual RawBuffer finalize(const RawBuffer& input) = 0;
+
+       virtual ~GCtx() {}
+};
+
+typedef std::shared_ptr<GCtx> GCtxShPtr;
+
+} // namespace Crypto
+} // namespace CKM
index 8433e67..f67a0bb 100644 (file)
@@ -26,6 +26,7 @@
 #include <ckm/ckm-type.h>
 
 #include <generic-backend/exception.h>
+#include <generic-backend/gctx.h>
 #include <crypto-backend.h>
 #include <token.h>
 
@@ -91,6 +92,12 @@ public:
                ThrowErr(Exc::Crypto::OperationNotSupported);
        }
 
+       // onward = true for encryption/signing, false for decryption/verification
+       virtual GCtxShPtr initContext(const CryptoAlgorithm &, bool /*onward*/)
+       {
+               ThrowErr(Exc::Crypto::OperationNotSupported);
+       }
+
        virtual ~GObj()
        {
        }
index a8a522e..0b49afd 100644 (file)
@@ -45,9 +45,19 @@ struct Base {
                                          "Unsupported type inside conatainer.");
        }
        Base(const Base &) = delete;
-       Base(Base &&) = delete;
+       Base(Base &&other) {
+               this->m_ctx = other->m_ctx;
+               other->m_ctx = nullptr;
+       }
        Base<T> &operator=(const Base &) = delete;
-       Base<T> &operator=(Base &&) = delete;
+       Base<T> &operator=(Base &&other) {
+               if (this == &other)
+                       return *this;
+
+               this->m_ctx = other->m_ctx;
+               other->m_ctx = nullptr;
+               return *this;
+       }
 
        // Low level api.
        // Allows various cipher specific parameters to be determined and set.
@@ -63,6 +73,15 @@ struct Base {
        {
                EVP_CIPHER_CTX_free(m_ctx);
        }
+       int Mode() const
+       {
+               return EVP_CIPHER_CTX_mode(m_ctx);
+       }
+
+       bool Encrypting() const
+       {
+               return (EVP_CIPHER_CTX_encrypting(m_ctx) == 1);
+       }
 
 protected:
        EVP_CIPHER_CTX *m_ctx;
diff --git a/src/manager/crypto/sw-backend/ctx.cpp b/src/manager/crypto/sw-backend/ctx.cpp
new file mode 100644 (file)
index 0000000..cffd4f4
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *  Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#include <generic-backend/exception.h>
+#include <sw-backend/ctx.h>
+#include <openssl/evp.h>
+
+namespace CKM {
+namespace Crypto {
+
+namespace {
+constexpr uint8_t STATE_INITIALIZED = 1;
+constexpr uint8_t STATE_UPDATED     = 2;
+constexpr uint8_t STATE_FINALIZED   = 3;
+}
+
+CipherCtx::CipherCtx(SW::Internals::EvpCipherPtr&& ctx, int tagLen) :
+       m_ctx(std::move(ctx)),
+       m_tagLen(tagLen),
+       m_state(STATE_INITIALIZED)
+{
+}
+
+void CipherCtx::customize(const CryptoAlgorithm& algo)
+{
+       if (m_ctx->Mode() != EVP_CIPH_GCM_MODE)
+               ThrowErr(Exc::InputParam, "Cipher mode does not support customization");
+
+       if (m_state > STATE_INITIALIZED)
+               ThrowErr(Exc::InputParam, "Customization is not allowed at this point");
+
+       RawBuffer aad;
+       if (!algo.getParam(ParamName::ED_AAD, aad))
+               ThrowErr(Exc::InputParam, "Missing AAD");
+
+       m_ctx->AppendAAD(aad);
+}
+
+RawBuffer CipherCtx::update(const RawBuffer& input)
+{
+       if (m_state > STATE_UPDATED)
+               ThrowErr(Exc::InputParam, "Update is not allowed at this point");
+       m_state = STATE_UPDATED;
+
+       return m_ctx->Append(input);
+}
+
+RawBuffer CipherCtx::finalize(const RawBuffer& input)
+{
+       m_state = STATE_FINALIZED;
+
+       auto mode = m_ctx->Mode();
+       bool encrypting = m_ctx->Encrypting();
+
+       if (!input.empty()) {
+               if (mode != EVP_CIPH_GCM_MODE)
+                       ThrowErr(Exc::InputParam, "Cipher mode does not support authentication tags");
+
+               if (encrypting)
+                       ThrowErr(Exc::InputParam, "Authentication tag can only be provided during decryption.");
+
+               // In case of GCM decryption input must be a complete tag only
+               m_ctx->Control(EVP_CTRL_GCM_SET_TAG,
+                              input.size(),
+                              const_cast<unsigned char*>(input.data()));
+       }
+
+       RawBuffer ret;
+       try {
+               ret = m_ctx->Finalize();
+       } catch (const Exc::Exception &) {
+               ThrowErr(Exc::InputParam,
+                        "Tag authentication failed in AES finalize function (the tag doesn't match).");
+       }
+
+       if (mode != EVP_CIPH_GCM_MODE || !encrypting)
+               return ret;
+
+       /*
+        * It is assumed that finalize for GCM encryption will return no data. Instead the complete GCM
+        * tag will be retrieved with a separate call and returned.
+        *
+        * https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption
+        *
+        * Finalise the encryption. Normally ciphertext bytes may be written at
+        * this stage, but this does not occur in GCM mode
+        *
+        * if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
+        * ...
+        */
+       if (!ret.empty())
+               ThrowErr(Exc::InternalError, "Finalize() returned non-empty output for GCM.");
+
+       RawBuffer tag(m_tagLen);
+       m_ctx->Control(EVP_CTRL_GCM_GET_TAG, m_tagLen, tag.data());
+       return tag;
+}
+
+} // namespace Crypto
+} // namespace CKM
diff --git a/src/manager/crypto/sw-backend/ctx.h b/src/manager/crypto/sw-backend/ctx.h
new file mode 100644 (file)
index 0000000..04f65a3
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+#pragma once
+
+#include <utility>
+#include <generic-backend/gctx.h>
+#include <openssl/ossl_typ.h>
+#include <sw-backend/internals.h>
+#include <ckm/ckm-type.h>
+
+namespace CKM {
+namespace Crypto {
+
+class CipherCtx : public GCtx {
+public:
+       CipherCtx(SW::Internals::EvpCipherPtr&& ctx, int tagLen);
+
+       void customize(const CryptoAlgorithm& algo) override;
+       RawBuffer update(const RawBuffer& input) override;
+       RawBuffer finalize(const RawBuffer& input) override;
+
+private:
+       SW::Internals::EvpCipherPtr m_ctx;
+       int m_tagLen; // in bytes, GCM only
+       uint8_t m_state;
+};
+
+} // namespace Crypto
+} // namespace CKM
index 529f4f1..77d1252 100644 (file)
@@ -45,7 +45,6 @@
 #include <generic-backend/algo-validation.h>
 #include <generic-backend/crypto-params.h>
 #include <sw-backend/internals.h>
-#include <sw-backend/crypto.h>
 #include <openssl-error-handler.h>
 #include "kbkdf.h"
 
@@ -285,8 +284,6 @@ void validateParams(const CryptoAlgorithm &ca)
                validator->Check(ca);
 }
 
-typedef std::unique_ptr<Cipher::EvpCipherWrapper<RawBuffer>> EvpCipherPtr;
-
 typedef std::function<void(EvpCipherPtr &, const RawBuffer &key, const RawBuffer &iv)>
 InitCipherFn;
 
@@ -902,6 +899,29 @@ RawBuffer symmetricDecrypt(const RawBuffer &key,
        return decryptDataAes(algo, key, data, unpack<RawBuffer>(alg, ParamName::ED_IV));
 }
 
+EvpCipherPtr initCipher(const RawBuffer &key, const CryptoAlgorithm &alg, bool encrypt, int& tagLen)
+{
+       validateParams<IsSymEncryption>(alg);
+       AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+       auto iv = unpack<RawBuffer>(alg, ParamName::ED_IV);
+       tagLen = 0;
+
+       EvpCipherPtr cipher;
+       selectCipher(algo, key.size(), encrypt)(cipher, key, iv);
+
+       if (algo == AlgoType::AES_GCM) {
+               int tagLenBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
+               alg.getParam(ParamName::ED_TAG_LEN, tagLenBits);
+               tagLen = tagLenBits / 8;
+
+               RawBuffer aad;
+               alg.getParam(ParamName::ED_AAD, aad);
+               if (!aad.empty())
+                       cipher->AppendAAD(aad);
+       }
+       return cipher;
+}
+
 RawBuffer asymmetricEncrypt(const EvpShPtr &pkey,
                                                        const CryptoAlgorithm &alg,
                                                        const RawBuffer &data)
index b2669a6..d91dddb 100644 (file)
@@ -23,6 +23,7 @@
 #include <ckm/ckm-type.h>
 #include <openssl/evp.h>
 #include <sw-backend/obj.h>
+#include <sw-backend/crypto.h>
 
 namespace CKM {
 namespace Crypto {
@@ -37,6 +38,8 @@ struct Data {
 
 typedef std::pair<Data, Data> DataPair;
 
+typedef std::unique_ptr<Cipher::EvpCipherWrapper<RawBuffer>> EvpCipherPtr;
+
 DataPair generateAKey(const CryptoAlgorithm &algorithm);
 Data generateSKey(const CryptoAlgorithm &algorithm);
 
@@ -80,6 +83,10 @@ RawBuffer decryptDataAes(AlgoType type,
                                                 const RawBuffer &key,
                                                 const RawBuffer &data,
                                                 const RawBuffer &iv);
+EvpCipherPtr initCipher(const RawBuffer &key,
+                                               const CryptoAlgorithm &alg,
+                                               bool encrypt,
+                                               int& tagLen);
 
 RawBuffer sign(EVP_PKEY *pkey,
                           const CryptoAlgorithm &alg,
index 97ea75c..9043f83 100644 (file)
@@ -18,6 +18,8 @@
  * @author     BartÅ‚omiej Grzelewski (b.grzelewski@samsung.com)
  * @version    1.0
  */
+#include <utility>
+
 #include <openssl/bio.h>
 #include <openssl/evp.h>
 #include <openssl/x509.h>
@@ -29,6 +31,7 @@
 #include <sw-backend/obj.h>
 #include <sw-backend/store.h>
 #include <sw-backend/internals.h>
+#include <sw-backend/ctx.h>
 #include <ckm/ckm-key.h>
 
 namespace CKM {
@@ -112,6 +115,14 @@ RawBuffer SKey::decrypt(const CryptoAlgorithm &alg, const RawBuffer &cipher)
        return Internals::symmetricDecrypt(getBinary(), alg, cipher);
 }
 
+GCtxShPtr SKey::initContext(const CryptoAlgorithm &alg, bool onward)
+{
+       int tagLen = 0;
+       auto ctx = Internals::initCipher(getBinary(), alg, onward, tagLen);
+
+       return std::make_shared<CipherCtx>(std::move(ctx), tagLen);
+}
+
 RawBuffer AKey::sign(
        const CryptoAlgorithm &alg,
        const RawBuffer &message)
@@ -203,6 +214,11 @@ EvpShPtr AKey::getEvpShPtr()
        return m_evp;
 }
 
+GCtxShPtr AKey::initContext(const CryptoAlgorithm &, bool)
+{
+       ThrowErr(Exc::Crypto::OperationNotSupported);
+}
+
 EvpShPtr Cert::getEvpShPtr()
 {
        if (m_evp)
index 945a85f..697e4ff 100644 (file)
@@ -70,6 +70,7 @@ public:
 
        RawBuffer encrypt(const CryptoAlgorithm &, const RawBuffer &) override;
        RawBuffer decrypt(const CryptoAlgorithm &, const RawBuffer &) override;
+       GCtxShPtr initContext(const CryptoAlgorithm &, bool) override;
 };
 
 class AKey : public Key {
@@ -83,6 +84,7 @@ public:
        RawBuffer encrypt(const CryptoAlgorithm &, const RawBuffer &) override;
        RawBuffer decrypt(const CryptoAlgorithm &, const RawBuffer &) override;
        Token derive(const CryptoAlgorithm &, const Password &, const RawBuffer &) override;
+       GCtxShPtr initContext(const CryptoAlgorithm &, bool) override;
 
 protected:
        virtual EvpShPtr getEvpShPtr();
index 349e221..b862516 100644 (file)
@@ -115,6 +115,7 @@ SET(UNIT_TESTS_SOURCES
     ${MANAGER_PATH}/crypto/sw-backend/obj.cpp
     ${MANAGER_PATH}/crypto/sw-backend/store.cpp
     ${MANAGER_PATH}/crypto/sw-backend/kbkdf.cpp
+    ${MANAGER_PATH}/crypto/sw-backend/ctx.cpp
     ${MANAGER_PATH}/dpl/core/src/binary_queue.cpp
     ${MANAGER_PATH}/dpl/core/src/colors.cpp
     ${MANAGER_PATH}/dpl/core/src/errno_string.cpp