Support for encrypted initial-values
[platform/core/security/key-manager.git] / src / manager / service / ckm-logic.cpp
1 /*
2  *  Copyright (c) 2014 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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
15  *
16  *
17  * @file        ckm-logic.cpp
18  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
19  * @version     1.0
20  * @brief       Sample service implementation.
21  */
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>
29 #include <key-impl.h>
30 #include <key-aes-impl.h>
31 #include <certificate-config.h>
32 #include <certificate-store.h>
33 #include <algorithm>
34 #include <sw-backend/store.h>
35 #include <generic-backend/exception.h>
36 #include <ss-migrate.h>
37
38 namespace {
39 const char *const CERT_SYSTEM_DIR          = CA_CERTS_DIR;
40 const char *const SYSTEM_DB_PASSWD         = "cAtRugU7";
41
42 bool isClientValid(const CKM::ClientId &client)
43 {
44         if (client.find(CKM::ALIAS_SEPARATOR) != CKM::ClientId::npos)
45                 return false;
46
47         return true;
48 }
49
50 bool isNameValid(const CKM::Name &name)
51 {
52         if (name.find(CKM::ALIAS_SEPARATOR) != CKM::Name::npos)
53                 return false;
54
55         return true;
56 }
57
58 } // anonymous namespace
59
60 namespace CKM {
61
62 const uid_t CKMLogic::SYSTEM_DB_UID = 0;
63 const uid_t CKMLogic::ADMIN_USER_DB_UID = 5001;
64
65 CKMLogic::CKMLogic()
66 {
67         CertificateConfig::addSystemCertificateDir(CERT_SYSTEM_DIR);
68
69         m_accessControl.updateCCMode();
70 }
71
72 CKMLogic::~CKMLogic() {}
73
74 void CKMLogic::loadDKEKFile(uid_t user, const Password &password)
75 {
76         auto &handle = m_userDataMap[user];
77
78         FileSystem fs(user);
79
80         auto wrappedDKEK = fs.getDKEK();
81
82         if (wrappedDKEK.empty()) {
83                 wrappedDKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
84                 fs.saveDKEK(wrappedDKEK);
85         }
86
87         handle.keyProvider = KeyProvider(wrappedDKEK, password);
88 }
89
90 void CKMLogic::saveDKEKFile(uid_t user, const Password &password)
91 {
92         auto &handle = m_userDataMap[user];
93
94         FileSystem fs(user);
95         fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
96 }
97
98 void CKMLogic::migrateSecureStorageData(bool isAdminUser)
99 {
100         SsMigration::migrate(isAdminUser, [this](const std::string &name,
101                                                                                          const Crypto::Data &data,
102                                                                                          bool adminUserFlag) {
103                 LogInfo("Migrate data called with  name: " << name);
104                 auto ownerId = adminUserFlag ? CLIENT_ID_ADMIN_USER : CLIENT_ID_SYSTEM;
105                 auto uid = adminUserFlag ? ADMIN_USER_DB_UID : SYSTEM_DB_UID;
106
107                 int ret = verifyAndSaveDataHelper(Credentials(uid, ownerId), name, ownerId, data,
108                                                                                   PolicySerializable());
109
110                 if (ret == CKM_API_ERROR_DB_ALIAS_EXISTS)
111                         LogWarning("Alias already exist for migrated name: " << name);
112                 else if (ret != CKM_API_SUCCESS)
113                         LogError("Failed to migrate secure-storage data. name: " << name <<
114                                          " ret: " << ret);
115         });
116 }
117
118 int CKMLogic::unlockDatabase(uid_t user, const Password &password)
119 {
120         if (0 < m_userDataMap.count(user) &&
121                         m_userDataMap[user].keyProvider.isInitialized())
122                 return CKM_API_SUCCESS;
123
124         int retCode = CKM_API_SUCCESS;
125
126         try {
127                 auto &handle = m_userDataMap[user];
128
129                 FileSystem fs(user);
130                 loadDKEKFile(user, password);
131
132                 auto wrappedDatabaseDEK = fs.getDBDEK();
133
134                 if (wrappedDatabaseDEK.empty()) {
135                         wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
136                         fs.saveDBDEK(wrappedDatabaseDEK);
137                 }
138
139                 RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
140
141                 handle.database = DB::Crypto(fs.getDBPath(), key);
142                 handle.crypto = CryptoLogic();
143
144                 if (!m_accessControl.isSystemService(user)) {
145                         // remove data of removed apps during locked state
146                         ClientIdVector removedApps = fs.clearRemovedsApps();
147
148                         for (auto &app : removedApps) {
149                                 handle.crypto.removeKey(app);
150                                 handle.database.deleteKey(app);
151                         }
152                 }
153
154                 if (user == SYSTEM_DB_UID && SsMigration::hasData())
155                         migrateSecureStorageData(false);
156                 else if (user == ADMIN_USER_DB_UID && SsMigration::hasData())
157                         migrateSecureStorageData(true);
158         } catch (const Exc::Exception &e) {
159                 retCode = e.error();
160         } catch (const CKM::Exception &e) {
161                 LogError("CKM::Exception: " << e.GetMessage());
162                 retCode = CKM_API_ERROR_SERVER_ERROR;
163         }
164
165         if (CKM_API_SUCCESS != retCode)
166                 m_userDataMap.erase(user);
167
168         return retCode;
169 }
170
171 int CKMLogic::unlockSystemDB()
172 {
173         return unlockDatabase(SYSTEM_DB_UID, SYSTEM_DB_PASSWD);
174 }
175
176 UserData &CKMLogic::selectDatabase(const Credentials &cred,
177                                                                    const ClientId &explicitOwner)
178 {
179         // if user trying to access system service - check:
180         //    * if user database is unlocked [mandatory]
181         //    * if not - proceed with regular user database
182         //    * if explicit system database owner given -> switch to system DB
183         if (!m_accessControl.isSystemService(cred)) {
184                 if (0 == m_userDataMap.count(cred.clientUid))
185                         ThrowErr(Exc::DatabaseLocked, "database with UID: ", cred.clientUid, " locked");
186
187                 if (0 != explicitOwner.compare(CLIENT_ID_SYSTEM))
188                         return m_userDataMap[cred.clientUid];
189         }
190
191         // system database selected, modify the owner id
192         if (CKM_API_SUCCESS != unlockSystemDB())
193                 ThrowErr(Exc::DatabaseLocked, "can not unlock system database");
194
195         return m_userDataMap[SYSTEM_DB_UID];
196 }
197
198 RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password)
199 {
200         int retCode = CKM_API_SUCCESS;
201
202         if (!m_accessControl.isSystemService(user))
203                 retCode = unlockDatabase(user, password);
204         else // do not allow lock/unlock operations for system users
205                 retCode = CKM_API_ERROR_INPUT_PARAM;
206
207         return MessageBuffer::Serialize(retCode).Pop();
208 }
209
210 RawBuffer CKMLogic::updateCCMode()
211 {
212         m_accessControl.updateCCMode();
213         return MessageBuffer::Serialize(CKM_API_SUCCESS).Pop();
214 }
215
216 RawBuffer CKMLogic::lockUserKey(uid_t user)
217 {
218         int retCode = CKM_API_SUCCESS;
219
220         if (!m_accessControl.isSystemService(user))
221                 m_userDataMap.erase(user);
222         else // do not allow lock/unlock operations for system users
223                 retCode = CKM_API_ERROR_INPUT_PARAM;
224
225         return MessageBuffer::Serialize(retCode).Pop();
226 }
227
228 RawBuffer CKMLogic::removeUserData(uid_t user)
229 {
230         int retCode = CKM_API_SUCCESS;
231
232         if (m_accessControl.isSystemService(user))
233                 user = SYSTEM_DB_UID;
234
235         m_userDataMap.erase(user);
236
237         FileSystem fs(user);
238         fs.removeUserData();
239
240         return MessageBuffer::Serialize(retCode).Pop();
241 }
242
243 int CKMLogic::changeUserPasswordHelper(uid_t user,
244                                                                            const Password &oldPassword,
245                                                                            const Password &newPassword)
246 {
247         // do not allow to change system database password
248         if (m_accessControl.isSystemService(user))
249                 return CKM_API_ERROR_INPUT_PARAM;
250
251         loadDKEKFile(user, oldPassword);
252         saveDKEKFile(user, newPassword);
253
254         return CKM_API_SUCCESS;
255 }
256
257 RawBuffer CKMLogic::changeUserPassword(
258         uid_t user,
259         const Password &oldPassword,
260         const Password &newPassword)
261 {
262         int retCode = CKM_API_SUCCESS;
263
264         try {
265                 retCode = changeUserPasswordHelper(user, oldPassword, newPassword);
266         } catch (const Exc::Exception &e) {
267                 retCode = e.error();
268         } catch (const CKM::Exception &e) {
269                 LogError("CKM::Exception: " << e.GetMessage());
270                 retCode = CKM_API_ERROR_SERVER_ERROR;
271         }
272
273         return MessageBuffer::Serialize(retCode).Pop();
274 }
275
276 int CKMLogic::resetUserPasswordHelper(
277         uid_t user,
278         const Password &newPassword)
279 {
280         // do not allow to reset system database password
281         if (m_accessControl.isSystemService(user))
282                 return CKM_API_ERROR_INPUT_PARAM;
283
284         int retCode = CKM_API_SUCCESS;
285
286         if (0 == m_userDataMap.count(user)) {
287                 // Check if key exists. If exists we must return error
288                 FileSystem fs(user);
289                 auto wrappedDKEKMain = fs.getDKEK();
290
291                 if (!wrappedDKEKMain.empty())
292                         retCode = CKM_API_ERROR_BAD_REQUEST;
293         } else {
294                 saveDKEKFile(user, newPassword);
295         }
296
297         return retCode;
298 }
299
300 RawBuffer CKMLogic::resetUserPassword(
301         uid_t user,
302         const Password &newPassword)
303 {
304         int retCode = CKM_API_SUCCESS;
305
306         try {
307                 retCode = resetUserPasswordHelper(user, newPassword);
308         } catch (const Exc::Exception &e) {
309                 retCode = e.error();
310         } catch (const CKM::Exception &e) {
311                 LogError("CKM::Exception: " << e.GetMessage());
312                 retCode = CKM_API_ERROR_SERVER_ERROR;
313         }
314
315         return MessageBuffer::Serialize(retCode).Pop();
316 }
317
318 RawBuffer CKMLogic::removeApplicationData(const ClientId &owner)
319 {
320         int retCode = CKM_API_SUCCESS;
321
322         try {
323                 if (owner.empty()) {
324                         retCode = CKM_API_ERROR_INPUT_PARAM;
325                 } else {
326                         UidVector uids = FileSystem::getUIDsFromDBFile();
327
328                         for (auto userId : uids) {
329                                 if (0 == m_userDataMap.count(userId)) {
330                                         FileSystem fs(userId);
331                                         fs.addRemovedApp(owner);
332                                 } else {
333                                         auto &handle = m_userDataMap[userId];
334                                         handle.crypto.removeKey(owner);
335                                         handle.database.deleteKey(owner);
336                                 }
337                         }
338                 }
339         } catch (const Exc::Exception &e) {
340                 retCode = e.error();
341         } catch (const CKM::Exception &e) {
342                 LogError("CKM::Exception: " << e.GetMessage());
343                 retCode = CKM_API_ERROR_SERVER_ERROR;
344         }
345
346         return MessageBuffer::Serialize(retCode).Pop();
347 }
348
349 int CKMLogic::checkSaveConditions(
350         const Credentials &accessorCred,
351         UserData &handler,
352         const Name &name,
353         const ClientId &owner)
354 {
355         // verify name and client are correct
356         if (!isNameValid(name) || !isClientValid(owner)) {
357                 LogDebug("Invalid parameter passed to key-manager");
358                 return CKM_API_ERROR_INPUT_PARAM;
359         }
360
361         // check if accessor is allowed to save owner's items
362         int access_ec = m_accessControl.canSave(accessorCred, owner);
363
364         if (access_ec != CKM_API_SUCCESS) {
365                 LogDebug("accessor " << accessorCred.client << " can not save rows owned by " <<
366                                  owner);
367                 return access_ec;
368         }
369
370         // check if not a duplicate
371         if (handler.database.isNameOwnerPresent(name, owner))
372                 return CKM_API_ERROR_DB_ALIAS_EXISTS;
373
374         // encryption section
375         if (!handler.crypto.haveKey(owner)) {
376                 RawBuffer got_key;
377                 auto key_optional = handler.database.getKey(owner);
378
379                 if (!key_optional) {
380                         LogDebug("No Key in database found. Generating new one for client: " <<
381                                          owner);
382                         got_key = handler.keyProvider.generateDEK(owner);
383                         handler.database.saveKey(owner, got_key);
384                 } else {
385                         LogDebug("Key from DB");
386                         got_key = *key_optional;
387                 }
388
389                 got_key = handler.keyProvider.getPureDEK(got_key);
390                 handler.crypto.pushKey(owner, got_key);
391         }
392
393         return CKM_API_SUCCESS;
394 }
395
396 DB::Row CKMLogic::createEncryptedRow(
397         CryptoLogic &crypto,
398         const Name &name,
399         const ClientId &owner,
400         const Crypto::Data &data,
401         const Policy &policy) const
402 {
403         Crypto::GStore &store = m_decider.getStore(data.type, policy);
404
405         // do not encrypt data with password during cc_mode on
406         Token token = store.import(data,
407                                                            m_accessControl.isCCMode() ? "" : policy.password,
408                                                            Crypto::EncryptionParams());
409         DB::Row row(std::move(token), name, owner,
410                                 static_cast<int>(policy.extractable));
411         crypto.encryptRow(row);
412         return row;
413 }
414
415 int CKMLogic::verifyBinaryData(Crypto::Data &input) const
416 {
417         Crypto::Data dummy;
418         return toBinaryData(input, dummy);
419 }
420
421 int CKMLogic::toBinaryData(const Crypto::Data &input,
422                                                    Crypto::Data &output) const
423 {
424         // verify the data integrity
425         if (input.type.isKey()) {
426                 KeyShPtr output_key;
427
428                 if (input.type.isSKey())
429                         output_key = CKM::Key::createAES(input.data);
430                 else
431                         output_key = CKM::Key::create(input.data);
432
433                 if (output_key.get() == NULL) {
434                         LogDebug("provided binary data is not valid key data");
435                         return CKM_API_ERROR_INPUT_PARAM;
436                 }
437
438                 output = std::move(Crypto::Data(input.type, output_key->getDER()));
439         } else if (input.type.isCertificate() || input.type.isChainCert()) {
440                 CertificateShPtr cert = CKM::Certificate::create(input.data,
441                                                                 DataFormat::FORM_DER);
442
443                 if (cert.get() == NULL) {
444                         LogDebug("provided binary data is not valid certificate data");
445                         return CKM_API_ERROR_INPUT_PARAM;
446                 }
447
448                 output = std::move(Crypto::Data(input.type, cert->getDER()));
449         } else {
450                 output = input;
451         }
452
453         // TODO: add here BINARY_DATA verification, i.e: max size etc.
454         return CKM_API_SUCCESS;
455 }
456
457 int CKMLogic::verifyAndSaveDataHelper(
458         const Credentials &cred,
459         const Name &name,
460         const ClientId &explicitOwner,
461         const Crypto::Data &data,
462         const PolicySerializable &policy)
463 {
464         int retCode = CKM_API_ERROR_UNKNOWN;
465
466         try {
467                 // check if data is correct
468                 Crypto::Data binaryData;
469                 retCode = toBinaryData(data, binaryData);
470
471                 if (retCode != CKM_API_SUCCESS)
472                         return retCode;
473                 else
474                         return saveDataHelper(cred, name, explicitOwner, binaryData, policy);
475         } catch (const Exc::Exception &e) {
476                 return e.error();
477         } catch (const CKM::Exception &e) {
478                 LogError("CKM::Exception: " << e.GetMessage());
479                 return CKM_API_ERROR_SERVER_ERROR;
480         }
481 }
482
483 int CKMLogic::getKeyForService(
484         const Credentials &cred,
485         const Name &name,
486         const ClientId &explicitOwner,
487         const Password &pass,
488         Crypto::GObjShPtr &key)
489 {
490         try {
491                 // Key is for internal service use. It won't be exported to the client
492                 Crypto::GObjUPtr obj;
493                 int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, explicitOwner,
494                                                                          pass, obj);
495
496                 if (retCode == CKM_API_SUCCESS)
497                         key = std::move(obj);
498
499                 return retCode;
500         } catch (const Exc::Exception &e) {
501                 return e.error();
502         } catch (const CKM::Exception &e) {
503                 LogError("CKM::Exception: " << e.GetMessage());
504                 return CKM_API_ERROR_SERVER_ERROR;
505         }
506 }
507
508 RawBuffer CKMLogic::saveData(
509         const Credentials &cred,
510         int commandId,
511         const Name &name,
512         const ClientId &explicitOwner,
513         const Crypto::Data &data,
514         const PolicySerializable &policy)
515 {
516         int retCode = verifyAndSaveDataHelper(cred, name, explicitOwner, data, policy);
517         auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE),
518                                         commandId,
519                                         retCode,
520                                         static_cast<int>(data.type));
521         return response.Pop();
522 }
523
524 int CKMLogic::extractPKCS12Data(
525         CryptoLogic &crypto,
526         const Name &name,
527         const ClientId &owner,
528         const PKCS12Serializable &pkcs,
529         const PolicySerializable &keyPolicy,
530         const PolicySerializable &certPolicy,
531         DB::RowVector &output) const
532 {
533         // private key is mandatory
534         auto key = pkcs.getKey();
535
536         if (!key) {
537                 LogError("Failed to get private key from pkcs");
538                 return CKM_API_ERROR_INVALID_FORMAT;
539         }
540
541         Crypto::Data keyData(DataType(key->getType()), key->getDER());
542         int retCode = verifyBinaryData(keyData);
543
544         if (retCode != CKM_API_SUCCESS)
545                 return retCode;
546
547         output.push_back(createEncryptedRow(crypto, name, owner, keyData,
548                                                                                 keyPolicy));
549
550         // certificate is mandatory
551         auto cert = pkcs.getCertificate();
552
553         if (!cert) {
554                 LogError("Failed to get certificate from pkcs");
555                 return CKM_API_ERROR_INVALID_FORMAT;
556         }
557
558         Crypto::Data certData(DataType::CERTIFICATE, cert->getDER());
559         retCode = verifyBinaryData(certData);
560
561         if (retCode != CKM_API_SUCCESS)
562                 return retCode;
563
564         output.push_back(createEncryptedRow(crypto, name, owner, certData,
565                                                                                 certPolicy));
566
567         // CA cert chain
568         unsigned int cert_index = 0;
569
570         for (const auto &ca : pkcs.getCaCertificateShPtrVector()) {
571                 Crypto::Data caCertData(DataType::getChainDatatype(cert_index ++),
572                                                                 ca->getDER());
573                 int retCode = verifyBinaryData(caCertData);
574
575                 if (retCode != CKM_API_SUCCESS)
576                         return retCode;
577
578                 output.push_back(createEncryptedRow(crypto, name, owner, caCertData,
579                                                                                         certPolicy));
580         }
581
582         return CKM_API_SUCCESS;
583 }
584
585 RawBuffer CKMLogic::savePKCS12(
586         const Credentials &cred,
587         int commandId,
588         const Name &name,
589         const ClientId &explicitOwner,
590         const PKCS12Serializable &pkcs,
591         const PolicySerializable &keyPolicy,
592         const PolicySerializable &certPolicy)
593 {
594         int retCode = CKM_API_ERROR_UNKNOWN;
595
596         try {
597                 retCode = saveDataHelper(cred, name, explicitOwner, pkcs, keyPolicy, certPolicy);
598         } catch (const Exc::Exception &e) {
599                 retCode = e.error();
600         } catch (const CKM::Exception &e) {
601                 LogError("CKM::Exception: " << e.GetMessage());
602                 retCode = CKM_API_ERROR_SERVER_ERROR;
603         }
604
605         auto response = MessageBuffer::Serialize(static_cast<int>
606                                         (LogicCommand::SAVE_PKCS12),
607                                         commandId,
608                                         retCode);
609         return response.Pop();
610 }
611
612
613 int CKMLogic::removeDataHelper(
614         const Credentials &cred,
615         const Name &name,
616         const ClientId &explicitOwner)
617 {
618         auto &handler = selectDatabase(cred, explicitOwner);
619
620         // use client id if not explicitly provided
621         const ClientId &owner = explicitOwner.empty() ? cred.client : explicitOwner;
622
623         if (!isNameValid(name) || !isClientValid(owner)) {
624                 LogDebug("Invalid owner or name format");
625                 return CKM_API_ERROR_INPUT_PARAM;
626         }
627
628         DB::Crypto::Transaction transaction(&handler.database);
629
630         // read and check permissions
631         PermissionMaskOptional permissionRowOpt =
632                 handler.database.getPermissionRow(name, owner, cred.client);
633         int retCode = m_accessControl.canDelete(cred,
634                                                                                         toPermissionMask(permissionRowOpt));
635
636         if (retCode != CKM_API_SUCCESS) {
637                 LogWarning("access control check result: " << retCode);
638                 return retCode;
639         }
640
641         // get all matching rows
642         DB::RowVector rows;
643         handler.database.getRows(name, owner, DataType::DB_FIRST,
644                                                          DataType::DB_LAST, rows);
645
646         if (rows.empty()) {
647                 LogDebug("No row for given name and owner");
648                 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
649         }
650
651         // load app key if needed
652         retCode = loadAppKey(handler, rows.front().owner);
653
654         if (CKM_API_SUCCESS != retCode)
655                 return retCode;
656
657         // destroy it in store
658         for (auto &r : rows) {
659                 try {
660                         handler.crypto.decryptRow(Password(), r);
661                         m_decider.getStore(r).destroy(r);
662                 } catch (const Exc::AuthenticationFailed &) {
663                         LogDebug("Authentication failed when removing data. Ignored.");
664                 }
665         }
666
667         // delete row in db
668         handler.database.deleteRow(name, owner);
669         transaction.commit();
670
671         return CKM_API_SUCCESS;
672 }
673
674 RawBuffer CKMLogic::removeData(
675         const Credentials &cred,
676         int commandId,
677         const Name &name,
678         const ClientId &explicitOwner)
679 {
680         int retCode = CKM_API_ERROR_UNKNOWN;
681
682         try {
683                 retCode = removeDataHelper(cred, name, explicitOwner);
684         } catch (const Exc::Exception &e) {
685                 retCode = e.error();
686         } catch (const CKM::Exception &e) {
687                 LogError("Error: " << e.GetMessage());
688                 retCode = CKM_API_ERROR_DB_ERROR;
689         }
690
691         auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::REMOVE),
692                                         commandId,
693                                         retCode);
694         return response.Pop();
695 }
696
697 int CKMLogic::readSingleRow(const Name &name,
698                                                         const ClientId &owner,
699                                                         DataType dataType,
700                                                         DB::Crypto &database,
701                                                         DB::Row &row)
702 {
703         DB::Crypto::RowOptional row_optional;
704
705         if (dataType.isKey()) {
706                 // read all key types
707                 row_optional = database.getRow(name,
708                                                                            owner,
709                                                                            DataType::DB_KEY_FIRST,
710                                                                            DataType::DB_KEY_LAST);
711         } else {
712                 // read anything else
713                 row_optional = database.getRow(name,
714                                                                            owner,
715                                                                            dataType);
716         }
717
718         if (!row_optional) {
719                 LogDebug("No row for given name, owner and type");
720                 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
721         } else {
722                 row = *row_optional;
723         }
724
725         return CKM_API_SUCCESS;
726 }
727
728
729 int CKMLogic::readMultiRow(const Name &name,
730                                                    const ClientId &owner,
731                                                    DataType dataType,
732                                                    DB::Crypto &database,
733                                                    DB::RowVector &output)
734 {
735         if (dataType.isKey())
736                 // read all key types
737                 database.getRows(name,
738                                                  owner,
739                                                  DataType::DB_KEY_FIRST,
740                                                  DataType::DB_KEY_LAST,
741                                                  output);
742         else if (dataType.isChainCert())
743                 // read all key types
744                 database.getRows(name,
745                                                  owner,
746                                                  DataType::DB_CHAIN_FIRST,
747                                                  DataType::DB_CHAIN_LAST,
748                                                  output);
749         else
750                 // read anything else
751                 database.getRows(name,
752                                                  owner,
753                                                  dataType,
754                                                  output);
755
756         if (!output.size()) {
757                 LogDebug("No row for given name, owner and type");
758                 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
759         }
760
761         return CKM_API_SUCCESS;
762 }
763
764 int CKMLogic::checkDataPermissionsHelper(const Credentials &accessorCred,
765                 const Name &name,
766                 const ClientId &owner,
767                 const DB::Row &row,
768                 bool exportFlag,
769                 DB::Crypto &database)
770 {
771         PermissionMaskOptional permissionRowOpt =
772                 database.getPermissionRow(name, owner, accessorCred.client);
773
774         if (exportFlag)
775                 return m_accessControl.canExport(accessorCred,
776                                                                                  row,
777                                                                                  toPermissionMask(permissionRowOpt));
778
779         return m_accessControl.canRead(accessorCred,
780                                                                    toPermissionMask(permissionRowOpt));
781 }
782
783 Crypto::GObjUPtr CKMLogic::rowToObject(
784         UserData &handler,
785         DB::Row row,
786         const Password &password)
787 {
788         Crypto::GStore &store = m_decider.getStore(row);
789
790         Password pass = m_accessControl.isCCMode() ? "" : password;
791
792         // decrypt row
793         Crypto::GObjUPtr obj;
794
795         if (CryptoLogic::getSchemeVersion(row.encryptionScheme) ==
796                         CryptoLogic::ENCRYPTION_V2) {
797                 handler.crypto.decryptRow(Password(), row);
798
799                 obj = store.getObject(row, pass);
800         } else {
801                 // decrypt entirely with old scheme: b64(pass(appkey(data))) -> data
802                 handler.crypto.decryptRow(pass, row);
803                 // destroy it in store
804                 store.destroy(row);
805
806                 // import it to store with new scheme: data -> pass(data)
807                 Token token = store.import(Crypto::Data(row.dataType, row.data), pass, Crypto::EncryptionParams());
808
809                 // get it from the store (it can be different than the data we imported into store)
810                 obj = store.getObject(token, pass);
811
812                 // update row with new token
813                 *static_cast<Token *>(&row) = std::move(token);
814
815                 // encrypt it with app key: pass(data) -> b64(appkey(pass(data))
816                 handler.crypto.encryptRow(row);
817
818                 // update it in db
819                 handler.database.updateRow(row);
820         }
821
822         return obj;
823 }
824
825 int CKMLogic::readDataHelper(
826         bool exportFlag,
827         const Credentials &cred,
828         DataType dataType,
829         const Name &name,
830         const ClientId &explicitOwner,
831         const Password &password,
832         Crypto::GObjUPtrVector &objs)
833 {
834         auto &handler = selectDatabase(cred, explicitOwner);
835
836         // use client id if not explicitly provided
837         const ClientId &owner = explicitOwner.empty() ? cred.client : explicitOwner;
838
839         if (!isNameValid(name) || !isClientValid(owner))
840                 return CKM_API_ERROR_INPUT_PARAM;
841
842         // read rows
843         DB::Crypto::Transaction transaction(&handler.database);
844         DB::RowVector rows;
845         int retCode = readMultiRow(name, owner, dataType, handler.database, rows);
846
847         if (CKM_API_SUCCESS != retCode)
848                 return retCode;
849
850         // all read rows belong to the same owner
851         DB::Row &firstRow = rows.at(0);
852
853         // check access rights
854         retCode = checkDataPermissionsHelper(cred, name, owner, firstRow,
855                                                                                  exportFlag, handler.database);
856
857         if (CKM_API_SUCCESS != retCode)
858                 return retCode;
859
860         // load app key if needed
861         retCode = loadAppKey(handler, firstRow.owner);
862
863         if (CKM_API_SUCCESS != retCode)
864                 return retCode;
865
866         // decrypt row
867         for (auto &row : rows)
868                 objs.push_back(rowToObject(handler, std::move(row), password));
869
870         // rowToObject may modify db
871         transaction.commit();
872
873         return CKM_API_SUCCESS;
874 }
875
876 int CKMLogic::readDataHelper(
877         bool exportFlag,
878         const Credentials &cred,
879         DataType dataType,
880         const Name &name,
881         const ClientId &explicitOwner,
882         const Password &password,
883         Crypto::GObjUPtr &obj)
884 {
885         DataType objDataType;
886         return readDataHelper(exportFlag, cred, dataType, name, explicitOwner,
887                                                   password, obj, objDataType);
888 }
889
890 int CKMLogic::readDataHelper(
891         bool exportFlag,
892         const Credentials &cred,
893         DataType dataType,
894         const Name &name,
895         const ClientId &explicitOwner,
896         const Password &password,
897         Crypto::GObjUPtr &obj,
898         DataType &objDataType)
899 {
900         auto &handler = selectDatabase(cred, explicitOwner);
901
902         // use client id if not explicitly provided
903         const ClientId &owner = explicitOwner.empty() ? cred.client : explicitOwner;
904
905         if (!isNameValid(name) || !isClientValid(owner))
906                 return CKM_API_ERROR_INPUT_PARAM;
907
908         // read row
909         DB::Crypto::Transaction transaction(&handler.database);
910         DB::Row row;
911         int retCode = readSingleRow(name, owner, dataType, handler.database, row);
912
913         if (CKM_API_SUCCESS != retCode)
914                 return retCode;
915
916         objDataType = row.dataType;
917
918         // check access rights
919         retCode = checkDataPermissionsHelper(cred, name, owner, row, exportFlag,
920                                                                                  handler.database);
921
922         if (CKM_API_SUCCESS != retCode)
923                 return retCode;
924
925         // load app key if needed
926         retCode = loadAppKey(handler, row.owner);
927
928         if (CKM_API_SUCCESS != retCode)
929                 return retCode;
930
931         obj = rowToObject(handler, std::move(row), password);
932         // rowToObject may modify db
933         transaction.commit();
934
935         return CKM_API_SUCCESS;
936 }
937
938 RawBuffer CKMLogic::getData(
939         const Credentials &cred,
940         int commandId,
941         DataType dataType,
942         const Name &name,
943         const ClientId &explicitOwner,
944         const Password &password)
945 {
946         int retCode = CKM_API_SUCCESS;
947         RawBuffer rowData;
948         DataType objDataType;
949
950         try {
951                 Crypto::GObjUPtr obj;
952                 retCode = readDataHelper(true, cred, dataType, name, explicitOwner,
953                                                                  password, obj, objDataType);
954
955                 if (retCode == CKM_API_SUCCESS)
956                         rowData = obj->getBinary();
957         } catch (const Exc::Exception &e) {
958                 retCode = e.error();
959         } catch (const CKM::Exception &e) {
960                 LogError("CKM::Exception: " << e.GetMessage());
961                 retCode = CKM_API_ERROR_SERVER_ERROR;
962         }
963
964         if (CKM_API_SUCCESS != retCode)
965                 rowData.clear();
966
967         auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET),
968                                         commandId,
969                                         retCode,
970                                         static_cast<int>(objDataType),
971                                         rowData);
972         return response.Pop();
973 }
974
975 int CKMLogic::getPKCS12Helper(
976         const Credentials &cred,
977         const Name &name,
978         const ClientId &explicitOwner,
979         const Password &keyPassword,
980         const Password &certPassword,
981         KeyShPtr &privKey,
982         CertificateShPtr &cert,
983         CertificateShPtrVector &caChain)
984 {
985         int retCode;
986
987         // read private key (mandatory)
988         Crypto::GObjUPtr keyObj;
989         retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, explicitOwner,
990                                                          keyPassword, keyObj);
991
992         if (retCode != CKM_API_SUCCESS) {
993                 if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
994                         return retCode;
995         } else {
996                 privKey = CKM::Key::create(keyObj->getBinary());
997         }
998
999         // read certificate (mandatory)
1000         Crypto::GObjUPtr certObj;
1001         retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, explicitOwner,
1002                                                          certPassword, certObj);
1003
1004         if (retCode != CKM_API_SUCCESS) {
1005                 if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
1006                         return retCode;
1007         } else {
1008                 cert = CKM::Certificate::create(certObj->getBinary(), DataFormat::FORM_DER);
1009         }
1010
1011         // read CA cert chain (optional)
1012         Crypto::GObjUPtrVector caChainObjs;
1013         retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, explicitOwner,
1014                                                          certPassword, caChainObjs);
1015
1016         if (retCode != CKM_API_SUCCESS && retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
1017                 if (retCode != CKM_API_ERROR_NOT_EXPORTABLE)
1018                         return retCode;
1019         } else {
1020                 for (auto &caCertObj : caChainObjs)
1021                         caChain.push_back(CKM::Certificate::create(caCertObj->getBinary(),
1022                                                                                                            DataFormat::FORM_DER));
1023         }
1024
1025         // if anything found, return it
1026         if (privKey || cert || caChain.size() > 0)
1027                 retCode = CKM_API_SUCCESS;
1028
1029         return retCode;
1030 }
1031
1032 RawBuffer CKMLogic::getPKCS12(
1033         const Credentials &cred,
1034         int commandId,
1035         const Name &name,
1036         const ClientId &explicitOwner,
1037         const Password &keyPassword,
1038         const Password &certPassword)
1039 {
1040         int retCode = CKM_API_ERROR_UNKNOWN;
1041
1042         PKCS12Serializable output;
1043
1044         try {
1045                 KeyShPtr privKey;
1046                 CertificateShPtr cert;
1047                 CertificateShPtrVector caChain;
1048                 retCode = getPKCS12Helper(cred, name, explicitOwner, keyPassword,
1049                                                                   certPassword, privKey, cert, caChain);
1050
1051                 // prepare response
1052                 if (retCode == CKM_API_SUCCESS)
1053                         output = PKCS12Serializable(std::move(privKey), std::move(cert),
1054                                                                                 std::move(caChain));
1055         } catch (const Exc::Exception &e) {
1056                 retCode = e.error();
1057         } catch (const CKM::Exception &e) {
1058                 LogError("CKM::Exception: " << e.GetMessage());
1059                 retCode = CKM_API_ERROR_SERVER_ERROR;
1060         }
1061
1062         auto response = MessageBuffer::Serialize(static_cast<int>
1063                                         (LogicCommand::GET_PKCS12),
1064                                         commandId,
1065                                         retCode,
1066                                         output);
1067         return response.Pop();
1068 }
1069
1070 int CKMLogic::getDataListHelper(const Credentials &cred,
1071                                                                 const DataType dataType,
1072                                                                 OwnerNameVector &ownerNameVector)
1073 {
1074         int retCode = CKM_API_ERROR_DB_LOCKED;
1075
1076         if (0 < m_userDataMap.count(cred.clientUid)) {
1077                 auto &database = m_userDataMap[cred.clientUid].database;
1078
1079                 try {
1080                         OwnerNameVector tmpVector;
1081
1082                         if (dataType.isKey()) {
1083                                 // list all key types
1084                                 database.listNames(cred.client,
1085                                                                    tmpVector,
1086                                                                    DataType::DB_KEY_FIRST,
1087                                                                    DataType::DB_KEY_LAST);
1088                         } else {
1089                                 // list anything else
1090                                 database.listNames(cred.client,
1091                                                                    tmpVector,
1092                                                                    dataType);
1093                         }
1094
1095                         ownerNameVector.insert(ownerNameVector.end(), tmpVector.begin(),
1096                                                                    tmpVector.end());
1097                         retCode = CKM_API_SUCCESS;
1098                 } catch (const CKM::Exception &e) {
1099                         LogError("Error: " << e.GetMessage());
1100                         retCode = CKM_API_ERROR_DB_ERROR;
1101                 } catch (const Exc::Exception &e) {
1102                         retCode = e.error();
1103                 }
1104         }
1105
1106         return retCode;
1107 }
1108
1109 RawBuffer CKMLogic::getDataList(
1110         const Credentials &cred,
1111         int commandId,
1112         DataType dataType)
1113 {
1114         OwnerNameVector systemVector;
1115         OwnerNameVector userVector;
1116         OwnerNameVector ownerNameVector;
1117
1118         int retCode = unlockSystemDB();
1119
1120         if (CKM_API_SUCCESS == retCode) {
1121                 // system database
1122                 if (m_accessControl.isSystemService(cred)) {
1123                         // lookup system DB
1124                         retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
1125                                                                                                         CLIENT_ID_SYSTEM),
1126                                                                                 dataType,
1127                                                                                 systemVector);
1128                 } else {
1129                         // user - lookup system, then client DB
1130                         retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
1131                                                                                                         cred.client),
1132                                                                                 dataType,
1133                                                                                 systemVector);
1134
1135                         // private database
1136                         if (retCode == CKM_API_SUCCESS) {
1137                                 retCode = getDataListHelper(cred,
1138                                                                                         dataType,
1139                                                                                         userVector);
1140                         }
1141                 }
1142         }
1143
1144         if (retCode == CKM_API_SUCCESS) {
1145                 ownerNameVector.insert(ownerNameVector.end(), systemVector.begin(),
1146                                                            systemVector.end());
1147                 ownerNameVector.insert(ownerNameVector.end(), userVector.begin(),
1148                                                            userVector.end());
1149         }
1150
1151         auto response = MessageBuffer::Serialize(static_cast<int>
1152                                         (LogicCommand::GET_LIST),
1153                                         commandId,
1154                                         retCode,
1155                                         static_cast<int>(dataType),
1156                                         ownerNameVector);
1157         return response.Pop();
1158 }
1159
1160 int CKMLogic::importInitialData(
1161         const Name &name,
1162         const Crypto::Data &data,
1163         const Crypto::EncryptionParams &encParams,
1164         const Policy &policy)
1165 {
1166         try {
1167                 if (encParams.iv.empty() != encParams.tag.empty()) {
1168                         LogError("Both iv and tag must be empty or set");
1169                         return CKM_API_ERROR_INPUT_PARAM;
1170                 }
1171
1172                 // Inital values are always imported with root credentials. Client id is not important.
1173                 Credentials rootCred(0, "");
1174
1175                 auto &handler = selectDatabase(rootCred, CLIENT_ID_SYSTEM);
1176
1177                 // check if save is possible
1178                 DB::Crypto::Transaction transaction(&handler.database);
1179                 int retCode = checkSaveConditions(rootCred, handler, name, CLIENT_ID_SYSTEM);
1180
1181                 if (retCode != CKM_API_SUCCESS)
1182                         return retCode;
1183
1184                 Crypto::GStore &store =
1185                                 m_decider.getStore(data.type, policy, !encParams.iv.empty());
1186
1187                 Token token;
1188
1189                 if (encParams.iv.empty()) {
1190             // Data are not encrypted, let's try to verify them
1191                         Crypto::Data binaryData;
1192
1193                         if (CKM_API_SUCCESS != (retCode = toBinaryData(data, binaryData)))
1194                                 return retCode;
1195
1196                         token = store.import(binaryData,
1197                                                                  m_accessControl.isCCMode() ? "" : policy.password,
1198                                                                  encParams);
1199                 } else {
1200                         token = store.import(data,
1201                                                                  m_accessControl.isCCMode() ? "" : policy.password,
1202                                                                  encParams);
1203                 }
1204
1205                 DB::Row row(std::move(token), name, CLIENT_ID_SYSTEM,
1206                                         static_cast<int>(policy.extractable));
1207                 handler.crypto.encryptRow(row);
1208
1209                 handler.database.saveRow(row);
1210                 transaction.commit();
1211         } catch (const Exc::Exception &e) {
1212                 return e.error();
1213         } catch (const CKM::Exception &e) {
1214                 LogError("CKM::Exception: " << e.GetMessage());
1215                 return CKM_API_ERROR_SERVER_ERROR;
1216         } catch (const std::exception &e) {
1217                 LogError("Std::exception: " << e.what());
1218                 return CKM_API_ERROR_SERVER_ERROR;
1219         }
1220
1221         return CKM_API_SUCCESS;
1222 }
1223
1224 int CKMLogic::saveDataHelper(
1225         const Credentials &cred,
1226         const Name &name,
1227         const ClientId &explicitOwner,
1228         const Crypto::Data &data,
1229         const PolicySerializable &policy)
1230 {
1231         auto &handler = selectDatabase(cred, explicitOwner);
1232
1233         // use client id if not explicitly provided
1234         const ClientId &owner = explicitOwner.empty() ? cred.client : explicitOwner;
1235
1236         if (m_accessControl.isSystemService(cred) &&
1237                         owner.compare(CLIENT_ID_SYSTEM) != 0) {
1238                 LogError("System services can only use " << CLIENT_ID_SYSTEM << " as owner id") ;
1239                 return CKM_API_ERROR_INPUT_PARAM;
1240         }
1241
1242         // check if save is possible
1243         DB::Crypto::Transaction transaction(&handler.database);
1244         int retCode = checkSaveConditions(cred, handler, name, owner);
1245
1246         if (retCode != CKM_API_SUCCESS)
1247                 return retCode;
1248
1249         // save the data
1250         DB::Row encryptedRow = createEncryptedRow(handler.crypto, name, owner,
1251                                                    data, policy);
1252         handler.database.saveRow(encryptedRow);
1253
1254         transaction.commit();
1255         return CKM_API_SUCCESS;
1256 }
1257
1258 int CKMLogic::saveDataHelper(
1259         const Credentials &cred,
1260         const Name &name,
1261         const ClientId &explicitOwner,
1262         const PKCS12Serializable &pkcs,
1263         const PolicySerializable &keyPolicy,
1264         const PolicySerializable &certPolicy)
1265 {
1266         auto &handler = selectDatabase(cred, explicitOwner);
1267
1268         // use client id if not explicitly provided
1269         const ClientId &owner = explicitOwner.empty() ? cred.client : explicitOwner;
1270
1271         if (m_accessControl.isSystemService(cred) &&
1272                         owner.compare(CLIENT_ID_SYSTEM) != 0)
1273                 return CKM_API_ERROR_INPUT_PARAM;
1274
1275         // check if save is possible
1276         DB::Crypto::Transaction transaction(&handler.database);
1277         int retCode = checkSaveConditions(cred, handler, name, owner);
1278
1279         if (retCode != CKM_API_SUCCESS)
1280                 return retCode;
1281
1282         // extract and encrypt the data
1283         DB::RowVector encryptedRows;
1284         retCode = extractPKCS12Data(handler.crypto, name, owner, pkcs, keyPolicy,
1285                                                                 certPolicy, encryptedRows);
1286
1287         if (retCode != CKM_API_SUCCESS)
1288                 return retCode;
1289
1290         // save the data
1291         handler.database.saveRows(name, owner, encryptedRows);
1292         transaction.commit();
1293
1294         return CKM_API_SUCCESS;
1295 }
1296
1297
1298 int CKMLogic::createKeyAESHelper(
1299         const Credentials &cred,
1300         const int size,
1301         const Name &name,
1302         const ClientId &explicitOwner,
1303         const PolicySerializable &policy)
1304 {
1305         auto &handler = selectDatabase(cred, explicitOwner);
1306
1307         // use client id if not explicitly provided
1308         const ClientId &owner = explicitOwner.empty() ? cred.client : explicitOwner;
1309
1310         if (m_accessControl.isSystemService(cred) &&
1311                         owner.compare(CLIENT_ID_SYSTEM) != 0)
1312                 return CKM_API_ERROR_INPUT_PARAM;
1313
1314         // check if save is possible
1315         DB::Crypto::Transaction transaction(&handler.database);
1316         int retCode = checkSaveConditions(cred, handler, name, owner);
1317
1318         if (retCode != CKM_API_SUCCESS)
1319                 return retCode;
1320
1321         // create key in store
1322         CryptoAlgorithm keyGenAlgorithm;
1323         keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN);
1324         keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
1325         Token key = m_decider.getStore(DataType::KEY_AES,
1326                                        policy).generateSKey(keyGenAlgorithm, policy.password);
1327
1328         // save the data
1329         DB::Row row(std::move(key), name, owner,
1330                                 static_cast<int>(policy.extractable));
1331         handler.crypto.encryptRow(row);
1332
1333         handler.database.saveRow(row);
1334
1335         transaction.commit();
1336         return CKM_API_SUCCESS;
1337 }
1338
1339 int CKMLogic::createKeyPairHelper(
1340         const Credentials &cred,
1341         const CryptoAlgorithmSerializable &keyGenParams,
1342         const Name &namePrivate,
1343         const ClientId &explicitOwnerPrivate,
1344         const Name &namePublic,
1345         const ClientId &explicitOwnerPublic,
1346         const PolicySerializable &policyPrivate,
1347         const PolicySerializable &policyPublic)
1348 {
1349         auto &handlerPriv = selectDatabase(cred, explicitOwnerPrivate);
1350         auto &handlerPub = selectDatabase(cred, explicitOwnerPublic);
1351
1352         AlgoType keyType = AlgoType::RSA_GEN;
1353
1354         if (!keyGenParams.getParam(ParamName::ALGO_TYPE, keyType))
1355                 ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE not found.");
1356
1357         DataType dt(keyType);
1358
1359         if (!dt.isKey())
1360                 ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value.");
1361
1362         if (policyPrivate.backend != policyPublic.backend)
1363                 ThrowErr(Exc::InputParam, "Error, key pair must be supported with the same backend.");
1364
1365         // use client id if not explicitly provided
1366         const ClientId &ownerPrv = explicitOwnerPrivate.empty() ? cred.client :
1367                                                            explicitOwnerPrivate;
1368
1369         if (m_accessControl.isSystemService(cred) &&
1370                         ownerPrv.compare(CLIENT_ID_SYSTEM) != 0)
1371                 return CKM_API_ERROR_INPUT_PARAM;
1372
1373         const ClientId &ownerPub = explicitOwnerPublic.empty() ? cred.client :
1374                                                            explicitOwnerPublic;
1375
1376         if (m_accessControl.isSystemService(cred) &&
1377                         ownerPub.compare(CLIENT_ID_SYSTEM) != 0)
1378                 return CKM_API_ERROR_INPUT_PARAM;
1379
1380         bool exportable = policyPrivate.extractable || policyPublic.extractable;
1381         Policy lessRestricted(Password(), exportable, policyPrivate.backend);
1382
1383         TokenPair keys = m_decider.getStore(dt, lessRestricted).generateAKey(keyGenParams,
1384                                          policyPrivate.password,
1385                                          policyPublic.password);
1386
1387         DB::Crypto::Transaction transactionPriv(&handlerPriv.database);
1388         // in case the same database is used for private and public - the second
1389         // transaction will not be executed
1390         DB::Crypto::Transaction transactionPub(&handlerPub.database);
1391
1392         int retCode;
1393         retCode = checkSaveConditions(cred, handlerPriv, namePrivate, ownerPrv);
1394
1395         if (CKM_API_SUCCESS != retCode)
1396                 return retCode;
1397
1398         retCode = checkSaveConditions(cred, handlerPub, namePublic, ownerPub);
1399
1400         if (CKM_API_SUCCESS != retCode)
1401                 return retCode;
1402
1403         // save the data
1404         DB::Row rowPrv(std::move(keys.first), namePrivate, ownerPrv,
1405                                    static_cast<int>(policyPrivate.extractable));
1406         handlerPriv.crypto.encryptRow(rowPrv);
1407         handlerPriv.database.saveRow(rowPrv);
1408
1409         DB::Row rowPub(std::move(keys.second), namePublic, ownerPub,
1410                                    static_cast<int>(policyPublic.extractable));
1411         handlerPub.crypto.encryptRow(rowPub);
1412         handlerPub.database.saveRow(rowPub);
1413
1414         transactionPub.commit();
1415         transactionPriv.commit();
1416         return CKM_API_SUCCESS;
1417 }
1418
1419 RawBuffer CKMLogic::createKeyPair(
1420         const Credentials &cred,
1421         int commandId,
1422         const CryptoAlgorithmSerializable &keyGenParams,
1423         const Name &namePrivate,
1424         const ClientId &explicitOwnerPrivate,
1425         const Name &namePublic,
1426         const ClientId &explicitOwnerPublic,
1427         const PolicySerializable &policyPrivate,
1428         const PolicySerializable &policyPublic)
1429 {
1430         int retCode = CKM_API_SUCCESS;
1431
1432         try {
1433                 retCode = createKeyPairHelper(
1434                                           cred,
1435                                           keyGenParams,
1436                                           namePrivate,
1437                                           explicitOwnerPrivate,
1438                                           namePublic,
1439                                           explicitOwnerPublic,
1440                                           policyPrivate,
1441                                           policyPublic);
1442         } catch (const Exc::Exception &e) {
1443                 retCode = e.error();
1444         } catch (const CKM::Exception &e) {
1445                 LogError("CKM::Exception: " << e.GetMessage());
1446                 retCode = CKM_API_ERROR_SERVER_ERROR;
1447         }
1448
1449         return MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_KEY_PAIR),
1450                                                                         commandId, retCode).Pop();
1451 }
1452
1453 RawBuffer CKMLogic::createKeyAES(
1454         const Credentials &cred,
1455         int commandId,
1456         const int size,
1457         const Name &name,
1458         const ClientId &explicitOwner,
1459         const PolicySerializable &policy)
1460 {
1461         int retCode = CKM_API_SUCCESS;
1462
1463         try {
1464                 retCode = createKeyAESHelper(cred, size, name, explicitOwner, policy);
1465         } catch (const Exc::Exception &e) {
1466                 retCode = e.error();
1467         } catch (std::invalid_argument &e) {
1468                 LogDebug("invalid argument error: " << e.what());
1469                 retCode = CKM_API_ERROR_INPUT_PARAM;
1470         } catch (const CKM::Exception &e) {
1471                 LogError("CKM::Exception: " << e.GetMessage());
1472                 retCode = CKM_API_ERROR_SERVER_ERROR;
1473         }
1474
1475         return MessageBuffer::Serialize(static_cast<int>(LogicCommand::CREATE_KEY_AES),
1476                                                                         commandId, retCode).Pop();
1477 }
1478
1479 int CKMLogic::readCertificateHelper(
1480         const Credentials &cred,
1481         const OwnerNameVector &ownerNameVector,
1482         CertificateImplVector &certVector)
1483 {
1484         for (auto &i : ownerNameVector) {
1485                 // certificates can't be protected with custom user password
1486                 Crypto::GObjUPtr obj;
1487                 int ec;
1488                 ec = readDataHelper(true,
1489                                                         cred,
1490                                                         DataType::CERTIFICATE,
1491                                                         i.second,
1492                                                         i.first,
1493                                                         Password(),
1494                                                         obj);
1495
1496                 if (ec != CKM_API_SUCCESS)
1497                         return ec;
1498
1499                 certVector.emplace_back(obj->getBinary(), DataFormat::FORM_DER);
1500
1501                 // try to read chain certificates (if present)
1502                 Crypto::GObjUPtrVector caChainObjs;
1503                 ec = readDataHelper(true,
1504                                                         cred,
1505                                                         DataType::DB_CHAIN_FIRST,
1506                                                         i.second,
1507                                                         i.first,
1508                                                         CKM::Password(),
1509                                                         caChainObjs);
1510
1511                 if (ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1512                         return ec;
1513
1514                 for (auto &caCertObj : caChainObjs)
1515                         certVector.emplace_back(caCertObj->getBinary(), DataFormat::FORM_DER);
1516         }
1517
1518         return CKM_API_SUCCESS;
1519 }
1520
1521 int CKMLogic::getCertificateChainHelper(
1522         const CertificateImpl &cert,
1523         const RawBufferVector &untrustedCertificates,
1524         const RawBufferVector &trustedCertificates,
1525         bool useTrustedSystemCertificates,
1526         RawBufferVector &chainRawVector)
1527 {
1528         CertificateImplVector untrustedCertVector;
1529         CertificateImplVector trustedCertVector;
1530         CertificateImplVector chainVector;
1531
1532         if (cert.empty())
1533                 return CKM_API_ERROR_INPUT_PARAM;
1534
1535         for (auto &e : untrustedCertificates) {
1536                 CertificateImpl c(e, DataFormat::FORM_DER);
1537
1538                 if (c.empty())
1539                         return CKM_API_ERROR_INPUT_PARAM;
1540
1541                 untrustedCertVector.push_back(std::move(c));
1542         }
1543
1544         for (auto &e : trustedCertificates) {
1545                 CertificateImpl c(e, DataFormat::FORM_DER);
1546
1547                 if (c.empty())
1548                         return CKM_API_ERROR_INPUT_PARAM;
1549
1550                 trustedCertVector.push_back(std::move(c));
1551         }
1552
1553         CertificateStore store;
1554         int retCode = store.verifyCertificate(cert,
1555                                                                                   untrustedCertVector,
1556                                                                                   trustedCertVector,
1557                                                                                   useTrustedSystemCertificates,
1558                                                                                   m_accessControl.isCCMode(),
1559                                                                                   chainVector);
1560
1561         if (retCode != CKM_API_SUCCESS)
1562                 return retCode;
1563
1564         for (auto &e : chainVector)
1565                 chainRawVector.push_back(e.getDER());
1566
1567         return CKM_API_SUCCESS;
1568 }
1569
1570 int CKMLogic::getCertificateChainHelper(
1571         const Credentials &cred,
1572         const CertificateImpl &cert,
1573         const OwnerNameVector &untrusted,
1574         const OwnerNameVector &trusted,
1575         bool useTrustedSystemCertificates,
1576         RawBufferVector &chainRawVector)
1577 {
1578         CertificateImplVector untrustedCertVector;
1579         CertificateImplVector trustedCertVector;
1580         CertificateImplVector chainVector;
1581
1582         if (cert.empty())
1583                 return CKM_API_ERROR_INPUT_PARAM;
1584
1585         int retCode = readCertificateHelper(cred, untrusted, untrustedCertVector);
1586
1587         if (retCode != CKM_API_SUCCESS)
1588                 return retCode;
1589
1590         retCode = readCertificateHelper(cred, trusted, trustedCertVector);
1591
1592         if (retCode != CKM_API_SUCCESS)
1593                 return retCode;
1594
1595         CertificateStore store;
1596         retCode = store.verifyCertificate(cert,
1597                                                                           untrustedCertVector,
1598                                                                           trustedCertVector,
1599                                                                           useTrustedSystemCertificates,
1600                                                                           m_accessControl.isCCMode(),
1601                                                                           chainVector);
1602
1603         if (retCode != CKM_API_SUCCESS)
1604                 return retCode;
1605
1606         for (auto &i : chainVector)
1607                 chainRawVector.push_back(i.getDER());
1608
1609         return CKM_API_SUCCESS;
1610 }
1611
1612 RawBuffer CKMLogic::getCertificateChain(
1613         const Credentials & /*cred*/,
1614         int commandId,
1615         const RawBuffer &certificate,
1616         const RawBufferVector &untrustedCertificates,
1617         const RawBufferVector &trustedCertificates,
1618         bool useTrustedSystemCertificates)
1619 {
1620         CertificateImpl cert(certificate, DataFormat::FORM_DER);
1621         RawBufferVector chainRawVector;
1622         int retCode = CKM_API_ERROR_UNKNOWN;
1623
1624         try {
1625                 retCode = getCertificateChainHelper(cert,
1626                                                                                         untrustedCertificates,
1627                                                                                         trustedCertificates,
1628                                                                                         useTrustedSystemCertificates,
1629                                                                                         chainRawVector);
1630         } catch (const Exc::Exception &e) {
1631                 retCode = e.error();
1632         } catch (const std::exception &e) {
1633                 LogError("STD exception " << e.what());
1634                 retCode = CKM_API_ERROR_SERVER_ERROR;
1635         } catch (...) {
1636                 LogError("Unknown error.");
1637         }
1638
1639         auto response = MessageBuffer::Serialize(static_cast<int>
1640                                         (LogicCommand::GET_CHAIN_CERT),
1641                                         commandId,
1642                                         retCode,
1643                                         chainRawVector);
1644         return response.Pop();
1645 }
1646
1647 RawBuffer CKMLogic::getCertificateChain(
1648         const Credentials &cred,
1649         int commandId,
1650         const RawBuffer &certificate,
1651         const OwnerNameVector &untrustedCertificates,
1652         const OwnerNameVector &trustedCertificates,
1653         bool useTrustedSystemCertificates)
1654 {
1655         int retCode = CKM_API_ERROR_UNKNOWN;
1656         CertificateImpl cert(certificate, DataFormat::FORM_DER);
1657         RawBufferVector chainRawVector;
1658
1659         try {
1660                 retCode = getCertificateChainHelper(cred,
1661                                                                                         cert,
1662                                                                                         untrustedCertificates,
1663                                                                                         trustedCertificates,
1664                                                                                         useTrustedSystemCertificates,
1665                                                                                         chainRawVector);
1666         } catch (const Exc::Exception &e) {
1667                 retCode = e.error();
1668         } catch (const std::exception &e) {
1669                 LogError("STD exception " << e.what());
1670                 retCode = CKM_API_ERROR_SERVER_ERROR;
1671         } catch (...) {
1672                 LogError("Unknown error.");
1673         }
1674
1675         auto response = MessageBuffer::Serialize(static_cast<int>
1676                                         (LogicCommand::GET_CHAIN_ALIAS),
1677                                         commandId,
1678                                         retCode,
1679                                         chainRawVector);
1680         return response.Pop();
1681 }
1682
1683 RawBuffer CKMLogic::createSignature(
1684         const Credentials &cred,
1685         int commandId,
1686         const Name &privateKeyName,
1687         const ClientId &explicitOwner,
1688         const Password &password,           // password for private_key
1689         const RawBuffer &message,
1690         const CryptoAlgorithm &cryptoAlg)
1691 {
1692         RawBuffer signature;
1693
1694         int retCode = CKM_API_SUCCESS;
1695
1696         try {
1697                 Crypto::GObjUPtr obj;
1698                 retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName,
1699                                                                  explicitOwner, password, obj);
1700
1701                 if (retCode == CKM_API_SUCCESS)
1702                         signature = obj->sign(cryptoAlg, message);
1703         } catch (const Exc::Exception &e) {
1704                 retCode = e.error();
1705         } catch (const CKM::Exception &e) {
1706                 LogError("Unknown CKM::Exception: " << e.GetMessage());
1707                 retCode = CKM_API_ERROR_SERVER_ERROR;
1708         } catch (const std::exception &e) {
1709                 LogError("STD exception " << e.what());
1710                 retCode = CKM_API_ERROR_SERVER_ERROR;
1711         }
1712
1713         auto response = MessageBuffer::Serialize(static_cast<int>
1714                                         (LogicCommand::CREATE_SIGNATURE),
1715                                         commandId,
1716                                         retCode,
1717                                         signature);
1718         return response.Pop();
1719 }
1720
1721 RawBuffer CKMLogic::verifySignature(
1722         const Credentials &cred,
1723         int commandId,
1724         const Name &publicKeyOrCertName,
1725         const ClientId &explicitOwner,
1726         const Password &password,           // password for public_key (optional)
1727         const RawBuffer &message,
1728         const RawBuffer &signature,
1729         const CryptoAlgorithm &params)
1730 {
1731         int retCode = CKM_API_ERROR_VERIFICATION_FAILED;
1732
1733         try {
1734                 // try certificate first - looking for a public key.
1735                 // in case of PKCS, pub key from certificate will be found first
1736                 // rather than private key from the same PKCS.
1737                 Crypto::GObjUPtr obj;
1738                 retCode = readDataHelper(false, cred, DataType::CERTIFICATE,
1739                                                                  publicKeyOrCertName, explicitOwner, password, obj);
1740
1741                 if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN)
1742                         retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
1743                                                                          publicKeyOrCertName, explicitOwner, password, obj);
1744
1745                 if (retCode == CKM_API_SUCCESS)
1746                         retCode = obj->verify(params, message, signature);
1747         } catch (const Exc::Exception &e) {
1748                 retCode = e.error();
1749         } catch (const CKM::Exception &e) {
1750                 LogError("Unknown CKM::Exception: " << e.GetMessage());
1751                 retCode = CKM_API_ERROR_SERVER_ERROR;
1752         }
1753
1754         auto response = MessageBuffer::Serialize(static_cast<int>
1755                                         (LogicCommand::VERIFY_SIGNATURE),
1756                                         commandId,
1757                                         retCode);
1758         return response.Pop();
1759 }
1760
1761 int CKMLogic::setPermissionHelper(
1762         const Credentials &cred,                // who's the client
1763         const Name &name,
1764         const ClientId &explicitOwner,                     // who's the owner
1765         const ClientId &accessor,             // who will get the access
1766         const PermissionMask permissionMask)
1767 {
1768         auto &handler = selectDatabase(cred, explicitOwner);
1769
1770         // we don't know the client
1771         if (cred.client.empty() || !isClientValid(cred.client))
1772                 return CKM_API_ERROR_INPUT_PARAM;
1773
1774         // use client id if not explicitly provided
1775         const ClientId &owner = explicitOwner.empty() ? cred.client : explicitOwner;
1776
1777         // verify name and owner are correct
1778         if (!isNameValid(name) || !isClientValid(owner) ||
1779                         !isClientValid(accessor))
1780                 return CKM_API_ERROR_INPUT_PARAM;
1781
1782         // currently we don't support modification of owner's permissions to his own rows
1783         if (owner == accessor)
1784                 return CKM_API_ERROR_INPUT_PARAM;
1785
1786         // system database does not support write/remove permissions
1787         if ((0 == owner.compare(CLIENT_ID_SYSTEM)) &&
1788                         (permissionMask & Permission::REMOVE))
1789                 return CKM_API_ERROR_INPUT_PARAM;
1790
1791         // can the client modify permissions to owner's row?
1792         int retCode = m_accessControl.canModify(cred, owner);
1793
1794         if (retCode != CKM_API_SUCCESS)
1795                 return retCode;
1796
1797         DB::Crypto::Transaction transaction(&handler.database);
1798
1799         if (!handler.database.isNameOwnerPresent(name, owner))
1800                 return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
1801
1802         // set permissions to the row owned by owner for accessor
1803         handler.database.setPermission(name, owner, accessor, permissionMask);
1804         transaction.commit();
1805
1806         return CKM_API_SUCCESS;
1807 }
1808
1809 RawBuffer CKMLogic::setPermission(
1810         const Credentials &cred,
1811         const int command,
1812         const int msgID,
1813         const Name &name,
1814         const ClientId &explicitOwner,
1815         const ClientId &accessor,
1816         const PermissionMask permissionMask)
1817 {
1818         int retCode;
1819
1820         try {
1821                 retCode = setPermissionHelper(cred, name, explicitOwner, accessor, permissionMask);
1822         } catch (const Exc::Exception &e) {
1823                 retCode = e.error();
1824         } catch (const CKM::Exception &e) {
1825                 LogError("Error: " << e.GetMessage());
1826                 retCode = CKM_API_ERROR_DB_ERROR;
1827         }
1828
1829         return MessageBuffer::Serialize(command, msgID, retCode).Pop();
1830 }
1831
1832 int CKMLogic::loadAppKey(UserData &handle, const ClientId &owner)
1833 {
1834         if (!handle.crypto.haveKey(owner)) {
1835                 RawBuffer key;
1836                 auto key_optional = handle.database.getKey(owner);
1837
1838                 if (!key_optional) {
1839                         LogError("No key for given owner in database");
1840                         return CKM_API_ERROR_DB_ERROR;
1841                 }
1842
1843                 key = *key_optional;
1844                 key = handle.keyProvider.getPureDEK(key);
1845                 handle.crypto.pushKey(owner, key);
1846         }
1847
1848         return CKM_API_SUCCESS;
1849 }
1850
1851 } // namespace CKM
1852