Transactions
[platform/core/security/key-manager.git] / src / manager / service / ckm-logic.cpp
1 /*
2  *  Copyright (c) 2000 - 2014 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
25 #include <ckm/ckm-error.h>
26 #include <ckm/ckm-type.h>
27 #include <key-provider.h>
28 #include <file-system.h>
29 #include <CryptoService.h>
30 #include <ckm-logic.h>
31 #include <generic-key.h>
32
33 namespace CKM {
34
35 CKMLogic::CKMLogic(){
36     int retCode = FileSystem::init();
37     // TODO what can I do when init went wrong? exit(-1) ??
38     if (retCode) {
39         LogError("Fatal error in FileSystem::init()");
40     }
41 }
42
43 CKMLogic::~CKMLogic(){}
44
45 RawBuffer CKMLogic::unlockUserKey(uid_t user, const std::string &password) {
46     // TODO try catch for all errors that should be supported by error code
47     int retCode = KEY_MANAGER_API_SUCCESS;
48
49     try {
50         if (0 == m_userDataMap.count(user) || !(m_userDataMap[user].keyProvider.isInitialized())) {
51             auto &handle = m_userDataMap[user];
52             FileSystem fs(user);
53             auto wrappedDomainKEK = fs.getDomainKEK();
54
55             if (wrappedDomainKEK.empty()) {
56                 wrappedDomainKEK = KeyProvider::generateDomainKEK(std::to_string(user), password);
57                 fs.saveDomainKEK(wrappedDomainKEK);
58             }
59
60             handle.keyProvider = KeyProvider(wrappedDomainKEK, password);
61
62             RawBuffer key = handle.keyProvider.getPureDomainKEK();
63             handle.database = DBCrypto(fs.getDBPath(), key);
64             handle.crypto = DBCryptoModule(key);
65             // TODO wipe key
66         }
67     } catch (const KeyProvider::Exception::Base &e) {
68         LogError("Error in KeyProvider " << e.GetMessage());
69         retCode = KEY_MANAGER_API_ERROR_SERVER_ERROR;
70     }
71
72     MessageBuffer response;
73     Serialization::Serialize(response, retCode);
74     return response.Pop();
75 }
76
77 RawBuffer CKMLogic::lockUserKey(uid_t user) {
78     int retCode = KEY_MANAGER_API_SUCCESS;
79     // TODO try catch for all errors that should be supported by error code
80     m_userDataMap.erase(user);
81
82     MessageBuffer response;
83     Serialization::Serialize(response, retCode);
84     return response.Pop();
85 }
86
87 RawBuffer CKMLogic::removeUserData(uid_t user) {
88     int retCode = KEY_MANAGER_API_SUCCESS;
89     // TODO try catch for all errors that should be supported by error code
90     m_userDataMap.erase(user);
91
92     FileSystem fs(user);
93     fs.removeUserData();
94
95     MessageBuffer response;
96     Serialization::Serialize(response, retCode);
97     return response.Pop();
98 }
99
100 RawBuffer CKMLogic::changeUserPassword(
101     uid_t user,
102     const std::string &oldPassword,
103     const std::string &newPassword)
104 {
105     int retCode = KEY_MANAGER_API_SUCCESS;
106     // TODO try-catch
107     FileSystem fs(user);
108     auto wrappedDomainKEK = fs.getDomainKEK();
109     if (wrappedDomainKEK.empty()) {
110         retCode = KEY_MANAGER_API_ERROR_BAD_REQUEST;
111     } else {
112         wrappedDomainKEK = KeyProvider::reencrypt(wrappedDomainKEK, oldPassword, newPassword);
113         fs.saveDomainKEK(wrappedDomainKEK);
114     }
115     MessageBuffer response;
116     Serialization::Serialize(response, retCode);
117     return response.Pop();
118 }
119
120 RawBuffer CKMLogic::resetUserPassword(
121     uid_t user,
122     const std::string &newPassword)
123 {
124     int retCode = KEY_MANAGER_API_SUCCESS;
125     // TODO try-catch
126     if (0 == m_userDataMap.count(user)) {
127         retCode = KEY_MANAGER_API_ERROR_BAD_REQUEST;
128     } else {
129         auto &handler = m_userDataMap[user];
130         FileSystem fs(user);
131         fs.saveDomainKEK(handler.keyProvider.getWrappedDomainKEK(newPassword));
132     }
133
134     MessageBuffer response;
135     Serialization::Serialize(response, retCode);
136     return response.Pop();
137 }
138
139 int CKMLogic::saveDataHelper(
140     Credentials &cred,
141     DBDataType dataType,
142     const Alias &alias,
143     const RawBuffer &key,
144     const PolicySerializable &policy)
145 {
146     if (0 == m_userDataMap.count(cred.uid))
147         return KEY_MANAGER_API_ERROR_DB_LOCKED;
148
149     DBRow row = { alias, cred.smackLabel, policy.restricted,
150          policy.extractable, dataType, DBCMAlgType::NONE,
151          0, RawBuffer(10, 'c'), key.size(), key };
152
153     auto &handler = m_userDataMap[cred.uid];
154     DBCrypto::Transaction transaction(&handler.database);
155     if (!handler.crypto.haveKey(cred.smackLabel)) {
156         RawBuffer key;
157         auto key_optional = handler.database.getKey(cred.smackLabel);
158         if(!key_optional) {
159             LogDebug("No Key in database found. Generating new one for label: "
160                     << cred.smackLabel);
161             key = handler.keyProvider.generateDEK(cred.smackLabel);
162         } else {
163             key = *key_optional;
164         }
165
166         key = handler.keyProvider.getPureDEK(key);
167         handler.crypto.pushKey(cred.smackLabel, key);
168         handler.database.saveKey(cred.smackLabel, key);
169     }
170     handler.crypto.encryptRow(policy.password, row);
171     handler.database.saveDBRow(row);
172     transaction.commit();
173     return KEY_MANAGER_API_SUCCESS;
174 }
175
176 RawBuffer CKMLogic::saveData(
177     Credentials &cred,
178     int commandId,
179     DBDataType dataType,
180     const Alias &alias,
181     const RawBuffer &key,
182     const PolicySerializable &policy)
183 {
184     int retCode = KEY_MANAGER_API_SUCCESS;
185     try {
186         retCode = saveDataHelper(cred, dataType, alias, key, policy);
187         LogDebug("SaveDataHelper returned: " << retCode);
188     } catch (const KeyProvider::Exception::Base &e) {
189         LogError("KeyProvider failed with message: " << e.GetMessage());
190         retCode = KEY_MANAGER_API_ERROR_SERVER_ERROR;
191     } catch (const DBCryptoModule::Exception::Base &e) {
192         LogError("DBCryptoModule failed with message: " << e.GetMessage());
193         retCode = KEY_MANAGER_API_ERROR_SERVER_ERROR;
194     } catch (const DBCrypto::Exception::InternalError &e) {
195         LogError("DBCrypto failed with message: " << e.GetMessage());
196         retCode = KEY_MANAGER_API_ERROR_DB_ERROR;
197     } catch (const DBCrypto::Exception::AliasExists &e) {
198         LogError("DBCrypto couldn't save duplicate alias");
199         retCode = KEY_MANAGER_API_ERROR_DB_ALIAS_EXISTS;
200     } catch (const DBCrypto::Exception::TransactionError &e) {
201         LogError("DBCrypto transaction failed with message " << e.GetMessage());
202         retCode = KEY_MANAGER_API_ERROR_DB_ERROR;
203     }
204
205     MessageBuffer response;
206     Serialization::Serialize(response, static_cast<int>(LogicCommand::SAVE));
207     Serialization::Serialize(response, commandId);
208     Serialization::Serialize(response, retCode);
209     Serialization::Serialize(response, static_cast<int>(dataType));
210
211     return response.Pop();
212 }
213
214 RawBuffer CKMLogic::removeData(
215     Credentials &cred,
216     int commandId,
217     DBDataType dataType,
218     const Alias &alias)
219 {
220     int retCode = KEY_MANAGER_API_SUCCESS;
221
222     if (0 < m_userDataMap.count(cred.uid)) {
223         Try {
224             m_userDataMap[cred.uid].database.deleteDBRow(alias, cred.smackLabel);
225         } Catch (CKM::Exception) {
226             LogError("Error in deleting row!");
227             retCode = KEY_MANAGER_API_ERROR_DB_ERROR;
228         }
229     } else {
230         retCode = KEY_MANAGER_API_ERROR_DB_LOCKED;
231     }
232
233     MessageBuffer response;
234     Serialization::Serialize(response, static_cast<int>(LogicCommand::REMOVE));
235     Serialization::Serialize(response, commandId);
236     Serialization::Serialize(response, retCode);
237     Serialization::Serialize(response, static_cast<int>(dataType));
238
239     return response.Pop();
240 }
241
242 int CKMLogic::getDataHelper(
243     Credentials &cred,
244     DBDataType dataType,
245     const Alias &alias,
246     const std::string &password,
247     DBRow &row)
248 {
249
250     if (0 == m_userDataMap.count(cred.uid))
251         return KEY_MANAGER_API_ERROR_DB_LOCKED;
252
253     auto &handler = m_userDataMap[cred.uid];
254
255     DBCrypto::DBRowOptional row_optional;
256     if (dataType == DBDataType::CERTIFICATE || dataType == DBDataType::BINARY_DATA) {
257         row_optional = handler.database.getDBRow(alias, cred.smackLabel, dataType);
258     } else if ((static_cast<int>(dataType) >= static_cast<int>(DBDataType::DB_KEY_FIRST))
259             && (static_cast<int>(dataType) <= static_cast<int>(DBDataType::DB_KEY_LAST)))
260     {
261         row_optional = handler.database.getKeyDBRow(alias, cred.smackLabel);
262     } else {
263         LogError("Unknown type of requested data" << (int)dataType);
264         return KEY_MANAGER_API_ERROR_BAD_REQUEST;
265     }
266     if(!row_optional) {
267         LogError("No row for given alias, label and type");
268         return KEY_MANAGER_API_ERROR_DB_ALIAS_UNKNOWN;
269     } else {
270         row = *row_optional;
271     }
272
273     if (!handler.crypto.haveKey(row.smackLabel)) {
274         RawBuffer key;
275         auto key_optional = handler.database.getKey(row.smackLabel);
276         if(!key_optional) {
277             LogError("No key for given label in database");
278             return KEY_MANAGER_API_ERROR_DB_ERROR;
279         }
280         key = *key_optional;
281         key = handler.keyProvider.getPureDEK(key);
282         handler.crypto.pushKey(cred.smackLabel, key);
283     }
284     handler.crypto.decryptRow(password, row);
285
286     LogError("Datatype: " << (int) row.dataType);
287
288     return KEY_MANAGER_API_SUCCESS;
289 }
290
291 RawBuffer CKMLogic::getData(
292     Credentials &cred,
293     int commandId,
294     DBDataType dataType,
295     const Alias &alias,
296     const std::string &password)
297 {
298     int retCode = KEY_MANAGER_API_SUCCESS;
299     DBRow row;
300
301     try {
302         retCode = getDataHelper(cred, dataType, alias, password, row);
303     } catch (const KeyProvider::Exception::Base &e) {
304         LogError("KeyProvider failed with error: " << e.GetMessage());
305         retCode = KEY_MANAGER_API_ERROR_SERVER_ERROR;
306     } catch (const DBCryptoModule::Exception::Base &e) {
307         LogError("DBCryptoModule failed with message: " << e.GetMessage());
308         retCode = KEY_MANAGER_API_ERROR_SERVER_ERROR;
309     } catch (const DBCrypto::Exception::Base &e) {
310         LogError("DBCrypto failed with message: " << e.GetMessage());
311         retCode = KEY_MANAGER_API_ERROR_DB_ERROR;
312     }
313
314     if (KEY_MANAGER_API_SUCCESS != retCode) {
315         row.data.clear();
316         row.dataType = dataType;
317     }
318
319     LogError("Sending dataType: " << (int)row.dataType);
320
321     MessageBuffer response;
322     Serialization::Serialize(response, static_cast<int>(LogicCommand::GET));
323     Serialization::Serialize(response, commandId);
324     Serialization::Serialize(response, retCode);
325     Serialization::Serialize(response, static_cast<int>(row.dataType));
326     Serialization::Serialize(response, row.data);
327     return response.Pop();
328 }
329
330 RawBuffer CKMLogic::getDataList(
331     Credentials &cred,
332     int commandId,
333     DBDataType dataType)
334 {
335     int retCode = KEY_MANAGER_API_SUCCESS;
336     AliasVector aliasVector;
337
338     if (0 < m_userDataMap.count(cred.uid)) {
339         auto &handler = m_userDataMap[cred.uid];
340         Try {
341             if (dataType == DBDataType::CERTIFICATE || dataType == DBDataType::BINARY_DATA) {
342                 handler.database.getAliases(dataType, cred.smackLabel, aliasVector);
343             } else {
344                 handler.database.getKeyAliases(cred.smackLabel, aliasVector);
345             }
346         } Catch (CKM::Exception) {
347             LogError("Failed to get aliases");
348             retCode = KEY_MANAGER_API_ERROR_DB_ERROR;
349         }
350     } else {
351         retCode = KEY_MANAGER_API_ERROR_DB_LOCKED;
352     }
353
354     MessageBuffer response;
355     Serialization::Serialize(response, static_cast<int>(LogicCommand::GET_LIST));
356     Serialization::Serialize(response, commandId);
357     Serialization::Serialize(response, retCode);
358     Serialization::Serialize(response, static_cast<int>(dataType));
359     Serialization::Serialize(response, aliasVector);
360     return response.Pop();
361 }
362
363 int CKMLogic::createKeyPairRSAHelper(
364     Credentials &cred,
365     int size,
366     const Alias &aliasPrivate,
367     const Alias &aliasPublic,
368     const PolicySerializable &policyPrivate,
369     const PolicySerializable &policyPublic)
370 {
371     if (0 >= m_userDataMap.count(cred.uid))
372         return KEY_MANAGER_API_ERROR_DB_LOCKED;
373
374     auto &handler = m_userDataMap[cred.uid];
375     GenericKey prv, pub;
376     CryptoService cr;
377     int retCode;
378
379     if (CKM_CRYPTO_CREATEKEY_SUCCESS != (retCode = cr.createKeyPairRSA(size, prv, pub))) {
380         LogError("CryptoService failed with code: " << retCode);
381         return KEY_MANAGER_API_ERROR_SERVER_ERROR; // TODO error code
382     }
383
384     retCode = saveDataHelper(cred,
385                             toDBDataType(prv.getType()),
386                             aliasPrivate,
387                             prv.getDER(),
388                             policyPrivate);
389
390     if (KEY_MANAGER_API_SUCCESS != retCode)
391         return retCode;
392
393     retCode = saveDataHelper(cred,
394                             toDBDataType(pub.getType()),
395                             aliasPublic,
396                             pub.getDER(),
397                             policyPublic);
398
399     if (KEY_MANAGER_API_SUCCESS != retCode) {
400         handler.database.deleteDBRow(aliasPrivate, cred.smackLabel);
401     }
402
403     return retCode;
404 }
405
406 RawBuffer CKMLogic::createKeyPairRSA(
407     Credentials &cred,
408     int commandId,
409     int size,
410     const Alias &aliasPrivate,
411     const Alias &aliasPublic,
412     const PolicySerializable &policyPrivate,
413     const PolicySerializable &policyPublic)
414 {
415     int retCode = createKeyPairRSAHelper(
416                         cred,
417                         size,
418                         aliasPrivate,
419                         aliasPublic,
420                         policyPrivate,
421                         policyPublic);
422
423     MessageBuffer response;
424     Serialization::Serialize(response, static_cast<int>(LogicCommand::CREATE_KEY_PAIR_RSA));
425     Serialization::Serialize(response, commandId);
426     Serialization::Serialize(response, retCode);
427  
428     return response.Pop();
429 }
430
431 int CKMLogic::createKeyPairECDSAHelper(
432     Credentials &cred,
433     int type,
434     const Alias &aliasPrivate,
435     const Alias &aliasPublic,
436     const PolicySerializable &policyPrivate,
437     const PolicySerializable &policyPublic)
438 {
439     if (0 >= m_userDataMap.count(cred.uid))
440         return KEY_MANAGER_API_ERROR_DB_LOCKED;
441
442     auto &handler = m_userDataMap[cred.uid];
443     GenericKey prv, pub;
444     CryptoService cr;
445     int retCode;
446
447     if (CKM_CRYPTO_CREATEKEY_SUCCESS != (retCode = cr.createKeyPairECDSA(
448               static_cast<ElipticCurve>(type), prv, pub)))
449     {
450         LogError("CryptoService failed with code: " << retCode);
451         return KEY_MANAGER_API_ERROR_SERVER_ERROR; // TODO error code
452     }
453
454     retCode = saveDataHelper(cred,
455                             toDBDataType(prv.getType()),
456                             aliasPrivate,
457                             prv.getDER(),
458                             policyPrivate);
459
460     if (KEY_MANAGER_API_SUCCESS != retCode)
461         return retCode;
462
463     retCode = saveDataHelper(cred,
464                             toDBDataType(pub.getType()),
465                             aliasPublic,
466                             pub.getDER(),
467                             policyPublic);
468
469     if (KEY_MANAGER_API_SUCCESS != retCode) {
470         handler.database.deleteDBRow(aliasPrivate, cred.smackLabel);
471     }
472
473     return retCode;
474 }
475
476 RawBuffer CKMLogic::createKeyPairECDSA(
477     Credentials &cred,
478     int commandId,
479     int type,
480     const Alias &aliasPrivate,
481     const Alias &aliasPublic,
482     const PolicySerializable &policyPrivate,
483     const PolicySerializable &policyPublic)
484 {
485     int retCode = createKeyPairECDSAHelper(
486                         cred,
487                         type,
488                         aliasPrivate,
489                         aliasPublic,
490                         policyPrivate,
491                         policyPublic);
492
493     MessageBuffer response;
494     Serialization::Serialize(response, static_cast<int>(LogicCommand::CREATE_KEY_PAIR_RSA));
495     Serialization::Serialize(response, commandId);
496     Serialization::Serialize(response, retCode);
497  
498     return response.Pop();
499 }
500
501 } // namespace CKM
502