From 7bc501bef926142ed84d330749608e05ab55facb Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Mon, 11 Feb 2019 17:04:46 +0100 Subject: [PATCH 01/16] Check fs errors before saving the file GetFd(os) on a non-existing file causes segfault. Change-Id: I8365dfbddace160ae99b1e7d1f6070ee1032f6cd --- src/manager/service/file-system.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/manager/service/file-system.cpp b/src/manager/service/file-system.cpp index 6a70c20..079a4cd 100644 --- a/src/manager/service/file-system.cpp +++ b/src/manager/service/file-system.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2019 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. @@ -122,11 +122,18 @@ void FileSystem::saveFile(const std::string &path, { std::ofstream os(path, std::ios::out | std::ofstream::binary | std::ofstream::trunc); + + if (os.fail()) + ThrowErr(Exc::FileSystemFailed, "Can't open file for writing: ", path); + std::copy(buffer.begin(), buffer.end(), std::ostreambuf_iterator(os)); - // Prevent desynchronization in batter remove test. + // Prevent desynchronization in battery remove test. os.flush(); - fsync(FstreamAccessors::GetFd(os)); // flush kernel space buffer + if (fsync(FstreamAccessors::GetFd(os)) != 0) { // flush kernel space buffer + auto desc = GetErrnoString(errno); + ThrowErr(Exc::FileSystemFailed, "Failed to sync file: ", path, " Reason: ", desc); + } os.close(); if (os.fail()) -- 2.7.4 From a9844c2ed624b961164fa1e04ee9691c1c43d895 Mon Sep 17 00:00:00 2001 From: Konrad Lipinski Date: Mon, 6 May 2019 20:24:55 +0200 Subject: [PATCH 02/16] Fix svace defects va_start / va_end must be called in the same function Change-Id: I5176fc2686a62eb0a21e6eb9a5f737dbc3880056 --- src/manager/dpl/db/src/sql_connection.cpp | 34 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/manager/dpl/db/src/sql_connection.cpp b/src/manager/dpl/db/src/sql_connection.cpp index cb4ee0b..902c94d 100644 --- a/src/manager/dpl/db/src/sql_connection.cpp +++ b/src/manager/dpl/db/src/sql_connection.cpp @@ -36,16 +36,6 @@ namespace { const int MAX_RETRY = 10; - -struct ScopedVaList { - ~ScopedVaList() - { - va_end(args); - } - va_list args; -}; - -#define scoped_va_start(name, param) ScopedVaList name; va_start(name.args, param); } namespace CKM { @@ -952,17 +942,29 @@ void SqlConnection::ExecCommandHelper(Output *out, const char *format, //LCOV_EXCL_START void SqlConnection::ExecCommand(Output *out, const char *format, ...) { - scoped_va_start(svl, format); - - ExecCommandHelper(out, format, svl.args); + va_list args; + va_start(args, format); + try { + ExecCommandHelper(out, format, args); + } catch (...) { + va_end(args); + throw; + } + va_end(args); } //LCOV_EXCL_STOP void SqlConnection::ExecCommand(const char *format, ...) { - scoped_va_start(svl, format); - - ExecCommandHelper(NULL, format, svl.args); + va_list args; + va_start(args, format); + try { + ExecCommandHelper(NULL, format, args); + } catch (...) { + va_end(args); + throw; + } + va_end(args); } SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand( -- 2.7.4 From 062dcfeebc57f34472a116fd518ee2910e35f1e9 Mon Sep 17 00:00:00 2001 From: Tomasz Swierczek Date: Mon, 13 May 2019 11:14:00 +0200 Subject: [PATCH 03/16] Fix file name in file header Change-Id: I3e087729762d16b84327863317643387c304ef88 --- src/manager/common/ckm-error.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/manager/common/ckm-error.cpp b/src/manager/common/ckm-error.cpp index 520bcbe..e738fac 100644 --- a/src/manager/common/ckm-error.cpp +++ b/src/manager/common/ckm-error.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2019 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. @@ -14,7 +14,7 @@ * limitations under the License */ /* - * @file ckm-zero-memory.cpp + * @file ckm-error.cpp * @author Tomasz Swierczek (t.swierczek@samsung.com) * @version 1.0 */ -- 2.7.4 From f28d202efe7074c3d8334c8e577a55b0191e8810 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Tue, 14 May 2019 15:53:58 +0200 Subject: [PATCH 04/16] Increase backlog for listening sockets When systemd's socket activaction is utilized, the default backlog parameter passed to the listen() function is set to SOMAXCONN, which is equal to 128. In distributions where systemd is not used for socket activation, the default UNIX socket implementation sets the backlog value to 5. This may lead to rare overflow of an internal connection queue. This manifests itself as the -EAGAIN error returned by connect(). To mitigate the issue, the backlog parameter has been set to SOMAXCONN, which is a default value used by systemd. Change-Id: I906cd4de478b0dac0eaf860550fccd2f9cd6e184 --- src/manager/main/socket-manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/manager/main/socket-manager.cpp b/src/manager/main/socket-manager.cpp index f3f6e3f..07ce31c 100644 --- a/src/manager/main/socket-manager.cpp +++ b/src/manager/main/socket-manager.cpp @@ -617,7 +617,7 @@ int SocketManager::CreateDomainSocketHelp( umask(originalUmask); - if (-1 == listen(sockfd, 5)) { + if (-1 == listen(sockfd, SOMAXCONN)) { int err = errno; close(sockfd); LogError("Error in listen: " << GetErrnoString(err)); -- 2.7.4 From 3a49b5305d0739d3165b25e406305dad841d52e1 Mon Sep 17 00:00:00 2001 From: Tomasz Swierczek Date: Wed, 15 May 2019 10:05:49 +0200 Subject: [PATCH 05/16] Adjust to boost 1.65 Change-Id: I43e986a010030db949053a8e1b3669495fa1a986 --- tests/colour_log_formatter.cpp | 33 +++++++++++++++++++++++++++++++++ tests/colour_log_formatter.h | 8 ++++++++ 2 files changed, 41 insertions(+) diff --git a/tests/colour_log_formatter.cpp b/tests/colour_log_formatter.cpp index 87e862b..b2d2b9b 100644 --- a/tests/colour_log_formatter.cpp +++ b/tests/colour_log_formatter.cpp @@ -297,6 +297,39 @@ colour_log_formatter::log_entry_finish( //____________________________________________________________________________// +#if BOOST_VERSION >= 106501 +void colour_log_formatter::log_exception_start(std::ostream& os, boost::unit_test::log_checkpoint_data const& lcd, boost::execution_exception const& ex) +{ + (void)os; + (void)lcd; + (void)ex; +} + +void colour_log_formatter::log_exception_finish(std::ostream& os) +{ + (void)os; +} + +void colour_log_formatter::entry_context_start(std::ostream& os, boost::unit_test::log_level l) +{ + (void)os; + (void)l; +} + +void colour_log_formatter::log_entry_context(std::ostream& os, boost::unit_test::log_level l, boost::unit_test::const_string value) +{ + (void)os; + (void)l; + (void)value; +} + +void colour_log_formatter::entry_context_finish(std::ostream& os, boost::unit_test::log_level l) +{ + (void)os; + (void)l; +} +#endif + //____________________________________________________________________________// } // namespace CKM diff --git a/tests/colour_log_formatter.h b/tests/colour_log_formatter.h index 3c5dae0..064cfe2 100644 --- a/tests/colour_log_formatter.h +++ b/tests/colour_log_formatter.h @@ -54,6 +54,14 @@ public: boost::unit_test::lazy_ostream const &value); void log_entry_finish(std::ostream &); +#if BOOST_VERSION >= 106501 + void log_exception_start(std::ostream& os, boost::unit_test::log_checkpoint_data const& lcd, boost::execution_exception const& ex); + void log_exception_finish(std::ostream& os); + void entry_context_start(std::ostream& os, boost::unit_test::log_level l); + void log_entry_context(std::ostream& os, boost::unit_test::log_level l, boost::unit_test::const_string value); + void entry_context_finish(std::ostream& os, boost::unit_test::log_level l); +#endif + private: bool m_isTestCaseFailed; }; -- 2.7.4 From 39795557d02a1e2ae0dd5ea2fa7a2085bed329c2 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Wed, 20 Feb 2019 12:40:21 +0100 Subject: [PATCH 06/16] Get rid of misleading SCHEMA_INFO error During startup the key-manager attempts to read a table SCHEMA_INFO to get the information about the database version. In older versions of the database that table is missing. Key-manager properly handles that case but produces 3 lines of error log which may suggest that something went wrong. This commit checks the existence of the table before attempting to use it. Whole operation is enclosed in a transaction. Change-Id: Ie7f1fbe1182c2add5965f8e5ddada262ffcb42fe --- src/manager/service/db-crypto.cpp | 64 +++++++++++++++++---------------------- src/manager/service/db-crypto.h | 6 ++-- 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/src/manager/service/db-crypto.cpp b/src/manager/service/db-crypto.cpp index 2bc2a92..d7acb0f 100644 --- a/src/manager/service/db-crypto.cpp +++ b/src/manager/service/db-crypto.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014 - 2019 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. @@ -229,25 +229,28 @@ void Crypto::createView(const char *create_cmd) bool Crypto::getDBVersion(int &schemaVersion) { - SchemaInfo SchemaInfo(this); - - if (SchemaInfo.getVersionInfo(schemaVersion)) { - LogDebug("Current DB version: " << schemaVersion); - return true; - } else { - LogDebug("No DB version known or DB not present"); + Transaction transaction(this); - if (m_connection->CheckTableExist("CKM_TABLE")) { - // special case: old CKM_TABLE exists - schemaVersion = DB_VERSION_1; - return true; - } else if (m_connection->CheckTableExist("NAME_TABLE")) { - // special case: new scheme exists, but no SCHEMA_INFO table present - schemaVersion = DB_VERSION_2; + if (m_connection->CheckTableExist("SCHEMA_INFO")) { + SchemaInfo SchemaInfo(m_connection); + if (SchemaInfo.getVersionInfo(schemaVersion)) { + LogDebug("Current DB version: " << schemaVersion); return true; } } + LogDebug("No DB version known or DB not present"); + + if (m_connection->CheckTableExist("CKM_TABLE")) { + // special case: old CKM_TABLE exists + schemaVersion = DB_VERSION_1; + return true; + } else if (m_connection->CheckTableExist("NAME_TABLE")) { + // special case: new scheme exists, but no SCHEMA_INFO table present + schemaVersion = DB_VERSION_2; + return true; + } + // not recognized - proceed with an empty DBs return false; } @@ -282,7 +285,7 @@ void Crypto::initDatabase() } // update DB version info - SchemaInfo SchemaInfo(this); + SchemaInfo SchemaInfo(m_connection); SchemaInfo.setVersionInfo(); transaction.commit(); } @@ -320,7 +323,7 @@ void Crypto::createDBSchema() "Can not create the database schema: no initialization script"); m_connection->ExecCommand((*script).c_str()); - SchemaInfo SchemaInfo(this); + SchemaInfo SchemaInfo(m_connection); SchemaInfo.setVersionInfo(); transaction.commit(); } @@ -712,34 +715,23 @@ void Crypto::setPermission( void Crypto::SchemaInfo::setVersionInfo() { SqlConnection::DataCommandUniquePtr insertContextCommand = - m_db->m_connection->PrepareDataCommand(DB_CMD_SCHEMA_SET); + m_connection->PrepareDataCommand(DB_CMD_SCHEMA_SET); insertContextCommand->BindString(101, DB_SCHEMA_VERSION_FIELD); insertContextCommand->BindString(103, std::to_string(DB_VERSION_CURRENT).c_str()); insertContextCommand->Step(); } -bool Crypto::SchemaInfo::getVersionInfo(int &version) const +bool Crypto::SchemaInfo::getVersionInfo(int &version) { - // Try..Catch mandatory here - we don't need to escalate the error - // if it happens - we just won't return the version, allowing CKM to work - try { - SqlConnection::DataCommandUniquePtr selectCommand = - m_db->m_connection->PrepareDataCommand(DB_CMD_SCHEMA_GET); - selectCommand->BindString(101, DB_SCHEMA_VERSION_FIELD); + SqlConnection::DataCommandUniquePtr selectCommand = + m_connection->PrepareDataCommand(DB_CMD_SCHEMA_GET); + selectCommand->BindString(101, DB_SCHEMA_VERSION_FIELD); - if (selectCommand->Step()) { - version = static_cast(atoi(selectCommand->GetColumnString(1).c_str())); - return true; - } - } catch (const SqlConnection::Exception::InvalidColumn &) { - LogError("Select statement invalid column error"); - } catch (const SqlConnection::Exception::SyntaxError &) { - LogError("Couldn't prepare select statement"); - } catch (const SqlConnection::Exception::InternalError &) { - LogError("Couldn't execute select statement"); + if (selectCommand->Step()) { + version = static_cast(atoi(selectCommand->GetColumnString(1).c_str())); + return true; } - return false; } diff --git a/src/manager/service/db-crypto.h b/src/manager/service/db-crypto.h index 65ef3a3..ad0ef12 100644 --- a/src/manager/service/db-crypto.h +++ b/src/manager/service/db-crypto.h @@ -231,13 +231,13 @@ private: class SchemaInfo { public: - explicit SchemaInfo(const Crypto *db) : m_db(db) {} + explicit SchemaInfo(SqlConnection *connection) : m_connection(connection) {} void setVersionInfo(); - bool getVersionInfo(int &version) const; + bool getVersionInfo(int &version); private: - const Crypto *m_db; + SqlConnection *m_connection; }; public: -- 2.7.4 From 8e0e1fbd45c1297b3cbf3b205c3e1d669751204c Mon Sep 17 00:00:00 2001 From: Tomasz Swierczek Date: Wed, 15 May 2019 14:22:54 +0200 Subject: [PATCH 07/16] Release 0.1.29 * Get rid of misleading SCHEMA_INFO error * Adjust to boost 1.65 * Fix file name in file header * Fix svace defects * Check fs errors before saving the file Change-Id: Ic90ecdd256a23cec9f9356a7e59c85be982cd8e9 --- packaging/key-manager.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/key-manager.spec b/packaging/key-manager.spec index 6b8b61e..089cfe3 100644 --- a/packaging/key-manager.spec +++ b/packaging/key-manager.spec @@ -5,7 +5,7 @@ Name: key-manager Summary: Central Key Manager and utilities -Version: 0.1.28 +Version: 0.1.29 Release: 1 Group: Security/Secure Storage License: Apache-2.0 and BSD-3-Clause -- 2.7.4 From ae8aeca3723fc26e07d666dfb63277d4eba7ea52 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Tue, 5 Feb 2019 12:13:56 +0100 Subject: [PATCH 08/16] decider: Allow multiple policies for more complex logic When generating asymmetric keys, ckm-logic selected less restrictive policy out of two provided and selected key store this way. Now, both policies are supplied to Decider, which will allow for more complex backend selection logic. Change-Id: Id2b845326cae7bbf5d90bb575645c8af36c20d0f --- src/manager/common/data-type.cpp | 36 +---------------- src/manager/common/data-type.h | 3 +- src/manager/crypto/platform/decider.cpp | 63 ++++++++++++++++++----------- src/manager/crypto/platform/decider.h | 21 +++++++++- src/manager/crypto/tz-backend/internals.cpp | 4 +- src/manager/service/ckm-logic.cpp | 23 +++++++++-- tests/test_data-type.cpp | 44 +------------------- 7 files changed, 82 insertions(+), 112 deletions(-) diff --git a/src/manager/common/data-type.cpp b/src/manager/common/data-type.cpp index 9049d1b..0bcf74f 100644 --- a/src/manager/common/data-type.cpp +++ b/src/manager/common/data-type.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2019 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. @@ -76,40 +76,6 @@ DataType::DataType(KeyType key) } } -DataType::DataType(AlgoType algorithmType) -{ - switch (algorithmType) { - case AlgoType::AES_CTR: - case AlgoType::AES_CBC: - case AlgoType::AES_GCM: - case AlgoType::AES_CFB: - case AlgoType::AES_GEN: - m_dataType = DataType::KEY_AES; - break; - - case AlgoType::RSA_SV: - case AlgoType::RSA_OAEP: - case AlgoType::RSA_GEN: - m_dataType = DataType::KEY_RSA_PUBLIC; - break; - - case AlgoType::DSA_SV: - case AlgoType::DSA_GEN: - m_dataType = DataType::KEY_DSA_PUBLIC; - break; - - case AlgoType::ECDSA_SV: - case AlgoType::ECDSA_GEN: - m_dataType = DataType::KEY_ECDSA_PUBLIC; - break; - - default: - ThrowErr(Exc::InputParam, - "Invalid conversion from AlgoType=", static_cast(algorithmType), - " to DBDataType"); - } -} - DataType::DataType(int data) : m_dataType(static_cast(data)) { diff --git a/src/manager/common/data-type.h b/src/manager/common/data-type.h index ba3c4fd..30829e1 100644 --- a/src/manager/common/data-type.h +++ b/src/manager/common/data-type.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2019 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. @@ -70,7 +70,6 @@ public: DataType(Type data); explicit DataType(int data); explicit DataType(KeyType key); - explicit DataType(AlgoType algorithmType); DataType(const DataType &) = default; DataType &operator=(const DataType &) = default; diff --git a/src/manager/crypto/platform/decider.cpp b/src/manager/crypto/platform/decider.cpp index a7e6b32..e14e9b6 100644 --- a/src/manager/crypto/platform/decider.cpp +++ b/src/manager/crypto/platform/decider.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015 - 2019 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. @@ -56,34 +56,41 @@ std::string ValueToString(const T& value) return str.str(); } -CryptoBackend chooseCryptoBackend(DataType data, - const Policy &policy, - bool encrypted) +CryptoBackend chooseCryptoBackend(const DataParams& params) { #ifdef TZ_BACKEND_ENABLED + if (params.size() != 1 && params.size() != 2) { + ThrowErr(Exc::Crypto::InternalError, "Invalid number of key parameters provided to decider"); + } + // user directly point proper backend - we will not discuss with it - if (policy.backend == CKM::PolicyBackend::FORCE_SOFTWARE) + if (params[0].policy.backend == CKM::PolicyBackend::FORCE_SOFTWARE) return CryptoBackend::OpenSSL; // user directly point proper backend - we will not discuss with it - if (policy.backend == CKM::PolicyBackend::FORCE_HARDWARE) + if (params[0].policy.backend == CKM::PolicyBackend::FORCE_HARDWARE) return CryptoBackend::TrustZone; - // For now only software backend supports device encyption key - // TODO tz-backend could support the master key, but it would require - // hardcoding a known key ID and querying TA whether the key is - // reachable - if (encrypted) - return CryptoBackend::OpenSSL; - - // tz-backend allows only for data binary export - if (policy.extractable && !data.isBinaryData()) - return CryptoBackend::OpenSSL; - - // Use TrustZone only with symmetric keys or unencrypted binary - // data until asymmetric cryptography is implemented - if (!data.isSKey() && !data.isBinaryData()) + if (params.size() == 1) { + // For now only software backend supports device encyption key + // TODO tz-backend could support the master key, but it would require + // hardcoding a known key ID and querying TA whether the key is + // reachable + if (params[0].encrypted) + return CryptoBackend::OpenSSL; + + // tz-backend allows only for data binary export + if (params[0].policy.extractable && !params[0].data.isBinaryData()) + return CryptoBackend::OpenSSL; + + // Use TrustZone only with symmetric keys or unencrypted binary + // data until asymmetric cryptography is implemented + if (!params[0].data.isSKey() && !params[0].data.isBinaryData()) + return CryptoBackend::OpenSSL; + } else if (params.size() == 2) { + LogDebug("2 keys - asymmetric encryption not yet supported, selecting OpenSSL"); return CryptoBackend::OpenSSL; + } try { LogDebug("Trying to open TA session..."); @@ -95,10 +102,9 @@ CryptoBackend chooseCryptoBackend(DataType data, LogDebug("...succeeded. Selecting TZ backend."); return CryptoBackend::TrustZone; + #else // TZ_BACKEND_ENABLED - (void) data; - (void) policy; - (void) encrypted; + (void) params; return CryptoBackend::OpenSSL; #endif // TZ_BACKEND_ENABLED } @@ -137,7 +143,16 @@ GStore &Decider::getStore(CryptoBackend cryptoBackend) const GStore &Decider::getStore(DataType data, const Policy &policy, bool encrypted) const { - return getStore(chooseCryptoBackend(data, policy, encrypted)); + DataParams params{ + DataParam(data, policy, encrypted) + }; + + return getStore(chooseCryptoBackend(params)); +} + +GStore &Decider::getStore(const DataParams& params) const +{ + return getStore(chooseCryptoBackend(params)); } } // namespace Crypto diff --git a/src/manager/crypto/platform/decider.h b/src/manager/crypto/platform/decider.h index ef0522c..14d1071 100644 --- a/src/manager/crypto/platform/decider.h +++ b/src/manager/crypto/platform/decider.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015 - 2019 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 @@ #pragma once #include +#include #include @@ -32,11 +33,28 @@ namespace CKM { namespace Crypto { +struct DataParam { + DataParam() = delete; + DataParam(const DataType &d, const Policy &pol, bool enc = false) + : data(d) + , policy(pol) + , encrypted(enc) + { + } + + DataType data; + Policy policy; + bool encrypted; +}; + +using DataParams = std::vector; + class Decider { public: Decider(); GStore &getStore(const Token &token) const; GStore &getStore(DataType data, const Policy &policy, bool encrypted = false) const; + GStore &getStore(const DataParams& params) const; virtual ~Decider() {} @@ -49,4 +67,3 @@ protected: } // Crypto } // CKM - diff --git a/src/manager/crypto/tz-backend/internals.cpp b/src/manager/crypto/tz-backend/internals.cpp index 317a775..71038e0 100644 --- a/src/manager/crypto/tz-backend/internals.cpp +++ b/src/manager/crypto/tz-backend/internals.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2019 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. @@ -86,7 +86,7 @@ Data generateSKey(const CryptoAlgorithm &alg, int keyBits = unpack(alg, ParamName::GEN_KEY_LEN); Data keyData; - keyData.type = DataType(keyType); + keyData.type = DataType(KeyType::KEY_AES); if (!pwd.empty()) { if (iv.empty()) { diff --git a/src/manager/service/ckm-logic.cpp b/src/manager/service/ckm-logic.cpp index c54b9a4..aedf064 100644 --- a/src/manager/service/ckm-logic.cpp +++ b/src/manager/service/ckm-logic.cpp @@ -55,6 +55,16 @@ bool isNameValid(const CKM::Name &name) return true; } +// keypair data type, having private key data type and public key data type +// private is assumed to be .first, public .second +using DataTypePair = std::pair; + +const std::map ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP = { + { CKM::AlgoType::RSA_GEN, { CKM::DataType(CKM::KeyType::KEY_RSA_PRIVATE), CKM::DataType(CKM::KeyType::KEY_RSA_PUBLIC) } }, + { CKM::AlgoType::DSA_GEN, { CKM::DataType(CKM::KeyType::KEY_DSA_PRIVATE), CKM::DataType(CKM::KeyType::KEY_DSA_PUBLIC) } }, + { CKM::AlgoType::ECDSA_GEN, { CKM::DataType(CKM::KeyType::KEY_ECDSA_PRIVATE), CKM::DataType(CKM::KeyType::KEY_ECDSA_PUBLIC) } }, +}; + } // anonymous namespace namespace CKM { @@ -1391,10 +1401,10 @@ int CKMLogic::createKeyPairHelper( if (!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType)) ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found."); - DataType dt(keyType); - - if (!dt.isKey()) + const auto dtIt = ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.find(keyType); + if (dtIt == ALGO_TYPE_TO_DATA_TYPE_PAIR_MAP.end()) ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value."); + const DataTypePair& dt = dtIt->second; if (policyPrivate.backend != policyPublic.backend) ThrowErr(Exc::InputParam, "Error, key pair must be supported with the same backend."); @@ -1417,7 +1427,12 @@ int CKMLogic::createKeyPairHelper( bool exportable = policyPrivate.extractable || policyPublic.extractable; Policy lessRestricted(Password(), exportable, policyPrivate.backend); - TokenPair keys = m_decider.getStore(dt, lessRestricted).generateAKey(keyGenParams, + Crypto::DataParams params{ + Crypto::DataParam(dt.first, policyPrivate), + Crypto::DataParam(dt.second, policyPublic), + }; + + TokenPair keys = m_decider.getStore(params).generateAKey(keyGenParams, policyPrivate.password, policyPublic.password); diff --git a/tests/test_data-type.cpp b/tests/test_data-type.cpp index 3598273..c147541 100644 --- a/tests/test_data-type.cpp +++ b/tests/test_data-type.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 - 2019 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. @@ -37,48 +37,6 @@ BOOST_AUTO_TEST_CASE(CONSTRUCTOR) CKM::Exc::InputParam); BOOST_REQUIRE_THROW(DataType(static_cast(999)), CKM::Exc::InputParam); - - std::vector types; - - types.emplace_back(AlgoType::AES_CTR); - types.emplace_back(AlgoType::AES_CBC); - types.emplace_back(AlgoType::AES_GCM); - types.emplace_back(AlgoType::AES_CFB); - types.emplace_back(AlgoType::AES_GEN); - - for (auto &type : types) - BOOST_REQUIRE(type == DataType(DataType::KEY_AES)); - - types.clear(); - - types.emplace_back(AlgoType::RSA_SV); - types.emplace_back(AlgoType::RSA_OAEP); - types.emplace_back(AlgoType::RSA_GEN); - - for (auto &type : types) - BOOST_REQUIRE(type == DataType(DataType::KEY_RSA_PUBLIC)); - - types.clear(); - - types.emplace_back(AlgoType::DSA_SV); - types.emplace_back(AlgoType::DSA_GEN); - - for (auto &type : types) - BOOST_REQUIRE(type == DataType(DataType::KEY_DSA_PUBLIC)); - - types.clear(); - - types.emplace_back(AlgoType::ECDSA_SV); - types.emplace_back(AlgoType::ECDSA_GEN); - - for (auto &type : types) - BOOST_REQUIRE(type == DataType(DataType::KEY_ECDSA_PUBLIC)); - - types.clear(); - - BOOST_REQUIRE_THROW( - DataType(static_cast(-1)), - CKM::Exc::InputParam); } BOOST_AUTO_TEST_CASE(KEY_TYPE_CASTING) -- 2.7.4 From 1ea5a9fe774a68052cfec974b6f8b04da3b14fab Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Fri, 1 Mar 2019 17:11:55 +0100 Subject: [PATCH 09/16] tz-backend: Add serialization wrapper Change-Id: I304452444887de48d808a6aa11eb42a1de385bf0 --- src/CMakeLists.txt | 1 + src/manager/crypto/tz-backend/tz-context.cpp | 228 +++++------------------- src/manager/crypto/tz-backend/tz-serializer.cpp | 173 ++++++++++++++++++ src/manager/crypto/tz-backend/tz-serializer.h | 130 ++++++++++++++ tests/CMakeLists.txt | 1 + tools/ckm_db_tool/CMakeLists.txt | 1 + 6 files changed, 355 insertions(+), 179 deletions(-) create mode 100644 src/manager/crypto/tz-backend/tz-serializer.cpp create mode 100644 src/manager/crypto/tz-backend/tz-serializer.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 70dca66..1dcfb8b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -93,6 +93,7 @@ SET(KEY_MANAGER_SOURCES ${KEY_MANAGER_PATH}/crypto/tz-backend/internals.cpp ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-context.cpp ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-memory.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-serializer.cpp ) ENDIF() diff --git a/src/manager/crypto/tz-backend/tz-context.cpp b/src/manager/crypto/tz-backend/tz-context.cpp index c6f2527..f9b2f2b 100644 --- a/src/manager/crypto/tz-backend/tz-context.cpp +++ b/src/manager/crypto/tz-backend/tz-context.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2019 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 #include +#include #include #include #include @@ -665,101 +666,30 @@ void TrustZoneContext::importData( // [2].memref - reference to serialized buffer: // KM_BinaryData with data id // KM_BinaryData with tag id (optional, if password was provided) - uint32_t inMemorySize = 0; - // place for dataType - inMemorySize += KM_SizeOfFlag(); - - KM_BinaryData ta_data; - ta_data.data_size = static_cast(data.size()); - ta_data.data = const_cast(data.data()); - inMemorySize += KM_SizeOfBinaryData(&ta_data); - - uint32_t keySizeBits_flags = static_cast(keySizeBits); - inMemorySize += KM_SizeOfFlag(); - - KM_BinaryData ta_data_enc_iv; - ta_data_enc_iv.data_size = static_cast(encData.iv.size()); - ta_data_enc_iv.data = const_cast(encData.iv.data()); - inMemorySize += KM_SizeOfBinaryData(&ta_data_enc_iv); - - KM_BinaryData ta_data_enc_tag; - ta_data_enc_tag.data_size = static_cast(encData.tag.size()); - ta_data_enc_tag.data = const_cast(encData.tag.data()); - inMemorySize += KM_SizeOfBinaryData(&ta_data_enc_tag); + TZSerializer sIn; + sIn.Push(new TZSerializableFlag(dataType)); + sIn.Push(new TZSerializableBinary(data)); + sIn.Push(new TZSerializableFlag(keySizeBits)); + sIn.Push(new TZSerializableBinary(encData.iv)); + sIn.Push(new TZSerializableBinary(encData.tag)); uint32_t pwd_flag = pwd.empty() ? 0 : 1; - inMemorySize += KM_SizeOfFlag(); - - KM_PwdData kmPwdData; - if (pwd_flag) { - memset(&kmPwdData, 0, sizeof(KM_PwdData)); - kmPwdData.pwd = const_cast(pwd.data()); - kmPwdData.pwd_size = pwd.size(); - kmPwdData.iv = const_cast(iv.data()); - kmPwdData.iv_size = iv.size(); - kmPwdData.tag = NULL; - kmPwdData.tag_size = 0; - kmPwdData.derive_len_bits = Params::DERIVED_KEY_LENGTH_BITS; - kmPwdData.it_count = Params::DERIVED_KEY_ITERATIONS; - kmPwdData.tag_len_bits = pwdTagSizeBits; - - inMemorySize += KM_SizeOfPwdData(&kmPwdData); - } - - TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); - void *inMemoryPtr = inMemory.Get()->buffer; - - int ret = KM_SerializeFlag(&inMemoryPtr, &inMemorySize, dataType); - if (ret){ - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } - - ret = KM_SerializeBinaryData(&inMemoryPtr, &inMemorySize, &ta_data); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } - - ret = KM_SerializeFlag(&inMemoryPtr, &inMemorySize, keySizeBits_flags); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } - - ret = KM_SerializeBinaryData(&inMemoryPtr, &inMemorySize, &ta_data_enc_iv); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } + sIn.Push(new TZSerializableFlag(pwd_flag)); + if (pwd_flag) + sIn.Push(new TZSerializablePwdData(pwd, iv, pwdTagSizeBits)); - ret = KM_SerializeBinaryData(&inMemoryPtr, &inMemorySize, &ta_data_enc_tag); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } - - ret = KM_SerializeFlag(&inMemoryPtr, &inMemorySize, pwd_flag); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } + TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT); + sIn.Serialize(inMemory); - if (pwd_flag) { - ret = KM_SerializePwdData(&inMemoryPtr, &inMemorySize, &kmPwdData); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } - } - KM_BinaryData kmDataId; - KM_BinaryData kmTag; - memset(&kmDataId, 0, sizeof(KM_BinaryData)); - memset(&kmTag, 0, sizeof(KM_BinaryData)); - kmDataId.data_size = KM_DATA_ID_SIZE; - uint32_t outMemorySize = KM_SizeOfBinaryData(&kmDataId); + TZSerializer sOut; + sOut.Push(new TZSerializableBinary(KM_DATA_ID_SIZE)); if (pwd_flag) { - kmTag.data_size = pwdTagSizeBits / 8; - outMemorySize += KM_SizeOfBinaryData(&kmTag); + sOut.Push(new TZSerializableBinary(pwdTagSizeBits / 8)); } - TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT); - void *outMemoryPtr = outMemory.Get()->buffer; + TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT); TEEC_Operation op; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, @@ -773,19 +703,10 @@ void TrustZoneContext::importData( Execute(CMD_IMPORT_DATA, &op); - ret = KM_DeserializeBinaryData(&outMemoryPtr, &outMemorySize, &kmDataId); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize data, ret: ", ret); - } - dataId.resize(kmDataId.data_size); - memcpy(dataId.data(), kmDataId.data, kmDataId.data_size); + sOut.Deserialize(outMemory); + sOut.Pull(dataId); if (pwd_flag) { - ret = KM_DeserializeBinaryData(&outMemoryPtr, &outMemorySize, &kmTag); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize data, ret: ", ret); - } - pwdTag.resize(kmTag.data_size); - memcpy(pwdTag.data(), kmTag.data, kmTag.data_size); + sOut.Pull(pwdTag); } LogDebug("Imported object ID is (hex): " << rawToHexString(dataId)); @@ -802,16 +723,13 @@ void TrustZoneContext::GetDataSize(const RawBuffer &dataId, uint32_t &dataSize) // [0].value.a - return code // [0].value.b - size of buffer to be passed from CA LogDebug("Object ID (passed to CMD_GET_DATA_SIZE) is (hex): " << rawToHexString(dataId)); - KM_BinaryData kmDataId; - kmDataId.data_size = static_cast(dataId.size()); - kmDataId.data = const_cast(dataId.data()); - uint32_t inMemorySize = KM_SizeOfBinaryData(&kmDataId); - TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); - void *inMemoryPtr = inMemory.Get()->buffer; - int ret = KM_SerializeBinaryData(&inMemoryPtr, &inMemorySize, &kmDataId); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize data, ret: ", ret); - } + + TZSerializer sIn; + sIn.Push(new TZSerializableBinary(dataId)); + + TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT); + sIn.Serialize(inMemory); + TEEC_Operation op; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_MEMREF_WHOLE, TEEC_NONE, TEEC_NONE); @@ -839,66 +757,30 @@ void TrustZoneContext::getData(const RawBuffer &dataId, // [2].memref - reference to serialized buffer: // KM_BinaryData with binary data LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId)); - uint32_t data_size = 0; - GetDataSize(dataId, data_size); - KM_BinaryData kmDataId; - kmDataId.data_size = static_cast(dataId.size()); - kmDataId.data = const_cast(dataId.data()); - uint32_t inMemorySize = KM_SizeOfBinaryData(&kmDataId) + KM_SizeOfFlag(); - uint32_t pwd_flag = pwd.getPassword().empty() ? 0 : 1; - uint32_t pwdTagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS; - - KM_PwdData kmPwdData; - if (pwd_flag) { - memset(&kmPwdData, 0, sizeof(KM_PwdData)); - kmPwdData.pwd = const_cast(pwd.getPassword().data()); - kmPwdData.pwd_size = pwd.getPassword().size(); - kmPwdData.iv = const_cast(pwd.getIV().data()); - kmPwdData.iv_size = pwd.getIV().size(); - kmPwdData.tag = const_cast(pwd.getTag().data()); - kmPwdData.tag_size = pwd.getTag().size(); - kmPwdData.derive_len_bits = Params::DERIVED_KEY_LENGTH_BITS; - kmPwdData.it_count = Params::DERIVED_KEY_ITERATIONS; - kmPwdData.tag_len_bits = pwdTagSizeBits; - - inMemorySize += KM_SizeOfPwdData(&kmPwdData); - } + TZSerializer sIn; + sIn.Push(new TZSerializableBinary(dataId)); - TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); - void *inMemoryPtr = inMemory.Get()->buffer; + uint32_t pwd_flag = pwd.getPassword().empty() ? 0 : 1; + sIn.Push(new TZSerializableFlag(pwd_flag)); - int ret = KM_SerializeBinaryData(&inMemoryPtr, &inMemorySize, &kmDataId); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } - ret = KM_SerializeFlag(&inMemoryPtr, &inMemorySize, pwd_flag); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } if (pwd_flag) { - ret = KM_SerializePwdData(&inMemoryPtr, &inMemorySize, &kmPwdData); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } + sIn.Push(new TZSerializablePwdData(pwd.getPassword(), + pwd.getIV(), + Params::DEFAULT_AES_GCM_TAG_LEN_BITS, + pwd.getTag())); } - KM_BinaryData kmExtractedData; - memset(&kmExtractedData, 0, sizeof(KM_BinaryData)); - kmExtractedData.data_size = data_size; - - uint32_t outMemorySize = KM_SizeOfBinaryData(&kmExtractedData); - uint32_t outMemorySize2 = outMemorySize; + TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT); + sIn.Serialize(inMemory); - TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT); - void *outMemoryPtr = outMemory.Get()->buffer; - void *outMemoryPtr2 = outMemory.Get()->buffer; + uint32_t data_size = 0; + GetDataSize(dataId, data_size); - // requesting size is saved in this buffer - ret = KM_SerializeBinaryData(&outMemoryPtr2, &outMemorySize2, &kmExtractedData); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } + TZSerializer sOut; + sOut.Push(new TZSerializableBinary(data_size)); + TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT); + sOut.Serialize(outMemory); TEEC_Operation op; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, @@ -912,13 +794,8 @@ void TrustZoneContext::getData(const RawBuffer &dataId, Execute(CMD_GET_DATA, &op); - ret = KM_DeserializeBinaryData(&outMemoryPtr, &outMemorySize, &kmExtractedData); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } - - data.resize(kmExtractedData.data_size); - memcpy(data.data(), kmExtractedData.data, kmExtractedData.data_size); + sOut.Deserialize(outMemory); + sOut.Pull(data); } @@ -932,18 +809,11 @@ void TrustZoneContext::destroyData(const RawBuffer &dataId) // output: // [0].value.a - return code LogDebug("Object ID (passed to CMD_GET_DATA) is (hex): " << rawToHexString(dataId)); - KM_BinaryData kmDataId; - kmDataId.data_size = static_cast(dataId.size()); - kmDataId.data = const_cast(dataId.data()); - uint32_t inMemorySize = KM_SizeOfBinaryData(&kmDataId); - TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); - void *inMemoryPtr = inMemory.Get()->buffer; - - int ret = KM_SerializeBinaryData(&inMemoryPtr, &inMemorySize, &kmDataId); + TZSerializer sIn; + sIn.Push(new TZSerializableBinary(dataId)); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); - } + TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT); + sIn.Serialize(inMemory); TEEC_Operation op; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_MEMREF_WHOLE, diff --git a/src/manager/crypto/tz-backend/tz-serializer.cpp b/src/manager/crypto/tz-backend/tz-serializer.cpp new file mode 100644 index 0000000..27cf705 --- /dev/null +++ b/src/manager/crypto/tz-backend/tz-serializer.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2019 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 + */ +/* + * @file tz-serializer.cpp + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief + */ +#include "tz-serializer.h" + +#include + +#include + +namespace CKM { +namespace Crypto { +namespace TZ { +namespace Internals { + +// TZSerializable +void TZSerializable::Pull(RawBuffer &) const +{ + ThrowErr(Exc::Crypto::InternalError, + "This serializable does not support conversion to RawBuffer"); +} + +void TZSerializable::Pull(uint32_t &) const +{ + ThrowErr(Exc::Crypto::InternalError, + "This serializable does not support conversion to uint32_t"); +} + + +// TZSerializableBinary +TZSerializableBinary::TZSerializableBinary(uint32_t data_size) +{ + m_data.data = nullptr; + m_data.data_size = data_size; +} + +TZSerializableBinary::TZSerializableBinary(const RawBuffer &data) +{ + m_data.data = data.empty() ? nullptr : const_cast(data.data()); + m_data.data_size = data.size(); +} + +uint32_t TZSerializableBinary::GetSize() const +{ + return KM_SizeOfBinaryData(const_cast(&m_data)); +} + +int TZSerializableBinary::Serialize(void **buffer, uint32_t *size_guard) const +{ + return KM_SerializeBinaryData(buffer, size_guard, const_cast(&m_data)); +} + +int TZSerializableBinary::Deserialize(void **buffer, uint32_t *size_guard) +{ + return KM_DeserializeBinaryData(buffer, size_guard, &m_data); +} + +void TZSerializableBinary::Pull(RawBuffer &buffer) const +{ + buffer.resize(m_data.data_size); + memcpy(buffer.data(), m_data.data, m_data.data_size); +} + + +// TZSerializablePwdData +TZSerializablePwdData::TZSerializablePwdData(const RawBuffer &pwd, + const RawBuffer &iv, + uint32_t tagSizeBits, + const RawBuffer &tag) +{ + memset(&m_data, 0, sizeof(KM_PwdData)); + m_data.pwd = pwd.empty() ? nullptr : const_cast(pwd.data()); + m_data.pwd_size = pwd.size(); + m_data.iv = iv.empty() ? nullptr : const_cast(iv.data()); + m_data.iv_size = iv.size(); + m_data.tag = tag.empty() ? nullptr : const_cast(tag.data()); + m_data.tag_size = tag.size(); + m_data.derive_len_bits = Params::DERIVED_KEY_LENGTH_BITS; + m_data.it_count = Params::DERIVED_KEY_ITERATIONS; + m_data.tag_len_bits = tagSizeBits; +} + +uint32_t TZSerializablePwdData::GetSize() const +{ + return KM_SizeOfPwdData(const_cast(&m_data)); +} + +int TZSerializablePwdData::Serialize(void **buffer, uint32_t *size_guard) const +{ + return KM_SerializePwdData(buffer, size_guard, const_cast(&m_data)); +} + +int TZSerializablePwdData::Deserialize(void **buffer, uint32_t *size_guard) +{ + return KM_DeserializePwdData(buffer, size_guard, &m_data); +} + +// TZSerializableFlag +uint32_t TZSerializableFlag::GetSize() const +{ + return KM_SizeOfFlag(); +} + +int TZSerializableFlag::Serialize(void **buffer, uint32_t *size_guard) const +{ + return KM_SerializeFlag(buffer, size_guard, m_flag); +} + +int TZSerializableFlag::Deserialize(void **buffer, uint32_t *size_guard) +{ + return KM_DeserializeFlag(buffer, size_guard, &m_flag); +} + +void TZSerializableFlag::Pull(uint32_t &flag) const +{ + flag = m_flag; +} + + +// TZSerializer +void TZSerializer::Push(TZSerializable *serializable) +{ + m_serializables.emplace_back(serializable); + m_memorySize += serializable->GetSize(); +} + +void TZSerializer::Serialize(TrustZoneMemory &memory) const +{ + void *inBuffer = memory.Get()->buffer; + uint32_t inBufferGuard = m_memorySize; + + for (const auto& s : m_serializables) { + int ret = s->Serialize(&inBuffer, &inBufferGuard); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize data, ret: ", ret); + } + } +} + +void TZSerializer::Deserialize(const TrustZoneMemory &memory) +{ + void *outBuffer = memory.Get()->buffer; + uint32_t outBufferGuard = m_memorySize; + + for (const auto& s : m_serializables) { + int ret = s->Deserialize(&outBuffer, &outBufferGuard); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize data, ret: ", ret); + } + } +} + +} // namespace Internals +} // namespace TZ +} // namespace Crypto +} // namespace CKM diff --git a/src/manager/crypto/tz-backend/tz-serializer.h b/src/manager/crypto/tz-backend/tz-serializer.h new file mode 100644 index 0000000..6a5b572 --- /dev/null +++ b/src/manager/crypto/tz-backend/tz-serializer.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2019 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 + */ +/* + * @file tz-serializer.h + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief + */ + +#pragma once + +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace CKM { +namespace Crypto { +namespace TZ { +namespace Internals { + +class TZSerializable { +public: + TZSerializable() {} + virtual ~TZSerializable() {} + TZSerializable(const TZSerializable&) = delete; + TZSerializable& operator=(const TZSerializable&) = delete; + + virtual uint32_t GetSize() const = 0; + virtual int Serialize(void **buffer, uint32_t *size_guard) const = 0; + virtual int Deserialize(void **buffer, uint32_t *size_guard) = 0; + virtual void Pull(RawBuffer &buffer) const; + virtual void Pull(uint32_t &flag) const; +}; + + +class TZSerializableBinary : public TZSerializable { +public: + explicit TZSerializableBinary(uint32_t data_size); + explicit TZSerializableBinary(const RawBuffer &data); + uint32_t GetSize() const override; + int Serialize(void **buffer, uint32_t *size_guard) const override; + int Deserialize(void **buffer, uint32_t *size_guard) override; + void Pull(RawBuffer &buffer) const override; +private: + KM_BinaryData m_data; +}; + + +class TZSerializablePwdData : public TZSerializable { +public: + TZSerializablePwdData(const RawBuffer &pwd, + const RawBuffer &iv, + uint32_t tagSizeBits, + const RawBuffer &tag = RawBuffer()); + uint32_t GetSize() const override; + int Serialize(void **buffer, uint32_t *size_guard) const override; + int Deserialize(void **buffer, uint32_t *size_guard) override; +private: + KM_PwdData m_data; +}; + + +class TZSerializableFlag : public TZSerializable { +public: + TZSerializableFlag() : m_flag(0) {} + explicit TZSerializableFlag(uint32_t flag) : m_flag(flag) {} + uint32_t GetSize() const override; + int Serialize(void **buffer, uint32_t *size_guard) const override; + int Deserialize(void **buffer, uint32_t *size_guard) override; + void Pull(uint32_t &flag) const override; +private: + uint32_t m_flag; +}; + + +class TZSerializer { +public: + TZSerializer() : m_memorySize(0) {} + ~TZSerializer() {} + TZSerializer(const TZSerializer&) = delete; + TZSerializer& operator=(const TZSerializer&) = delete; + + void Push(TZSerializable *serializable); + + template + void Pull(T &buffer); + uint32_t GetSize() const { return m_memorySize; } + void Serialize(TrustZoneMemory &memory) const; + void Deserialize(const TrustZoneMemory &memory); + +private: + std::list> m_serializables; + uint32_t m_memorySize; +}; + +template +void TZSerializer::Pull(T &data) +{ + if (m_serializables.empty()) { + ThrowErr(Exc::Crypto::InternalError, "No more serializables to extract"); + } + + m_serializables.front()->Pull(data); + m_serializables.pop_front(); +} + +} // namespace Internals +} // namespace TZ +} // namespace Crypto +} // namespace CKM diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8b4f863..8b1d31e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -163,6 +163,7 @@ SET(TEST_MERGED_SOURCES ${KEY_MANAGER_PATH}/crypto/tz-backend/internals.cpp ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-context.cpp ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-memory.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-serializer.cpp ) ENDIF() diff --git a/tools/ckm_db_tool/CMakeLists.txt b/tools/ckm_db_tool/CMakeLists.txt index a25e497..cb7f759 100644 --- a/tools/ckm_db_tool/CMakeLists.txt +++ b/tools/ckm_db_tool/CMakeLists.txt @@ -89,6 +89,7 @@ SET(CKM_DB_TOOLS_SOURCES ${KEY_MANAGER_PATH}/crypto/tz-backend/store.cpp ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-context.cpp ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-memory.cpp + ${KEY_MANAGER_PATH}/crypto/tz-backend/tz-serializer.cpp ) ENDIF() -- 2.7.4 From 72e8c2c638e3631f01907cd361f094b39c47bac6 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Wed, 20 Feb 2019 12:27:33 +0100 Subject: [PATCH 10/16] tz-backend: Implement asymmetric operations Change-Id: Ie98b4e72addb257c2a8de1de57097fe077fff380 --- src/manager/common/data-type.cpp | 5 + src/manager/common/data-type.h | 1 + src/manager/crypto/platform/decider.cpp | 20 +- src/manager/crypto/tz-backend/internals.cpp | 250 ++++++++++++-- src/manager/crypto/tz-backend/internals.h | 10 +- src/manager/crypto/tz-backend/store.cpp | 30 +- src/manager/crypto/tz-backend/tz-context.cpp | 475 ++++++++++++++++++++++++--- src/manager/crypto/tz-backend/tz-context.h | 56 +++- 8 files changed, 753 insertions(+), 94 deletions(-) diff --git a/src/manager/common/data-type.cpp b/src/manager/common/data-type.cpp index 0bcf74f..8de9e15 100644 --- a/src/manager/common/data-type.cpp +++ b/src/manager/common/data-type.cpp @@ -181,6 +181,11 @@ bool DataType::isBinaryData() const return m_dataType == BINARY_DATA; } +bool DataType::isEllipticCurve() const +{ + return (m_dataType == KEY_ECDSA_PRIVATE) || (m_dataType == KEY_ECDSA_PUBLIC); +} + bool DataType::isInRange(int data) { if (data < static_cast(DB_FIRST)) diff --git a/src/manager/common/data-type.h b/src/manager/common/data-type.h index 30829e1..014869f 100644 --- a/src/manager/common/data-type.h +++ b/src/manager/common/data-type.h @@ -84,6 +84,7 @@ public: bool isKeyPublic() const; bool isCertificate() const; bool isBinaryData() const; + bool isEllipticCurve() const; static bool isInRange(int data); static DataType getChainDatatype(unsigned int index); diff --git a/src/manager/crypto/platform/decider.cpp b/src/manager/crypto/platform/decider.cpp index e14e9b6..4ffe83a 100644 --- a/src/manager/crypto/platform/decider.cpp +++ b/src/manager/crypto/platform/decider.cpp @@ -76,20 +76,30 @@ CryptoBackend chooseCryptoBackend(const DataParams& params) // TODO tz-backend could support the master key, but it would require // hardcoding a known key ID and querying TA whether the key is // reachable - if (params[0].encrypted) + if (params[0].encrypted) { return CryptoBackend::OpenSSL; + } // tz-backend allows only for data binary export - if (params[0].policy.extractable && !params[0].data.isBinaryData()) + if (params[0].policy.extractable && !params[0].data.isBinaryData()) { return CryptoBackend::OpenSSL; + } // Use TrustZone only with symmetric keys or unencrypted binary // data until asymmetric cryptography is implemented - if (!params[0].data.isSKey() && !params[0].data.isBinaryData()) + if (!params[0].data.isSKey() && !params[0].data.isBinaryData()) { return CryptoBackend::OpenSSL; + } } else if (params.size() == 2) { - LogDebug("2 keys - asymmetric encryption not yet supported, selecting OpenSSL"); - return CryptoBackend::OpenSSL; + // extractable private key can only be handled by OpenSSL + if (params[0].policy.extractable) { + return CryptoBackend::OpenSSL; + } + + // ECDSA algorithm is unsupported by GP API 1.0 + if (params[0].data.isEllipticCurve() || params[1].data.isEllipticCurve()) { + return CryptoBackend::OpenSSL; + } } try { diff --git a/src/manager/crypto/tz-backend/internals.cpp b/src/manager/crypto/tz-backend/internals.cpp index 71038e0..7b7b9be 100644 --- a/src/manager/crypto/tz-backend/internals.cpp +++ b/src/manager/crypto/tz-backend/internals.cpp @@ -24,18 +24,66 @@ #include #include #include +#include +#include +#include +#include #include #include +#include #include +#include + +namespace { + +using DSAPtr = std::unique_ptr>; + +CKM::RawBuffer extractBignumData(BIGNUM* bn) +{ + size_t size = static_cast(BN_num_bytes(bn)); + + CKM::RawBuffer result(size); + int ret = BN_bn2bin(bn, result.data()); + if (ret != static_cast(size)) { + ThrowErr(CKM::Exc::Crypto::InternalError, + "Error while converting bignums - expected " + + std::to_string(size) + " bytes of data, got " + std::to_string(ret)); + } + + return result; +} + +void generateDSAParams(const int sizeBits, CKM::RawBuffer &prime, + CKM::RawBuffer &subprime, CKM::RawBuffer &base) +{ + DSAPtr dsa(DSA_new(), DSA_free); + if (!dsa) { + ThrowErr(CKM::Exc::Crypto::InternalError, + "Failed to create DSA context for parameter gen"); + } + + if (DSA_generate_parameters_ex(dsa.get(), sizeBits, NULL, 0, NULL, NULL, NULL) == 0) { + ThrowErr(CKM::Exc::Crypto::InternalError, + "Failed to generate DSA params, err = " + std::to_string(ERR_get_error())); + } + + // at this stage dsa->p, dsa->q & dsa->r should contain our params + // extract them into buffers + prime = extractBignumData(dsa->p); + subprime = extractBignumData(dsa->q); + base = extractBignumData(dsa->g); +} + +} // namespace namespace CKM { namespace Crypto { namespace TZ { namespace Internals { -tz_algo_type getGenKeyType(AlgoType type) +tz_algo_type getGenSKeyType(AlgoType type) { switch (type) { @@ -52,6 +100,10 @@ tz_algo_type getAlgType(AlgoType type) case AlgoType::AES_CTR: return ALGO_AES_CTR; case AlgoType::AES_CFB: return ALGO_AES_CFB; case AlgoType::AES_GCM: return ALGO_AES_GCM; + case AlgoType::RSA_OAEP: return ALGO_RSA; + case AlgoType::RSA_SV: return ALGO_RSA_SV; + case AlgoType::DSA_SV: return ALGO_DSA_SV; + case AlgoType::ECDSA_SV: return ALGO_ECDSA_SV; default: ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported"); }; } @@ -65,11 +117,30 @@ tz_algo_type getAlgType(KeyType keyType) case KeyType::KEY_RSA_PUBLIC: case KeyType::KEY_RSA_PRIVATE: return ALGO_RSA_GEN; + case KeyType::KEY_DSA_PUBLIC: + case KeyType::KEY_DSA_PRIVATE: + return ALGO_DSA_GEN; + case KeyType::KEY_ECDSA_PUBLIC: + case KeyType::KEY_ECDSA_PRIVATE: + return ALGO_ECDSA_GEN; default: ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported"); }; } +tz_hash_type getHashType(HashAlgorithm hash) +{ + switch (hash) + { + case HashAlgorithm::SHA1: return HASH_SHA1; + case HashAlgorithm::SHA256: return HASH_SHA256; + case HashAlgorithm::SHA384: return HASH_SHA384; + case HashAlgorithm::SHA512: return HASH_SHA512; + default: + ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported"); + } +} + RawBuffer generateIV() { RawBuffer result; @@ -94,23 +165,84 @@ Data generateSKey(const CryptoAlgorithm &alg, } RawBuffer pwdBuf(pwd.begin(), pwd.end()); - TrustZoneContext::Instance().generateSKeyPwd(getGenKeyType(keyType), + TrustZoneContext::Instance().generateSKeyPwd(getGenSKeyType(keyType), pwdBuf, iv, keyBits, keyData.data, tag); } else { - TrustZoneContext::Instance().generateSKey(getGenKeyType(keyType), keyBits, + TrustZoneContext::Instance().generateSKey(getGenSKeyType(keyType), keyBits, keyData.data); } return keyData; } -DataPair generateAKey(const CryptoAlgorithm &, - const Password &, - const RawBuffer &) +DataPair generateAKey(const CryptoAlgorithm &alg, + const Password &pubPwd, + const Password &privPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwdIv, + RawBuffer &pubTag, + RawBuffer &privTag) { - ThrowErr(Exc::Crypto::OperationNotSupported, - "AKeys are not yet implemented in TrustZone backend"); + AlgoType keyType = unpack(alg, ParamName::ALGO_TYPE); + int keyBits = unpack(alg, ParamName::GEN_KEY_LEN); + + Data pubKeyData; + Data privKeyData; + + RawBuffer pubPwdBuf; + if (!pubPwd.empty()) + pubPwdBuf.assign(pubPwd.begin(), pubPwd.end()); + + RawBuffer privPwdBuf; + if (!privPwd.empty()) + privPwdBuf.assign(privPwd.begin(), privPwd.end()); + + switch (keyType) { + case AlgoType::RSA_GEN: { + pubKeyData.type = DataType(KeyType::KEY_RSA_PUBLIC); + privKeyData.type = DataType(KeyType::KEY_RSA_PRIVATE); + + TrustZoneContext::Instance().generateRSAKey(keyBits, + pubPwdBuf, + pubPwdIv, + privPwdBuf, + privPwdIv, + pubKeyData.data, + pubTag, + privKeyData.data, + privTag); + break; + } + case AlgoType::DSA_GEN: { + pubKeyData.type = DataType(KeyType::KEY_DSA_PUBLIC); + privKeyData.type = DataType(KeyType::KEY_DSA_PRIVATE); + + RawBuffer prime; + RawBuffer subprime; + RawBuffer base; + generateDSAParams(keyBits, prime, subprime, base); + TrustZoneContext::Instance().generateDSAKey(keyBits, + prime, + subprime, + base, + pubPwdBuf, + pubPwdIv, + privPwdBuf, + privPwdIv, + pubKeyData.data, + pubTag, + privKeyData.data, + privTag); + break; + } + default: { + ThrowErr(Exc::Crypto::InputParam, + "Invalid algo type provided for generateAKey function"); + } + } + + return DataPair(pubKeyData, privKeyData); } void destroyKey(const RawBuffer &key) @@ -131,6 +263,10 @@ RawBuffer importData(const Data &data, dataType = TYPE_SKEY; } else if (data.type.isBinaryData()) { dataType = TYPE_GENERIC_SECRET; + } else if (data.type.isKeyPrivate()) { + dataType = TYPE_AKEY_PRIVATE; + } else if (data.type.isKeyPublic()) { + dataType = TYPE_AKEY_PUBLIC; } else { ThrowErr(Exc::Crypto::DataTypeNotSupported, "Data type could not be impoted by tz-backend"); @@ -334,41 +470,93 @@ RawBuffer symmetricDecrypt(const RawBuffer &key, "Incorrect algorithm provided for symmetric crypto operation"); } -RawBuffer asymmetricEncrypt(const RawBuffer &, - const Pwd &, - const CryptoAlgorithm &, - const RawBuffer &) +RawBuffer asymmetricEncrypt(const RawBuffer &key, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &data) { + AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); + RawBuffer result; + + switch (algo) + { + case AlgoType::RSA_OAEP: { + TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT, + getAlgType(algo), + key, + pwd, + unpack(alg, ParamName::ED_IV), + data, + result); + return result; + } + default: + break; + } + ThrowErr(Exc::Crypto::OperationNotSupported, - "Asymmetric encryption is not yet supported on TrustZone backend"); + "Incorrect algorithm provided for asymmetric crypto operation"); } -RawBuffer asymmetricDecrypt(const RawBuffer &, - const Pwd &, - const CryptoAlgorithm &, - const RawBuffer &) +RawBuffer asymmetricDecrypt(const RawBuffer &key, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &cipher) { + AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); + RawBuffer result; + + switch (algo) + { + case AlgoType::RSA_OAEP: { + TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT, + getAlgType(algo), + key, + pwd, + unpack(alg, ParamName::ED_IV), + cipher, + result); + return result; + } + default: + break; + } + ThrowErr(Exc::Crypto::OperationNotSupported, - "Asymmetric encryption is not yet supported on TrustZone backend"); + "Incorrect algorithm provided for asymmetric crypto operation"); } -RawBuffer sign(const RawBuffer &, - const Pwd &, - const CryptoAlgorithm &, - const RawBuffer &) +RawBuffer sign(const RawBuffer &pkey, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &message) { - ThrowErr(Exc::Crypto::OperationNotSupported, - "Certificate signing is not yet supported on TrustZone backend"); + AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); + HashAlgorithm hash = unpack(alg, ParamName::SV_HASH_ALGO); + RawBuffer signature; + TrustZoneContext::Instance().executeSign(getAlgType(algo), + getHashType(hash), + pkey, + pwd, + message, + signature); + return signature; } -int verify(const RawBuffer &, - const Pwd &, - const CryptoAlgorithm &, - const RawBuffer &, - const RawBuffer &) +int verify(const RawBuffer &pkey, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &message, + const RawBuffer &signature) { - ThrowErr(Exc::Crypto::OperationNotSupported, - "Certificate signing is not yet supported on TrustZone backend"); + AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); + HashAlgorithm hash = unpack(alg, ParamName::SV_HASH_ALGO); + return TrustZoneContext::Instance().executeVerify(getAlgType(algo), + getHashType(hash), + pkey, + pwd, + message, + signature); } } // namespace Internals diff --git a/src/manager/crypto/tz-backend/internals.h b/src/manager/crypto/tz-backend/internals.h index 1c76f8d..b66351c 100644 --- a/src/manager/crypto/tz-backend/internals.h +++ b/src/manager/crypto/tz-backend/internals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2019 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. @@ -40,8 +40,12 @@ using KeyIdPair = std::pair; RawBuffer generateIV(); DataPair generateAKey(const CryptoAlgorithm &alg, - const Password &pwd, - const RawBuffer &iv); + const Password &pubPwd, + const Password &privPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwdIv, + RawBuffer &pubTag, + RawBuffer &privTag); Data generateSKey(const CryptoAlgorithm &alg, const Password &pwd, diff --git a/src/manager/crypto/tz-backend/store.cpp b/src/manager/crypto/tz-backend/store.cpp index 9549693..978a155 100644 --- a/src/manager/crypto/tz-backend/store.cpp +++ b/src/manager/crypto/tz-backend/store.cpp @@ -113,12 +113,15 @@ GObjUPtr Store::getObject(const Token &token, const Password &pass) ThrowErr(Exc::Crypto::AuthenticationFailed, "This token is not protected with password but passed one"); } - // TODO AKeys + + if (token.dataType.isKeyPrivate() || token.dataType.isKeyPublic()) + return make_unique(scheme, id, Pwd(pass, iv, tag), token.dataType); if (token.dataType.isSKey()) return make_unique(scheme, id, Pwd(pass, iv, tag), token.dataType); - // TODO certificate/chaincert + if (token.dataType.isCertificate() || token.dataType.isChainCert()) + return make_unique(scheme, id, Pwd(pass, iv, tag), token.dataType); if (token.dataType.isBinaryData()) { RawBuffer exported_data = Internals::getData(id, Pwd(pass, iv, tag)); @@ -129,11 +132,24 @@ GObjUPtr Store::getObject(const Token &token, const Password &pass) "This type of data is not supported by trustzone backend: ", (int)token.dataType); } -TokenPair Store::generateAKey(const CryptoAlgorithm &, const Password &, - const Password &) +TokenPair Store::generateAKey(const CryptoAlgorithm &alg, const Password &privPass, + const Password &pubPass) { - ThrowErr(Exc::Crypto::OperationNotSupported, - "AKey operations are not implemented on TrustZone backend!"); + RawBuffer pubIv, privIv; + RawBuffer pubTag, privTag; + if (!pubPass.empty()) { + pubIv = Internals::generateIV(); + } + if (!privPass.empty()) { + privIv = Internals::generateIV(); + } + + Internals::DataPair ret = Internals::generateAKey(alg, pubPass, privPass, pubIv, privIv, pubTag, privTag); + + return std::make_pair( + Token(m_backendId, ret.second.type, pack(ret.second.data, privPass, privIv, privTag)), + Token(m_backendId, ret.first.type, pack(ret.first.data, pubPass, pubIv, pubTag)) + ); } Token Store::generateSKey(const CryptoAlgorithm &alg, const Password &pass) @@ -151,7 +167,7 @@ Token Store::generateSKey(const CryptoAlgorithm &alg, const Password &pass) Token Store::import(const Data &data, const Password &pass, const EncryptionParams &e) { - if (!data.type.isBinaryData() && !data.type.isSKey()) + if (!data.type.isBinaryData() && !data.type.isKey()) ThrowErr(Exc::Crypto::DataTypeNotSupported, "Invalid data provided for import"); RawBuffer passIV; diff --git a/src/manager/crypto/tz-backend/tz-context.cpp b/src/manager/crypto/tz-backend/tz-context.cpp index f9b2f2b..0b54bb4 100644 --- a/src/manager/crypto/tz-backend/tz-context.cpp +++ b/src/manager/crypto/tz-backend/tz-context.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -32,6 +31,10 @@ #include #include +#include +#include +#include +#include namespace CKM { namespace Crypto { @@ -65,6 +68,41 @@ static std::string rawToHexString(const RawBuffer &raw) return dump; } +/* + * Maximum size for given key type in bytes according to key-manager-ta implementation. + * Note that they are greater than TEE Internal Core API v1.1.2.50 (Table 5-9) values. + */ +const std::unordered_map MAX_KEY_SIZE = { + { ALGO_RSA, 4096 / 8 }, + { ALGO_RSA_SV, 4096 / 8 }, + { ALGO_DSA_SV, 4096 / 8 } +}; + +void DeserializeKeyID(TrustZoneMemory &mem, RawBuffer &id) +{ + LogDebug("Deserializing key ID"); + + KM_SymmetricInput* output = nullptr; + int ret = KM_ParamsDeserializationInit(mem.Get()->buffer, mem.Get()->size, &output); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize key ID data deserialization: ", ret); + } + + KM_OutData* outData = nullptr; + ret = KM_ParamsDeserializeOutData(output, &outData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize key ID data: ", ret); + } + + if (outData == nullptr || outData->data_size != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "Deserialized invalid key ID"); + } + + // data_size should contain how much memory we actually took for our cipher operation + id.resize(outData->data_size); + memcpy(id.data(), outData->data, outData->data_size); +} + } // anonymous namespace TrustZoneContext::TrustZoneContext() @@ -144,24 +182,7 @@ void TrustZoneContext::generateSKey(tz_algo_type algo, op.params[1].memref.size = keyMemorySize; Execute(CMD_GENERATE_KEY, &op); - KM_SymmetricInput* output = nullptr; - int ret = KM_ParamsDeserializationInit(keyMemory.Get()->buffer, keyMemory.Get()->size, &output); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to initialize deserialization for generated key ID"); - } - - KM_OutData* outData = nullptr; - ret = KM_ParamsDeserializeOutData(output, &outData); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize generated key ID"); - } - - if (outData == nullptr || outData->data_size != KM_KEY_ID_SIZE) { - ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key ID"); - } - - keyId.resize(KM_KEY_ID_SIZE); - memcpy(keyId.data(), outData->data, KM_KEY_ID_SIZE); + DeserializeKeyID(keyMemory, keyId); } void TrustZoneContext::generateSKeyPwd(tz_algo_type algo, @@ -223,6 +244,8 @@ void TrustZoneContext::generateSKeyPwd(tz_algo_type algo, op.params[2].memref.size = keyMemory.Get()->size; Execute(CMD_GENERATE_KEY_PWD, &op); + DeserializeKeyID(keyMemory, keyId); + KM_SymmetricInput* output = nullptr; ret = KM_ParamsDeserializationInit(keyMemory.Get()->buffer, keyMemory.Get()->size, &output); if (ret) { @@ -256,9 +279,174 @@ void TrustZoneContext::generateSKeyPwd(tz_algo_type algo, memcpy(pwdTag.data(), tagData->data, Params::DEFAULT_AES_GCM_TAG_LEN_BYTES); } +void TrustZoneContext::GenerateAKey(tz_command commandId, + TZSerializer &sIn, + uint32_t keySizeBits, + const RawBuffer &pubPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwd, + const RawBuffer &privPwdIv, + RawBuffer &pubKeyId, + RawBuffer &pubKeyTag, + RawBuffer &privKeyId, + RawBuffer &privKeyTag) +{ + uint32_t pubTagSize = 0; + uint32_t privTagSize = 0; + + uint32_t pubPwdExists = pubPwd.empty() ? 0 : 1; + sIn.Push(new TZSerializableFlag(pubPwdExists)); + if (pubPwdExists) { + sIn.Push(new TZSerializablePwdData(pubPwd, pubPwdIv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS)); + pubTagSize = (Params::DEFAULT_AES_GCM_TAG_LEN_BITS + 7) >> 3; + } + uint32_t privPwdExists = privPwd.empty() ? 0 : 1; + sIn.Push(new TZSerializableFlag(privPwdExists)); + if (privPwdExists) { + sIn.Push(new TZSerializablePwdData(privPwd, privPwdIv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS)); + privTagSize = (Params::DEFAULT_AES_GCM_TAG_LEN_BITS + 7) >> 3; + } + + TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT); + sIn.Serialize(inMemory); + + TZSerializer sOut; + sOut.Push(new TZSerializableBinary(KM_KEY_ID_SIZE)); + sOut.Push(new TZSerializableBinary(pubTagSize)); + sOut.Push(new TZSerializableBinary(KM_KEY_ID_SIZE)); + sOut.Push(new TZSerializableBinary(privTagSize)); + + TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_MEMREF_WHOLE, TEEC_NONE); + op.params[0].value.b = keySizeBits; + op.params[1].memref.parent = inMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = inMemory.Get()->size; + op.params[2].memref.parent = outMemory.Get(); + op.params[2].memref.offset = 0; + op.params[2].memref.size = outMemory.Get()->size; + Execute(commandId, &op); + + sOut.Deserialize(outMemory); + + sOut.Pull(pubKeyId); + if (pubKeyId.size() != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize public key ID"); + } + + if (pubPwdExists) { + sOut.Pull(pubKeyTag); + } + + sOut.Pull(privKeyId); + if (privKeyId.size() != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize private key ID"); + } + + if (privPwdExists) { + sOut.Pull(privKeyTag); + } +} + +void TrustZoneContext::generateRSAKey(uint32_t keySizeBits, + const RawBuffer &pubPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwd, + const RawBuffer &privPwdIv, + RawBuffer &pubKeyId, + RawBuffer &pubKeyTag, + RawBuffer &privKeyId, + RawBuffer &privKeyTag) +{ + // command ID = CMD_GENERATE_RSA_KEYPAIR + // + // TEEC_Operation layout: + // params: + // [0].value.b - key bit size + // [1].memref - reference to serialized buffer: + // flag marking the public key password presence, + // public key password data if the flag above is not 0, + // flag marking the private key password presence, + // public key private data if the flag above is not 0, + // output: + // [0].value.a - return code + // [2].memref + // Public key ID, + // public key tag if password was present, + // Private key ID, + // private key tag if password was present, + + TZSerializer sIn; + + GenerateAKey(CMD_GENERATE_RSA_KEYPAIR, + sIn, + keySizeBits, + pubPwd, + pubPwdIv, + privPwd, + privPwdIv, + pubKeyId, + pubKeyTag, + privKeyId, + privKeyTag); +} + +void TrustZoneContext::generateDSAKey(uint32_t keySizeBits, + const RawBuffer &prime, + const RawBuffer &subprime, + const RawBuffer &base, + const RawBuffer &pubPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwd, + const RawBuffer &privPwdIv, + RawBuffer &pubKeyId, + RawBuffer &pubKeyTag, + RawBuffer &privKeyId, + RawBuffer &privKeyTag) +{ + // command ID = CMD_GENERATE_DSA_KEYPAIR + // + // TEEC_Operation layout: + // params: + // [0].value.b - key bit size + // [1].memref - reference to serialized buffer: + // prime, subprime, base, + // flag marking the public key password presence, + // public key password data if the flag above is not 0, + // flag marking the private key password presence, + // public key private data if the flag above is not 0, + // output: + // [0].value.a - return code + // [2].memref + // Public key ID, + // public key tag if password was present, + // Private key ID, + // private key tag if password was present, + + TZSerializer sIn; + sIn.Push(new TZSerializableBinary(prime)); + sIn.Push(new TZSerializableBinary(subprime)); + sIn.Push(new TZSerializableBinary(base)); + + GenerateAKey(CMD_GENERATE_DSA_KEYPAIR, + sIn, + keySizeBits, + pubPwd, + pubPwdIv, + privPwd, + privPwdIv, + pubKeyId, + pubKeyTag, + privKeyId, + privKeyTag); +} + void TrustZoneContext::executeCrypt(tz_command cmd, tz_algo_type algo, - const RawBuffer &key, + const RawBuffer &keyId, const Pwd &pwd, const RawBuffer &iv, const RawBuffer &data, @@ -275,9 +463,9 @@ void TrustZoneContext::executeCrypt(tz_command cmd, // [0].value.a - return code // [2].memref - serialized output buffer - if (key.size() != KM_KEY_ID_SIZE) { + if (keyId.size() != KM_KEY_ID_SIZE) { ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = " - + std::to_string(key.size()) + ")"); + + std::to_string(keyId.size()) + ")"); } KM_BufferSizeDesc bufSize; @@ -289,15 +477,22 @@ void TrustZoneContext::executeCrypt(tz_command cmd, bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); bufSize.iv_size = static_cast(iv.size()); - bufSize.key_id_size = static_cast(key.size()); + bufSize.key_id_size = static_cast(keyId.size()); uint32_t inMemorySize = KM_CalcBufferSize(bufSize); TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); - // decrypt operation does not require padding memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); - bufSize.out_size = static_cast((cmd == CMD_ENCRYPT) ? - data.size() + CIPHER_EXTRA_PADDING_SIZE : - data.size()); + + // decrypt operation does not require padding + bufSize.out_size = static_cast(data.size()); + if (cmd == CMD_ENCRYPT) { + if (algo == ALGO_RSA) { + // We don't know the key length + bufSize.out_size = MAX_KEY_SIZE.at(ALGO_RSA); + } else { + bufSize.out_size = static_cast(data.size() + CIPHER_EXTRA_PADDING_SIZE); + } + } uint32_t outMemorySize = KM_CalcBufferSize(bufSize); TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT); @@ -328,7 +523,7 @@ void TrustZoneContext::executeCrypt(tz_command cmd, ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret); } - ret = KM_ParamsSerializeKeyId(input, key.data(), key.size()); + ret = KM_ParamsSerializeKeyId(input, keyId.data(), keyId.size()); if (ret) { ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret); } @@ -362,7 +557,7 @@ void TrustZoneContext::executeCrypt(tz_command cmd, memcpy(out.data(), outData->data, outData->data_size); } -void TrustZoneContext::executeEncryptAE(const RawBuffer &key, +void TrustZoneContext::executeEncryptAE(const RawBuffer &keyId, const Pwd &pwd, const RawBuffer &iv, int tagSizeBits, @@ -382,7 +577,7 @@ void TrustZoneContext::executeEncryptAE(const RawBuffer &key, // [0].value.a - return code // [2].memref - output - if (key.size() != KM_KEY_ID_SIZE) { + if (keyId.size() != KM_KEY_ID_SIZE) { ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer"); } @@ -396,7 +591,7 @@ void TrustZoneContext::executeEncryptAE(const RawBuffer &key, bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); bufSize.iv_size = static_cast(iv.size()); - bufSize.key_id_size = static_cast(key.size()); + bufSize.key_id_size = static_cast(keyId.size()); bufSize.with_ae_data = true; bufSize.aad_size = static_cast(aad.size()); uint32_t inMemorySize = KM_CalcBufferSize(bufSize); @@ -435,7 +630,7 @@ void TrustZoneContext::executeEncryptAE(const RawBuffer &key, ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret); } - ret = KM_ParamsSerializeKeyId(input, key.data(), key.size()); + ret = KM_ParamsSerializeKeyId(input, keyId.data(), keyId.size()); if (ret) { ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret); } @@ -484,7 +679,7 @@ void TrustZoneContext::executeEncryptAE(const RawBuffer &key, } } -void TrustZoneContext::executeDecryptAE(const RawBuffer &key, +void TrustZoneContext::executeDecryptAE(const RawBuffer &keyId, const Pwd &pwd, const RawBuffer &iv, int tagSizeBits, @@ -504,7 +699,7 @@ void TrustZoneContext::executeDecryptAE(const RawBuffer &key, // [0].value.a - output size // [2].memref - output (decrypted data) - if (key.size() != KM_KEY_ID_SIZE) { + if (keyId.size() != KM_KEY_ID_SIZE) { ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer"); } @@ -517,7 +712,7 @@ void TrustZoneContext::executeDecryptAE(const RawBuffer &key, bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); bufSize.iv_size = static_cast(iv.size()); - bufSize.key_id_size = static_cast(key.size()); + bufSize.key_id_size = static_cast(keyId.size()); bufSize.with_ae_data = true; bufSize.aad_size = static_cast(aad.size()); bufSize.tag_size = static_cast(tag.size()); @@ -556,7 +751,7 @@ void TrustZoneContext::executeDecryptAE(const RawBuffer &key, ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret); } - ret = KM_ParamsSerializeKeyId(input, key.data(), key.size()); + ret = KM_ParamsSerializeKeyId(input, keyId.data(), keyId.size()); if (ret) { ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret); } @@ -599,6 +794,197 @@ void TrustZoneContext::executeDecryptAE(const RawBuffer &key, memcpy(out.data(), outData->data, outData->data_size); } +void TrustZoneContext::executeSign(tz_algo_type algo, + tz_hash_type hash, + const RawBuffer &keyId, + const Pwd &pwd, + const RawBuffer &message, + RawBuffer &signature) +{ + // command ID = CMD_SIGN (from km_ta_defines.h) + // + // TEEC_Operation layout: + // input params: + // [0].value.a - algorithm type (tz_algo_type) + // [0].value.b - hash type (tz_hash_type) + // [1].memref - reference to serialized buffer: + // KM_ParamsSerializeInputData with data to sign + // KM_ParamsSerializeKeyId with key id + // output params: + // [0].value.a - return code + // [2].memref - reference to serialized buffer: + // KM_ParamsSerializeOutData with signature data + + if (keyId.size() != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = " + + std::to_string(keyId.size()) + ")"); + } + + KM_BufferSizeDesc bufSize; + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.input_size = static_cast(message.size()); + bufSize.with_pwd_data = true; + bufSize.pwd_size = static_cast(pwd.getPassword().size()); + bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); + bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); + bufSize.key_id_size = static_cast(keyId.size()); + uint32_t inMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.out_size = MAX_KEY_SIZE.at(algo); + uint32_t outMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT); + + KM_SymmetricInput* input = nullptr; + int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ sign operations"); + } + + ret = KM_ParamsSerializeInputData(input, message.data(), message.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ sign operation: ", ret); + } + + uint32_t pwdTagSizeBits = pwd.getTag().size() * 8; + ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(), + pwd.getIV().data(), pwd.getIV().size(), + pwd.getTag().data(), pwd.getTag().size(), + Params::DERIVED_KEY_LENGTH_BITS, + Params::DERIVED_KEY_ITERATIONS, + pwdTagSizeBits); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ sign operation: ", ret); + } + + ret = KM_ParamsSerializeKeyId(input, keyId.data(), keyId.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ sign operation: ", ret); + } + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_MEMREF_WHOLE, TEEC_NONE); + op.params[0].value.a = algo; + op.params[0].value.b = hash; + op.params[1].memref.parent = inMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = inMemory.Get()->size; + op.params[2].memref.parent = outMemory.Get(); + op.params[2].memref.offset = 0; + op.params[2].memref.size = outMemory.Get()->size; + Execute(CMD_SIGN, &op); + + KM_SymmetricInput* output = nullptr; + ret = KM_ParamsDeserializationInit(outMemory.Get()->buffer, outMemory.Get()->size, &output); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize output data deserialization: ", ret); + } + + KM_OutData* outData = nullptr; + ret = KM_ParamsDeserializeOutData(output, &outData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret); + } + + signature.resize(outData->data_size); + memcpy(signature.data(), outData->data, outData->data_size); +} + +int TrustZoneContext::executeVerify(tz_algo_type algo, + tz_hash_type hash, + const RawBuffer &keyId, + const Pwd &pwd, + const RawBuffer &message, + const RawBuffer &signature) +{ + // command ID = CMD_VERIFY (from km_ta_defines.h) + // + // TEEC_Operation layout: + // input params: + // [0].value.a - algorithm type (tz_algo_type) + // [0].value.b - hash type (tz_hash_type) + // [1].memref - reference to serialized buffer: + // KM_ParamsSerializeInputData with verify data (signature hidden in Tag data) + // KM_ParamsSerializeKeyId with key id + // output params: + // [0].value.a - return code + + if (keyId.size() != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = " + + std::to_string(keyId.size()) + ")"); + } + + KM_BufferSizeDesc bufSize; + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.input_size = static_cast(message.size()); + bufSize.with_pwd_data = true; + bufSize.pwd_size = static_cast(pwd.getPassword().size()); + bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); + bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); + bufSize.key_id_size = static_cast(keyId.size()); + bufSize.tag_size = static_cast(signature.size()); + uint32_t inMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); + + KM_SymmetricInput* input = nullptr; + int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ sign operations"); + } + + ret = KM_ParamsSerializeInputData(input, message.data(), message.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ sign operation: ", ret); + } + + uint32_t pwdTagSizeBits = pwd.getTag().size() * 8; + ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(), + pwd.getIV().data(), pwd.getIV().size(), + pwd.getTag().data(), pwd.getTag().size(), + Params::DERIVED_KEY_LENGTH_BITS, + Params::DERIVED_KEY_ITERATIONS, + pwdTagSizeBits); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ sign operation: ", ret); + } + + ret = KM_ParamsSerializeKeyId(input, keyId.data(), keyId.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ sign operation: ", ret); + } + + ret = KM_ParamsSerializeTagData(input, signature.data(), signature.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize signature data for TZ sign operation: ", ret); + } + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_NONE, TEEC_NONE); + op.params[0].value.a = algo; + op.params[0].value.b = hash; + op.params[1].memref.parent = inMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = inMemory.Get()->size; + Execute(CMD_VERIFY, &op); + + int opRet = op.params[0].value.a; + switch (opRet) { + case KM_TA_SUCCESS: + return CKM_API_SUCCESS; + case KM_TA_ERROR_SIGNATURE: + LogWarning("Signature verification failed"); + return CKM_API_ERROR_VERIFICATION_FAILED; + default: + assert(false); // This condition should be checked inside Execute() function + ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", opRet); + } +} + void TrustZoneContext::executeDestroy(const RawBuffer &keyId) { // command ID = CMD_DESTROY_KEY (from km_ta_defines.h) @@ -888,14 +1274,15 @@ void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op) } int ta_ret = op->params[0].value.a; - if (ta_ret != KM_TA_SUCCESS) { - switch (ta_ret) { - case KM_TA_ERROR_AUTH_FAILED: - // Authentication cipher failed - notify with proper exception - ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed"); - default: - ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret); - } + switch (ta_ret) { + case KM_TA_SUCCESS: + case KM_TA_ERROR_SIGNATURE: + break; + case KM_TA_ERROR_AUTH_FAILED: + // Authentication cipher failed - notify with proper exception + ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed"); + default: + ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret); } } diff --git a/src/manager/crypto/tz-backend/tz-context.h b/src/manager/crypto/tz-backend/tz-context.h index 123c21e..05c336e 100644 --- a/src/manager/crypto/tz-backend/tz-context.h +++ b/src/manager/crypto/tz-backend/tz-context.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2019 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. @@ -27,6 +27,7 @@ #include #include #include +#include namespace CKM { namespace Crypto { @@ -48,6 +49,28 @@ public: const uint32_t pwdKeySizeBits, RawBuffer &keyId, RawBuffer &pwdTag); + void generateRSAKey(uint32_t keySizeBits, + const RawBuffer &pubPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwd, + const RawBuffer &privPwdIv, + RawBuffer &pubKeyId, + RawBuffer &pubKeyTag, + RawBuffer &privKeyId, + RawBuffer &privKeyTag); + void generateDSAKey(uint32_t keySizeBits, + const RawBuffer &prime, + const RawBuffer &subprime, + const RawBuffer &base, + const RawBuffer &pubPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwd, + const RawBuffer &privPwdIv, + RawBuffer &pubKeyId, + RawBuffer &pubKeyTag, + RawBuffer &privKeyId, + RawBuffer &privKeyTag); + void importData(uint32_t dataType, const RawBuffer &data, const Crypto::EncryptionParams &encData, @@ -60,13 +83,13 @@ public: void executeCrypt(tz_command cmd, tz_algo_type algo, - const RawBuffer &key, + const RawBuffer &keyId, const Pwd &pwd, const RawBuffer &iv, const RawBuffer &data, RawBuffer &out); - void executeEncryptAE(const RawBuffer &key, + void executeEncryptAE(const RawBuffer &keyId, const Pwd &pwd, const RawBuffer &iv, int tagSizeBits, @@ -74,7 +97,7 @@ public: const RawBuffer &data, RawBuffer &out, RawBuffer &tag); - void executeDecryptAE(const RawBuffer &key, + void executeDecryptAE(const RawBuffer &keyId, const Pwd &pwd, const RawBuffer &iv, int tagSizeBits, @@ -83,6 +106,19 @@ public: const RawBuffer &data, RawBuffer &out); + void executeSign(tz_algo_type algo, + tz_hash_type hash, + const RawBuffer &keyId, + const Pwd &pwd, + const RawBuffer &message, + RawBuffer &signature); + int executeVerify(tz_algo_type algo, + tz_hash_type hash, + const RawBuffer &keyId, + const Pwd &pwd, + const RawBuffer &message, + const RawBuffer &signature); + void executeDestroy(const RawBuffer &keyId); void getData(const RawBuffer &dataId, @@ -105,6 +141,18 @@ private: void Execute(tz_command commandID, TEEC_Operation* op); + void GenerateAKey(tz_command commandID, + TZSerializer &sIn, + uint32_t keySizeBits, + const RawBuffer &pubPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwd, + const RawBuffer &privPwdIv, + RawBuffer &pubKeyId, + RawBuffer &pubKeyTag, + RawBuffer &privKeyId, + RawBuffer &privKeyTag); + TEEC_Context m_Context; TEEC_Session m_Session; -- 2.7.4 From 6a9b2661d5ebf635c46200632873cccfb154dae8 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Thu, 21 Mar 2019 15:21:02 +0100 Subject: [PATCH 11/16] Be prepared for no data from TA Deserialization may return an empty buffer with no error. Adjust code to handle that case. Change-Id: Ife80b4d35914eda700798e0515812b3b638e735e --- src/manager/crypto/tz-backend/tz-context.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/manager/crypto/tz-backend/tz-context.cpp b/src/manager/crypto/tz-backend/tz-context.cpp index 0b54bb4..eb42ff4 100644 --- a/src/manager/crypto/tz-backend/tz-context.cpp +++ b/src/manager/crypto/tz-backend/tz-context.cpp @@ -553,8 +553,11 @@ void TrustZoneContext::executeCrypt(tz_command cmd, } // data_size should contain how much memory we actually took for our cipher operation - out.resize(outData->data_size); - memcpy(out.data(), outData->data, outData->data_size); + out.clear(); + if (outData) { + out.resize(outData->data_size); + memcpy(out.data(), outData->data, outData->data_size); + } } void TrustZoneContext::executeEncryptAE(const RawBuffer &keyId, @@ -670,10 +673,14 @@ void TrustZoneContext::executeEncryptAE(const RawBuffer &keyId, ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize tag data: ", ret); } - out.resize(outData->data_size); - memcpy(out.data(), outData->data, outData->data_size); + out.clear(); + if (outData) { + out.resize(outData->data_size); + memcpy(out.data(), outData->data, outData->data_size); + } - if (tagData->data_size) { + tag.clear(); + if (tagData && tagData->data_size) { tag.resize(tagData->data_size); memcpy(tag.data(), tagData->data, tagData->data_size); } @@ -790,8 +797,11 @@ void TrustZoneContext::executeDecryptAE(const RawBuffer &keyId, ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret); } - out.resize(outData->data_size); - memcpy(out.data(), outData->data, outData->data_size); + out.clear(); + if (outData) { + out.resize(outData->data_size); + memcpy(out.data(), outData->data, outData->data_size); + } } void TrustZoneContext::executeSign(tz_algo_type algo, @@ -885,7 +895,7 @@ void TrustZoneContext::executeSign(tz_algo_type algo, KM_OutData* outData = nullptr; ret = KM_ParamsDeserializeOutData(output, &outData); - if (ret) { + if (ret || !outData || outData->data_size == 0) { ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret); } -- 2.7.4 From 0be32159737cb86cdc1a319d752cfdaa58b872f3 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Fri, 5 Apr 2019 11:44:10 +0200 Subject: [PATCH 12/16] Setup verification algorithm if not provided Verification API has no knowledge about the algorithm type. It has to be derived from the key type. Change-Id: I2e0d094372e4bf8c28275544204e431c4023e391 --- src/manager/crypto/tz-backend/obj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/manager/crypto/tz-backend/obj.cpp b/src/manager/crypto/tz-backend/obj.cpp index 81aabaa..351f24e 100644 --- a/src/manager/crypto/tz-backend/obj.cpp +++ b/src/manager/crypto/tz-backend/obj.cpp @@ -85,7 +85,7 @@ int AKey::verify(const CryptoAlgorithm &alg, const RawBuffer &message, // setup algorithm type basing on key type if it doesn't exist if (!algWithType.getParam(ParamName::ALGO_TYPE, type)) { - ThrowErr(Exc::Crypto::InputParam, "Invalid key type: ", "not given"); + algWithType.setParam(ParamName::ALGO_TYPE, key2algo(m_type)); } return Internals::verify(getBinary(), getPassword(), algWithType, message, sign); -- 2.7.4 From 79141629106d3097f8a4013d3744cef046265a3e Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Wed, 15 May 2019 17:46:58 +0200 Subject: [PATCH 13/16] Forbid HashAlgorithm::NONE for DSA & ECDSA signatures Openssl uses SHA1 if no hash algorithm is provided for DSA & ECDSA signatures. TZ does not support that option at all. It's better to forbid it. This commit changes the API behavior and may lead to errors in clients that used HashAlgorithm::NONE with DSA or ECDSA which is highly unlikely. Change-Id: I8522e8f157b5ef2d6599bb672ef790ee8ea48644 --- src/include/ckmc/ckmc-manager.h | 4 ++-- src/manager/crypto/sw-backend/internals.cpp | 8 +++++++- src/manager/crypto/tz-backend/internals.cpp | 6 ++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/include/ckmc/ckmc-manager.h b/src/include/ckmc/ckmc-manager.h index 22a295c..251052c 100644 --- a/src/include/ckmc/ckmc-manager.h +++ b/src/include/ckmc/ckmc-manager.h @@ -607,7 +607,7 @@ int ckmc_create_key_aes(size_t size, const char *key_alias, ckmc_policy_s key_po * @param[in] private_key_alias The name of private key * @param[in] password The password used in decrypting a private key value * @param[in] message The message that is signed with a private key - * @param[in] hash The hash algorithm used in creating signature + * @param[in] hash The hash algorithm used in creating signature. CKMC_HASH_NONE is invalid for DSA & ECDSA * @param[in] padding The RSA padding algorithm used in creating signature \n * It is used only when the signature algorithm is RSA. If * @a padding is CKMC_NONE_PADDING you must use CKMC_HASH_NONE @@ -643,7 +643,7 @@ int ckmc_create_signature(const char *private_key_alias, const char *password, c * @param[in] password The password used in decrypting a public key value * @param[in] message The input on which the signature is created * @param[in] signature The signature that is verified with public key - * @param[in] hash The hash algorithm used in verifying signature + * @param[in] hash The hash algorithm used in verifying signature. CKMC_HASH_NONE is invalid for DSA & ECDSA * @param[in] padding The RSA padding algorithm used in verifying signature \n * It is used only when the signature algorithm is RSA. If * @a padding is CKMC_NONE_PADDING you must use CKMC_HASH_NONE diff --git a/src/manager/crypto/sw-backend/internals.cpp b/src/manager/crypto/sw-backend/internals.cpp index afa3c88..a5f2f9e 100644 --- a/src/manager/crypto/sw-backend/internals.cpp +++ b/src/manager/crypto/sw-backend/internals.cpp @@ -817,6 +817,9 @@ RawBuffer signMessage(EVP_PKEY *privKey, const RawBuffer &message, const int rsa_padding) { + if (EVP_PKEY_type(privKey->type) != EVP_PKEY_RSA) + ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option"); + EvpPkeyCtxUPtr pctx(EVP_PKEY_CTX_new(privKey, NULL), EVP_PKEY_CTX_free); if (!pctx.get()) @@ -931,6 +934,9 @@ int verifyMessage(EVP_PKEY *pubKey, const RawBuffer &signature, const int rsa_padding) { + if (EVP_PKEY_type(pubKey->type) != EVP_PKEY_RSA) + ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option"); + EvpPkeyCtxUPtr pctx(EVP_PKEY_CTX_new(pubKey, NULL), EVP_PKEY_CTX_free); if (!pctx.get()) @@ -1048,4 +1054,4 @@ bool verifyBinaryData(DataType dataType, const RawBuffer &buffer) } // namespace Internals } // namespace SW } // namespace Crypto -} // namespace CKM \ No newline at end of file +} // namespace CKM diff --git a/src/manager/crypto/tz-backend/internals.cpp b/src/manager/crypto/tz-backend/internals.cpp index 7b7b9be..8aee58a 100644 --- a/src/manager/crypto/tz-backend/internals.cpp +++ b/src/manager/crypto/tz-backend/internals.cpp @@ -533,6 +533,9 @@ RawBuffer sign(const RawBuffer &pkey, { AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); HashAlgorithm hash = unpack(alg, ParamName::SV_HASH_ALGO); + if (algo != AlgoType::RSA_SV && hash == HashAlgorithm::NONE) + ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option"); + RawBuffer signature; TrustZoneContext::Instance().executeSign(getAlgType(algo), getHashType(hash), @@ -551,6 +554,9 @@ int verify(const RawBuffer &pkey, { AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); HashAlgorithm hash = unpack(alg, ParamName::SV_HASH_ALGO); + if (algo != AlgoType::RSA_SV && hash == HashAlgorithm::NONE) + ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option"); + return TrustZoneContext::Instance().executeVerify(getAlgType(algo), getHashType(hash), pkey, -- 2.7.4 From e709b9380f0308576372e37faea4d7e7db0bb4b0 Mon Sep 17 00:00:00 2001 From: Tomasz Swierczek Date: Mon, 20 May 2019 11:08:27 +0200 Subject: [PATCH 14/16] Release 0.1.30 * Forbid HashAlgorithm::NONE for DSA & ECDSA signatures * Setup verification algorithm if not provided * Be prepared for no data from TA * tz-backend: Implement asymmetric operations * tz-backend: Add serialization wrapper * decider: Allow multiple policies for more complex logic Change-Id: Ie09953ce89557b32fe036855f65329b1ed307996 --- packaging/key-manager.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/key-manager.spec b/packaging/key-manager.spec index 089cfe3..95e55e1 100644 --- a/packaging/key-manager.spec +++ b/packaging/key-manager.spec @@ -5,7 +5,7 @@ Name: key-manager Summary: Central Key Manager and utilities -Version: 0.1.29 +Version: 0.1.30 Release: 1 Group: Security/Secure Storage License: Apache-2.0 and BSD-3-Clause -- 2.7.4 From c81121cb5e889379efa46e61b68d4af8bba229fa Mon Sep 17 00:00:00 2001 From: Tomasz Swierczek Date: Tue, 4 Jun 2019 08:55:09 +0200 Subject: [PATCH 15/16] Add minor fixes for listing aliases from db * update list out pointer to null if there are no aliases to list This is in accordance to official header documentation; in such case, the code returns CKMC_ERROR_DB_ALIAS_UNKNOWN but also the list should be properly null'ed. Change-Id: I2861e67ae80fe0ce73b0e2e180aba393f66e255c --- src/manager/client-capi/ckmc-manager.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/manager/client-capi/ckmc-manager.cpp b/src/manager/client-capi/ckmc-manager.cpp index a765f3a..970fed5 100644 --- a/src/manager/client-capi/ckmc-manager.cpp +++ b/src/manager/client-capi/ckmc-manager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 - 2019 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000-2019 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. @@ -213,8 +213,10 @@ int _toNewCkmcAliasInfoList(const CKM::AliasPwdVector &aliasPwdVector, if (alias_info_list == nullptr) return CKMC_ERROR_UNKNOWN; - if (aliasPwdVector.size() == 0) + if (aliasPwdVector.size() == 0) { + *alias_info_list = nullptr; // according to documentation from header return CKMC_ERROR_DB_ALIAS_UNKNOWN; + } ckmc_alias_info_list_s *start = nullptr; ckmc_alias_info_list_s *plist = nullptr; @@ -387,11 +389,11 @@ int ckmc_get_key_alias_list(ckmc_alias_list_s **alias_list) start = plist; } + *alias_list = start; // according to documentation in header + if (plist == nullptr) // if the alias_list size is zero return CKMC_ERROR_DB_ALIAS_UNKNOWN; - *alias_list = start; - return CKMC_ERROR_NONE; EXCEPTION_GUARD_END @@ -490,11 +492,11 @@ int ckmc_get_cert_alias_list(ckmc_alias_list_s **alias_list) start = plist; } + *alias_list = start; // according to documentation from header + if (plist == nullptr) // if the alias_list size is zero return CKMC_ERROR_DB_ALIAS_UNKNOWN; - *alias_list = start; - return CKMC_ERROR_NONE; EXCEPTION_GUARD_END @@ -687,11 +689,11 @@ int ckmc_get_data_alias_list(ckmc_alias_list_s **alias_list) start = plist; } + *alias_list = start; // according to documentation in header + if (plist == nullptr) // if the alias_list size is zero return CKMC_ERROR_DB_ALIAS_UNKNOWN; - *alias_list = start; - return CKMC_ERROR_NONE; EXCEPTION_GUARD_END -- 2.7.4 From 1b8ae67fb712354857570d0aa3c8f02e92c4f041 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Fri, 23 Feb 2018 13:04:02 +0100 Subject: [PATCH 16/16] Adapt key-manager to work with OpenSSL 1.1 preserving 1.0 compatibility Change-Id: Ia62003a44d3dcb6d8c076706387e88399bf6cfb1 --- src/manager/client-capi/ckmc-type.cpp | 2 +- src/manager/common/crypto-init.cpp | 53 ++++++++++++++++---------- src/manager/common/key-impl.cpp | 6 +-- src/manager/common/openssl-error-handler.cpp | 6 +++ src/manager/common/pkcs12-impl.cpp | 5 +-- src/manager/crypto/sw-backend/internals.cpp | 32 +++++++++++----- src/manager/crypto/sw-backend/obj.cpp | 4 +- src/manager/service/certificate-store.cpp | 4 +- src/manager/service/ss-crypto.cpp | 5 ++- src/manager/sqlcipher/sqlcipher.c | 57 ++++++++++++++++++++-------- 10 files changed, 116 insertions(+), 58 deletions(-) diff --git a/src/manager/client-capi/ckmc-type.cpp b/src/manager/client-capi/ckmc-type.cpp index 6567c97..3b03f12 100644 --- a/src/manager/client-capi/ckmc-type.cpp +++ b/src/manager/client-capi/ckmc-type.cpp @@ -414,7 +414,7 @@ int ckmc_load_from_pkcs12_file(const char *file_path, const char *passphrase, output.resize(size); - int type = EVP_PKEY_type(pkey->type); + int type = EVP_PKEY_type(EVP_PKEY_id(pkey)); ckmc_key_type_e key_type = CKMC_KEY_NONE; switch (type) { diff --git a/src/manager/common/crypto-init.cpp b/src/manager/common/crypto-init.cpp index 573a4d6..7fa6671 100644 --- a/src/manager/common/crypto-init.cpp +++ b/src/manager/common/crypto-init.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2019 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. @@ -43,6 +43,25 @@ const char *DEV_HW_RANDOM_FILE = "/dev/hwrng"; const char *DEV_URANDOM_FILE = "/dev/urandom"; const size_t RANDOM_BUFFER_LEN = 32; +void initializeEntropy() // entropy sources - /dev/random,/dev/urandom(Default) +{ + int ret = 0; + + std::ifstream ifile(DEV_HW_RANDOM_FILE); + + if (ifile.is_open()) + ret = RAND_load_file(DEV_HW_RANDOM_FILE, RANDOM_BUFFER_LEN); + + if (ret != RANDOM_BUFFER_LEN) { + LogWarning("Error in HW_RAND file load"); + ret = RAND_load_file(DEV_URANDOM_FILE, RANDOM_BUFFER_LEN); + + if (ret != RANDOM_BUFFER_LEN) + LogError("Error in U_RAND_file_load"); + } +} + +#if OPENSSL_VERSION_NUMBER < 0x10100000L std::mutex *g_mutexes = NULL; void lockingCallback(int mode, int type, const char *, int) @@ -94,24 +113,7 @@ void initOpenSsl(bool isLib) // below initializes only for executable client. (key-manager daemon) - /* - * Initialize entropy - * entropy sources - /dev/random,/dev/urandom(Default) - */ - int ret = 0; - - std::ifstream ifile(DEV_HW_RANDOM_FILE); - - if (ifile.is_open()) - ret = RAND_load_file(DEV_HW_RANDOM_FILE, RANDOM_BUFFER_LEN); - - if (ret != RANDOM_BUFFER_LEN) { - LogWarning("Error in HW_RAND file load"); - ret = RAND_load_file(DEV_URANDOM_FILE, RANDOM_BUFFER_LEN); - - if (ret != RANDOM_BUFFER_LEN) - LogError("Error in U_RAND_file_load"); - } + initializeEntropy(); /* * Initialize libssl (OCSP uses it) @@ -162,9 +164,10 @@ void initOpenSslAndDetach() initFn.store(&initEmpty, std::memory_order_release); } } - +#endif } // namespace anonymous +#if OPENSSL_VERSION_NUMBER < 0x10100000L void initOpenSsl() { initOpenSsl(false); @@ -193,5 +196,15 @@ void initOpenSslOnce() */ initFn.load(std::memory_order_acquire)(); } +#else +void initOpenSsl() +{ + initializeEntropy(); +} + +void deinitOpenSsl() {} +void deinitOpenSslThread() {} +void initOpenSslOnce() {} +#endif } // namespace CKM diff --git a/src/manager/common/key-impl.cpp b/src/manager/common/key-impl.cpp index 2a12818..63c4be5 100644 --- a/src/manager/common/key-impl.cpp +++ b/src/manager/common/key-impl.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved +/* Copyright (c) 2000 - 2019 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. @@ -145,7 +145,7 @@ KeyImpl::KeyImpl(const RawBuffer &buf, const Password &password) : m_pkey.reset(pkey, EVP_PKEY_free); - switch (EVP_PKEY_type(pkey->type)) { + switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) { case EVP_PKEY_RSA: m_type = isPrivate ? KeyType::KEY_RSA_PRIVATE : KeyType::KEY_RSA_PUBLIC; break; @@ -193,7 +193,7 @@ KeyImpl::KeyImpl(EvpShPtr pkey, KeyType type) : m_pkey(pkey), m_type(type) } // verify if actual key type matches the expected tpe - int given_key_type = EVP_PKEY_type(pkey->type); + int given_key_type = EVP_PKEY_type(EVP_PKEY_id(pkey.get())); if (given_key_type == EVP_PKEY_NONE || expected_type != given_key_type) { m_pkey.reset(); diff --git a/src/manager/common/openssl-error-handler.cpp b/src/manager/common/openssl-error-handler.cpp index e8649c1..a43e094 100644 --- a/src/manager/common/openssl-error-handler.cpp +++ b/src/manager/common/openssl-error-handler.cpp @@ -90,6 +90,10 @@ void errorHandle(const char *file, int line, const char *function, int openssl_r #if OPENSSL_VERSION_NUMBER > 0x10100000L case ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_OSSL_PRIVATE_DECRYPT, RSA_R_DATA_GREATER_THAN_MOD_LEN): case ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_OSSL_PUBLIC_DECRYPT, RSA_R_DATA_GREATER_THAN_MOD_LEN): + case ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_OSSL_PUBLIC_ENCRYPT, RSA_R_DATA_TOO_LARGE_FOR_MODULUS): + case ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_OSSL_PUBLIC_DECRYPT, RSA_R_DATA_TOO_LARGE_FOR_MODULUS): + case ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_DATA_TOO_LARGE_FOR_MODULUS): + case ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_OSSL_PRIVATE_DECRYPT, RSA_R_DATA_TOO_LARGE_FOR_MODULUS): #else /* OPENSSL_VERSION_NUMBER > 0x10100000L */ case ERR_PACK(ERR_LIB_RSA, RSA_F_PKEY_RSA_CTRL, RSA_R_INVALID_KEYBITS): case ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_EAY_PRIVATE_DECRYPT, RSA_R_DATA_TOO_LARGE_FOR_MODULUS): @@ -122,8 +126,10 @@ void errorHandle(const char *file, int line, const char *function, int openssl_r case ERR_PACK(ERR_LIB_X509, X509_F_X509_VERIFY_CERT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED): case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_VERIFY, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE): case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_VERIFY, EVP_R_OPERATON_NOT_INITIALIZED): +#if OPENSSL_VERSION_NUMBER < 0x10100000L case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_VERIFYFINAL, EVP_R_WRONG_PUBLIC_KEY_TYPE): case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_VERIFYFINAL, EVP_R_NO_VERIFY_FUNCTION_CONFIGURED): +#endif ret = CKM_API_ERROR_VERIFICATION_FAILED; break; } diff --git a/src/manager/common/pkcs12-impl.cpp b/src/manager/common/pkcs12-impl.cpp index c53a377..100e9b5 100644 --- a/src/manager/common/pkcs12-impl.cpp +++ b/src/manager/common/pkcs12-impl.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2014 Samsung Electronics Co. +/* Copyright (c) 2014 - 2019 Samsung Electronics Co. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -87,7 +87,7 @@ PKCS12Impl::PKCS12Impl(const RawBuffer &buffer, const Password &password) if (pkey) { KeyImpl::EvpShPtr ptr(pkey, EVP_PKEY_free); - switch (EVP_PKEY_type(pkey->type)) { + switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) { case EVP_PKEY_RSA: m_pkey = std::make_shared(ptr, KeyType::KEY_RSA_PRIVATE); break; @@ -189,4 +189,3 @@ PKCS12ShPtr PKCS12::create(const RawBuffer &rawBuffer, const Password &password) } } // namespace CKM - diff --git a/src/manager/crypto/sw-backend/internals.cpp b/src/manager/crypto/sw-backend/internals.cpp index a5f2f9e..a0f0239 100644 --- a/src/manager/crypto/sw-backend/internals.cpp +++ b/src/manager/crypto/sw-backend/internals.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2019 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. @@ -817,7 +817,7 @@ RawBuffer signMessage(EVP_PKEY *privKey, const RawBuffer &message, const int rsa_padding) { - if (EVP_PKEY_type(privKey->type) != EVP_PKEY_RSA) + if (EVP_PKEY_type(EVP_PKEY_id(privKey)) != EVP_PKEY_RSA) ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option"); EvpPkeyCtxUPtr pctx(EVP_PKEY_CTX_new(privKey, NULL), EVP_PKEY_CTX_free); @@ -828,7 +828,7 @@ RawBuffer signMessage(EVP_PKEY *privKey, OPENSSL_ERROR_HANDLE(EVP_PKEY_sign_init(pctx.get())); /* Set padding algorithm */ - if (EVP_PKEY_type(privKey->type) == EVP_PKEY_RSA) + if (EVP_PKEY_type(EVP_PKEY_id(privKey)) == EVP_PKEY_RSA) OPENSSL_ERROR_HANDLE(EVP_PKEY_CTX_set_rsa_padding(pctx.get(), rsa_padding)); /* Finalize the Sign operation */ @@ -853,18 +853,23 @@ RawBuffer digestSignMessage(EVP_PKEY *privKey, const EVP_MD *md_algo, const int rsa_padding) { - EvpMdCtxUPtr mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy); - EVP_PKEY_CTX *pctx = NULL; // Create the Message Digest Context +#if OPENSSL_VERSION_NUMBER < 0x10100000L + EvpMdCtxUPtr mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy); if (!mdctx.get()) ThrowErr(Exc::Crypto::InternalError, "Error in EVP_MD_CTX_create function"); +#else + EvpMdCtxUPtr mdctx(EVP_MD_CTX_new(), EVP_MD_CTX_free); + if (!mdctx.get()) + ThrowErr(Exc::Crypto::InternalError, "Error in EVP_MD_CTX_new function"); +#endif OPENSSL_ERROR_HANDLE(EVP_DigestSignInit(mdctx.get(), &pctx, md_algo, NULL, privKey)); /* Set padding algorithm */ - if (EVP_PKEY_type(privKey->type) == EVP_PKEY_RSA) + if (EVP_PKEY_type(EVP_PKEY_id(privKey)) == EVP_PKEY_RSA) OPENSSL_ERROR_HANDLE(EVP_PKEY_CTX_set_rsa_padding(pctx, rsa_padding)); /* Call update with the message */ @@ -934,7 +939,7 @@ int verifyMessage(EVP_PKEY *pubKey, const RawBuffer &signature, const int rsa_padding) { - if (EVP_PKEY_type(pubKey->type) != EVP_PKEY_RSA) + if (EVP_PKEY_type(EVP_PKEY_id(pubKey)) != EVP_PKEY_RSA) ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option"); EvpPkeyCtxUPtr pctx(EVP_PKEY_CTX_new(pubKey, NULL), EVP_PKEY_CTX_free); @@ -945,7 +950,7 @@ int verifyMessage(EVP_PKEY *pubKey, OPENSSL_ERROR_HANDLE(EVP_PKEY_verify_init(pctx.get())); /* Set padding algorithm */ - if (EVP_PKEY_type(pubKey->type) == EVP_PKEY_RSA) + if (EVP_PKEY_type(EVP_PKEY_id(pubKey)) == EVP_PKEY_RSA) OPENSSL_ERROR_HANDLE(EVP_PKEY_CTX_set_rsa_padding(pctx.get(), rsa_padding)); if (OPENSSL_SUCCESS == EVP_PKEY_verify(pctx.get(), signature.data(), @@ -962,15 +967,22 @@ int digestVerifyMessage(EVP_PKEY *pubKey, const EVP_MD *md_algo, const int rsa_padding) { - EvpMdCtxUPtr mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy); EVP_PKEY_CTX *pctx = NULL; + // Create the Message Digest Context +#if OPENSSL_VERSION_NUMBER < 0x10100000L + EvpMdCtxUPtr mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy); if (!mdctx.get()) ThrowErr(Exc::Crypto::InternalError, "Error in EVP_MD_CTX_create function"); +#else + EvpMdCtxUPtr mdctx(EVP_MD_CTX_new(), EVP_MD_CTX_free); + if (!mdctx.get()) + ThrowErr(Exc::Crypto::InternalError, "Error in EVP_MD_CTX_new function"); +#endif OPENSSL_ERROR_HANDLE(EVP_DigestVerifyInit(mdctx.get(), &pctx, md_algo, NULL, pubKey)); - if (EVP_PKEY_type(pubKey->type) == EVP_PKEY_RSA) + if (EVP_PKEY_type(EVP_PKEY_id(pubKey)) == EVP_PKEY_RSA) OPENSSL_ERROR_HANDLE(EVP_PKEY_CTX_set_rsa_padding(pctx, rsa_padding)); OPENSSL_ERROR_HANDLE(EVP_DigestVerifyUpdate(mdctx.get(), message.data(), message.size())); diff --git a/src/manager/crypto/sw-backend/obj.cpp b/src/manager/crypto/sw-backend/obj.cpp index a7a7cdc..f5bb466 100644 --- a/src/manager/crypto/sw-backend/obj.cpp +++ b/src/manager/crypto/sw-backend/obj.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2000 - 2019 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. @@ -87,7 +87,7 @@ int AKey::verify(const CryptoAlgorithm &alg, const RawBuffer &message, // setup algorithm type basing on evp key type if it doesn't exist if (!algWithType.getParam(ParamName::ALGO_TYPE, type)) { - int subType = EVP_PKEY_type(evp->type); + int subType = EVP_PKEY_type(EVP_PKEY_id(evp)); switch (subType) { case EVP_PKEY_RSA: diff --git a/src/manager/service/certificate-store.cpp b/src/manager/service/certificate-store.cpp index 871b8a9..195316b 100644 --- a/src/manager/service/certificate-store.cpp +++ b/src/manager/service/certificate-store.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved +/* Copyright (c) 2000 - 2019 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. @@ -103,7 +103,7 @@ int CertificateStore::verifyCertificate( } if (stateCCMode) - X509_VERIFY_PARAM_set_flags(csc->param, X509_V_FLAG_X509_STRICT); + X509_VERIFY_PARAM_set_flags(X509_STORE_CTX_get0_param(csc.get()), X509_V_FLAG_X509_STRICT); int result = X509_verify_cert(csc.get()); // 1 == ok; 0 == fail; -1 == error diff --git a/src/manager/service/ss-crypto.cpp b/src/manager/service/ss-crypto.cpp index 1e79b48..f6a2de2 100644 --- a/src/manager/service/ss-crypto.cpp +++ b/src/manager/service/ss-crypto.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 - 2019 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. @@ -81,7 +81,8 @@ RawBuffer _get_iv(const RawBuffer &src) RawBuffer _decrypt(const RawBuffer &key, const RawBuffer &iv, const RawBuffer &ciphertext) { auto algo = ::EVP_aes_128_cbc(); - int tmp_len = (ciphertext.size() / algo->block_size + 1) * algo->block_size; + auto block_size = ::EVP_CIPHER_block_size(algo); + int tmp_len = (ciphertext.size() / block_size + 1) * block_size; if (key.size() != KEY_SIZE) { LogError("Invalid key size: " << key.size() << ", expected: " << KEY_SIZE); diff --git a/src/manager/sqlcipher/sqlcipher.c b/src/manager/sqlcipher/sqlcipher.c index c881d32..cad24d8 100644 --- a/src/manager/sqlcipher/sqlcipher.c +++ b/src/manager/sqlcipher/sqlcipher.c @@ -13193,8 +13193,8 @@ SQLCIPHER_PRIVATE void sqlcipher3CodecGetKey(sqlcipher3* db, int nDb, void **zKe typedef struct { int derive_key; EVP_CIPHER *evp_cipher; - EVP_CIPHER_CTX ectx; - HMAC_CTX hctx; + EVP_CIPHER_CTX *ectx; + HMAC_CTX *hctx; int kdf_iter; int fast_kdf_iter; int key_sz; @@ -13598,18 +13598,43 @@ void sqlcipher_codec_ctx_free(codec_ctx **iCtx) { sqlcipher_free(ctx, sizeof(codec_ctx)); } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static HMAC_CTX *HMAC_CTX_new(void) +{ + HMAC_CTX *ctx = OPENSSL_malloc(sizeof(*ctx)); + if (ctx != NULL) { + HMAC_CTX_init(ctx); + } + return ctx; +} + +// Per 1.1.0 (https://wiki.openssl.org/index.php/1.1_API_Changes) +// HMAC_CTX_free should call HMAC_CTX_cleanup, then EVP_MD_CTX_Cleanup. +// HMAC_CTX_cleanup internally calls EVP_MD_CTX_cleanup so these +// calls are not needed. +static void HMAC_CTX_free(HMAC_CTX *ctx) +{ + if (ctx != NULL) { + HMAC_CTX_cleanup(ctx); + OPENSSL_free(ctx); + } +} +#endif + int sqlcipher_page_hmac(cipher_ctx *ctx, Pgno pgno, unsigned char *in, int in_sz, unsigned char *out) { - HMAC_CTX_init(&ctx->hctx); - - HMAC_Init_ex(&ctx->hctx, ctx->hmac_key, ctx->key_sz, EVP_sha1(), NULL); + ctx->hctx = HMAC_CTX_new(); + if(ctx->hctx == NULL) return SQLCIPHER_NOMEM; + + HMAC_Init_ex(ctx->hctx, ctx->hmac_key, ctx->key_sz, EVP_sha1(), NULL); /* include the encrypted page data, initialization vector, and page number in HMAC. This will prevent both tampering with the ciphertext, manipulation of the IV, or resequencing otherwise valid pages out of order in a database */ - HMAC_Update(&ctx->hctx, in, in_sz); - HMAC_Update(&ctx->hctx, (const unsigned char*) &pgno, sizeof(Pgno)); - HMAC_Final(&ctx->hctx, out, NULL); - HMAC_CTX_cleanup(&ctx->hctx); + HMAC_Update(ctx->hctx, in, in_sz); + HMAC_Update(ctx->hctx, (const unsigned char*) &pgno, sizeof(Pgno)); + HMAC_Final(ctx->hctx, out, NULL); + HMAC_CTX_free(ctx->hctx); return SQLCIPHER_OK; } @@ -13671,15 +13696,17 @@ int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int } } - EVP_CipherInit(&c_ctx->ectx, c_ctx->evp_cipher, NULL, NULL, mode); - EVP_CIPHER_CTX_set_padding(&c_ctx->ectx, 0); - EVP_CipherInit(&c_ctx->ectx, NULL, c_ctx->key, iv_out, mode); - EVP_CipherUpdate(&c_ctx->ectx, out, &tmp_csz, in, size); + c_ctx->ectx = EVP_CIPHER_CTX_new(); + if(c_ctx->ectx == NULL) return SQLCIPHER_NOMEM; + EVP_CipherInit(c_ctx->ectx, c_ctx->evp_cipher, NULL, NULL, mode); + EVP_CIPHER_CTX_set_padding(c_ctx->ectx, 0); + EVP_CipherInit(c_ctx->ectx, NULL, c_ctx->key, iv_out, mode); + EVP_CipherUpdate(c_ctx->ectx, out, &tmp_csz, in, size); csz = tmp_csz; out += tmp_csz; - EVP_CipherFinal(&c_ctx->ectx, out, &tmp_csz); + EVP_CipherFinal(c_ctx->ectx, out, &tmp_csz); csz += tmp_csz; - EVP_CIPHER_CTX_cleanup(&c_ctx->ectx); + EVP_CIPHER_CTX_free(c_ctx->ectx); assert(size == csz); if(c_ctx->use_hmac && (mode == CIPHER_ENCRYPT)) { -- 2.7.4