2 * Copyright (c) 2000 - 2014 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
18 * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
20 * @brief Sample service implementation.
22 #include <dpl/serialization.h>
23 #include <dpl/log/log.h>
24 #include <ckm/ckm-error.h>
25 #include <ckm/ckm-type.h>
26 #include <key-provider.h>
27 #include <file-system.h>
28 #include <ckm-logic.h>
30 #include <key-aes-impl.h>
31 #include <certificate-config.h>
32 #include <certificate-store.h>
35 #include <InitialValuesFile.h>
36 #include <sw-backend/store.h>
37 #include <generic-backend/exception.h>
40 const char * const CERT_SYSTEM_DIR = "/etc/ssl/certs";
41 const char * const INIT_VALUES_DIR = "/opt/data/ckm/initial_values/";
42 const char * const INIT_VALUES_XSD = "/usr/share/ckm/initial_values.xsd";
43 const char * const INIT_VALUES_FILE_SUFFIX = ".xml";
44 const char * const SYSTEM_DB_PASSWD = "cAtRugU7";
46 bool isLabelValid(const CKM::Label &label) {
47 // TODO: copy code from libprivilege control (for check smack label)
48 if (label.find(CKM::LABEL_NAME_SEPARATOR) != CKM::Label::npos)
53 bool isNameValid(const CKM::Name &name) {
54 if (name.find(CKM::LABEL_NAME_SEPARATOR) != CKM::Name::npos)
58 } // anonymous namespace
62 const uid_t CKMLogic::SYSTEM_DB_UID = 0;
66 CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR);
68 m_accessControl.updateCCMode();
70 // make initial file list
71 std::vector<std::string> filesToParse;
72 DIR *dp = opendir(INIT_VALUES_DIR);
76 while ((entry = readdir(dp)))
78 std::string filename = std::string(entry->d_name);
81 std::string lowercaseFilename = filename;
82 std::transform(lowercaseFilename.begin(), lowercaseFilename.end(), lowercaseFilename.begin(), ::tolower);
83 if(lowercaseFilename.find(INIT_VALUES_FILE_SUFFIX) == std::string::npos)
86 filesToParse.push_back(std::string(INIT_VALUES_DIR) + filename);
92 for(const auto & file : filesToParse)
94 InitialValues::InitialValuesFile xmlFile(file.c_str(), *this);
95 int rc = xmlFile.Validate(INIT_VALUES_XSD);
96 if(rc == XML::Parser::PARSE_SUCCESS)
99 if(rc != XML::Parser::PARSE_SUCCESS)
100 LogError("invalid initial values file: " << file << ", parsing code: " << rc);
103 LogError("invalid initial values file: " << file << ", validation code: " << rc);
104 unlink(file.c_str());
108 CKMLogic::~CKMLogic(){}
110 void CKMLogic::loadDKEKFile(uid_t user, const Password &password) {
111 auto &handle = m_userDataMap[user];
115 auto wrappedDKEK = fs.getDKEK();
117 if (wrappedDKEK.empty()) {
118 wrappedDKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
119 fs.saveDKEK(wrappedDKEK);
122 handle.keyProvider = KeyProvider(wrappedDKEK, password);
125 void CKMLogic::saveDKEKFile(uid_t user, const Password &password) {
126 auto &handle = m_userDataMap[user];
129 fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
132 int CKMLogic::unlockDatabase(uid_t user, const Password & password)
134 if (0<m_userDataMap.count(user) && m_userDataMap[user].keyProvider.isInitialized())
135 return CKM_API_SUCCESS;
137 int retCode = CKM_API_SUCCESS;
140 auto &handle = m_userDataMap[user];
143 loadDKEKFile(user, password);
145 auto wrappedDatabaseDEK = fs.getDBDEK();
146 if (wrappedDatabaseDEK.empty()) {
147 wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
148 fs.saveDBDEK(wrappedDatabaseDEK);
151 RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
153 handle.database = DB::Crypto(fs.getDBPath(), key);
154 handle.crypto = CryptoLogic();
156 if ( !m_accessControl.isSystemService(user) )
158 // remove data of removed apps during locked state
159 AppLabelVector removedApps = fs.clearRemovedsApps();
160 for(auto& appSmackLabel : removedApps) {
161 handle.crypto.removeKey(appSmackLabel);
162 handle.database.deleteKey(appSmackLabel);
165 } catch (const Exc::Exception &e) {
167 } catch (const CKM::Exception &e) {
168 LogError("CKM::Exception: " << e.GetMessage());
169 retCode = CKM_API_ERROR_SERVER_ERROR;
172 if (CKM_API_SUCCESS != retCode)
173 m_userDataMap.erase(user);
178 int CKMLogic::unlockSystemDB()
180 return unlockDatabase(SYSTEM_DB_UID, SYSTEM_DB_PASSWD);
183 UserData & CKMLogic::selectDatabase(const Credentials &cred, const Label &incoming_label)
185 // if user trying to access system service - check:
186 // * if user database is unlocked [mandatory]
187 // * if not - proceed with regular user database
188 // * if explicit system database label given -> switch to system DB
189 if ( !m_accessControl.isSystemService(cred) )
191 if (0 == m_userDataMap.count(cred.clientUid))
192 ThrowErr(Exc::DatabaseLocked, "database with UID: ", cred.clientUid, " locked");
194 if (0 != incoming_label.compare(LABEL_SYSTEM_DB))
195 return m_userDataMap[cred.clientUid];
198 // system database selected, modify the label
199 if (CKM_API_SUCCESS != unlockSystemDB() )
200 ThrowErr(Exc::DatabaseLocked, "can not unlock system database");
201 return m_userDataMap[SYSTEM_DB_UID];
204 RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password)
206 int retCode = CKM_API_SUCCESS;
208 if( !m_accessControl.isSystemService(user) )
210 retCode = unlockDatabase(user, password);
214 // do not allow lock/unlock operations for system users
215 retCode = CKM_API_ERROR_INPUT_PARAM;
218 return MessageBuffer::Serialize(retCode).Pop();
221 RawBuffer CKMLogic::updateCCMode() {
222 m_accessControl.updateCCMode();
223 return MessageBuffer::Serialize(CKM_API_SUCCESS).Pop();
226 RawBuffer CKMLogic::lockUserKey(uid_t user)
228 int retCode = CKM_API_SUCCESS;
229 if( !m_accessControl.isSystemService(user) )
231 m_userDataMap.erase(user);
235 // do not allow lock/unlock operations for system users
236 retCode = CKM_API_ERROR_INPUT_PARAM;
239 return MessageBuffer::Serialize(retCode).Pop();
243 RawBuffer CKMLogic::removeUserData(uid_t user) {
244 int retCode = CKM_API_SUCCESS;
246 if (m_accessControl.isSystemService(user))
247 user = SYSTEM_DB_UID;
249 m_userDataMap.erase(user);
254 return MessageBuffer::Serialize(retCode).Pop();
257 int CKMLogic::changeUserPasswordHelper(uid_t user,
258 const Password &oldPassword,
259 const Password &newPassword)
261 // do not allow to change system database password
262 if( m_accessControl.isSystemService(user) )
263 return CKM_API_ERROR_INPUT_PARAM;
265 loadDKEKFile(user, oldPassword);
266 saveDKEKFile(user, newPassword);
268 return CKM_API_SUCCESS;
271 RawBuffer CKMLogic::changeUserPassword(
273 const Password &oldPassword,
274 const Password &newPassword)
276 int retCode = CKM_API_SUCCESS;
279 retCode = changeUserPasswordHelper(user, oldPassword, newPassword);
280 } catch (const Exc::Exception &e) {
282 } catch (const CKM::Exception &e) {
283 LogError("CKM::Exception: " << e.GetMessage());
284 retCode = CKM_API_ERROR_SERVER_ERROR;
287 return MessageBuffer::Serialize(retCode).Pop();
290 int CKMLogic::resetUserPasswordHelper(
292 const Password &newPassword)
294 // do not allow to reset system database password
295 if( m_accessControl.isSystemService(user) )
296 return CKM_API_ERROR_INPUT_PARAM;
298 int retCode = CKM_API_SUCCESS;
299 if (0 == m_userDataMap.count(user))
301 // Check if key exists. If exists we must return error
303 auto wrappedDKEKMain = fs.getDKEK();
304 if (!wrappedDKEKMain.empty())
305 retCode = CKM_API_ERROR_BAD_REQUEST;
307 saveDKEKFile(user, newPassword);
313 RawBuffer CKMLogic::resetUserPassword(
315 const Password &newPassword)
317 int retCode = CKM_API_SUCCESS;
319 retCode = resetUserPasswordHelper(user, newPassword);
320 } catch (const Exc::Exception &e) {
322 } catch (const CKM::Exception &e) {
323 LogError("CKM::Exception: " << e.GetMessage());
324 retCode = CKM_API_ERROR_SERVER_ERROR;
327 return MessageBuffer::Serialize(retCode).Pop();
330 RawBuffer CKMLogic::removeApplicationData(const Label &smackLabel) {
331 int retCode = CKM_API_SUCCESS;
335 if (smackLabel.empty()) {
336 retCode = CKM_API_ERROR_INPUT_PARAM;
338 UidVector uids = FileSystem::getUIDsFromDBFile();
339 for (auto userId : uids) {
340 if (0 == m_userDataMap.count(userId)) {
341 FileSystem fs(userId);
342 fs.addRemovedApp(smackLabel);
344 auto &handle = m_userDataMap[userId];
345 handle.crypto.removeKey(smackLabel);
346 handle.database.deleteKey(smackLabel);
351 } catch (const DB::Crypto::Exception::InternalError &e) {
352 LogError("DB::Crypto couldn't remove data: " << e.GetMessage());
353 retCode = CKM_API_ERROR_DB_ERROR;
354 } catch (const DB::Crypto::Exception::TransactionError &e) {
355 LogError("DB::Crypto transaction failed with message " << e.GetMessage());
356 retCode = CKM_API_ERROR_DB_ERROR;
357 } catch (const Exc::Exception &e) {
359 } catch (const CKM::Exception &e) {
360 LogError("CKM::Exception: " << e.GetMessage());
361 retCode = CKM_API_ERROR_SERVER_ERROR;
364 return MessageBuffer::Serialize(retCode).Pop();
367 int CKMLogic::checkSaveConditions(
368 const Credentials &cred,
371 const Label &ownerLabel)
373 // verify name and label are correct
374 if (!isNameValid(name) || !isLabelValid(ownerLabel)) {
375 LogWarning("Invalid parameter passed to key-manager");
376 return CKM_API_ERROR_INPUT_PARAM;
379 // check if allowed to save using ownerLabel
380 int access_ec = m_accessControl.canSave(cred, ownerLabel);
381 if( access_ec != CKM_API_SUCCESS)
383 LogWarning("label " << cred.smackLabel << " can not save rows using label " << ownerLabel);
387 // check if not a duplicate
388 if( handler.database.isNameLabelPresent(name, ownerLabel))
389 return CKM_API_ERROR_DB_ALIAS_EXISTS;
391 // encryption section
392 if (!handler.crypto.haveKey(ownerLabel))
395 auto key_optional = handler.database.getKey(ownerLabel);
397 LogDebug("No Key in database found. Generating new one for label: " << ownerLabel);
398 got_key = handler.keyProvider.generateDEK(ownerLabel);
399 handler.database.saveKey(ownerLabel, got_key);
401 LogDebug("Key from DB");
402 got_key = *key_optional;
405 got_key = handler.keyProvider.getPureDEK(got_key);
406 handler.crypto.pushKey(ownerLabel, got_key);
409 return CKM_API_SUCCESS;
412 DB::Row CKMLogic::createEncryptedRow(
417 const RawBuffer &data,
418 const Policy &policy) const
420 DB::Row row(name, label, static_cast<int>(policy.extractable), dataType, data, static_cast<int>(data.size()));
421 row.backendId = m_decider.chooseCryptoBackend(dataType, policy.extractable);
423 // do not encrypt data with password during cc_mode on
424 if(m_accessControl.isCCMode()) {
425 crypto.encryptRow("", row);
427 crypto.encryptRow(policy.password, row);
432 int CKMLogic::verifyBinaryData(DataType dataType, RawBuffer &input_data) const
435 return toBinaryData(dataType, input_data, dummy);
438 int CKMLogic::toBinaryData(DataType dataType,
439 const RawBuffer &input_data,
440 RawBuffer &output_data) const
442 // verify the data integrity
443 if (dataType.isKey())
446 if(dataType.isSKey())
447 output_key = CKM::Key::createAES(input_data);
449 output_key = CKM::Key::create(input_data);
450 if(output_key.get() == NULL)
452 LogError("provided binary data is not valid key data");
453 return CKM_API_ERROR_INPUT_PARAM;
455 output_data = output_key->getDER();
457 else if (dataType.isCertificate() || dataType.isChainCert())
459 CertificateShPtr cert = CKM::Certificate::create(input_data, DataFormat::FORM_DER);
460 if(cert.get() == NULL)
462 LogError("provided binary data is not valid certificate data");
463 return CKM_API_ERROR_INPUT_PARAM;
465 output_data = cert->getDER();
468 output_data = input_data;
469 // TODO: add here BINARY_DATA verification, i.e: max size etc.
470 return CKM_API_SUCCESS;
473 int CKMLogic::verifyAndSaveDataHelper(
474 const Credentials &cred,
477 const RawBuffer &data,
479 const PolicySerializable &policy)
481 int retCode = CKM_API_ERROR_UNKNOWN;
484 // check if data is correct
485 RawBuffer binaryData;
486 retCode = toBinaryData(dataType, data, binaryData);
487 if(retCode == CKM_API_SUCCESS)
489 retCode = saveDataHelper(cred, name, label, dataType, binaryData, policy);
491 } catch (const DB::Crypto::Exception::InternalError &e) {
492 LogError("DB::Crypto failed with message: " << e.GetMessage());
493 retCode = CKM_API_ERROR_DB_ERROR;
494 } catch (const DB::Crypto::Exception::TransactionError &e) {
495 LogError("DB::Crypto transaction failed with message " << e.GetMessage());
496 retCode = CKM_API_ERROR_DB_ERROR;
497 } catch (const Exc::Exception &e) {
499 } catch (const CKM::Exception &e) {
500 LogError("CKM::Exception: " << e.GetMessage());
501 retCode = CKM_API_ERROR_SERVER_ERROR;
506 int CKMLogic::getKeyForService(
507 const Credentials &cred,
510 const Password &pass,
511 Crypto::GKeyShPtr &key)
515 // Key is for internal service use. It won't be exported to the client
516 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, label, pass, row);
517 if (retCode == CKM_API_SUCCESS)
518 key = m_decider.getStore(row).getKey(row);
520 } catch (const DB::Crypto::Exception::Base &e) {
521 LogError("DB::Crypto failed with message: " << e.GetMessage());
522 return CKM_API_ERROR_DB_ERROR;
523 } catch (const Exc::Exception &e) {
525 } catch (const CKM::Exception &e) {
526 LogError("CKM::Exception: " << e.GetMessage());
527 return CKM_API_ERROR_SERVER_ERROR;
531 RawBuffer CKMLogic::saveData(
532 const Credentials &cred,
536 const RawBuffer &data,
538 const PolicySerializable &policy)
540 int retCode = verifyAndSaveDataHelper(cred, name, label, data, dataType, policy);
541 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE),
544 static_cast<int>(dataType));
545 return response.Pop();
548 int CKMLogic::extractPKCS12Data(
551 const Label &ownerLabel,
552 const PKCS12Serializable &pkcs,
553 const PolicySerializable &keyPolicy,
554 const PolicySerializable &certPolicy,
555 DB::RowVector &output) const
557 // private key is mandatory
559 return CKM_API_ERROR_INVALID_FORMAT;
560 Key* keyPtr = pkcs.getKey().get();
561 DataType keyType = DataType(keyPtr->getType());
562 RawBuffer keyData = keyPtr->getDER();
563 int retCode = verifyBinaryData(keyType, keyData);
564 if(retCode != CKM_API_SUCCESS)
566 output.push_back(createEncryptedRow(crypto, name, ownerLabel, keyType, keyData, keyPolicy));
568 // certificate is mandatory
569 if( !pkcs.getCertificate() )
570 return CKM_API_ERROR_INVALID_FORMAT;
571 RawBuffer certData = pkcs.getCertificate().get()->getDER();
572 retCode = verifyBinaryData(DataType::CERTIFICATE, certData);
573 if(retCode != CKM_API_SUCCESS)
575 output.push_back(createEncryptedRow(crypto, name, ownerLabel, DataType::CERTIFICATE, certData, certPolicy));
578 unsigned int cert_index = 0;
579 for(const auto & ca : pkcs.getCaCertificateShPtrVector())
581 DataType chainDataType = DataType::getChainDatatype(cert_index ++);
582 RawBuffer caCertData = ca->getDER();
583 int retCode = verifyBinaryData(chainDataType, caCertData);
584 if(retCode != CKM_API_SUCCESS)
587 output.push_back(createEncryptedRow(crypto, name, ownerLabel, chainDataType, caCertData, certPolicy));
590 return CKM_API_SUCCESS;
593 RawBuffer CKMLogic::savePKCS12(
594 const Credentials &cred,
598 const PKCS12Serializable &pkcs,
599 const PolicySerializable &keyPolicy,
600 const PolicySerializable &certPolicy)
602 int retCode = CKM_API_ERROR_UNKNOWN;
604 retCode = saveDataHelper(cred, name, label, pkcs, keyPolicy, certPolicy);
605 } catch (const Exc::Exception &e) {
607 } catch (const DB::Crypto::Exception::InternalError &e) {
608 LogError("DB::Crypto failed with message: " << e.GetMessage());
609 retCode = CKM_API_ERROR_DB_ERROR;
610 } catch (const DB::Crypto::Exception::TransactionError &e) {
611 LogError("DB::Crypto transaction failed with message " << e.GetMessage());
612 retCode = CKM_API_ERROR_DB_ERROR;
613 } catch (const CKM::Exception &e) {
614 LogError("CKM::Exception: " << e.GetMessage());
615 retCode = CKM_API_ERROR_SERVER_ERROR;
618 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE_PKCS12),
621 return response.Pop();
625 int CKMLogic::removeDataHelper(
626 const Credentials &cred,
630 auto &handler = selectDatabase(cred, label);
632 // use client label if not explicitly provided
633 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
634 if (!isNameValid(name) || !isLabelValid(ownerLabel)) {
635 LogError("Invalid label or name format");
636 return CKM_API_ERROR_INPUT_PARAM;
639 DB::Crypto::Transaction transaction(&handler.database);
641 // read and check permissions
642 PermissionMaskOptional permissionRowOpt =
643 handler.database.getPermissionRow(name, ownerLabel, cred.smackLabel);
644 int retCode = m_accessControl.canDelete(cred,
645 PermissionForLabel(cred.smackLabel, permissionRowOpt));
646 if(retCode != CKM_API_SUCCESS)
648 LogWarning("access control check result: " << retCode);
652 auto erased = handler.database.deleteRow(name, ownerLabel);
653 // check if the data existed or not
655 transaction.commit();
657 LogError("No row for given name and label");
658 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
661 return CKM_API_SUCCESS;
664 RawBuffer CKMLogic::removeData(
665 const Credentials &cred,
670 int retCode = CKM_API_ERROR_UNKNOWN;
674 retCode = removeDataHelper(cred, name, label);
676 catch (const Exc::Exception &e)
680 catch (const CKM::Exception &)
682 LogError("Error in deleting row!");
683 retCode = CKM_API_ERROR_DB_ERROR;
686 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::REMOVE),
689 return response.Pop();
692 int CKMLogic::readSingleRow(const Name &name,
693 const Label &ownerLabel,
695 DB::Crypto & database,
698 DB::Crypto::RowOptional row_optional;
699 if (dataType.isKey())
701 // read all key types
702 row_optional = database.getRow(name,
704 DataType::DB_KEY_FIRST,
705 DataType::DB_KEY_LAST);
707 // read anything else
708 row_optional = database.getRow(name,
714 LogError("No row for given name, label and type");
715 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
720 return CKM_API_SUCCESS;
724 int CKMLogic::readMultiRow(const Name &name,
725 const Label &ownerLabel,
727 DB::Crypto & database,
728 DB::RowVector &output)
730 if (dataType.isKey())
732 // read all key types
733 database.getRows(name,
735 DataType::DB_KEY_FIRST,
736 DataType::DB_KEY_LAST,
739 else if (dataType.isChainCert())
741 // read all key types
742 database.getRows(name,
744 DataType::DB_CHAIN_FIRST,
745 DataType::DB_CHAIN_LAST,
750 // read anything else
751 database.getRows(name,
758 LogError("No row for given name, label and type");
759 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
762 return CKM_API_SUCCESS;
765 int CKMLogic::checkDataPermissionsHelper(const Credentials &cred,
767 const Label &ownerLabel,
768 const Label &accessorLabel,
771 DB::Crypto & database)
773 PermissionMaskOptional permissionRowOpt =
774 database.getPermissionRow(name, ownerLabel, accessorLabel);
777 return m_accessControl.canExport(cred, row, PermissionForLabel(accessorLabel, permissionRowOpt));
778 return m_accessControl.canRead(cred, PermissionForLabel(accessorLabel, permissionRowOpt));
781 int CKMLogic::readDataHelper(
783 const Credentials &cred,
787 const Password &password,
790 auto &handler = selectDatabase(cred, label);
792 // use client label if not explicitly provided
793 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
795 if (!isNameValid(name) || !isLabelValid(ownerLabel))
796 return CKM_API_ERROR_INPUT_PARAM;
799 DB::Crypto::Transaction transaction(&handler.database);
800 int retCode = readMultiRow(name, ownerLabel, dataType, handler.database, rows);
801 if(CKM_API_SUCCESS != retCode)
804 // all read rows belong to the same owner
805 DB::Row & firstRow = rows.at(0);
807 // check access rights
808 retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel, firstRow, exportFlag, handler.database);
809 if(CKM_API_SUCCESS != retCode)
813 if (!handler.crypto.haveKey(firstRow.ownerLabel)) {
815 auto key_optional = handler.database.getKey(firstRow.ownerLabel);
817 LogError("No key for given label in database");
818 return CKM_API_ERROR_DB_ERROR;
821 key = handler.keyProvider.getPureDEK(key);
822 handler.crypto.pushKey(firstRow.ownerLabel, key);
824 for(auto &row : rows)
825 handler.crypto.decryptRow(password, row);
827 return CKM_API_SUCCESS;
830 int CKMLogic::readDataHelper(
832 const Credentials &cred,
836 const Password &password,
839 auto &handler = selectDatabase(cred, label);
841 // use client label if not explicitly provided
842 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
844 if (!isNameValid(name) || !isLabelValid(ownerLabel))
845 return CKM_API_ERROR_INPUT_PARAM;
848 DB::Crypto::Transaction transaction(&handler.database);
849 int retCode = readSingleRow(name, ownerLabel, dataType, handler.database, row);
850 if(CKM_API_SUCCESS != retCode)
853 // check access rights
854 retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel, row, exportFlag, handler.database);
855 if(CKM_API_SUCCESS != retCode)
859 if (!handler.crypto.haveKey(row.ownerLabel)) {
861 auto key_optional = handler.database.getKey(row.ownerLabel);
863 LogError("No key for given label in database");
864 return CKM_API_ERROR_DB_ERROR;
867 key = handler.keyProvider.getPureDEK(key);
868 handler.crypto.pushKey(row.ownerLabel, key);
870 handler.crypto.decryptRow(password, row);
872 return CKM_API_SUCCESS;
875 RawBuffer CKMLogic::getData(
876 const Credentials &cred,
881 const Password &password)
883 int retCode = CKM_API_SUCCESS;
887 retCode = readDataHelper(true, cred, dataType, name, label, password, row);
888 } catch (const DB::Crypto::Exception::Base &e) {
889 LogError("DB::Crypto failed with message: " << e.GetMessage());
890 retCode = CKM_API_ERROR_DB_ERROR;
891 } catch (const Exc::Exception &e) {
893 } catch (const CKM::Exception &e) {
894 LogError("CKM::Exception: " << e.GetMessage());
895 retCode = CKM_API_ERROR_SERVER_ERROR;
898 if (CKM_API_SUCCESS != retCode) {
900 row.dataType = dataType;
903 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET),
906 static_cast<int>(row.dataType),
908 return response.Pop();
911 int CKMLogic::getPKCS12Helper(
912 const Credentials &cred,
915 const Password &keyPassword,
916 const Password &certPassword,
918 CertificateShPtr & cert,
919 CertificateShPtrVector & caChain)
923 // read private key (mandatory)
925 retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, label, keyPassword, privKeyRow);
926 if(retCode != CKM_API_SUCCESS)
928 privKey = CKM::Key::create(privKeyRow.data);
930 // read certificate (mandatory)
932 retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, label, certPassword, certRow);
933 if(retCode != CKM_API_SUCCESS)
935 cert = CKM::Certificate::create(certRow.data, DataFormat::FORM_DER);
937 // read CA cert chain (optional)
938 DB::RowVector rawCaChain;
939 retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, label, certPassword, rawCaChain);
940 if(retCode != CKM_API_SUCCESS &&
941 retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
943 for(auto &rawCaCert : rawCaChain)
944 caChain.push_back(CKM::Certificate::create(rawCaCert.data, DataFormat::FORM_DER));
946 // if anything found, return it
947 if(privKey || cert || caChain.size()>0)
948 retCode = CKM_API_SUCCESS;
953 RawBuffer CKMLogic::getPKCS12(
954 const Credentials &cred,
958 const Password &keyPassword,
959 const Password &certPassword)
961 int retCode = CKM_API_ERROR_UNKNOWN;
963 PKCS12Serializable output;
966 CertificateShPtr cert;
967 CertificateShPtrVector caChain;
968 retCode = getPKCS12Helper(cred, name, label, keyPassword, certPassword, privKey, cert, caChain);
971 if(retCode == CKM_API_SUCCESS)
972 output = PKCS12Serializable(privKey, cert, caChain);
973 } catch (const DB::Crypto::Exception::Base &e) {
974 LogError("DB::Crypto failed with message: " << e.GetMessage());
975 retCode = CKM_API_ERROR_DB_ERROR;
976 } catch (const Exc::Exception &e) {
978 } catch (const CKM::Exception &e) {
979 LogError("CKM::Exception: " << e.GetMessage());
980 retCode = CKM_API_ERROR_SERVER_ERROR;
983 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_PKCS12),
987 return response.Pop();
990 int CKMLogic::getDataListHelper(const Credentials &cred,
991 const DataType dataType,
992 LabelNameVector &labelNameVector)
994 int retCode = CKM_API_ERROR_DB_LOCKED;
995 if (0 < m_userDataMap.count(cred.clientUid))
997 auto &database = m_userDataMap[cred.clientUid].database;
1000 LabelNameVector tmpVector;
1001 if (dataType.isKey()) {
1002 // list all key types
1003 database.listNames(cred.smackLabel,
1005 DataType::DB_KEY_FIRST,
1006 DataType::DB_KEY_LAST);
1008 // list anything else
1009 database.listNames(cred.smackLabel,
1013 labelNameVector.insert(labelNameVector.end(), tmpVector.begin(), tmpVector.end());
1014 retCode = CKM_API_SUCCESS;
1016 Catch (CKM::Exception) {
1017 LogError("Failed to get names");
1018 retCode = CKM_API_ERROR_DB_ERROR;
1024 RawBuffer CKMLogic::getDataList(
1025 const Credentials &cred,
1029 LabelNameVector systemVector;
1030 LabelNameVector userVector;
1031 LabelNameVector labelNameVector;
1033 int retCode = unlockSystemDB();
1034 if (CKM_API_SUCCESS == retCode)
1037 if (m_accessControl.isSystemService(cred))
1040 retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
1047 // user - lookup system, then client DB
1048 retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
1054 if(retCode == CKM_API_SUCCESS)
1056 retCode = getDataListHelper(cred,
1063 if(retCode == CKM_API_SUCCESS)
1065 labelNameVector.insert(labelNameVector.end(), systemVector.begin(), systemVector.end());
1066 labelNameVector.insert(labelNameVector.end(), userVector.begin(), userVector.end());
1068 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_LIST),
1071 static_cast<int>(dataType),
1073 return response.Pop();
1076 int CKMLogic::saveDataHelper(
1077 const Credentials &cred,
1081 const RawBuffer &data,
1082 const PolicySerializable &policy)
1084 auto &handler = selectDatabase(cred, label);
1086 // use client label if not explicitly provided
1087 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
1088 if( m_accessControl.isSystemService(cred) && ownerLabel.compare(LABEL_SYSTEM_DB)!=0)
1089 return CKM_API_ERROR_INPUT_PARAM;
1091 // check if save is possible
1092 DB::Crypto::Transaction transaction(&handler.database);
1093 int retCode = checkSaveConditions(cred, handler, name, ownerLabel);
1094 if(retCode != CKM_API_SUCCESS)
1098 DB::Row encryptedRow = createEncryptedRow(handler.crypto, name, ownerLabel, dataType, data, policy);
1099 handler.database.saveRow(encryptedRow);
1101 transaction.commit();
1102 return CKM_API_SUCCESS;
1105 int CKMLogic::saveDataHelper(
1106 const Credentials &cred,
1109 const PKCS12Serializable &pkcs,
1110 const PolicySerializable &keyPolicy,
1111 const PolicySerializable &certPolicy)
1113 auto &handler = selectDatabase(cred, label);
1115 // use client label if not explicitly provided
1116 const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
1117 if( m_accessControl.isSystemService(cred) && ownerLabel.compare(LABEL_SYSTEM_DB)!=0)
1118 return CKM_API_ERROR_INPUT_PARAM;
1120 // check if save is possible
1121 DB::Crypto::Transaction transaction(&handler.database);
1122 int retCode = checkSaveConditions(cred, handler, name, ownerLabel);
1123 if(retCode != CKM_API_SUCCESS)
1126 // extract and encrypt the data
1127 DB::RowVector encryptedRows;
1128 retCode = extractPKCS12Data(handler.crypto, name, ownerLabel, pkcs, keyPolicy, certPolicy, encryptedRows);
1129 if(retCode != CKM_API_SUCCESS)
1133 handler.database.saveRows(name, ownerLabel, encryptedRows);
1134 transaction.commit();
1136 return CKM_API_SUCCESS;
1140 int CKMLogic::createKeyAESHelper(
1141 const Credentials &cred,
1145 const PolicySerializable &policy)
1147 CryptoAlgorithm keyGenAlgorithm;
1148 keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
1149 Token key = m_decider.getStore(DataType::KEY_AES, policy.extractable).generateSKey(keyGenAlgorithm);
1151 return saveDataHelper(cred,
1160 int CKMLogic::createKeyPairHelper(
1161 const Credentials &cred,
1162 const CryptoAlgorithmSerializable & keyGenParams,
1163 const Name &namePrivate,
1164 const Label &labelPrivate,
1165 const Name &namePublic,
1166 const Label &labelPublic,
1167 const PolicySerializable &policyPrivate,
1168 const PolicySerializable &policyPublic)
1170 auto &handlerPriv = selectDatabase(cred, labelPrivate);
1171 auto &handlerPub = selectDatabase(cred, labelPublic);
1173 AlgoType keyType = AlgoType::RSA_GEN;
1174 if(!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType))
1175 ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found.");
1176 DataType dt(keyType);
1178 ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value.");
1180 bool exportable = policyPrivate.extractable || policyPublic.extractable;
1181 TokenPair keys = m_decider.getStore(dt, exportable).generateAKey(keyGenParams);
1183 DB::Crypto::Transaction transactionPriv(&handlerPriv.database);
1184 // in case the same database is used for private and public - the second
1185 // transaction will not be executed
1186 DB::Crypto::Transaction transactionPub(&handlerPub.database);
1188 int retCode = saveDataHelper(cred,
1191 keys.first.dataType,
1194 if (CKM_API_SUCCESS != retCode)
1197 retCode = saveDataHelper(cred,
1200 keys.second.dataType,
1203 if (CKM_API_SUCCESS != retCode)
1206 transactionPub.commit();
1207 transactionPriv.commit();
1208 return CKM_API_SUCCESS;
1211 RawBuffer CKMLogic::createKeyPair(
1212 const Credentials &cred,
1214 const CryptoAlgorithmSerializable & keyGenParams,
1215 const Name &namePrivate,
1216 const Label &labelPrivate,
1217 const Name &namePublic,
1218 const Label &labelPublic,
1219 const PolicySerializable &policyPrivate,
1220 const PolicySerializable &policyPublic)
1222 int retCode = CKM_API_SUCCESS;
1225 retCode = createKeyPairHelper(
1234 } catch(const Exc::Exception &e) {
1235 retCode = e.error();
1236 } catch (DB::Crypto::Exception::TransactionError &e) {
1237 LogDebug("DB::Crypto error: transaction error: " << e.GetMessage());
1238 retCode = CKM_API_ERROR_DB_ERROR;
1239 } catch (DB::Crypto::Exception::InternalError &e) {
1240 LogDebug("DB::Crypto internal error: " << e.GetMessage());
1241 retCode = CKM_API_ERROR_DB_ERROR;
1242 } catch (const CKM::Exception &e) {
1243 LogError("CKM::Exception: " << e.GetMessage());
1244 retCode = CKM_API_ERROR_SERVER_ERROR;
1247 return MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_KEY_PAIR),
1248 commandId, retCode).Pop();
1251 RawBuffer CKMLogic::createKeyAES(
1252 const Credentials &cred,
1257 const PolicySerializable &policy)
1259 int retCode = CKM_API_SUCCESS;
1262 retCode = createKeyAESHelper(cred, size, name, label, policy);
1263 } catch (const Exc::Exception &e) {
1264 retCode = e.error();
1265 } catch (std::invalid_argument &e) {
1266 LogDebug("invalid argument error: " << e.what());
1267 retCode = CKM_API_ERROR_INPUT_PARAM;
1268 } catch (DB::Crypto::Exception::TransactionError &e) {
1269 LogDebug("DB::Crypto error: transaction error: " << e.GetMessage());
1270 retCode = CKM_API_ERROR_DB_ERROR;
1271 } catch (DB::Crypto::Exception::InternalError &e) {
1272 LogDebug("DB::Crypto internal error: " << e.GetMessage());
1273 retCode = CKM_API_ERROR_DB_ERROR;
1274 } catch (const CKM::Exception &e) {
1275 LogError("CKM::Exception: " << e.GetMessage());
1276 retCode = CKM_API_ERROR_SERVER_ERROR;
1279 return MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_KEY_AES),
1280 commandId, retCode).Pop();
1283 int CKMLogic::readCertificateHelper(
1284 const Credentials &cred,
1285 const LabelNameVector &labelNameVector,
1286 CertificateImplVector &certVector)
1289 for (auto &i: labelNameVector) {
1290 int ec = readDataHelper(false, cred, DataType::CERTIFICATE, i.second, i.first, Password(), row);
1291 if (ec != CKM_API_SUCCESS)
1293 certVector.push_back(CertificateImpl(row.data, DataFormat::FORM_DER));
1295 // try to read chain certificates (if present)
1296 DB::RowVector rawCaChain;
1297 ec = readDataHelper(false, cred, DataType::DB_CHAIN_FIRST, i.second, i.first, CKM::Password(), rawCaChain);
1298 if(ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1300 for(auto &rawCaCert : rawCaChain)
1301 certVector.push_back(CertificateImpl(rawCaCert.data, DataFormat::FORM_DER));
1303 return CKM_API_SUCCESS;
1306 int CKMLogic::getCertificateChainHelper(
1307 const CertificateImpl &cert,
1308 const RawBufferVector &untrustedCertificates,
1309 const RawBufferVector &trustedCertificates,
1310 bool useTrustedSystemCertificates,
1311 RawBufferVector &chainRawVector)
1313 CertificateImplVector untrustedCertVector;
1314 CertificateImplVector trustedCertVector;
1315 CertificateImplVector chainVector;
1318 return CKM_API_ERROR_INPUT_PARAM;
1320 for (auto &e: untrustedCertificates)
1321 untrustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER));
1322 for (auto &e: trustedCertificates)
1323 trustedCertVector.push_back(CertificateImpl(e, DataFormat::FORM_DER));
1325 CertificateStore store;
1326 int retCode = store.verifyCertificate(cert,
1327 untrustedCertVector,
1329 useTrustedSystemCertificates,
1330 m_accessControl.isCCMode(),
1332 if (retCode != CKM_API_SUCCESS)
1335 for (auto &e : chainVector)
1336 chainRawVector.push_back(e.getDER());
1337 return CKM_API_SUCCESS;
1340 int CKMLogic::getCertificateChainHelper(
1341 const Credentials &cred,
1342 const CertificateImpl &cert,
1343 const LabelNameVector &untrusted,
1344 const LabelNameVector &trusted,
1345 bool useTrustedSystemCertificates,
1346 RawBufferVector &chainRawVector)
1348 CertificateImplVector untrustedCertVector;
1349 CertificateImplVector trustedCertVector;
1350 CertificateImplVector chainVector;
1354 return CKM_API_ERROR_INPUT_PARAM;
1356 int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1357 if (retCode != CKM_API_SUCCESS)
1359 retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1360 if (retCode != CKM_API_SUCCESS)
1363 CertificateStore store;
1364 retCode = store.verifyCertificate(cert,
1365 untrustedCertVector,
1367 useTrustedSystemCertificates,
1368 m_accessControl.isCCMode(),
1370 if (retCode != CKM_API_SUCCESS)
1373 for (auto &i: chainVector)
1374 chainRawVector.push_back(i.getDER());
1376 return CKM_API_SUCCESS;
1379 RawBuffer CKMLogic::getCertificateChain(
1380 const Credentials & /*cred*/,
1382 const RawBuffer &certificate,
1383 const RawBufferVector &untrustedCertificates,
1384 const RawBufferVector &trustedCertificates,
1385 bool useTrustedSystemCertificates)
1387 CertificateImpl cert(certificate, DataFormat::FORM_DER);
1388 RawBufferVector chainRawVector;
1389 int retCode = CKM_API_ERROR_UNKNOWN;
1391 retCode = getCertificateChainHelper(cert,
1392 untrustedCertificates,
1393 trustedCertificates,
1394 useTrustedSystemCertificates,
1396 } catch (const Exc::Exception &e) {
1397 retCode = e.error();
1398 } catch (const DB::Crypto::Exception::Base &e) {
1399 LogError("DB::Crypto failed with message: " << e.GetMessage());
1400 retCode = CKM_API_ERROR_DB_ERROR;
1401 } catch (const std::exception& e) {
1402 LogError("STD exception " << e.what());
1403 retCode = CKM_API_ERROR_SERVER_ERROR;
1405 LogError("Unknown error.");
1408 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_CERT),
1412 return response.Pop();
1415 RawBuffer CKMLogic::getCertificateChain(
1416 const Credentials &cred,
1418 const RawBuffer &certificate,
1419 const LabelNameVector &untrustedCertificates,
1420 const LabelNameVector &trustedCertificates,
1421 bool useTrustedSystemCertificates)
1423 int retCode = CKM_API_ERROR_UNKNOWN;
1424 CertificateImpl cert(certificate, DataFormat::FORM_DER);
1425 RawBufferVector chainRawVector;
1427 retCode = getCertificateChainHelper(cred,
1429 untrustedCertificates,
1430 trustedCertificates,
1431 useTrustedSystemCertificates,
1433 } catch (const DB::Crypto::Exception::Base &e) {
1434 LogError("DB::Crypto failed with message: " << e.GetMessage());
1435 retCode = CKM_API_ERROR_DB_ERROR;
1436 } catch (const Exc::Exception &e) {
1437 retCode = e.error();
1438 } catch (const std::exception& e) {
1439 LogError("STD exception " << e.what());
1440 retCode = CKM_API_ERROR_SERVER_ERROR;
1442 LogError("Unknown error.");
1445 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_CHAIN_ALIAS),
1449 return response.Pop();
1452 RawBuffer CKMLogic::createSignature(
1453 const Credentials &cred,
1455 const Name &privateKeyName,
1456 const Label & ownerLabel,
1457 const Password &password, // password for private_key
1458 const RawBuffer &message,
1459 const HashAlgorithm hash,
1460 const RSAPaddingAlgorithm padding)
1463 RawBuffer signature;
1464 CryptoAlgorithm cryptoAlg;
1465 cryptoAlg.setParam(ParamName::SV_HASH_ALGO, hash);
1466 cryptoAlg.setParam(ParamName::SV_RSA_PADDING, padding);
1468 int retCode = CKM_API_SUCCESS;
1471 retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName, ownerLabel, password, row);
1472 if(retCode == CKM_API_SUCCESS) {
1473 signature = m_decider.getStore(row).getKey(row)->sign(cryptoAlg, message);
1475 } catch (const DB::Crypto::Exception::Base &e) {
1476 LogError("DB::Crypto failed with message: " << e.GetMessage());
1477 retCode = CKM_API_ERROR_DB_ERROR;
1478 } catch (const Exc::Exception &e) {
1479 retCode = e.error();
1480 } catch (const CKM::Exception &e) {
1481 LogError("Unknown CKM::Exception: " << e.GetMessage());
1482 retCode = CKM_API_ERROR_SERVER_ERROR;
1485 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_SIGNATURE),
1489 return response.Pop();
1492 RawBuffer CKMLogic::verifySignature(
1493 const Credentials &cred,
1495 const Name &publicKeyOrCertName,
1496 const Label & ownerLabel,
1497 const Password &password, // password for public_key (optional)
1498 const RawBuffer &message,
1499 const RawBuffer &signature,
1500 const HashAlgorithm hash,
1501 const RSAPaddingAlgorithm padding)
1503 int retCode = CKM_API_ERROR_VERIFICATION_FAILED;
1508 CryptoAlgorithm params;
1509 params.setParam(ParamName::SV_HASH_ALGO, hash);
1510 params.setParam(ParamName::SV_RSA_PADDING, padding);
1512 // try certificate first - looking for a public key.
1513 // in case of PKCS, pub key from certificate will be found first
1514 // rather than private key from the same PKCS.
1515 retCode = readDataHelper(false, cred, DataType::CERTIFICATE, publicKeyOrCertName, ownerLabel, password, row);
1516 if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
1517 retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, publicKeyOrCertName, ownerLabel, password, row);
1520 if (retCode == CKM_API_SUCCESS) {
1521 retCode = m_decider.getStore(row).getKey(row)->verify(params, message, signature);
1523 } catch (const Exc::Exception &e) {
1524 retCode = e.error();
1525 } catch (const DB::Crypto::Exception::Base &e) {
1526 LogError("DB::Crypto failed with message: " << e.GetMessage());
1527 retCode = CKM_API_ERROR_DB_ERROR;
1528 } catch (const CKM::Exception &e) {
1529 LogError("Unknown CKM::Exception: " << e.GetMessage());
1530 retCode = CKM_API_ERROR_SERVER_ERROR;
1533 auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::VERIFY_SIGNATURE),
1536 return response.Pop();
1539 int CKMLogic::setPermissionHelper(
1540 const Credentials &cred, // who's the client
1542 const Label &label, // who's the owner
1543 const Label &accessorLabel, // who will get the access
1544 const PermissionMask permissionMask)
1546 auto &handler = selectDatabase(cred, label);
1548 // we don't know the client
1549 if (cred.smackLabel.empty() || !isLabelValid(cred.smackLabel))
1550 return CKM_API_ERROR_INPUT_PARAM;
1552 // use client label if not explicitly provided
1553 const Label& ownerLabel = label.empty() ? cred.smackLabel : label;
1555 // verify name and label are correct
1556 if (!isNameValid(name) || !isLabelValid(ownerLabel) || !isLabelValid(accessorLabel))
1557 return CKM_API_ERROR_INPUT_PARAM;
1559 // currently we don't support modification of owner's permissions to his own rows
1560 if (ownerLabel==accessorLabel)
1561 return CKM_API_ERROR_INPUT_PARAM;
1563 // system database does not support write/remove permissions
1564 if ((0 == ownerLabel.compare(LABEL_SYSTEM_DB)) &&
1565 (permissionMask & Permission::REMOVE))
1566 return CKM_API_ERROR_INPUT_PARAM;
1568 // can the client modify permissions to owner's row?
1569 int retCode = m_accessControl.canModify(cred, ownerLabel);
1570 if(retCode != CKM_API_SUCCESS)
1573 DB::Crypto::Transaction transaction(&handler.database);
1575 if( !handler.database.isNameLabelPresent(name, ownerLabel) )
1576 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1578 // removing non-existing permissions: fail
1579 if(permissionMask == Permission::NONE)
1581 if(!handler.database.getPermissionRow(name, ownerLabel, accessorLabel))
1582 return CKM_API_ERROR_INPUT_PARAM;
1585 // set permissions to the row owned by ownerLabel for accessorLabel
1586 handler.database.setPermission(name, ownerLabel, accessorLabel, permissionMask);
1587 transaction.commit();
1589 return CKM_API_SUCCESS;
1592 RawBuffer CKMLogic::setPermission(
1593 const Credentials &cred,
1598 const Label &accessorLabel,
1599 const PermissionMask permissionMask)
1603 retCode = setPermissionHelper(cred, name, label, accessorLabel, permissionMask);
1604 } catch (const Exc::Exception &e) {
1605 retCode = e.error();
1606 } Catch (CKM::Exception) {
1607 LogError("Error in set row!");
1608 retCode = CKM_API_ERROR_DB_ERROR;
1611 return MessageBuffer::Serialize(command, msgID, retCode).Pop();