Refactor base64 implementation 19/240019/8
authorMateusz Cegielka <m.cegielka@samsung.com>
Fri, 31 Jul 2020 11:12:52 +0000 (13:12 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Wed, 2 Sep 2020 10:34:05 +0000 (10:34 +0000)
This codebase contains two slightly different base64 encoding wrappers,
both using low-level OpenSSL BIO API. The wrappers provide access to a
streaming interface, despite the fact that this property is not used
anywhere. To handle errors, the wrappers sometimes use exceptions and
sometimes return codes. To implement this, a stateful class was used,
and these four facts resulted in needlessly verbose code.

I have merged the two implementations and simplified them to two free
functions. The encode function now uses higher-level OpenSSL EVP API,
and the decode function was refactored.

Change-Id: I5016723158321d0c1aa10810aa9067cd2249f38e

19 files changed:
common/base64_generic.cpp [new file with mode: 0644]
common/base64_generic.h [new file with mode: 0644]
misc/ckm_db_tool/CMakeLists.txt
misc/ckm_db_tool/db-wrapper.cpp
misc/ckm_initial_values/CMakeLists.txt
misc/ckm_initial_values/base64.cpp [deleted file]
misc/ckm_initial_values/base64.h [deleted file]
misc/ckm_initial_values/main.cpp
src/CMakeLists.txt
src/manager/CMakeLists.txt
src/manager/common/base64.cpp [deleted file]
src/manager/common/base64.h
src/manager/common/certificate-impl.cpp
src/manager/initial-values/BufferHandler.cpp
src/manager/initial-values/InitialValuesFile.cpp
src/manager/service/crypto-logic.cpp
unit-tests/CMakeLists.txt
unit-tests/test_base64.cpp
unit-tests/test_crypto-logic.cpp

diff --git a/common/base64_generic.cpp b/common/base64_generic.cpp
new file mode 100644 (file)
index 0000000..5787904
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 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 <base64_generic.h>
+
+#include <algorithm>
+#include <cctype>
+#include <memory>
+#include <stdexcept>
+
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+
+namespace {
+
+bool isBase64Char(char c)
+{
+       return isalnum(c) || c == '+' || c == '/' || c == '=';
+}
+
+std::unique_ptr<BIO, decltype(&BIO_free)> makeBioPtr(BIO* ptr)
+{
+       if (!ptr)
+               throw std::bad_alloc();
+       return {ptr, &BIO_free};
+}
+
+} // anonymous namespace
+
+int base64EncodeGenericImpl(const void* input, size_t inputLen, void* output)
+{
+       return EVP_EncodeBlock(reinterpret_cast<unsigned char*>(output),
+               reinterpret_cast<const unsigned char*>(input), inputLen);
+}
+
+int base64DecodeGenericImpl(const void* input, size_t inputLen, void* output, size_t outputLen)
+{
+       if (inputLen == 0)
+               return 0;
+       if (!std::all_of(static_cast<const char*>(input), static_cast<const char*>(input) + inputLen, isBase64Char))
+               throw std::invalid_argument("decoding base64 failed, unexpected characters");
+
+       auto inputBio = makeBioPtr(BIO_new_mem_buf(input, inputLen));
+       auto base64Bio = makeBioPtr(BIO_new(BIO_f_base64()));
+       BIO_set_flags(base64Bio.get(), BIO_FLAGS_BASE64_NO_NL);
+       BIO_push(base64Bio.get(), inputBio.get());
+
+       int length = BIO_read(base64Bio.get(), output, outputLen);
+       if (length < 0)
+               throw std::invalid_argument("decoding base64 failed, openssl bio api error");
+
+       return length;
+}
diff --git a/common/base64_generic.h b/common/base64_generic.h
new file mode 100644 (file)
index 0000000..6f890b8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2020 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 <algorithm>
+
+#include <symbol-visibility.h>
+
+COMMON_API
+int base64EncodeGenericImpl(const void* input, size_t inputLen, void* output);
+
+COMMON_API
+int base64DecodeGenericImpl(const void* input, size_t inputLen, void* output, size_t outputLen);
+
+template <typename Output, typename Input>
+Output base64EncodeGeneric(const Input& input)
+{
+       // For each 3 input bytes (rounded up), 4 encoded bytes and a null terminator.
+       Output output((input.size() + 2) / 3 * 4 + 1, '\0');
+
+       static_assert(sizeof(input[0]) == 1);
+       static_assert(sizeof(output[0]) == 1);
+       int length = base64EncodeGenericImpl(input.data(), input.size(), &output[0]);
+
+       output.resize(length);
+       return output;
+}
+
+// Due to backwards compatibility, this function contains a few quirks. All '\n' newlines will be
+// removed, other non-base64 characters will throw an exception, and base64 must be implemented
+// using the OpenSSL BIO API. The last fact also implies that this function can accept padding in
+// the middle of text, or too much padding at the end.
+template <typename Output, typename Input>
+Output base64DecodeGeneric(Input input)
+{
+       input.erase(std::remove(input.begin(), input.end(), '\n'), input.end());
+
+       // For each 4 encoded bytes (rounded up), 3 decoded bytes.
+       Output output((input.size() + 3) / 4 * 3, '\0');
+
+       static_assert(sizeof(input[0]) == 1);
+       static_assert(sizeof(output[0]) == 1);
+       size_t length = base64DecodeGenericImpl(input.data(), input.size(), &output[0], output.size());
+
+       output.resize(length);
+       return output;
+}
index c4d9c15..a8ccca7 100644 (file)
@@ -7,6 +7,7 @@ FIND_PACKAGE(Threads REQUIRED)
 INCLUDE_DIRECTORIES(
     ${KEY_MANAGER_DEP_INCLUDE_DIRS}
     ${CMAKE_CURRENT_SOURCE_DIR}
+    ${PROJECT_SOURCE_DIR}/common
     ${KEY_MANAGER_PATH}/main
     ${KEY_MANAGER_PATH}/common
     ${KEY_MANAGER_PATH}/service
index 427fce1..b64a27c 100644 (file)
@@ -133,15 +133,8 @@ void DbWrapper::displayRow(const DB::SqlConnection::Output::Row &row, bool trim,
                 */
                if (std::any_of(col.begin(),
                                col.end(),
-                               [](const char c){ return isprint(c) + iscntrl(c) == 0; })) {
-                       Base64Encoder b64enc;
-                       RawBuffer tmp(col.begin(), col.end());
-                       b64enc.append(tmp);
-                       b64enc.finalize();
-                       col = "b64:";
-                       RawBuffer encoded = b64enc.get();
-                       std::copy(encoded.begin(), encoded.end(), std::back_inserter(col));
-               }
+                               [](const char c){ return isprint(c) + iscntrl(c) == 0; }))
+                       col = "b64:" + CKM::base64Encode<std::string>(col);
 
                if (trim && col.size() > MAX_LEN) {
                        col.resize(MAX_LEN);
index 4d2b792..4673a18 100644 (file)
@@ -21,11 +21,13 @@ PKG_CHECK_MODULES(CKM_INITIAL_VALUES_DEP
 
 INCLUDE_DIRECTORIES(
     ${CKM_INITIAL_VALUES_DEP_INCLUDE_DIRS}
+    ${PROJECT_SOURCE_DIR}/common
+    ${PROJECT_SOURCE_DIR}/src/manager/common
     )
 
 SET(CKM_INITIAL_VALUES_SOURCES
+    ${PROJECT_SOURCE_DIR}/common/base64_generic.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/base64.cpp
     )
 
 LINK_DIRECTORIES(${CKM_INITIAL_VALUES_DEP_LIBRARY_DIRS})
diff --git a/misc/ckm_initial_values/base64.cpp b/misc/ckm_initial_values/base64.cpp
deleted file mode 100644 (file)
index 1c0d497..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (c) 2011 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 "base64.h"
-
-#include <algorithm>
-#include <memory>
-
-#include <string.h>
-#include <openssl/bio.h>
-#include <openssl/evp.h>
-#include <openssl/buffer.h>
-
-
-namespace CKM {
-
-Base64Encoder::Base64Encoder() :
-       m_b64(0),
-       m_bmem(0),
-       m_finalized(false)
-{
-}
-
-void Base64Encoder::append(const RawBuffer &data)
-{
-       if (m_finalized) {
-               throw std::logic_error("Already finalized");
-       }
-
-       if (!m_b64)
-               reset();
-
-       BIO_write(m_b64, data.data(), data.size());
-}
-
-void Base64Encoder::finalize()
-{
-       if (m_finalized) {
-               throw std::logic_error("Already finalized.");
-       }
-
-       m_finalized = true;
-       (void)BIO_flush(m_b64);
-}
-
-RawBuffer Base64Encoder::get()
-{
-       if (!m_finalized) {
-               throw std::logic_error("Not finalized");
-       }
-
-       BUF_MEM *bptr = nullptr;
-       BIO_get_mem_ptr(m_b64, &bptr);
-
-       if (!bptr) {
-               throw std::logic_error("Bio internal error");
-       }
-
-       if (bptr->length > 0)
-               return RawBuffer(bptr->data, bptr->data + bptr->length);
-
-       return RawBuffer();
-}
-
-void Base64Encoder::reset()
-{
-       m_finalized = false;
-       BIO_free_all(m_b64);
-       m_b64 = BIO_new(BIO_f_base64());
-       m_bmem = BIO_new(BIO_s_mem());
-
-       if (!m_b64 || !m_bmem) {
-               throw std::logic_error("Error during allocation memory in BIO");
-       }
-
-       BIO_set_flags(m_b64, BIO_FLAGS_BASE64_NO_NL);
-       m_b64 = BIO_push(m_b64, m_bmem);
-}
-
-Base64Encoder::~Base64Encoder()
-{
-       BIO_free_all(m_b64);
-}
-
-Base64Decoder::Base64Decoder() :
-       m_finalized(false)
-{
-}
-
-void Base64Decoder::append(const RawBuffer &data)
-{
-       if (m_finalized) {
-               throw std::logic_error("Already finalized.");
-       }
-
-       std::copy(data.begin(), data.end(), std::back_inserter(m_input));
-}
-
-static bool whiteCharacter(char a)
-{
-       return a == '\n';
-}
-
-bool Base64Decoder::finalize()
-{
-       if (m_finalized) {
-               throw std::logic_error("Already finalized.");
-       }
-
-       m_finalized = true;
-
-       m_input.erase(std::remove_if(m_input.begin(),
-                                                                m_input.end(),
-                                                                whiteCharacter),
-                                 m_input.end());
-
-       for (size_t i = 0; i < m_input.size(); ++i) {
-               if (isalnum(m_input[i])
-                               || m_input[i] == '+'
-                               || m_input[i] == '/'
-                               || m_input[i] == '=')
-                       continue;
-
-               return false;
-       }
-
-       BIO *b64, *bmem;
-       size_t len = m_input.size();
-
-       RawBuffer buffer(len);
-
-       if (!buffer.data()) {
-               throw std::logic_error("Error in malloc.");
-       }
-
-       memset(buffer.data(), 0, buffer.size());
-       b64 = BIO_new(BIO_f_base64());
-
-       if (!b64) {
-               throw std::logic_error("Couldn't create BIO object.");
-       }
-
-       BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
-       RawBuffer tmp(m_input);
-       m_input.clear();
-
-       bmem = BIO_new_mem_buf(tmp.data(), len);
-
-       if (!bmem) {
-               BIO_free(b64);
-               throw std::logic_error("Internal error in BIO");
-       }
-
-       bmem = BIO_push(b64, bmem);
-
-       if (!bmem) {
-               BIO_free(b64);
-               throw std::logic_error("Internal error in BIO");
-       }
-
-       int readlen = BIO_read(bmem, buffer.data(), buffer.size());
-       m_output.clear();
-
-       bool status = true;
-
-       if (readlen > 0) {
-               buffer.resize(readlen);
-               m_output = std::move(buffer);
-       } else {
-               status = false;
-       }
-
-       BIO_free_all(bmem);
-       return status;
-}
-
-RawBuffer Base64Decoder::get() const
-{
-       if (!m_finalized) {
-               throw std::logic_error("Not finalized");
-       }
-
-       return m_output;
-}
-
-void Base64Decoder::reset()
-{
-       m_finalized = false;
-       m_input.clear();
-       m_output.clear();
-}
-
-} // namespace CKM
diff --git a/misc/ckm_initial_values/base64.h b/misc/ckm_initial_values/base64.h
deleted file mode 100644 (file)
index c9085bf..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2011 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.
- */
-#ifndef _BASE64_H_
-#define _BASE64_H_
-
-#include <string>
-#include <vector>
-
-typedef std::vector<unsigned char> RawBuffer;
-
-struct bio_st;
-typedef bio_st BIO;
-
-namespace CKM {
-
-class Base64Encoder {
-public:
-       Base64Encoder();
-       void append(const RawBuffer &data);
-       void finalize();
-       RawBuffer get();
-       void reset();
-       ~Base64Encoder();
-
-private:
-       BIO *m_b64;
-       BIO *m_bmem;
-       bool m_finalized;
-};
-
-class Base64Decoder {
-public:
-       Base64Decoder();
-       void append(const RawBuffer &data);
-
-       /*
-        *  Function will return false when BIO_read fails
-        *  (for example: when string was not in base64 format).
-        */
-       bool finalize();
-       RawBuffer get() const;
-       void reset();
-       ~Base64Decoder() {}
-
-private:
-       RawBuffer m_input;
-       RawBuffer m_output;
-       bool m_finalized;
-};
-} // namespace CKM
-
-#endif
index c5d9e7d..eccb805 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2018-2019 Samsung Electronics Co., Ltd. All rights reserved
+ *  Copyright (c) 2018-2020 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.
@@ -41,7 +41,7 @@
 #include <libxml/tree.h>
 #include <libxml/parser.h>
 
-#include "base64.h"
+#include <base64_generic.h>
 
 typedef std::vector<unsigned char> Buffer;
 typedef std::istreambuf_iterator<char> InputIterator;
@@ -89,11 +89,7 @@ const std::unordered_map<std::string, FormatTag> FORMAT = {
 std::string base64(const Buffer& data)
 {
        try {
-               CKM::Base64Encoder encoder;
-               encoder.append(data);
-               encoder.finalize();
-               auto result = encoder.get();
-               return std::string(result.begin(), result.end());
+               return base64EncodeGeneric<std::string>(data);
        } catch (std::exception &e) {
                std::cerr << "Error: " << e.what() << std::endl;
        }
index 88f8a37..2c06a86 100644 (file)
@@ -65,6 +65,7 @@ INCLUDE_DIRECTORIES(SYSTEM
 
 INCLUDE_DIRECTORIES(
     ${KEY_MANAGER_SRC_PATH}/include
+    ${PROJECT_SOURCE_DIR}/common
     ${KEY_MANAGER_PATH}/main
     ${KEY_MANAGER_PATH}/common
     ${KEY_MANAGER_PATH}/service
index cbf39b3..c614ab4 100644 (file)
@@ -12,8 +12,8 @@ SET(KEY_MANAGER_COMMON_VERSION ${KEY_MANAGER_COMMON_VERSION_MAJOR}.0.1)
 SET(COMMON_PATH ${PROJECT_SOURCE_DIR}/src/manager)
 
 SET(COMMON_SOURCES
+    ${PROJECT_SOURCE_DIR}/common/base64_generic.cpp
     ${COMMON_PATH}/common/algo-param.cpp
-    ${COMMON_PATH}/common/base64.cpp
     ${COMMON_PATH}/common/data-type.cpp
     ${COMMON_PATH}/common/openssl-error-handler.cpp
     ${COMMON_PATH}/common/exception.cpp
diff --git a/src/manager/common/base64.cpp b/src/manager/common/base64.cpp
deleted file mode 100644 (file)
index 091ddfd..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 2011 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 <algorithm>
-#include <memory>
-
-#include <string.h>
-#include <openssl/bio.h>
-#include <openssl/evp.h>
-#include <openssl/buffer.h>
-
-#include <dpl/log/log.h>
-
-#include <exception.h>
-#include <base64.h>
-
-namespace CKM {
-
-Base64Encoder::Base64Encoder() :
-       m_b64(0),
-       m_bmem(0),
-       m_finalized(false)
-{
-}
-
-void Base64Encoder::append(const RawBuffer &data)
-{
-       if (m_finalized) {
-               ThrowErr(Exc::InternalError, "Already finalized");
-       }
-
-       if (!m_b64)
-               reset();
-
-       BIO_write(m_b64, data.data(), data.size());
-}
-
-void Base64Encoder::finalize()
-{
-       if (m_finalized) {
-               ThrowErr(Exc::InternalError, "Already finalized.");
-       }
-
-       m_finalized = true;
-       (void)BIO_flush(m_b64);
-}
-
-RawBuffer Base64Encoder::get()
-{
-       if (!m_finalized) {
-               ThrowErr(Exc::InternalError, "Not finalized");
-       }
-
-       BUF_MEM *bptr = nullptr;
-       BIO_get_mem_ptr(m_b64, &bptr);
-
-       if (!bptr) {
-               ThrowErr(Exc::InternalError, "Bio internal error");
-       }
-
-       if (bptr->length > 0)
-               return RawBuffer(bptr->data, bptr->data + bptr->length);
-
-       return RawBuffer();
-}
-
-void Base64Encoder::reset()
-{
-       m_finalized = false;
-       BIO_free_all(m_b64);
-       m_b64 = BIO_new(BIO_f_base64());
-       m_bmem = BIO_new(BIO_s_mem());
-
-       if (!m_b64 || !m_bmem) {
-               ThrowErr(Exc::InternalError, "Error during allocation memory in BIO");
-       }
-
-       BIO_set_flags(m_b64, BIO_FLAGS_BASE64_NO_NL);
-       m_b64 = BIO_push(m_b64, m_bmem);
-}
-
-Base64Encoder::~Base64Encoder()
-{
-       BIO_free_all(m_b64);
-}
-
-Base64Decoder::Base64Decoder() :
-       m_finalized(false)
-{
-}
-
-void Base64Decoder::append(const RawBuffer &data)
-{
-       if (m_finalized) {
-               ThrowErr(Exc::InternalError, "Already finalized.");
-       }
-
-       std::copy(data.begin(), data.end(), std::back_inserter(m_input));
-}
-
-static bool whiteCharacter(char a)
-{
-       return a == '\n';
-}
-
-bool Base64Decoder::finalize()
-{
-       if (m_finalized) {
-               ThrowErr(Exc::InternalError, "Already finalized.");
-       }
-
-       m_finalized = true;
-
-       m_input.erase(std::remove_if(m_input.begin(),
-                                                                m_input.end(),
-                                                                whiteCharacter),
-                                 m_input.end());
-
-       for (size_t i = 0; i < m_input.size(); ++i) {
-               if (isalnum(m_input[i])
-                               || m_input[i] == '+'
-                               || m_input[i] == '/'
-                               || m_input[i] == '=')
-                       continue;
-
-               LogError("Base64 input contains illegal chars: " << m_input[i]);
-               return false;
-       }
-
-       BIO *b64, *bmem;
-       size_t len = m_input.size();
-
-       RawBuffer buffer(len);
-
-       if (!buffer.data()) {
-               ThrowErr(Exc::InternalError, "Error in malloc.");
-       }
-
-       memset(buffer.data(), 0, buffer.size());
-       b64 = BIO_new(BIO_f_base64());
-
-       if (!b64) {
-               ThrowErr(Exc::InternalError, "Couldn't create BIO object.");
-       }
-
-       BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
-       RawBuffer tmp(m_input);
-       m_input.clear();
-
-       bmem = BIO_new_mem_buf(tmp.data(), len);
-
-       if (!bmem) {
-               BIO_free(b64);
-               ThrowErr(Exc::InternalError, "Internal error in BIO");
-       }
-
-       bmem = BIO_push(b64, bmem);
-
-       if (!bmem) {
-               BIO_free(b64);
-               ThrowErr(Exc::InternalError, "Internal error in BIO");
-       }
-
-       int readlen = BIO_read(bmem, buffer.data(), buffer.size());
-       m_output.clear();
-
-       bool status = true;
-
-       if (readlen > 0) {
-               buffer.resize(readlen);
-               m_output = std::move(buffer);
-       } else {
-               status = false;
-       }
-
-       BIO_free_all(bmem);
-       return status;
-}
-
-RawBuffer Base64Decoder::get() const
-{
-       if (!m_finalized) {
-               ThrowErr(Exc::InternalError, "Not finalized");
-       }
-
-       return m_output;
-}
-
-void Base64Decoder::reset()
-{
-       m_finalized = false;
-       m_input.clear();
-       m_output.clear();
-}
-
-} // namespace CKM
index f73266e..a028661 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2011 - 2020 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.
  *    See the License for the specific language governing permissions and
  *    limitations under the License.
  */
-#ifndef _BASE64_H_
-#define _BASE64_H_
 
-#include <string>
+#pragma once
 
-#include <ckm/ckm-type.h>
-#include <noncopyable.h>
-#include <symbol-visibility.h>
+#include <base64_generic.h>
+#include <exception.h>
 
-struct bio_st;
-typedef bio_st BIO;
+#include <stdexcept>
 
 namespace CKM {
 
-class COMMON_API Base64Encoder {
-public:
-       NONCOPYABLE(Base64Encoder)
+template <typename Output, typename Input>
+Output base64Encode(const Input& input)
+{
+    return base64EncodeGeneric<Output, Input>(input);
+}
+
+template <typename Output, typename Input>
+Output base64Decode(const Input& input)
+{
+    try {
+        return base64DecodeGeneric<Output, Input>(input);
+    } catch (const std::invalid_argument& e) {
+        ThrowErr(Exc::InternalError, e.what());
+    }
+}
 
-       Base64Encoder();
-       void append(const RawBuffer &data);
-       void finalize();
-       RawBuffer get();
-       void reset();
-       ~Base64Encoder();
-
-private:
-       BIO *m_b64;
-       BIO *m_bmem;
-       bool m_finalized;
-};
-
-class COMMON_API Base64Decoder {
-public:
-       NONCOPYABLE(Base64Decoder)
-
-       Base64Decoder();
-       void append(const RawBuffer &data);
-
-       /*
-        *  Function will return false when BIO_read fails
-        *  (for example: when string was not in base64 format).
-        */
-       bool finalize();
-       RawBuffer get() const;
-       void reset();
-       ~Base64Decoder() {}
-
-private:
-       RawBuffer m_input;
-       RawBuffer m_output;
-       bool m_finalized;
-};
 } // namespace CKM
-
-#endif
index f81d44a..71b02eb 100644 (file)
@@ -19,6 +19,7 @@
  * @brief       Certificate implementation.
  */
 #include <cassert>
+#include <stdexcept>
 
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
@@ -28,7 +29,8 @@
 
 #include <key-impl.h>
 #include <certificate-impl.h>
-#include <base64.h>
+#include <base64_generic.h>
+#include <exception.h>
 
 namespace CKM {
 
@@ -38,11 +40,12 @@ CertificateImpl::CertificateImpl(const RawBuffer &der, DataFormat format)
        LogDebug("Certificate to parse. Size: " << der.size());
 
        if (DataFormat::FORM_DER_BASE64 == format) {
-               Base64Decoder base64;
-               base64.reset();
-               base64.append(der);
-               base64.finalize();
-               auto tmp = base64.get();
+               RawBuffer tmp;
+               try {
+                       tmp = base64DecodeGeneric<RawBuffer>(der);
+               } catch (const std::invalid_argument&) {
+                       LogError("Certificate in FORM_DER_BASE64 format is not valid base64.");
+               }
                auto ptr = reinterpret_cast<const unsigned char *>(tmp.data());
                auto size = static_cast<int>(tmp.size());
                m_x509 = d2i_X509(nullptr, &ptr, size);
index 5917844..404ec58 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2000 - 2020 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.
 #include <string>
 #include <algorithm>
 #include <cctype>
+#include <stdexcept>
 #include <BufferHandler.h>
 #include <xml-utils.h>
-#include <base64.h>
+#include <base64_generic.h>
+#include <dpl/log/log.h>
+#include <exception.h>
 
 namespace {
 const char *const XML_ATTR_IV  = "IV";
@@ -42,20 +45,20 @@ void BufferHandler::Start(const XML::Parser::Attributes &attr)
 {
        if (attr.find(XML_ATTR_IV) != attr.end()) {
                std::string IVstring = attr.at(XML_ATTR_IV);
-               Base64Decoder base64;
-               base64.reset();
-               base64.append(RawBuffer(IVstring.begin(), IVstring.end()));
-               base64.finalize();
-               m_encryptionParams.iv = base64.get();
+               try {
+                       m_encryptionParams.iv = base64DecodeGeneric<RawBuffer>(IVstring);
+               } catch (const std::invalid_argument&) {
+                       LogError("Encryption param IV is not valid base64.");
+               }
        }
 
        if (attr.find(XML_ATTR_TAG) != attr.end()) {
                std::string tag = attr.at(XML_ATTR_TAG);
-               Base64Decoder base64;
-               base64.reset();
-               base64.append(RawBuffer(tag.begin(), tag.end()));
-               base64.finalize();
-               m_encryptionParams.tag = base64.get();
+               try {
+                       m_encryptionParams.tag = base64DecodeGeneric<RawBuffer>(tag);
+               } catch (const std::invalid_argument&) {
+                       LogError("Encryption param tag is not valid base64.");
+               }
        }
 }
 
@@ -84,11 +87,12 @@ void BufferHandler::End()
        case ENCRYPTED: {
                std::string trimmed = XML::trimEachLine(std::string(m_data.begin(),
                                                                                                m_data.end()));
-               Base64Decoder base64;
-               base64.reset();
-               base64.append(RawBuffer(trimmed.begin(), trimmed.end()));
-               base64.finalize();
-               m_data = base64.get();
+               try {
+                       m_data = base64DecodeGeneric<RawBuffer>(trimmed);
+               } catch (const std::invalid_argument&) {
+                       LogError("Data is not valid base64.");
+                       m_data.clear();
+               }
                break;
        }
 
index 8108af1..6655825 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2000 - 2020 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.
@@ -21,6 +21,7 @@
  */
 
 #include <iostream>
+#include <stdexcept>
 #include <InitialValuesFile.h>
 #include <InitialValueHandler.h>
 #include <BufferHandler.h>
@@ -30,6 +31,7 @@
 #include <DataHandler.h>
 #include <EncodingType.h>
 #include <sw-backend/obj.h>
+#include <base64_generic.h>
 #include <dpl/log/log.h>
 
 namespace {
@@ -253,11 +255,12 @@ void InitialValuesFile::EncryptionKeyHandler::End()
 {
        std::string trimmed = XML::trimEachLine(std::string(m_encryptedKey.begin(),
                                                                                        m_encryptedKey.end()));
-       Base64Decoder base64;
-       base64.reset();
-       base64.append(RawBuffer(trimmed.begin(), trimmed.end()));
-       base64.finalize();
-       m_encryptedKey = base64.get();
+       try {
+               m_encryptedKey = base64DecodeGeneric<RawBuffer>(trimmed);
+       } catch (const std::invalid_argument&) {
+               LogError("Encrypted key is not valid base64.");
+               m_encryptedKey.clear();
+       }
 };
 
 CKM::RawBuffer InitialValuesFile::EncryptionKeyHandler::getEncryptedKey() const
index 6de54dc..2dcf715 100644 (file)
@@ -220,34 +220,20 @@ void CryptoLogic::decryptRow(const Password &password, DB::Row &row)
 
 void CryptoLogic::encBase64(RawBuffer &data)
 {
-       Base64Encoder benc;
-       RawBuffer encdata;
-
-       benc.append(data);
-       benc.finalize();
-       encdata = benc.get();
+       RawBuffer encdata = base64Encode<RawBuffer>(data);
 
        if (encdata.size() == 0)
-               ThrowErr(Exc::InternalError, "Base64Encoder returned empty data.");
+               ThrowErr(Exc::InternalError, "base64Encode returned empty data.");
 
        data = std::move(encdata);
 }
 
 void CryptoLogic::decBase64(RawBuffer &data)
 {
-       Base64Decoder bdec;
-       RawBuffer decdata;
-
-       bdec.reset();
-       bdec.append(data);
-
-       if (!bdec.finalize())
-               ThrowErr(Exc::InternalError, "Failed in Base64Decoder.finalize.");
-
-       decdata = bdec.get();
+       RawBuffer decdata = base64Decode<RawBuffer>(data);
 
        if (decdata.size() == 0)
-               ThrowErr(Exc::InternalError, "Base64Decoder returned empty data.");
+               ThrowErr(Exc::InternalError, "base64Decode returned empty data.");
 
        data = std::move(decdata);
 }
index 8478846..bc3e2bb 100644 (file)
@@ -66,6 +66,7 @@ INCLUDE_DIRECTORIES(
 LINK_DIRECTORIES(${KEY_MANAGER_DEP_LIBRARY_DIRS})
 
 SET(UNIT_TESTS_SOURCES
+    ${PROJECT_SOURCE_DIR}/common/base64_generic.cpp
     ${PROJECT_SOURCE_DIR}/common/colour_log_formatter.cpp
     ${PROJECT_SOURCE_DIR}/common/DBFixture.cpp
     ${PROJECT_SOURCE_DIR}/common/test_common.cpp
@@ -98,7 +99,6 @@ SET(UNIT_TESTS_SOURCES
 
     ${MANAGER_PATH}/client-async/descriptor-set.cpp
     ${MANAGER_PATH}/common/algo-param.cpp
-    ${MANAGER_PATH}/common/base64.cpp
     ${MANAGER_PATH}/common/certificate-impl.cpp
     ${MANAGER_PATH}/common/ckm-zero-memory.cpp
     ${MANAGER_PATH}/common/data-type.cpp
index 6a75d19..ad34421 100644 (file)
@@ -27,8 +27,8 @@
 #include <ckm/ckm-type.h>
 #include <exception.h>
 
-using CKM::Base64Encoder;
-using CKM::Base64Decoder;
+using CKM::base64Encode;
+using CKM::base64Decode;
 using CKM::RawBuffer;
 
 namespace {
@@ -50,22 +50,12 @@ BOOST_AUTO_TEST_SUITE(BASE64_TEST)
 POSITIVE_TEST_CASE(ENCODE_DECODE)
 {
        /* try encode */
-       Base64Encoder encoder;
-       BOOST_REQUIRE_NO_THROW(encoder.append(rawbuf));
-       BOOST_REQUIRE_NO_THROW(encoder.finalize());
-
        RawBuffer encdata;
-       BOOST_REQUIRE_NO_THROW(encdata = encoder.get());
-       BOOST_REQUIRE_NO_THROW(encoder.reset());
+       BOOST_REQUIRE_NO_THROW(encdata = base64Encode<RawBuffer>(rawbuf));
 
        /* try decode */
-       Base64Decoder decoder;
-       BOOST_REQUIRE_NO_THROW(decoder.append(encdata));
-       BOOST_REQUIRE_NO_THROW(decoder.finalize());
-
        RawBuffer decdata;
-       BOOST_REQUIRE_NO_THROW(decdata = decoder.get());
-       BOOST_REQUIRE_NO_THROW(decoder.reset());
+       BOOST_REQUIRE_NO_THROW(decdata = base64Decode<RawBuffer>(encdata));
 
        /* compare with orig data */
        BOOST_REQUIRE_MESSAGE(
@@ -74,44 +64,9 @@ POSITIVE_TEST_CASE(ENCODE_DECODE)
                "Original data and encoded-decoded data is different!");
 }
 
-NEGATIVE_TEST_CASE(THROW_SOMETHING)
-{
-       /* encode data */
-       Base64Encoder encoder;
-       BOOST_REQUIRE_THROW(encoder.get(), CKM::Exc::InternalError);
-
-       BOOST_REQUIRE_NO_THROW(encoder.append(rawbuf));
-       BOOST_REQUIRE_NO_THROW(encoder.finalize());
-
-       BOOST_REQUIRE_THROW(encoder.append(rawbuf),
-                                               CKM::Exc::InternalError);
-       BOOST_REQUIRE_THROW(encoder.finalize(),
-                                               CKM::Exc::InternalError);
-
-       RawBuffer encdata;
-       BOOST_REQUIRE_NO_THROW(encdata = encoder.get());
-
-       /* decode data */
-       Base64Decoder decoder;
-       BOOST_REQUIRE_THROW(decoder.get(), CKM::Exc::InternalError);
-
-       BOOST_REQUIRE_NO_THROW(decoder.append(encdata));
-       BOOST_REQUIRE_NO_THROW(decoder.finalize());
-
-       BOOST_REQUIRE_THROW(decoder.append(encdata),
-                                               CKM::Exc::InternalError);
-       BOOST_REQUIRE_THROW(decoder.finalize(),
-                                               CKM::Exc::InternalError);
-
-       RawBuffer decdata;
-       BOOST_REQUIRE_NO_THROW(decdata = decoder.get());
-}
-
 NEGATIVE_TEST_CASE(ILLEGAL_DATA)
 {
-       Base64Decoder decoder;
-       BOOST_REQUIRE_NO_THROW(decoder.append(rawbuf));
-       BOOST_REQUIRE(!decoder.finalize());
+       BOOST_REQUIRE_THROW(base64Decode<RawBuffer>(rawbuf), CKM::Exc::InternalError);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
index 907c766..c06e2a7 100644 (file)
@@ -37,18 +37,13 @@ const auto TEST_DATA = createRandom(10);
 
 void changeBase64(RawBuffer& data)
 {
-       auto b64 = [](auto&& coder, RawBuffer& data){
-               coder.append(data);
-               coder.finalize();
-               data = coder.get();
-
-               BOOST_REQUIRE(!data.empty());
-       };
-       b64(Base64Decoder(), data);
+       data = base64Decode<RawBuffer>(data);
+       BOOST_REQUIRE(!data.empty());
 
        ++data[0];
 
-       b64(Base64Encoder(), data);
+       data = base64Encode<RawBuffer>(data);
+       BOOST_REQUIRE(!data.empty());
 }
 
 } // namespace anonymous