Fix implementation of CKMLogic::createRSAKeyPair
[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     int retCode;
377
378     if (CKM_CRYPTO_CREATEKEY_SUCCESS !=
379         (retCode = CryptoService::createKeyPairRSA(size, prv, pub)))
380     {
381         LogDebug("CryptoService error with code: " << retCode);
382         return KEY_MANAGER_API_ERROR_SERVER_ERROR; // TODO error code
383     }
384
385     DBCrypto::Transaction transaction(&handler.database);
386     retCode = saveDataHelper(cred,
387                             toDBDataType(prv.getType()),
388                             aliasPrivate,
389                             prv.getDER(),
390                             policyPrivate);
391
392     if (KEY_MANAGER_API_SUCCESS != retCode)
393         return retCode;
394
395     retCode = saveDataHelper(cred,
396                             toDBDataType(pub.getType()),
397                             aliasPublic,
398                             pub.getDER(),
399                             policyPublic);
400
401     if (KEY_MANAGER_API_SUCCESS != retCode)
402         return retCode;
403
404     transaction.commit();
405
406     return retCode;
407 }
408
409 RawBuffer CKMLogic::createKeyPairRSA(
410     Credentials &cred,
411     int commandId,
412     int size,
413     const Alias &aliasPrivate,
414     const Alias &aliasPublic,
415     const PolicySerializable &policyPrivate,
416     const PolicySerializable &policyPublic)
417 {
418     int retCode = KEY_MANAGER_API_SUCCESS;
419
420     try {
421         retCode = createKeyPairRSAHelper(
422                         cred,
423                         size,
424                         aliasPrivate,
425                         aliasPublic,
426                         policyPrivate,
427                         policyPublic);
428
429     } catch (DBCrypto::Exception::AliasExists &e) {
430         LogDebug("DBCrypto error: alias exists: " << e.GetMessage());
431         retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
432     } catch (DBCrypto::Exception::TransactionError &e) {
433         LogDebug("DBCrypto error: transaction error: " << e.GetMessage());
434         retCode = CKM_API_ERROR_DB_ERROR;
435     } catch (DBCrypto::Exception::InternalError &e) {
436         LogDebug("DBCrypto internal error: " << e.GetMessage());
437         retCode = KEY_MANAGER_API_ERROR_DB_ERROR;
438     }
439
440     MessageBuffer response;
441     Serialization::Serialize(response, static_cast<int>(LogicCommand::CREATE_KEY_PAIR_RSA));
442     Serialization::Serialize(response, commandId);
443     Serialization::Serialize(response, retCode);
444  
445     return response.Pop();
446 }
447
448 int CKMLogic::createKeyPairECDSAHelper(
449     Credentials &cred,
450     int type,
451     const Alias &aliasPrivate,
452     const Alias &aliasPublic,
453     const PolicySerializable &policyPrivate,
454     const PolicySerializable &policyPublic)
455 {
456     if (0 >= m_userDataMap.count(cred.uid))
457         return KEY_MANAGER_API_ERROR_DB_LOCKED;
458
459     auto &handler = m_userDataMap[cred.uid];
460     GenericKey prv, pub;
461     int retCode;
462
463     if (CKM_CRYPTO_CREATEKEY_SUCCESS !=
464         (retCode = CryptoService::createKeyPairECDSA(static_cast<ElipticCurve>(type), prv, pub)))
465     {
466         LogError("CryptoService failed with code: " << retCode);
467         return KEY_MANAGER_API_ERROR_SERVER_ERROR; // TODO error code
468     }
469
470     DBCrypto::Transaction transaction(&handler.database);
471
472     retCode = saveDataHelper(cred,
473                             toDBDataType(prv.getType()),
474                             aliasPrivate,
475                             prv.getDER(),
476                             policyPrivate);
477
478     if (KEY_MANAGER_API_SUCCESS != retCode)
479         return retCode;
480
481     retCode = saveDataHelper(cred,
482                             toDBDataType(pub.getType()),
483                             aliasPublic,
484                             pub.getDER(),
485                             policyPublic);
486
487     if (KEY_MANAGER_API_SUCCESS != retCode)
488         return retCode;
489
490     transaction.commit();
491
492     return retCode;
493 }
494
495 RawBuffer CKMLogic::createKeyPairECDSA(
496     Credentials &cred,
497     int commandId,
498     int type,
499     const Alias &aliasPrivate,
500     const Alias &aliasPublic,
501     const PolicySerializable &policyPrivate,
502     const PolicySerializable &policyPublic)
503 {
504     int retCode = KEY_MANAGER_API_SUCCESS;
505     
506     try {
507         retCode = createKeyPairECDSAHelper(
508                         cred,
509                         type,
510                         aliasPrivate,
511                         aliasPublic,
512                         policyPrivate,
513                         policyPublic);
514     } catch (const DBCrypto::Exception::AliasExists &e) {
515         LogDebug("DBCrypto error: alias exists: " << e.GetMessage());
516         retCode = CKM_API_ERROR_DB_ALIAS_EXISTS;
517     } catch (const DBCrypto::Exception::TransactionError &e) {
518         LogDebug("DBCrypto error: transaction error: " << e.GetMessage());
519         retCode = CKM_API_ERROR_DB_ERROR;
520     } catch (const DBCrypto::Exception::InternalError &e) {
521         LogDebug("DBCrypto internal error: " << e.GetMessage());
522         retCode = KEY_MANAGER_API_ERROR_DB_ERROR;
523     }
524
525     MessageBuffer response;
526     Serialization::Serialize(response, static_cast<int>(LogicCommand::CREATE_KEY_PAIR_RSA));
527     Serialization::Serialize(response, commandId);
528     Serialization::Serialize(response, retCode);
529  
530     return response.Pop();
531 }
532
533 } // namespace CKM
534