--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#include <string>
+#include <vector>
+#include <unordered_map>
+
+#include <dpl/test/test_runner.h>
+#include <ckm-common.h>
+#include <ckmc/ckmc-manager.h>
+#include <ckmc/ckmc-control.h>
+
+namespace {
+
+const char* PASSWORD = "test-password";
+const uid_t UID = 5001;
+
+struct KeyAliasPair
+{
+ std::string prv;
+ std::string pub;
+};
+
+const KeyAliasPair OURS = { "our_ec_private", "our_ec_public" };
+const KeyAliasPair PEERS = { "peer_ec_private", "peer_ec_public" };
+const KeyAliasPair PEERS2 = { "peer2_ec_private", "peer2_ec_public" };
+const KeyAliasPair WRONG = { "wrong_ec_private", "wrong_ec_public" };
+const KeyAliasPair RSA = { "rsa_private", "rsa_public" };
+const std::string DERIVED = "derived";
+
+const ckmc_policy_s UNEXPORTABLE { nullptr, false };
+const ckmc_policy_s EXPORTABLE { nullptr, true };
+const ckmc_policy_s UNEXPORTABLE_PW { const_cast<char*>(PASSWORD), false };
+const ckmc_policy_s EXPORTABLE_PW { const_cast<char*>(PASSWORD), true };
+
+class EcdhGroupFixture: public DPL::Test::TestGroup
+{
+private:
+ void GenerateEC(ckmc_ec_type_e curve,
+ const KeyAliasPair& pair,
+ const ckmc_policy_s& policy_prv,
+ const ckmc_policy_s& policy_pub)
+ {
+ assert_positive(ckmc_create_key_pair_ecdsa,
+ curve,
+ pair.prv.c_str(),
+ pair.pub.c_str(),
+ policy_prv,
+ policy_pub);
+ }
+
+public:
+ void Init() override
+ {
+ remove_user_data(UID);
+ assert_positive(ckmc_unlock_user_key, UID, "db-pass");
+
+ GenerateEC(CKMC_EC_PRIME256V1, OURS, UNEXPORTABLE, EXPORTABLE);
+ GenerateEC(CKMC_EC_PRIME256V1, PEERS, UNEXPORTABLE_PW, EXPORTABLE);
+ GenerateEC(CKMC_EC_PRIME256V1, PEERS2, EXPORTABLE, EXPORTABLE);
+ GenerateEC(CKMC_EC_PRIME192V1, WRONG, UNEXPORTABLE, EXPORTABLE);
+
+ assert_positive(ckmc_create_key_pair_rsa,
+ 1024,
+ RSA.prv.c_str(),
+ RSA.pub.c_str(),
+ UNEXPORTABLE,
+ EXPORTABLE);
+ }
+
+ void Finish() override
+ {
+ int ret = ckmc_lock_user_key(UID);
+ if (ret != CKMC_ERROR_NONE)
+ RUNNER_ERROR_MSG("DB lock failed: " << CKMCErrorToString(ret));
+ remove_user_data(UID);
+ }
+};
+
+struct DerivedFixture
+{
+ void init(const std::string&)
+ {
+ }
+
+ void finish()
+ {
+ ckmc_remove_alias(DERIVED.c_str());
+ }
+};
+
+RawBufferPtr getPublicKey(const std::string& pub_alias)
+{
+ ckmc_key_s *pubKey = nullptr;
+ assert_positive(ckmc_get_key, pub_alias.c_str(), "", &pubKey);
+
+ ckmc_raw_buffer_s* pubBuffer = nullptr;
+ assert_positive(ckmc_buffer_new, pubKey->raw_key, pubKey->key_size, &pubBuffer);
+ ckmc_key_free(pubKey);
+
+ return create_raw_buffer(pubBuffer);
+}
+
+ParamListPtr getDefaultECDHParams(const std::string& pubAlias)
+{
+ auto ecdhParams = createParamListPtr();
+ setParam(ecdhParams, CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_ECDH);
+ auto pubKey = getPublicKey(pubAlias);
+ setParam(ecdhParams, CKMC_PARAM_ECDH_PUBKEY, pubKey.get());
+ return ecdhParams;
+}
+
+void deriveEcdh(const std::string& prvAlias,
+ const std::string& prvPass,
+ const std::string& pubAlias,
+ const std::string& derivedAlias,
+ const ckmc_policy_s& derivedPolicy,
+ int expected)
+{
+ auto ecdhParams = getDefaultECDHParams(pubAlias);
+
+ assert_result(expected,
+ ckmc_key_derive,
+ ecdhParams.get(),
+ prvAlias.c_str(),
+ prvPass.c_str(),
+ derivedAlias.c_str(),
+ derivedPolicy);
+}
+
+RawBufferPtr deriveEcdhAndGet(const std::string& prvAlias,
+ const std::string& prvPass,
+ const std::string& pubAlias,
+ const std::string& derivedAlias,
+ const ckmc_policy_s& derivedPolicy)
+{
+ deriveEcdh(prvAlias, prvPass, pubAlias, derivedAlias, derivedPolicy, CKMC_ERROR_NONE);
+
+ ckmc_raw_buffer_s *derivedBuffer = nullptr;
+ assert_positive(ckmc_get_data, derivedAlias.c_str(), derivedPolicy.password, &derivedBuffer);
+
+ ckmc_remove_alias(derivedAlias.c_str());
+
+ return create_raw_buffer(derivedBuffer);
+}
+
+void invalidDerive(const ParamListPtr& params)
+{
+ assert_invalid_param(ckmc_key_derive,
+ params.get(),
+ OURS.prv.c_str(),
+ "",
+ DERIVED.c_str(),
+ EXPORTABLE);
+}
+
+} // namespace anonymous
+
+RUNNER_TEST_GROUP_INIT_ENV(CKM_DERIVE_ECDH, EcdhGroupFixture);
+
+RUNNER_TEST(TECDH_0010_positive, DerivedFixture)
+{
+ auto ourDerived = deriveEcdhAndGet(OURS.prv, "", PEERS.pub, DERIVED, EXPORTABLE);
+ auto peerDerived = deriveEcdhAndGet(PEERS.prv, PASSWORD, OURS.pub, DERIVED, EXPORTABLE_PW);
+
+ assert_buffers_equal(ourDerived.get(), peerDerived.get());
+
+ auto wrongDerived = deriveEcdhAndGet(OURS.prv, "", PEERS2.pub, DERIVED, EXPORTABLE);
+
+ assert_buffers_equal(ourDerived.get(), wrongDerived.get(), false);
+}
+
+RUNNER_TEST(TECDH_0020_missing_arguments, DerivedFixture)
+{
+ auto ecdhParams = getDefaultECDHParams(PEERS.pub);
+
+ assert_invalid_param(ckmc_key_derive,
+ nullptr,
+ OURS.prv.c_str(),
+ "",
+ DERIVED.c_str(),
+ EXPORTABLE);
+
+ assert_invalid_param(ckmc_key_derive,
+ ecdhParams.get(),
+ nullptr,
+ "",
+ DERIVED.c_str(),
+ EXPORTABLE);
+
+ assert_invalid_param(ckmc_key_derive,
+ ecdhParams.get(),
+ OURS.prv.c_str(),
+ "",
+ nullptr,
+ EXPORTABLE);
+}
+
+RUNNER_TEST(TECDH_0030_unknown_alias, DerivedFixture)
+{
+ auto ecdhParams = getDefaultECDHParams(PEERS.pub);
+
+ assert_result(CKMC_ERROR_DB_ALIAS_UNKNOWN,
+ ckmc_key_derive,
+ ecdhParams.get(),
+ "nonexistent-alias",
+ "",
+ DERIVED.c_str(),
+ EXPORTABLE);
+}
+
+RUNNER_TEST(TECDH_0040_alias_exists, DerivedFixture)
+{
+ auto ecdhParams = getDefaultECDHParams(PEERS.pub);
+
+ assert_positive(ckmc_key_derive,
+ ecdhParams.get(),
+ OURS.prv.c_str(),
+ "",
+ DERIVED.c_str(),
+ EXPORTABLE);
+
+ assert_result(CKMC_ERROR_DB_ALIAS_EXISTS,
+ ckmc_key_derive,
+ ecdhParams.get(),
+ OURS.prv.c_str(),
+ "",
+ DERIVED.c_str(),
+ EXPORTABLE);
+}
+
+RUNNER_TEST(TECDH_0050_derived_password, DerivedFixture)
+{
+ auto ecdhParams = getDefaultECDHParams(PEERS.pub);
+
+ assert_positive(ckmc_key_derive,
+ ecdhParams.get(),
+ OURS.prv.c_str(),
+ "",
+ DERIVED.c_str(),
+ EXPORTABLE_PW);
+
+ ckmc_raw_buffer_s *derived = nullptr;
+ assert_result(CKMC_ERROR_AUTHENTICATION_FAILED, ckmc_get_data, DERIVED.c_str(), "", &derived);
+ assert_result(CKMC_ERROR_AUTHENTICATION_FAILED, ckmc_get_data, DERIVED.c_str(), "pw", &derived);
+
+ assert_positive(ckmc_remove_alias, DERIVED.c_str());
+
+ assert_positive(ckmc_key_derive,
+ ecdhParams.get(),
+ OURS.prv.c_str(),
+ "",
+ DERIVED.c_str(),
+ EXPORTABLE);
+
+ assert_result(CKMC_ERROR_AUTHENTICATION_FAILED, ckmc_get_data, DERIVED.c_str(), "pw", &derived);
+ assert_result(
+ CKMC_ERROR_AUTHENTICATION_FAILED, ckmc_get_data, DERIVED.c_str(), PASSWORD, &derived);
+}
+
+RUNNER_TEST(TECDH_0050_derived_unexportable, DerivedFixture)
+{
+ auto ecdhParams = getDefaultECDHParams(PEERS.pub);
+
+ assert_positive(ckmc_key_derive,
+ ecdhParams.get(),
+ OURS.prv.c_str(),
+ "",
+ DERIVED.c_str(),
+ UNEXPORTABLE);
+
+ ckmc_raw_buffer_s *derived = nullptr;
+ assert_result(CKMC_ERROR_NOT_EXPORTABLE, ckmc_get_data, DERIVED.c_str(), "", &derived);
+}
+
+RUNNER_TEST(TECDH_0100_wrong_parameters, DerivedFixture)
+{
+ auto ecdhParams = createParamListPtr();
+
+ // no algo
+ invalidDerive(ecdhParams);
+
+ // no pubkey
+ setParam(ecdhParams, CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_ECDH);
+ invalidDerive(ecdhParams);
+
+ // garbage pubkey
+ ckmc_raw_buffer_s* garbage = createRandomBufferCAPI(1);
+ auto buffer = create_raw_buffer(garbage);
+ setParam(ecdhParams, CKMC_PARAM_ECDH_PUBKEY, buffer.get());
+ invalidDerive(ecdhParams);
+
+ // private key instead of pubkey
+ buffer = getPublicKey(PEERS2.prv);
+ setParam(ecdhParams, CKMC_PARAM_ECDH_PUBKEY, buffer.get());
+ invalidDerive(ecdhParams);
+
+ // wrong algo
+ buffer = getPublicKey(OURS.pub);
+ setParam(ecdhParams, CKMC_PARAM_ECDH_PUBKEY, buffer.get());
+ setParam(ecdhParams, CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_KBKDF);
+ invalidDerive(ecdhParams);
+}
+
+RUNNER_TEST(TECDH_0200_wrong_password, DerivedFixture)
+{
+ deriveEcdh(PEERS.prv, "", OURS.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_AUTHENTICATION_FAILED);
+ deriveEcdh(OURS.prv,
+ UNEXPORTABLE_PW.password,
+ PEERS.pub,
+ DERIVED,
+ UNEXPORTABLE,
+ CKMC_ERROR_AUTHENTICATION_FAILED);
+}
+
+RUNNER_TEST(TECDH_0210_different_curves, DerivedFixture)
+{
+ deriveEcdh(OURS.prv, "", WRONG.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_INVALID_PARAMETER);
+ deriveEcdh(WRONG.prv, "", OURS.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_INVALID_PARAMETER);
+}
+
+RUNNER_TEST(TECDH_0220_different_key_types, DerivedFixture)
+{
+ deriveEcdh(OURS.prv, "", RSA.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_INVALID_PARAMETER);
+ deriveEcdh(RSA.prv, "", OURS.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_INVALID_PARAMETER);
+}
+
+RUNNER_TEST(TECDH_0230_public_instead_of_private, DerivedFixture)
+{
+ deriveEcdh(OURS.pub, "", OURS.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_INVALID_PARAMETER);
+}
+
+RUNNER_TEST(TECDH_0230_wrong_key_types, DerivedFixture)
+{
+ deriveEcdh(RSA.prv, "", RSA.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_INVALID_PARAMETER);
+}