2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "keymanager/keymanager_instance.h"
19 #include <ckmc/ckmc-manager.h>
22 #include "common/logger.h"
23 #include "common/optional.h"
24 #include "common/platform_result.h"
25 #include "common/scope_exit.h"
26 #include "common/task-queue.h"
27 #include "common/tools.h"
28 #include "common/virtual_fs.h"
31 namespace keymanager {
33 using common::ErrorCode;
34 using common::optional;
35 using common::PlatformResult;
36 using common::TaskQueue;
37 using common::VirtualFs;
41 typedef std::vector<unsigned char> RawBuffer;
43 const char* kTypeRSA = "RSA";
44 const char* kTypeECDSA = "ECDSA";
46 RawBuffer Base64ToRawBuffer(const std::string& base64) {
50 guchar* raw_data = g_base64_decode(base64.c_str(), &len);
54 raw_buffer.assign(raw_data, raw_data + len);
61 std::string RawBufferToBase64(const RawBuffer& buf) {
67 gchar* base64 = g_base64_encode(&buf[0], buf.size());
75 ckmc_ec_type_e GetEllipticCurveType(const std::string& type) {
78 if ("EC_PRIME256V1" == type) {
79 return CKMC_EC_PRIME256V1;
80 } else if ("EC_SECP384R1" == type) {
81 return CKMC_EC_SECP384R1;
83 return CKMC_EC_PRIME192V1;
87 ckmc_key_type_e StringToKeyType(const std::string& type) {
90 if ("KEY_RSA_PUBLIC" == type) {
91 return CKMC_KEY_RSA_PUBLIC;
92 } else if ("KEY_RSA_PRIVATE" == type) {
93 return CKMC_KEY_RSA_PRIVATE;
94 } else if ("KEY_ECDSA_PUBLIC" == type) {
95 return CKMC_KEY_ECDSA_PUBLIC;
96 } else if ("KEY_ECDSA_PRIVATE" == type) {
97 return CKMC_KEY_ECDSA_PRIVATE;
98 } else if ("KEY_DSA_PUBLIC" == type) {
99 return CKMC_KEY_DSA_PUBLIC;
100 } else if ("KEY_DSA_PRIVATE" == type) {
101 return CKMC_KEY_DSA_PRIVATE;
102 } else if ("KEY_AES" == type) {
105 return CKMC_KEY_NONE;
109 std::string KeyTypeToString(ckmc_key_type_e type) {
116 case CKMC_KEY_RSA_PUBLIC:
117 return "KEY_RSA_PUBLIC";
119 case CKMC_KEY_RSA_PRIVATE:
120 return "KEY_RSA_PRIVATE";
122 case CKMC_KEY_ECDSA_PUBLIC:
123 return "KEY_ECDSA_PUBLIC";
125 case CKMC_KEY_ECDSA_PRIVATE:
126 return "KEY_ECDSA_PRIVATE";
128 case CKMC_KEY_DSA_PUBLIC:
129 return "KEY_DSA_PUBLIC";
131 case CKMC_KEY_DSA_PRIVATE:
132 return "KEY_DSA_PRIVATE";
138 LoggerE("Unknown key type");
139 return "KEY_UNKNOWN";
142 RawBuffer ToRawBuffer(const ckmc_key_s* key) {
143 return RawBuffer(key->raw_key, key->raw_key + key->key_size);
148 KeyManagerInstance::KeyManagerInstance() {
150 using std::placeholders::_1;
151 using std::placeholders::_2;
153 RegisterSyncHandler("KeyManager_getKeyAliasList",
154 std::bind(&KeyManagerInstance::GetKeyAliasList, this, _1, _2));
155 RegisterSyncHandler("KeyManager_getCertificatesAliasList",
156 std::bind(&KeyManagerInstance::GetCertificateAliasList, this, _1, _2));
157 RegisterSyncHandler("KeyManager_getDataAliasList",
158 std::bind(&KeyManagerInstance::GetDataAliasList, this, _1, _2));
159 RegisterSyncHandler("KeyManager_getKey",
160 std::bind(&KeyManagerInstance::GetKey, this, _1, _2));
161 RegisterSyncHandler("KeyManager_saveKey",
162 std::bind(&KeyManagerInstance::SaveKey, this, _1, _2));
163 RegisterSyncHandler("KeyManager_removeAlias",
164 std::bind(&KeyManagerInstance::RemoveAlias, this, _1, _2));
165 RegisterSyncHandler("KeyManager_generateKeyPair",
166 std::bind(&KeyManagerInstance::GenerateKeyPair, this, _1, _2));
167 RegisterSyncHandler("KeyManager_getCertificate",
168 std::bind(&KeyManagerInstance::GetCertificate, this, _1, _2));
169 RegisterSyncHandler("KeyManager_saveCertificate",
170 std::bind(&KeyManagerInstance::SaveCertificate, this, _1, _2));
171 RegisterSyncHandler("KeyManager_loadCertificateFromFile",
172 std::bind(&KeyManagerInstance::LoadCertificateFromFile, this, _1, _2));
173 RegisterSyncHandler("KeyManager_saveData",
174 std::bind(&KeyManagerInstance::SaveData, this, _1, _2));
175 RegisterSyncHandler("KeyManager_getData",
176 std::bind(&KeyManagerInstance::GetData, this, _1, _2));
177 RegisterSyncHandler("KeyManager_createSignature",
178 std::bind(&KeyManagerInstance::CreateSignature, this, _1, _2));
179 RegisterSyncHandler("KeyManager_verifySignature",
180 std::bind(&KeyManagerInstance::VerifySignature, this, _1, _2));
181 RegisterSyncHandler("KeyManager_loadFromPKCS12File",
182 std::bind(&KeyManagerInstance::LoadFromPKCS12File, this, _1, _2));
183 RegisterSyncHandler("KeyManager_allowAccessControl",
184 std::bind(&KeyManagerInstance::AllowAccessControl, this, _1, _2));
185 RegisterSyncHandler("KeyManager_denyAccessControl",
186 std::bind(&KeyManagerInstance::DenyAccessControl, this, _1, _2));
189 KeyManagerInstance::~KeyManagerInstance() {
193 void KeyManagerInstance::GetKeyAliasList(const picojson::value& args,
194 picojson::object& out) {
198 void KeyManagerInstance::GetCertificateAliasList(const picojson::value& args,
199 picojson::object& out) {
203 void KeyManagerInstance::GetDataAliasList(const picojson::value& args,
204 picojson::object& out) {
208 void KeyManagerInstance::GetKey(const picojson::value& args,
209 picojson::object& out) {
211 const auto& key_alias = args.get("name").get<std::string>();
212 const auto& password_value = args.get("password");
214 std::string password;
216 if (password_value.is<std::string>()) {
217 password = password_value.get<std::string>();
220 ckmc_key_s* key = nullptr;
221 int ret = ckmc_get_key(key_alias.c_str(), password.c_str(), &key);
223 if (CKMC_ERROR_NONE == ret) {
224 picojson::object result;
226 result["name"] = picojson::value(key_alias);
227 result["password"] = picojson::value(key->password);
228 // if key was retrieved it is extractable from DB
229 result["extractable"] = picojson::value(true);
230 result["keyType"] = picojson::value(KeyTypeToString(key->key_type));
231 result["rawKey"] = picojson::value(RawBufferToBase64(ToRawBuffer(key)));
234 ReportSuccess(picojson::value{result}, out);
236 LoggerE("Failed to get key: %d", ret);
238 PlatformResult error(ErrorCode::UNKNOWN_ERR, "Failed to get key");
241 case CKMC_ERROR_DB_ALIAS_UNKNOWN:
242 error = PlatformResult(ErrorCode::NOT_FOUND_ERR, "Failed to find key");
245 case CKMC_ERROR_INVALID_PARAMETER:
246 error = PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Input parameter is invalid");
250 ReportError(error, &out);
254 void KeyManagerInstance::SaveKey(const picojson::value& args,
255 picojson::object& out) {
258 const picojson::value& key_obj = args.get("key");
259 const std::string& alias = key_obj.get("name").get<std::string>();
260 const std::string& type = key_obj.get("keyType").get<std::string>();
261 bool extractable = key_obj.get("extractable").get<bool>();
262 const double callback_id = args.get("callbackId").get<double>();
265 if (args.get("rawKey").is<std::string>()) {
266 base64 = args.get("rawKey").get<std::string>();
270 if (key_obj.get("password").is<std::string>()) {
271 pass = key_obj.get("password").get<std::string>();
274 RawBuffer* raw_buffer = new RawBuffer(std::move(Base64ToRawBuffer(base64)));
275 ckmc_key_type_e key_type = StringToKeyType(type);
277 auto save = [alias, pass, key_type, extractable, raw_buffer]
278 (const std::shared_ptr<picojson::value>& response) -> void {
280 ckmc_policy_s policy { const_cast<char*>(pass.c_str()), extractable };
281 ckmc_key_s key { const_cast<unsigned char*>(&(*raw_buffer)[0]),
282 raw_buffer->size(), key_type, const_cast<char*>(pass.c_str()) };
284 int ret = ckmc_save_key(alias.c_str(), key, policy);
285 if (CKMC_ERROR_NONE != ret) {
286 PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
287 if (CKMC_ERROR_INVALID_PARAMETER == ret) {
288 result = PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
290 result = PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to save key.");
292 common::tools::ReportError(result, &response->get<picojson::object>());
294 common::tools::ReportSuccess(response->get<picojson::object>());
300 auto save_response = [this, callback_id](const std::shared_ptr<picojson::value>& response) -> void {
301 picojson::object& obj = response->get<picojson::object>();
302 obj.insert(std::make_pair("callbackId", picojson::value(callback_id)));
303 this->PostMessage(response->serialize().c_str());
306 TaskQueue::GetInstance().Queue<picojson::value>(
309 std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
312 void KeyManagerInstance::RemoveAlias(const picojson::value& args,
313 picojson::object& out) {
316 const std::string& alias = args.get("alias").get<std::string>();
317 int ret = ckmc_remove_alias(alias.c_str());
319 if (CKMC_ERROR_NONE != ret) {
320 PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
322 case CKMC_ERROR_INVALID_PARAMETER:
323 result = PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed");
325 case CKMC_ERROR_DB_ALIAS_UNKNOWN:
326 result = PlatformResult(ErrorCode::NOT_FOUND_ERR, "Alias not found");
329 result = PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to remove alias");
331 ReportError(result, &out);
337 void KeyManagerInstance::GenerateKeyPair(const picojson::value& args,
338 picojson::object& out) {
341 const picojson::value& priv_key = args.get("privKeyName");
342 const picojson::value& pub_key = args.get("pubKeyName");
343 const std::string& priv_name = priv_key.get("name").get<std::string>();
344 const std::string& pub_name = pub_key.get("name").get<std::string>();
345 const std::string& type = args.get("type").get<std::string>();
346 const int size = std::stoi(args.get("size").get<std::string>());
347 const double callback_id = args.get("callbackId").get<double>();
349 std::string priv_pass;
350 if (priv_key.get("password").is<std::string>()) {
351 priv_pass = priv_key.get("password").get<std::string>();
353 bool extractable = priv_key.get("extractable").get<bool>();
354 ckmc_policy_s priv_policy { const_cast<char*>(priv_pass.c_str()), extractable };
356 std::string pub_pass;
357 if (pub_key.get("password").is<std::string>()) {
358 pub_pass = pub_key.get("password").get<std::string>();
360 extractable = pub_key.get("extractable").get<bool>();
361 ckmc_policy_s pub_policy { const_cast<char*>(pub_pass.c_str()), extractable };
363 std::string elliptic;
364 if (args.get("ellipticCurveType").is<std::string>()) {
365 elliptic = args.get("ellipticCurveType").get<std::string>();
368 auto generate = [size, priv_policy, pub_policy, priv_name, pub_name, type, elliptic]
369 (const std::shared_ptr<picojson::value>& response) -> void {
370 int ret = CKMC_ERROR_NONE;
371 if (kTypeRSA == type) {
372 ret = ckmc_create_key_pair_rsa(size, priv_name.c_str(),
373 pub_name.c_str(), priv_policy, pub_policy);
374 } else if (kTypeECDSA == type) {
375 ret = ckmc_create_key_pair_ecdsa(GetEllipticCurveType(elliptic), priv_name.c_str(),
376 pub_name.c_str(), priv_policy, pub_policy);
378 ret = ckmc_create_key_pair_dsa(size, priv_name.c_str(),
379 pub_name.c_str(), priv_policy, pub_policy);
382 if (CKMC_ERROR_NONE != ret) {
383 PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
384 if (CKMC_ERROR_INVALID_PARAMETER == ret) {
385 result = PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid value passed.");
387 result = PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to create key pair.");
389 common::tools::ReportError(result, &response->get<picojson::object>());
391 common::tools::ReportSuccess(response->get<picojson::object>());
395 auto generate_response = [this, callback_id](const std::shared_ptr<picojson::value>& response) -> void {
396 picojson::object& obj = response->get<picojson::object>();
397 obj.insert(std::make_pair("callbackId", picojson::value(callback_id)));
398 this->PostMessage(response->serialize().c_str());
401 TaskQueue::GetInstance().Queue<picojson::value>(
404 std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
407 void KeyManagerInstance::GetCertificate(const picojson::value& args,
408 picojson::object& out) {
411 const std::string& alias = args.get("name").get<std::string>();
414 if (args.get("password").is<std::string>()) {
415 pass = args.get("password").get<std::string>();
418 ckmc_cert_s* cert = nullptr;
419 int ret = ckmc_get_cert(alias.c_str(), pass.c_str(), &cert);
421 if (CKMC_ERROR_NONE != ret) {
422 LoggerE("Failed to get certificate: %d", ret);
423 PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
425 case CKMC_ERROR_DB_ALIAS_UNKNOWN:
426 result = PlatformResult(ErrorCode::NOT_FOUND_ERR, "Certificate alias not found");
428 case CKMC_ERROR_INVALID_PARAMETER:
429 result = PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed");
432 result = PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to get certificate");
435 ReportError(result, &out);
437 picojson::value result = picojson::value(picojson::object());
438 picojson::object& obj = result.get<picojson::object>();
440 //if cert was retrieved it is extractable from db
441 obj["extractable"] = picojson::value(true);
442 obj["name"] = picojson::value(alias);
444 obj["password"] = picojson::value(pass);
447 RawBuffer raw_cert (cert->raw_cert, cert->raw_cert + cert->cert_size);
448 obj["rawCert"] = picojson::value(RawBufferToBase64(raw_cert));
450 ReportSuccess(result, out);
454 void KeyManagerInstance::SaveCertificate(const picojson::value& args,
455 picojson::object& out) {
459 void KeyManagerInstance::LoadCertificateFromFile(const picojson::value& args,
460 picojson::object& out) {
464 void KeyManagerInstance::SaveData(const picojson::value& args,
465 picojson::object& out) {
469 void KeyManagerInstance::GetData(const picojson::value& args,
470 picojson::object& out) {
474 void KeyManagerInstance::CreateSignature(const picojson::value& args,
475 picojson::object& out) {
479 void KeyManagerInstance::VerifySignature(const picojson::value& args,
480 picojson::object& out) {
484 void KeyManagerInstance::LoadFromPKCS12File(const picojson::value& args,
485 picojson::object& out) {
488 const auto& file_uri = args.get("fileURI").get<std::string>();
489 const auto& key_alias = args.get("privKeyName").get<std::string>();
490 const auto& cert_alias = args.get("certificateName").get<std::string>();
491 const auto& password_value = args.get("password");
492 double callback_id = args.get("callbackId").get<double>();
494 std::string password;
496 if (password_value.is<std::string>()) {
497 password = password_value.get<std::string>();
500 auto load_file = [file_uri, password, cert_alias, key_alias](const std::shared_ptr<picojson::value>& result) {
501 LoggerD("Enter load_file");
502 std::string file = VirtualFs::GetInstance().GetRealPath(file_uri);
503 ckmc_pkcs12_s* pkcs12 = nullptr;
505 int ret = ckmc_pkcs12_load(file.c_str(), password.c_str(), &pkcs12);
507 if (CKMC_ERROR_NONE == ret) {
509 ckmc_pkcs12_free(pkcs12);
511 ckmc_policy_s policy { const_cast<char*>(password.c_str()), true };
513 // it's safer to use ckmc_save_pkcs12() here, however JS API specifies
514 // two different aliases for private key and certificate
516 ret = ckmc_save_cert(cert_alias.c_str(), *pkcs12->cert, policy);
517 if (CKMC_ERROR_NONE != ret) {
518 LoggerE("Failed to save certificate: %d", ret);
522 if (CKMC_ERROR_NONE == ret && pkcs12->priv_key) {
523 ret = ckmc_save_key(key_alias.c_str(), *pkcs12->priv_key, policy);
524 if (CKMC_ERROR_NONE != ret) {
525 LoggerE("Failed to save private key: %d", ret);
528 ckmc_remove_cert(cert_alias.c_str());
533 LoggerE("Failed to load PKCS12 file: %d", ret);
536 PlatformResult success(ErrorCode::NO_ERROR);
539 case CKMC_ERROR_NONE:
542 case CKMC_ERROR_FILE_ACCESS_DENIED:
543 success = PlatformResult(ErrorCode::NOT_FOUND_ERR, "Certificate file not found");
546 case CKMC_ERROR_INVALID_FORMAT:
547 case CKMC_ERROR_INVALID_PARAMETER:
548 success = PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Certificate file has wrong format");
551 case CKMC_ERROR_PERMISSION_DENIED:
552 success = PlatformResult(ErrorCode::IO_ERR, "Permission has been denied");
556 success = PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to open certificate file");
561 common::tools::ReportSuccess(result->get<picojson::object>());
563 common::tools::ReportError(success, &result->get<picojson::object>());
567 auto load_file_result = [this, callback_id](const std::shared_ptr<picojson::value>& result) {
568 LoggerD("Enter load_file_result");
569 result->get<picojson::object>()["callbackId"] = picojson::value{callback_id};
570 this->PostMessage(result->serialize().c_str());
573 TaskQueue::GetInstance().Queue<picojson::value>(
576 std::shared_ptr<picojson::value>{new picojson::value{picojson::object()}});
581 void KeyManagerInstance::AllowAccessControl(const picojson::value& args,
582 picojson::object& out) {
585 const std::string& data_name = args.get("dataName").get<std::string>();
586 const std::string& id = args.get("id").get<std::string>();
587 const double callback_id = args.get("callbackId").get<double>();
588 const std::string& access = args.get("accessControlType").get<std::string>();
589 ckmc_access_right_e granted = CKMC_AR_READ;
590 if ("READ_REMOVE" == access) {
591 granted = CKMC_AR_READ_REMOVE;
594 auto allow = [data_name, id, granted](const std::shared_ptr<picojson::value>& response) -> void {
595 int ret = ckmc_allow_access(data_name.c_str(), id.c_str(), granted);
596 if (CKMC_ERROR_NONE != ret) {
597 PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
598 if (CKMC_ERROR_DB_ALIAS_UNKNOWN == ret) {
599 result = PlatformResult(ErrorCode::NOT_FOUND_ERR, "Alias not found.");
601 result = PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to allow access.");
603 common::tools::ReportError(result, &response->get<picojson::object>());
605 common::tools::ReportSuccess(response->get<picojson::object>());
609 auto allow_response = [this, callback_id](const std::shared_ptr<picojson::value>& response) -> void {
610 picojson::object& obj = response->get<picojson::object>();
611 obj.insert(std::make_pair("callbackId", picojson::value(callback_id)));
612 this->PostMessage(response->serialize().c_str());
615 TaskQueue::GetInstance().Queue<picojson::value>(
618 std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
621 void KeyManagerInstance::DenyAccessControl(const picojson::value& args,
622 picojson::object& out) {
625 const std::string& data_name = args.get("dataName").get<std::string>();
626 const std::string& id = args.get("id").get<std::string>();
627 const double callback_id = args.get("callbackId").get<double>();
629 auto deny = [data_name, id](const std::shared_ptr<picojson::value>& response) -> void {
630 int ret = ckmc_deny_access(data_name.c_str(), id.c_str());
631 if (CKMC_ERROR_NONE != ret) {
632 PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
633 if (CKMC_ERROR_DB_ALIAS_UNKNOWN == ret) {
634 result = PlatformResult(ErrorCode::NOT_FOUND_ERR, "Alias not found.");
636 result = PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to deny access.");
638 common::tools::ReportError(result, &response->get<picojson::object>());
640 common::tools::ReportSuccess(response->get<picojson::object>());
644 auto deny_response = [this, callback_id](const std::shared_ptr<picojson::value>& response) -> void {
645 picojson::object& obj = response->get<picojson::object>();
646 obj.insert(std::make_pair("callbackId", picojson::value(callback_id)));
647 this->PostMessage(response->serialize().c_str());
650 TaskQueue::GetInstance().Queue<picojson::value>(
653 std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
656 } // namespace keymanager
657 } // namespace extension