blob: 0f8640b831495c0a4e7f0f61944c42e380622916 [file] [log] [blame]
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, Regents of the University of California
4 *
5 * This file is part of ndn-group-encrypt (Group-based Encryption Protocol for NDN).
6 * See AUTHORS.md for complete list of ndn-group-encrypt authors and contributors.
7 *
8 * ndn-group-encrypt is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * ndn-group-encrypt is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * ndn-group-encrypt, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * @author Zhiyi Zhang <dreamerbarrychang@gmail.com>
20 */
21
22#include "group-manager-db.hpp"
Zhiyi Zhang84986cc2015-09-21 00:26:07 +080023#include "algo/rsa.hpp"
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -070024
25#include <sqlite3.h>
26#include <boost/filesystem.hpp>
27#include <ndn-cxx/util/sqlite3-statement.hpp>
28#include <ndn-cxx/security/identity-certificate.hpp>
29
30namespace ndn {
31namespace gep {
32
33using util::Sqlite3Statement;
34
35static const std::string INITIALIZATION =
36 "CREATE TABLE IF NOT EXISTS \n"
37 " schedules( \n"
38 " schedule_id INTEGER PRIMARY KEY, \n"
39 " schedule_name TEXT NOT NULL, \n"
40 " schedule BLOB NOT NULL \n"
41 " ); \n"
42 "CREATE UNIQUE INDEX IF NOT EXISTS \n"
43 " scheduleNameIndex ON schedules(schedule_name); \n"
44 " \n"
45 "CREATE TABLE IF NOT EXISTS \n"
46 " members( \n"
47 " member_id INTEGER PRIMARY KEY, \n"
48 " schedule_id INTEGER NOT NULL, \n"
49 " member_name BLOB NOT NULL, \n"
Zhiyi Zhang84986cc2015-09-21 00:26:07 +080050 " key_name BLOB NOT NULL, \n"
51 " pubkey BLOB NOT NULL, \n"
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -070052 " FOREIGN KEY(schedule_id) \n"
53 " REFERENCES schedules(schedule_id) \n"
54 " ON DELETE CASCADE \n"
55 " ON UPDATE CASCADE \n"
56 " ); \n"
57 "CREATE UNIQUE INDEX IF NOT EXISTS \n"
Zhiyi Zhang67f90aa2016-10-16 14:29:15 -070058 " memNameIndex ON members(member_name); \n"
59 " \n"
60 "CREATE TABLE IF NOT EXISTS \n"
61 " ekeys( \n"
62 " ekey_id INTEGER PRIMARY KEY, \n"
63 " ekey_name BLOB NOT NULL, \n"
64 " pub_key BLOB NOT NULL, \n"
65 " pri_key BLOB NOT NULL \n"
66 " ); \n"
67 "CREATE UNIQUE INDEX IF NOT EXISTS \n"
68 " ekeyNameIndex ON ekeys(ekey_name); \n";
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -070069
70class GroupManagerDB::Impl
71{
72public:
Yingdi Yu8c43fcc2016-03-09 18:23:57 -080073 Impl(const std::string& dbPath)
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -070074 {
75 // open Database
76
Yingdi Yu8c43fcc2016-03-09 18:23:57 -080077 int result = sqlite3_open_v2(dbPath.c_str(), &m_database,
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -070078 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
79#ifdef NDN_CXX_DISABLE_SQLITE3_FS_LOCKING
80 "unix-dotfile"
81#else
82 nullptr
83#endif
84 );
85
86 if (result != SQLITE_OK)
Yingdi Yu8c43fcc2016-03-09 18:23:57 -080087 BOOST_THROW_EXCEPTION(Error("GroupManager DB cannot be opened/created: " + dbPath));
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -070088
89 // enable foreign key
90 sqlite3_exec(m_database, "PRAGMA foreign_keys = ON", nullptr, nullptr, nullptr);
91
92 // initialize database specific tables
93 char* errorMessage = nullptr;
94 result = sqlite3_exec(m_database, INITIALIZATION.c_str(), nullptr, nullptr, &errorMessage);
95 if (result != SQLITE_OK && errorMessage != nullptr) {
96 sqlite3_free(errorMessage);
97 BOOST_THROW_EXCEPTION(Error("GroupManager DB cannot be initialized"));
98 }
99 }
100
101 ~Impl()
102 {
103 sqlite3_close(m_database);
104 }
105
106 int
107 getScheduleId(const std::string& name) const
108 {
109 Sqlite3Statement statement(m_database,
110 "SELECT schedule_id FROM schedules WHERE schedule_name=?");
111 statement.bind(1, name, SQLITE_TRANSIENT);
112
113 int result = -1;
114 if (statement.step() == SQLITE_ROW)
115 result = statement.getInt(0);
116 return result;
117 }
118
119public:
120 sqlite3* m_database;
121};
122
Yingdi Yu8c43fcc2016-03-09 18:23:57 -0800123GroupManagerDB::GroupManagerDB(const std::string& dbPath)
124 : m_impl(new Impl(dbPath))
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700125{
126}
127
128GroupManagerDB::~GroupManagerDB() = default;
129
130bool
131GroupManagerDB::hasSchedule(const std::string& name) const
132{
133 Sqlite3Statement statement(m_impl->m_database,
134 "SELECT schedule_id FROM schedules where schedule_name=?");
135 statement.bind(1, name, SQLITE_TRANSIENT);
136 return (statement.step() == SQLITE_ROW);
137}
138
139std::list<std::string>
140GroupManagerDB::listAllScheduleNames() const
141{
142 std::list<std::string> result;
143 Sqlite3Statement statement(m_impl->m_database,
144 "SELECT schedule_name FROM schedules");
145
146 result.clear();
147 while (statement.step() == SQLITE_ROW) {
148 result.push_back(statement.getString(0));
149 }
150 return result;
151}
152
153Schedule
154GroupManagerDB::getSchedule(const std::string& name) const
155{
156 Sqlite3Statement statement(m_impl->m_database,
157 "SELECT schedule FROM schedules where schedule_name=?");
158 statement.bind(1, name, SQLITE_TRANSIENT);
159
160 Schedule result;
161 if (statement.step() == SQLITE_ROW) {
162 result.wireDecode(statement.getBlock(0));
163 }
164 else {
165 BOOST_THROW_EXCEPTION(Error("Cannot get the result from database"));
166 }
167 return result;
168}
169
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800170std::map<Name, Buffer>
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700171GroupManagerDB::getScheduleMembers(const std::string& name) const
172{
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800173 std::map<Name, Buffer> result;
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700174 Sqlite3Statement statement(m_impl->m_database,
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800175 "SELECT key_name, pubkey\
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700176 FROM members JOIN schedules\
177 ON members.schedule_id=schedules.schedule_id\
178 WHERE schedule_name=?");
179 statement.bind(1, name, SQLITE_TRANSIENT);
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700180 result.clear();
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800181
182 const uint8_t* keyBytes = nullptr;
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700183 while (statement.step() == SQLITE_ROW) {
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800184 keyBytes = statement.getBlob(1);
185 const int& keyBytesSize = statement.getSize(1);
186 result.insert(std::pair<Name, Buffer>(Name(statement.getBlock(0)),
187 Buffer(keyBytes, keyBytesSize)));
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700188 }
189 return result;
190}
191
192void
193GroupManagerDB::addSchedule(const std::string& name, const Schedule& schedule)
194{
195 BOOST_ASSERT(name.length() != 0);
196
197 Sqlite3Statement statement(m_impl->m_database,
198 "INSERT INTO schedules (schedule_name, schedule)\
199 values (?, ?)");
200 statement.bind(1, name, SQLITE_TRANSIENT);
201 statement.bind(2, schedule.wireEncode(), SQLITE_TRANSIENT);
202 if (statement.step() != SQLITE_DONE)
203 BOOST_THROW_EXCEPTION(Error("Cannot add the schedule to database"));
204}
205
206void
207GroupManagerDB::deleteSchedule(const std::string& name)
208{
209 Sqlite3Statement statement(m_impl->m_database,
210 "DELETE FROM schedules WHERE schedule_name=?");
211 statement.bind(1, name, SQLITE_TRANSIENT);
212 statement.step();
213}
214
215void
216GroupManagerDB::renameSchedule(const std::string& oldName, const std::string& newName)
217{
218 BOOST_ASSERT(newName.length() != 0);
219
220 Sqlite3Statement statement(m_impl->m_database,
221 "UPDATE schedules SET schedule_name=? WHERE schedule_name=?");
222 statement.bind(1, newName, SQLITE_TRANSIENT);
223 statement.bind(2, oldName, SQLITE_TRANSIENT);
224 if (statement.step() != SQLITE_DONE)
225 BOOST_THROW_EXCEPTION(Error("Cannot rename the schedule from database"));
226}
227
228void
229GroupManagerDB::updateSchedule(const std::string& name, const Schedule& schedule)
230{
231 if (!hasSchedule(name)) {
232 addSchedule(name, schedule);
233 return;
234 }
235
236 Sqlite3Statement statement(m_impl->m_database,
237 "UPDATE schedules SET schedule=? WHERE schedule_name=?");
238 statement.bind(1, schedule.wireEncode(), SQLITE_TRANSIENT);
239 statement.bind(2, name, SQLITE_TRANSIENT);
240 statement.step();
241}
242
243bool
244GroupManagerDB::hasMember(const Name& identity) const
245{
246 Sqlite3Statement statement(m_impl->m_database,
247 "SELECT member_id FROM members WHERE member_name=?");
248 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
249 return (statement.step() == SQLITE_ROW);
250}
251
252std::list<Name>
253GroupManagerDB::listAllMembers() const
254{
255 std::list<Name> result;
256 Sqlite3Statement statement(m_impl->m_database,
257 "SELECT member_name FROM members");
258
259 result.clear();
260 while (statement.step() == SQLITE_ROW) {
261 result.push_back(Name(statement.getBlock(0)));
262 }
263 return result;
264}
265
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700266std::string
267GroupManagerDB::getMemberSchedule(const Name& identity) const
268{
269 Sqlite3Statement statement(m_impl->m_database,
270 "SELECT schedule_name\
271 FROM schedules JOIN members\
272 ON schedules.schedule_id = members.schedule_id\
273 WHERE member_name=?");
274 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
275
276 std::string result = "";
277 if (statement.step() == SQLITE_ROW) {
278 result = statement.getString(0);
279 }
280 else {
281 BOOST_THROW_EXCEPTION(Error("Cannot get the result from database"));
282 }
283 return result;
284}
285
286void
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800287GroupManagerDB::addMember(const std::string& scheduleName, const Name& keyName,
288 const Buffer& key)
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700289{
290 int scheduleId = m_impl->getScheduleId(scheduleName);
291 if (scheduleId == -1)
292 BOOST_THROW_EXCEPTION(Error("The schedule dose not exist"));
293
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800294 // need to be changed in the future
295 Name memberName = keyName.getPrefix(-1);
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700296
297 Sqlite3Statement statement(m_impl->m_database,
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800298 "INSERT INTO members(schedule_id, member_name, key_name, pubkey)\
299 values (?, ?, ?, ?)");
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700300 statement.bind(1, scheduleId);
301 statement.bind(2, memberName.wireEncode(), SQLITE_TRANSIENT);
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800302 statement.bind(3, keyName.wireEncode(), SQLITE_TRANSIENT);
303 statement.bind(4, key.buf(), key.size(), SQLITE_TRANSIENT);
304
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700305 if (statement.step() != SQLITE_DONE)
306 BOOST_THROW_EXCEPTION(Error("Cannot add the member to database"));
307}
308
309void
310GroupManagerDB::updateMemberSchedule(const Name& identity, const std::string& scheduleName)
311{
312 int scheduleId = m_impl->getScheduleId(scheduleName);
313 if (scheduleId == -1)
314 BOOST_THROW_EXCEPTION(Error("The schedule dose not exist"));
315
316 Sqlite3Statement statement(m_impl->m_database,
317 "UPDATE members SET schedule_id=? WHERE member_name=?");
318 statement.bind(1, scheduleId);
319 statement.bind(2, identity.wireEncode(), SQLITE_TRANSIENT);
320 statement.step();
321}
322
323void
324GroupManagerDB::deleteMember(const Name& identity)
325{
326 Sqlite3Statement statement(m_impl->m_database,
327 "DELETE FROM members WHERE member_name=?");
328 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
329 statement.step();
330}
331
Zhiyi Zhang67f90aa2016-10-16 14:29:15 -0700332bool
333GroupManagerDB::hasEKey(const Name& eKeyName)
334{
335 Sqlite3Statement statement(m_impl->m_database,
336 "SELECT ekey_id FROM ekeys where ekey_name=?");
337 statement.bind(1, eKeyName.wireEncode(), SQLITE_TRANSIENT);
338 return (statement.step() == SQLITE_ROW);
339}
340
341void
342GroupManagerDB::addEKey(const Name& eKeyName, const Buffer& pubKey, const Buffer& priKey)
343{
344 Sqlite3Statement statement(m_impl->m_database,
345 "INSERT INTO ekeys(ekey_name, pub_key, pri_key) values (?, ?, ?)");
346 statement.bind(1, eKeyName.wireEncode(), SQLITE_TRANSIENT);
347 statement.bind(2, pubKey.buf(), pubKey.size(), SQLITE_TRANSIENT);
348 statement.bind(3, priKey.buf(), priKey.size(), SQLITE_TRANSIENT);
349 if (statement.step() != SQLITE_DONE)
350 BOOST_THROW_EXCEPTION(Error("Cannot add the EKey to database"));
351}
352
353std::tuple<Buffer, Buffer>
354GroupManagerDB::getEKey(const Name& eKeyName)
355{
356 Sqlite3Statement statement(m_impl->m_database,
357 "SELECT * FROM ekeys where ekey_name=?");
358 statement.bind(1, eKeyName.wireEncode(), SQLITE_TRANSIENT);
359
360 Buffer pubKey, priKey;
361 if (statement.step() == SQLITE_ROW) {
362 pubKey = Buffer(statement.getBlob(2), statement.getSize(2));
363 priKey = Buffer(statement.getBlob(3), statement.getSize(3));
364 }
365 else {
366 BOOST_THROW_EXCEPTION(Error("Cannot get the result from database"));
367 }
368 return std::make_tuple(pubKey, priKey);
369}
370
371void
372GroupManagerDB::cleanEKeys()
373{
374 Sqlite3Statement statement(m_impl->m_database, "DELETE FROM ekeys");
375 statement.step();
376}
377
378void
379GroupManagerDB::deleteEKey(const Name& eKeyName)
380{
381 Sqlite3Statement statement(m_impl->m_database,
382 "DELETE FROM ekeys WHERE ekey_name=?");
383 statement.bind(1, eKeyName.wireEncode(), SQLITE_TRANSIENT);
384 statement.step();
385}
386
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700387} // namespace gep
388} // namespace ndn