Modify encryption scheme
[platform/core/security/key-manager.git] / src / manager / service / db-crypto.cpp
1 /*
2  * Copyright (c) 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        db-crypto.cpp
18  * @author      Zofia Abramowska (z.abramowska@samsung.com)
19  * @version     1.0
20  * @brief       Implementation of encrypted db access layer
21  */
22
23 #include <fstream>
24 #include <db-crypto.h>
25 #include <dpl/db/sql_connection.h>
26 #include <dpl/log/log.h>
27 #include <ckm/ckm-error.h>
28
29 #pragma GCC diagnostic push
30 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
31
32 namespace {
33     const CKM::PermissionMask DEFAULT_PERMISSIONS =
34                         static_cast<CKM::PermissionMask>(CKM::Permission::READ | CKM::Permission::REMOVE);
35
36     const char *SCRIPTS_PATH = "/usr/share/ckm/scripts/";
37
38     enum DBVersion : int {
39         DB_VERSION_1                   = 1,
40         DB_VERSION_2                   = 2,
41         /* ... since version 3, there is no need to manually
42          * recognize database version.
43          * Remember only that if doing changes to the database,
44          * increment and update DB_VERSION_CURRENT,
45          * then provide migration mechanism!
46          */
47         DB_VERSION_CURRENT             = 4
48     };
49
50     const char *SCRIPT_CREATE_SCHEMA                = "create_schema";
51     const char *SCRIPT_DROP_ALL_ITEMS               = "drop_all";
52     const char *SCRIPT_MIGRATE                      = "migrate_";
53
54     // common substitutions:
55     // 100 - idx
56     // 101 - name
57     // 102 - label
58     // 103 - value
59     // 104 - permissionLabel
60     // 105 - permissionMask
61     const char *DB_CMD_SCHEMA_SET =
62             "REPLACE INTO SCHEMA_INFO(name, value) "
63             "   VALUES(?101, ?103);";
64
65     const char *DB_CMD_SCHEMA_GET =
66             "SELECT * FROM SCHEMA_INFO WHERE name=?101;";
67
68     const char *DB_SCHEMA_VERSION_FIELD = "schema_version";
69
70
71     const char *DB_CMD_NAME_INSERT =
72             "INSERT INTO NAMES("
73             "   name, label) "
74             "   VALUES(?101, ?102);";
75
76     const char *DB_CMD_NAME_COUNT_ROWS =
77             "SELECT COUNT(idx) FROM NAMES WHERE name=?101 AND label=?102;";
78
79     const char *DB_CMD_NAME_DELETE =
80             "DELETE FROM NAMES WHERE name=?101 AND label=?102;";
81
82     const char *DB_CMD_NAME_DELETE_BY_LABEL =
83             "DELETE FROM NAMES WHERE label=?102;";
84
85
86     const char *DB_CMD_OBJECT_INSERT =
87             "INSERT INTO OBJECTS("
88             "   exportable, dataType,"
89             "   algorithmType, encryptionScheme,"
90             "   iv, dataSize, data, tag, idx, backendId) "
91             "   VALUES(?001, ?002, ?003, ?004, ?005, "
92             "          ?006, ?007, ?008,"
93             "          (SELECT idx FROM NAMES WHERE name=?101 and label=?102),"
94             "          ?009"
95             "         );";
96
97     const char *DB_CMD_OBJECT_UPDATE =
98             "UPDATE OR FAIL OBJECTS SET"
99             "   algorithmType = ?003,"
100             "   encryptionScheme = ?004,"
101             "   iv = ?005,"
102             "   dataSize = ?006,"
103             "   data = ?007,"
104             "   tag = ?008"
105             "   WHERE idx IN (SELECT idx FROM NAMES WHERE name=?101 and label=?102)"
106             "   AND dataType = ?002;";
107
108     const char *DB_CMD_OBJECT_SELECT_BY_NAME_AND_LABEL =
109             "SELECT * FROM [join_name_object_tables] "
110             " WHERE (dataType BETWEEN ?001 AND ?002) "
111             " AND name=?101 and label=?102;";
112
113
114     const char *DB_CMD_KEY_INSERT =
115             "INSERT INTO KEYS(label, key) VALUES (?, ?);";
116     const char *DB_CMD_KEY_SELECT =
117             "SELECT key FROM KEYS WHERE label=?;";
118     const char *DB_CMD_KEY_DELETE =
119             "DELETE FROM KEYS WHERE label=?";
120
121
122     const char *DB_CMD_PERMISSION_SET = // SQLite does not support updating views
123             "REPLACE INTO PERMISSIONS(permissionLabel, permissionMask, idx) "
124             " VALUES (?104, ?105, (SELECT idx FROM NAMES WHERE name=?101 and label=?102));";
125
126     const char *DB_CMD_PERMISSION_SELECT =
127             "SELECT permissionMask FROM [join_name_permission_tables] "
128             " WHERE permissionLabel=?104 "
129             " AND name=?101 and label=?102;";
130
131     const char *DB_CMD_PERMISSION_DELETE = // SQLite does not support updating views
132             "DELETE FROM PERMISSIONS WHERE permissionLabel=?104 AND "
133             " idx=(SELECT idx FROM NAMES WHERE name=?101 and label=?102);";
134
135
136     /*
137      * GROUP BY is necessary because of the following case:
138      * -There are several permissions to L1, N1 (label, name) from other accessors. When listing
139      *  objects accessible by L1 the query will produce one result (L1, N1) for each allowed
140      *  accessor but GROUP BY will reduce them to one so L1 will have (L1, N1) on its list only once
141      */
142     const char *DB_CMD_NAME_SELECT_BY_TYPE_AND_PERMISSION =
143             "SELECT label, name FROM [join_all_tables] "
144             " WHERE dataType>=?001 AND dataType<=?002 "
145             " AND permissionLabel=?104 AND permissionMask&?004!=0 GROUP BY idx;";
146 }
147
148 namespace CKM {
149 namespace DB {
150     Crypto::Crypto(const std::string& path, const RawBuffer &rawPass)
151     {
152         m_connection = NULL;
153         m_inUserTransaction = false;
154         Try {
155             m_connection = new SqlConnection(path, SqlConnection::Flag::Option::CRW);
156             m_connection->SetKey(rawPass);
157             initDatabase();
158             m_connection->ExecCommand("VACUUM;");
159         } Catch(SqlConnection::Exception::ConnectionBroken) {
160             LogError("Couldn't connect to database: " << path);
161             ReThrow(Crypto::Exception::InternalError);
162         } Catch(SqlConnection::Exception::InvalidArguments) {
163             LogError("Couldn't set the key for database");
164             ReThrow(Crypto::Exception::InternalError);
165         } Catch(SqlConnection::Exception::SyntaxError) {
166             LogError("Couldn't initiate the database");
167             ReThrow(Crypto::Exception::InternalError);
168         } Catch(SqlConnection::Exception::InternalError) {
169             LogError("Couldn't create the database");
170             ReThrow(Crypto::Exception::InternalError);
171         }
172     }
173
174     Crypto::Crypto(Crypto &&other) :
175             m_connection(other.m_connection),
176             m_inUserTransaction(other.m_inUserTransaction)
177     {
178         other.m_connection = NULL;
179         other.m_inUserTransaction = false;
180     }
181
182     Crypto::~Crypto() {
183         delete m_connection;
184     }
185
186     Crypto& Crypto::operator=(Crypto&& other) {
187         if (this == &other)
188             return *this;
189         delete m_connection;
190
191         m_connection = other.m_connection;
192         other.m_connection = NULL;
193
194         m_inUserTransaction = other.m_inUserTransaction;
195         other.m_inUserTransaction = false;
196
197         return *this;
198     }
199
200     void Crypto::createTable(
201             const char* create_cmd,
202             const char *table_name)
203     {
204         Try {
205             m_connection->ExecCommand(create_cmd);
206         } Catch(SqlConnection::Exception::SyntaxError) {
207             LogError("Couldn't create table : " << table_name << "!");
208             throw;
209         } Catch(SqlConnection::Exception::InternalError) {
210             LogError("Sqlite got into infinite busy state");
211             throw;
212         }
213     }
214
215     void Crypto::createView(
216             const char* create_cmd)
217     {
218         Try {
219             m_connection->ExecCommand(create_cmd);
220         } Catch(SqlConnection::Exception::SyntaxError) {
221             LogError("Couldn't create view!");
222             throw;
223         } Catch(SqlConnection::Exception::InternalError) {
224             LogError("Sqlite got into infinite busy state");
225             throw;
226         }
227     }
228
229     bool Crypto::getDBVersion(int & schemaVersion)
230     {
231         SchemaInfo SchemaInfo(this);
232         if(SchemaInfo.getVersionInfo(schemaVersion)) {
233             LogDebug("Current DB version: " << schemaVersion);
234             return true;
235         }
236         else
237         {
238             LogDebug("No DB version known or DB not present");
239
240             // special case: old CKM_TABLE exists
241             if(m_connection->CheckTableExist("CKM_TABLE")) {
242                 schemaVersion = DB_VERSION_1;
243                 return true;
244             }
245
246             // special case: new scheme exists, but no SCHEMA_INFO table present
247             else if(m_connection->CheckTableExist("NAME_TABLE")) {
248                 schemaVersion = DB_VERSION_2;
249                 return true;
250             }
251         }
252         // not recognized - proceed with an empty DBs
253         return false;
254     }
255
256     void Crypto::initDatabase()
257     {
258         // run migration if old database is present
259         int schemaVersion;
260         if( getDBVersion(schemaVersion)==false ||       // DB empty or corrupted
261             schemaVersion > DB_VERSION_CURRENT)         // or too new scheme
262         {
263             LogDebug("no database or database corrupted, initializing the DB");
264             resetDB();
265         }
266         else
267         {
268             // migration needed
269             LogDebug("DB migration from version " << schemaVersion << " to version " << DB_VERSION_CURRENT << " started.");
270             Transaction transaction(this);
271             for(int vi=schemaVersion; vi<DB_VERSION_CURRENT; vi++)
272             {
273                 ScriptOptional script = getMigrationScript(vi);
274                 if(!script)
275                 {
276                     LogError("Error, script to migrate database from version: " << vi <<
277                              " to version: " << vi+1 << " not available, resetting the DB");
278                     resetDB();
279                     break;
280                 }
281
282                 LogInfo("migrating from version " << vi << " to version " << vi+1);
283                 m_connection->ExecCommand((*script).c_str());
284             }
285             // update DB version info
286             SchemaInfo SchemaInfo(this);
287             SchemaInfo.setVersionInfo();
288             transaction.commit();
289         }
290     }
291
292     Crypto::ScriptOptional Crypto::getScript(const std::string &scriptName) const
293     {
294         std::string scriptPath = SCRIPTS_PATH + scriptName + std::string(".sql");
295         std::ifstream is(scriptPath);
296         if(is.fail()) {
297             LogError("Script " << scriptPath << " not found!");
298             return ScriptOptional();
299         }
300
301         std::istreambuf_iterator<char> begin(is),end;
302         return ScriptOptional(std::string(begin, end));
303     }
304
305     Crypto::ScriptOptional Crypto::getMigrationScript(int db_version) const
306     {
307         std::string scriptPath = std::string(SCRIPT_MIGRATE) + std::to_string(db_version);
308         return getScript(scriptPath);
309     }
310
311     void Crypto::createDBSchema() {
312         Transaction transaction(this);
313
314         ScriptOptional script = getScript(SCRIPT_CREATE_SCHEMA);
315         if(!script)
316         {
317             std::string errmsg = "Can not create the database schema: no initialization script";
318             LogError(errmsg);
319             ThrowMsg(Exception::InternalError, errmsg);
320         }
321
322         m_connection->ExecCommand((*script).c_str());
323         SchemaInfo SchemaInfo(this);
324         SchemaInfo.setVersionInfo();
325         transaction.commit();
326     }
327
328     void Crypto::resetDB() {
329         Transaction transaction(this);
330         ScriptOptional script = getScript(SCRIPT_DROP_ALL_ITEMS);
331         if(!script)
332         {
333             std::string errmsg = "Can not clear the database: no clearing script";
334             LogError(errmsg);
335             ThrowMsg(Exception::InternalError, errmsg);
336         }
337
338         m_connection->ExecCommand((*script).c_str());
339         createDBSchema();
340         transaction.commit();
341     }
342
343     bool Crypto::isNameLabelPresent(const Name &name, const Label &owner) const {
344         Try {
345             NameTable nameTable(this->m_connection);
346             return nameTable.isPresent(name, owner);
347         } Catch(SqlConnection::Exception::SyntaxError) {
348             LogError("Couldn't prepare insert statement");
349         } Catch(SqlConnection::Exception::InternalError) {
350             LogError("Couldn't execute insert statement");
351         }
352         ThrowMsg(Crypto::Exception::InternalError,
353                 "Couldn't check if name and label pair is present");
354     }
355
356     void Crypto::saveRows(const Name &name, const Label &owner, const RowVector &rows)
357     {
358         Try {
359             // transaction is present in the layer above
360             NameTable nameTable(this->m_connection);
361             ObjectTable objectTable(this->m_connection);
362             PermissionTable permissionTable(this->m_connection);
363             nameTable.addRow(name, owner);
364             for (const auto &i: rows)
365                 objectTable.addRow(i);
366             permissionTable.setPermission(name,
367                                           owner,
368                                           owner,
369                                           static_cast<int>(DEFAULT_PERMISSIONS));
370             return;
371         } Catch(SqlConnection::Exception::SyntaxError) {
372             LogError("Couldn't prepare insert statement");
373         } Catch(SqlConnection::Exception::InternalError) {
374             LogError("Couldn't execute insert statement: " << _rethrown_exception.GetMessage());
375         }
376         ThrowMsg(Crypto::Exception::InternalError,
377                 "Couldn't save Row");
378     }
379
380     void Crypto::saveRow(const Row &row) {
381         Try {
382             // transaction is present in the layer above
383             NameTable nameTable(this->m_connection);
384             ObjectTable objectTable(this->m_connection);
385             PermissionTable permissionTable(this->m_connection);
386             nameTable.addRow(row.name, row.ownerLabel);
387             objectTable.addRow(row);
388             permissionTable.setPermission(row.name,
389                                           row.ownerLabel,
390                                           row.ownerLabel,
391                                           static_cast<int>(DEFAULT_PERMISSIONS));
392             return;
393         } Catch(SqlConnection::Exception::SyntaxError) {
394             LogError("Couldn't prepare insert statement");
395         } Catch(SqlConnection::Exception::InternalError) {
396             LogError("Couldn't execute insert statement");
397         }
398         ThrowMsg(Crypto::Exception::InternalError,
399                 "Couldn't save Row");
400     }
401
402     void Crypto::updateRow(const Row &row) {
403         Try {
404             // transaction is present in the layer above
405             ObjectTable objectTable(this->m_connection);
406             objectTable.updateRow(row);
407             return;
408         } Catch(SqlConnection::Exception::SyntaxError) {
409             LogError("Couldn't prepare update statement");
410         } Catch(SqlConnection::Exception::InternalError) {
411             LogError("Couldn't execute update statement");
412         }
413         ThrowMsg(Crypto::Exception::InternalError,
414                 "Couldn't update Row");
415     }
416
417     bool Crypto::deleteRow(
418             const Name &name,
419             const Label &ownerLabel)
420     {
421         Try {
422             // transaction is present in the layer above
423             NameTable nameTable(this->m_connection);
424             if(nameTable.isPresent(name, ownerLabel))
425             {
426                 nameTable.deleteRow(name, ownerLabel);
427                 return true;
428             }
429             return false;
430         } Catch (SqlConnection::Exception::SyntaxError) {
431             LogError("Couldn't prepare delete statement");
432         } Catch (SqlConnection::Exception::InternalError) {
433             LogError("Couldn't execute delete statement");
434         }
435         ThrowMsg(Crypto::Exception::InternalError,
436                 "Couldn't delete Row for name " << name << " using ownerLabel " << ownerLabel);
437     }
438
439     Row Crypto::getRow(
440             const SqlConnection::DataCommandUniquePtr &selectCommand) const {
441         Row row;
442         row.name = selectCommand->GetColumnString(0);
443         row.ownerLabel = selectCommand->GetColumnString(1);
444         row.exportable = selectCommand->GetColumnInteger(2);
445         row.dataType = DataType(selectCommand->GetColumnInteger(3));
446         row.algorithmType = static_cast<DBCMAlgType>(selectCommand->GetColumnInteger(4));
447         row.encryptionScheme = selectCommand->GetColumnInteger(5);
448         row.iv = selectCommand->GetColumnBlob(6);
449         row.dataSize = selectCommand->GetColumnInteger(7);
450         row.data = selectCommand->GetColumnBlob(8);
451         row.tag = selectCommand->GetColumnBlob(9);
452         row.backendId = static_cast<CryptoBackend>(selectCommand->GetColumnInteger(11));
453         return row;
454     }
455
456     PermissionMaskOptional Crypto::getPermissionRow(
457         const Name &name,
458         const Label &ownerLabel,
459         const Label &accessorLabel) const
460     {
461         Try {
462             PermissionTable permissionTable(this->m_connection);
463             return permissionTable.getPermissionRow(name, ownerLabel, accessorLabel);
464         } Catch (SqlConnection::Exception::InvalidColumn) {
465             LogError("Select statement invalid column error");
466         } Catch (SqlConnection::Exception::SyntaxError) {
467             LogError("Couldn't prepare select statement");
468         } Catch (SqlConnection::Exception::InternalError) {
469             LogError("Couldn't execute select statement");
470         }
471         return PermissionMaskOptional();
472     }
473
474     Crypto::RowOptional Crypto::getRow(
475         const Name &name,
476         const Label &ownerLabel,
477         DataType type)
478     {
479         return getRow(name, ownerLabel, type, type);
480     }
481
482     Crypto::RowOptional Crypto::getRow(
483         const Name &name,
484         const Label &ownerLabel,
485         DataType typeRangeStart,
486         DataType typeRangeStop)
487     {
488         Try {
489             SqlConnection::DataCommandUniquePtr selectCommand =
490                     m_connection->PrepareDataCommand(DB_CMD_OBJECT_SELECT_BY_NAME_AND_LABEL);
491             selectCommand->BindInteger(1, typeRangeStart);
492             selectCommand->BindInteger(2, typeRangeStop);
493
494             // name table reference
495             selectCommand->BindString (101, name.c_str());
496             selectCommand->BindString (102, ownerLabel.c_str());
497
498             if(selectCommand->Step())
499             {
500                 // extract data
501                 Row current_row = getRow(selectCommand);
502
503                 // all okay, proceed
504                 return RowOptional(current_row);
505             } else {
506                 return RowOptional();
507             }
508         } Catch (SqlConnection::Exception::InvalidColumn) {
509             LogError("Select statement invalid column error");
510         } Catch (SqlConnection::Exception::SyntaxError) {
511             LogError("Couldn't prepare select statement");
512         } Catch (SqlConnection::Exception::InternalError) {
513             LogError("Couldn't execute select statement");
514         }
515         ThrowMsg(Crypto::Exception::InternalError,
516                 "Couldn't get row of type <" <<
517                 static_cast<int>(typeRangeStart) << "," <<
518                 static_cast<int>(typeRangeStop)  << ">" <<
519                 " name " << name << " with owner label " << ownerLabel);
520     }
521
522     void Crypto::getRows(
523         const Name &name,
524         const Label &ownerLabel,
525         DataType type,
526         RowVector &output)
527     {
528         getRows(name, ownerLabel, type, type, output);
529     }
530
531     void Crypto::getRows(
532         const Name &name,
533         const Label &ownerLabel,
534         DataType typeRangeStart,
535         DataType typeRangeStop,
536         RowVector &output)
537     {
538         Try {
539             SqlConnection::DataCommandUniquePtr selectCommand =
540                     m_connection->PrepareDataCommand(DB_CMD_OBJECT_SELECT_BY_NAME_AND_LABEL);
541             selectCommand->BindInteger(1, typeRangeStart);
542             selectCommand->BindInteger(2, typeRangeStop);
543
544             // name table reference
545             selectCommand->BindString (101, name.c_str());
546             selectCommand->BindString (102, ownerLabel.c_str());
547
548             while(selectCommand->Step())
549             {
550                 // extract data
551                 output.push_back(getRow(selectCommand));
552             }
553             return;
554         } Catch (SqlConnection::Exception::InvalidColumn) {
555             LogError("Select statement invalid column error");
556         } Catch (SqlConnection::Exception::SyntaxError) {
557             LogError("Couldn't prepare select statement");
558         } Catch (SqlConnection::Exception::InternalError) {
559             LogError("Couldn't execute select statement");
560         }
561         ThrowMsg(Crypto::Exception::InternalError,
562                 "Couldn't get row of type <" <<
563                 static_cast<int>(typeRangeStart) << "," <<
564                 static_cast<int>(typeRangeStop)  << ">" <<
565                 " name " << name << " with owner label " << ownerLabel);
566     }
567
568     void Crypto::listNames(
569         const Label &smackLabel,
570         LabelNameVector& labelNameVector,
571         DataType type)
572     {
573         listNames(smackLabel, labelNameVector, type, type);
574     }
575
576     void Crypto::listNames(
577         const Label &smackLabel,
578         LabelNameVector& labelNameVector,
579         DataType typeRangeStart,
580         DataType typeRangeStop)
581     {
582         Try{
583             Transaction transaction(this);
584             SqlConnection::DataCommandUniquePtr selectCommand =
585                             m_connection->PrepareDataCommand(DB_CMD_NAME_SELECT_BY_TYPE_AND_PERMISSION);
586             selectCommand->BindInteger(1, static_cast<int>(typeRangeStart));
587             selectCommand->BindInteger(2, static_cast<int>(typeRangeStop));
588             selectCommand->BindString(104, smackLabel.c_str());
589             selectCommand->BindInteger(4, static_cast<int>(Permission::READ | Permission::REMOVE));
590
591             while(selectCommand->Step()) {
592                 Label ownerLabel = selectCommand->GetColumnString(0);
593                 Name name = selectCommand->GetColumnString(1);
594                 labelNameVector.push_back(std::make_pair(ownerLabel, name));
595             }
596             return;
597         } Catch (SqlConnection::Exception::InvalidColumn) {
598             LogError("Select statement invalid column error");
599         } Catch (SqlConnection::Exception::SyntaxError) {
600             LogError("Couldn't prepare select statement");
601         } Catch (SqlConnection::Exception::InternalError) {
602             LogError("Couldn't execute select statement");
603         }
604         ThrowMsg(Crypto::Exception::InternalError,
605                 "Couldn't list names of type <" <<
606                 static_cast<int>(typeRangeStart) << "," <<
607                 static_cast<int>(typeRangeStop)  << ">" <<
608                 " accessible to client label " << smackLabel);
609     }
610
611
612
613     void Crypto::saveKey(
614             const Label& label,
615             const RawBuffer &key)
616     {
617         Try {
618             SqlConnection::DataCommandUniquePtr insertCommand =
619                     m_connection->PrepareDataCommand(DB_CMD_KEY_INSERT);
620             insertCommand->BindString(1, label.c_str());
621             insertCommand->BindBlob(2, key);
622             insertCommand->Step();
623             return;
624         } Catch (SqlConnection::Exception::SyntaxError) {
625             LogError("Couldn't prepare insert key statement");
626         } Catch (SqlConnection::Exception::InternalError) {
627             LogError("Couldn't execute insert statement");
628         }
629         ThrowMsg(Crypto::Exception::InternalError,
630                 "Couldn't save key for label " << label);
631     }
632
633     Crypto::RawBufferOptional Crypto::getKey(const Label& label)
634     {
635         Try {
636             SqlConnection::DataCommandUniquePtr selectCommand =
637                     m_connection->PrepareDataCommand(DB_CMD_KEY_SELECT);
638             selectCommand->BindString(1, label.c_str());
639
640             if (selectCommand->Step()) {
641                 return RawBufferOptional(
642                         selectCommand->GetColumnBlob(0));
643             } else {
644                 return RawBufferOptional();
645             }
646
647         } Catch (SqlConnection::Exception::InvalidColumn) {
648             LogError("Select statement invalid column error");
649         } Catch (SqlConnection::Exception::SyntaxError) {
650             LogError("Couldn't prepare insert key statement");
651         } Catch (SqlConnection::Exception::InternalError) {
652             LogError("Couldn't execute insert statement");
653         }
654         ThrowMsg(Crypto::Exception::InternalError,
655                 "Couldn't get key for label " << label);
656     }
657
658     void Crypto::deleteKey(const Label& label) {
659         Try {
660             Transaction transaction(this);
661
662             SqlConnection::DataCommandUniquePtr deleteCommand =
663                     m_connection->PrepareDataCommand(DB_CMD_KEY_DELETE);
664             deleteCommand->BindString(1, label.c_str());
665             deleteCommand->Step();
666
667             NameTable nameTable(this->m_connection);
668             nameTable.deleteAllRows(label);
669
670             transaction.commit();
671             return;
672         } Catch (SqlConnection::Exception::SyntaxError) {
673             LogError("Couldn't prepare insert key statement");
674         } Catch (SqlConnection::Exception::InternalError) {
675             LogError("Couldn't execute insert statement");
676         }
677         ThrowMsg(Crypto::Exception::InternalError,
678                 "Couldn't delete key for label " << label);
679     }
680
681     void Crypto::setPermission(
682             const Name &name,
683             const Label& ownerLabel,
684             const Label& accessorLabel,
685             const PermissionMask permissionMask)
686     {
687         Try {
688             PermissionTable permissionTable(this->m_connection);
689             permissionTable.setPermission(name, ownerLabel, accessorLabel, permissionMask);
690             return;
691         } Catch (SqlConnection::Exception::SyntaxError) {
692             LogError("Couldn't prepare set statement");
693         } Catch (SqlConnection::Exception::InternalError) {
694             LogError("Couldn't execute set statement");
695         }
696         ThrowMsg(Crypto::Exception::InternalError,
697                 "Couldn't set permissions for name " << name );
698     }
699
700
701     void Crypto::SchemaInfo::setVersionInfo() {
702         SqlConnection::DataCommandUniquePtr insertContextCommand =
703                 m_db->m_connection->PrepareDataCommand(DB_CMD_SCHEMA_SET);
704         insertContextCommand->BindString(101, DB_SCHEMA_VERSION_FIELD);
705         insertContextCommand->BindString(103, std::to_string(DB_VERSION_CURRENT).c_str());
706         insertContextCommand->Step();
707     }
708
709     bool Crypto::SchemaInfo::getVersionInfo(int & version) const
710     {
711         // Try..Catch mandatory here - we don't need to escalate the error
712         // if it happens - we just won't return the version, allowing CKM to work
713         Try {
714             SqlConnection::DataCommandUniquePtr selectCommand =
715                     m_db->m_connection->PrepareDataCommand(DB_CMD_SCHEMA_GET);
716             selectCommand->BindString(101, DB_SCHEMA_VERSION_FIELD);
717
718             if(selectCommand->Step()) {
719                 version = static_cast<int>(atoi(selectCommand->GetColumnString(1).c_str()));
720                 return true;
721             }
722         } Catch (SqlConnection::Exception::InvalidColumn) {
723             LogError("Select statement invalid column error");
724         } Catch (SqlConnection::Exception::SyntaxError) {
725             LogError("Couldn't prepare select statement");
726         } Catch (SqlConnection::Exception::InternalError) {
727             LogError("Couldn't execute select statement");
728         }
729         return false;
730     }
731
732     void Crypto::PermissionTable::setPermission(
733             const Name &name,
734             const Label& ownerLabel,
735             const Label& accessorLabel,
736             const PermissionMask permissionMask)
737     {
738         if(permissionMask == Permission::NONE)
739         {
740             // clear permissions
741             SqlConnection::DataCommandUniquePtr deletePermissionCommand =
742                 m_connection->PrepareDataCommand(DB_CMD_PERMISSION_DELETE);
743             deletePermissionCommand->BindString(104, accessorLabel.c_str());
744             deletePermissionCommand->BindString(101, name.c_str());
745             deletePermissionCommand->BindString(102, ownerLabel.c_str());
746             deletePermissionCommand->Step();
747         }
748         else
749         {
750             // add new permissions
751             SqlConnection::DataCommandUniquePtr setPermissionCommand =
752                 m_connection->PrepareDataCommand(DB_CMD_PERMISSION_SET);
753             setPermissionCommand->BindString(104, accessorLabel.c_str());
754             setPermissionCommand->BindInteger(105, static_cast<int>(permissionMask));
755             setPermissionCommand->BindString(101, name.c_str());
756             setPermissionCommand->BindString(102, ownerLabel.c_str());
757             setPermissionCommand->Step();
758         }
759     }
760
761     PermissionMaskOptional Crypto::PermissionTable::getPermissionRow(
762             const Name &name,
763             const Label &ownerLabel,
764             const Label &accessorLabel) const
765     {
766         SqlConnection::DataCommandUniquePtr selectCommand =
767                 m_connection->PrepareDataCommand(DB_CMD_PERMISSION_SELECT);
768         selectCommand->BindString(104, accessorLabel.c_str());
769
770         // name table reference
771         selectCommand->BindString(101, name.c_str());
772         selectCommand->BindString(102, ownerLabel.c_str());
773
774         if(selectCommand->Step())
775         {
776             // there is entry for the <name, ownerLabel> pair
777             return PermissionMaskOptional(PermissionMask(selectCommand->GetColumnInteger(0)));
778         }
779         return PermissionMaskOptional();
780     }
781
782     void Crypto::NameTable::addRow(
783             const Name &name,
784             const Label &ownerLabel)
785     {
786         // insert NAMES item
787         SqlConnection::DataCommandUniquePtr insertNameCommand =
788                 m_connection->PrepareDataCommand(DB_CMD_NAME_INSERT);
789         insertNameCommand->BindString (101, name.c_str());
790         insertNameCommand->BindString (102, ownerLabel.c_str());
791         insertNameCommand->Step();
792     }
793
794     void Crypto::NameTable::deleteRow(
795             const Name &name,
796             const Label &ownerLabel)
797     {
798         SqlConnection::DataCommandUniquePtr deleteCommand =
799                 m_connection->PrepareDataCommand(DB_CMD_NAME_DELETE);
800         deleteCommand->BindString(101, name.c_str());
801         deleteCommand->BindString(102, ownerLabel.c_str());
802
803         // Step() result code does not provide information whether
804         // anything was removed.
805         deleteCommand->Step();
806     }
807
808     void Crypto::NameTable::deleteAllRows(const Label &ownerLabel)
809     {
810         SqlConnection::DataCommandUniquePtr deleteData =
811                 m_connection->PrepareDataCommand(DB_CMD_NAME_DELETE_BY_LABEL);
812         deleteData->BindString(102, ownerLabel.c_str());
813
814         // Step() result code does not provide information whether
815         // anything was removed.
816         deleteData->Step();
817     }
818
819     bool Crypto::NameTable::isPresent(const Name &name, const Label &ownerLabel) const
820     {
821         SqlConnection::DataCommandUniquePtr checkCmd =
822                 m_connection->PrepareDataCommand(DB_CMD_NAME_COUNT_ROWS);
823         checkCmd->BindString(101, name.c_str());
824         checkCmd->BindString(102, ownerLabel.c_str());
825         if(checkCmd->Step()) {
826             int element_count = checkCmd->GetColumnInteger(0);
827             LogDebug("Item name: " << name  << " ownerLabel: " << ownerLabel <<
828                      " hit count: " << element_count);
829             if(element_count > 0)
830                 return true;
831         }
832         return false;
833     }
834
835     void Crypto::ObjectTable::addRow(const Row &row)
836     {
837         SqlConnection::DataCommandUniquePtr insertObjectCommand =
838                 m_connection->PrepareDataCommand(DB_CMD_OBJECT_INSERT);
839         insertObjectCommand->BindInteger(1, row.exportable);
840         insertObjectCommand->BindInteger(2, static_cast<int>(row.dataType));
841         insertObjectCommand->BindInteger(3, static_cast<int>(row.algorithmType));
842         insertObjectCommand->BindInteger(4, row.encryptionScheme);
843         insertObjectCommand->BindBlob   (5, row.iv);
844         insertObjectCommand->BindInteger(6, row.dataSize);
845         insertObjectCommand->BindBlob   (7, row.data);
846         insertObjectCommand->BindBlob   (8, row.tag);
847         insertObjectCommand->BindInteger(9, static_cast<int>(row.backendId));
848
849         // name table reference
850         insertObjectCommand->BindString (101, row.name.c_str());
851         insertObjectCommand->BindString (102, row.ownerLabel.c_str());
852
853         insertObjectCommand->Step();
854     }
855
856     void Crypto::ObjectTable::updateRow(const Row &row)
857     {
858         SqlConnection::DataCommandUniquePtr updateObjectCommand =
859                 m_connection->PrepareDataCommand(DB_CMD_OBJECT_UPDATE);
860         updateObjectCommand->BindInteger(2, static_cast<int>(row.dataType));
861         updateObjectCommand->BindInteger(3, static_cast<int>(row.algorithmType));
862         updateObjectCommand->BindInteger(4, row.encryptionScheme);
863         updateObjectCommand->BindBlob   (5, row.iv);
864         updateObjectCommand->BindInteger(6, row.dataSize);
865         updateObjectCommand->BindBlob   (7, row.data);
866         updateObjectCommand->BindBlob   (8, row.tag);
867
868         // name table reference
869         updateObjectCommand->BindString (101, row.name.c_str());
870         updateObjectCommand->BindString (102, row.ownerLabel.c_str());
871
872         updateObjectCommand->Step();
873     }
874 } // namespace DB
875 } // namespace CKM
876
877 #pragma GCC diagnostic pop