blob: b20ee7c9f7139b81f0ef45844c8ff3d0e7abbbb9 [file] [log] [blame]
Mickey Sweatt11314b72015-06-10 17:20:19 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2015 Regents of the University of California.
4 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#include "pib-sqlite3.hpp"
23
24#include "common.hpp"
25#include "pib.hpp"
26#include "util/sqlite3-statement.hpp"
27
28#include <sqlite3.h>
29#include <boost/filesystem.hpp>
30#include <boost/algorithm/string.hpp>
31
32namespace ndn {
33namespace security {
34
35using std::string;
36using util::Sqlite3Statement;
37
38static const string INITIALIZATION =
39 "CREATE TABLE IF NOT EXISTS \n"
40 " tpmInfo( \n"
41 " tpm_locator BLOB \n"
42 " ); \n"
43 " \n"
44 "CREATE TRIGGER IF NOT EXISTS \n"
45 " tpm_update_trigger \n"
46 " BEFORE UPDATE ON tpmInfo \n"
47 " WHEN NEW.tpm_locator!=OLD.tpm_locator \n"
48 " BEGIN \n"
49 " DELETE FROM certificates; \n"
50 " DELETE FROM keys; \n"
51 " DELETE FROM identities; \n"
52 " END; \n"
53 " \n"
54 " \n"
55 "CREATE TABLE IF NOT EXISTS \n"
56 " identities( \n"
57 " id INTEGER PRIMARY KEY,\n"
58 " identity BLOB NOT NULL, \n"
59 " is_default INTEGER DEFAULT 0 \n"
60 " ); \n"
61 " \n"
62 "CREATE UNIQUE INDEX IF NOT EXISTS \n"
63 " identityIndex ON identities(identity); \n"
64 " \n"
65 "CREATE TRIGGER IF NOT EXISTS \n"
66 " identity_default_before_insert_trigger \n"
67 " BEFORE INSERT ON identities \n"
68 " FOR EACH ROW \n"
69 " WHEN NEW.is_default=1 \n"
70 " BEGIN \n"
71 " UPDATE identities SET is_default=0; \n"
72 " END; \n"
73 " \n"
74 "CREATE TRIGGER IF NOT EXISTS \n"
75 " identity_default_after_insert_trigger \n"
76 " AFTER INSERT ON identities \n"
77 " FOR EACH ROW \n"
78 " WHEN NOT EXISTS \n"
79 " (SELECT id \n"
80 " FROM identities \n"
81 " WHERE is_default=1) \n"
82 " BEGIN \n"
83 " UPDATE identities \n"
84 " SET is_default=1 \n"
85 " WHERE identity=NEW.identity; \n"
86 " END; \n"
87 " \n"
88 "CREATE TRIGGER IF NOT EXISTS \n"
89 " identity_default_update_trigger \n"
90 " BEFORE UPDATE ON identities \n"
91 " FOR EACH ROW \n"
92 " WHEN NEW.is_default=1 AND OLD.is_default=0 \n"
93 " BEGIN \n"
94 " UPDATE identities SET is_default=0; \n"
95 " END; \n"
96 " \n"
97 " \n"
98 "CREATE TABLE IF NOT EXISTS \n"
99 " keys( \n"
100 " id INTEGER PRIMARY KEY,\n"
101 " identity_id INTEGER NOT NULL, \n"
102 " key_name BLOB NOT NULL, \n"
103 " key_type INTEGER NOT NULL, \n"
104 " key_bits BLOB NOT NULL, \n"
105 " is_default INTEGER DEFAULT 0, \n"
106 " FOREIGN KEY(identity_id) \n"
107 " REFERENCES identities(id) \n"
108 " ON DELETE CASCADE \n"
109 " ON UPDATE CASCADE \n"
110 " ); \n"
111 " \n"
112 "CREATE UNIQUE INDEX IF NOT EXISTS \n"
113 " keyIndex ON keys(key_name); \n"
114 " \n"
115 "CREATE TRIGGER IF NOT EXISTS \n"
116 " key_default_before_insert_trigger \n"
117 " BEFORE INSERT ON keys \n"
118 " FOR EACH ROW \n"
119 " WHEN NEW.is_default=1 \n"
120 " BEGIN \n"
121 " UPDATE keys \n"
122 " SET is_default=0 \n"
123 " WHERE identity_id=NEW.identity_id; \n"
124 " END; \n"
125 " \n"
126 "CREATE TRIGGER IF NOT EXISTS \n"
127 " key_default_after_insert_trigger \n"
128 " AFTER INSERT ON keys \n"
129 " FOR EACH ROW \n"
130 " WHEN NOT EXISTS \n"
131 " (SELECT id \n"
132 " FROM keys \n"
133 " WHERE is_default=1 \n"
134 " AND identity_id=NEW.identity_id) \n"
135 " BEGIN \n"
136 " UPDATE keys \n"
137 " SET is_default=1 \n"
138 " WHERE key_name=NEW.key_name; \n"
139 " END; \n"
140 " \n"
141 "CREATE TRIGGER IF NOT EXISTS \n"
142 " key_default_update_trigger \n"
143 " BEFORE UPDATE ON keys \n"
144 " FOR EACH ROW \n"
145 " WHEN NEW.is_default=1 AND OLD.is_default=0 \n"
146 " BEGIN \n"
147 " UPDATE keys \n"
148 " SET is_default=0 \n"
149 " WHERE identity_id=NEW.identity_id; \n"
150 " END; \n"
151 " \n"
152 " \n"
153 "CREATE TABLE IF NOT EXISTS \n"
154 " certificates( \n"
155 " id INTEGER PRIMARY KEY,\n"
156 " key_id INTEGER NOT NULL, \n"
157 " certificate_name BLOB NOT NULL, \n"
158 " certificate_data BLOB NOT NULL, \n"
159 " is_default INTEGER DEFAULT 0, \n"
160 " FOREIGN KEY(key_id) \n"
161 " REFERENCES keys(id) \n"
162 " ON DELETE CASCADE \n"
163 " ON UPDATE CASCADE \n"
164 " ); \n"
165 " \n"
166 "CREATE UNIQUE INDEX IF NOT EXISTS \n"
167 " certIndex ON certificates(certificate_name);\n"
168 " \n"
169 "CREATE TRIGGER IF NOT EXISTS \n"
170 " cert_default_before_insert_trigger \n"
171 " BEFORE INSERT ON certificates \n"
172 " FOR EACH ROW \n"
173 " WHEN NEW.is_default=1 \n"
174 " BEGIN \n"
175 " UPDATE certificates \n"
176 " SET is_default=0 \n"
177 " WHERE key_id=NEW.key_id; \n"
178 " END; \n"
179 " \n"
180 "CREATE TRIGGER IF NOT EXISTS \n"
181 " cert_default_after_insert_trigger \n"
182 " AFTER INSERT ON certificates \n"
183 " FOR EACH ROW \n"
184 " WHEN NOT EXISTS \n"
185 " (SELECT id \n"
186 " FROM certificates \n"
187 " WHERE is_default=1 \n"
188 " AND key_id=NEW.key_id) \n"
189 " BEGIN \n"
190 " UPDATE certificates \n"
191 " SET is_default=1 \n"
192 " WHERE certificate_name=NEW.certificate_name;\n"
193 " END; \n"
194 " \n"
195 "CREATE TRIGGER IF NOT EXISTS \n"
196 " cert_default_update_trigger \n"
197 " BEFORE UPDATE ON certificates \n"
198 " FOR EACH ROW \n"
199 " WHEN NEW.is_default=1 AND OLD.is_default=0 \n"
200 " BEGIN \n"
201 " UPDATE certificates \n"
202 " SET is_default=0 \n"
203 " WHERE key_id=NEW.key_id; \n"
204 " END; \n";
205
206static Name
207getKeyName(const Name& identity, const name::Component& keyId)
208{
209 Name keyName = identity;
210 keyName.append(keyId);
211 return keyName;
212}
213
214PibSqlite3::PibSqlite3(const string& dir)
215{
216 // Determine the path of PIB DB
217 boost::filesystem::path actualDir;
218 if (dir == "") {
219 if (getenv("HOME") == nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700220 BOOST_THROW_EXCEPTION(PibImpl::Error("Environment variable HOME is not set"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700221
222 actualDir = boost::filesystem::path(getenv("HOME")) / ".ndn";
223 boost::filesystem::create_directories(actualDir);
224 }
225 else {
226 actualDir = boost::filesystem::path(dir);
227 boost::filesystem::create_directories(actualDir);
228 }
229 // Open PIB
230 int result = sqlite3_open_v2((actualDir / "pib.db").c_str(), &m_database,
231 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
232#ifdef NDN_CXX_DISABLE_SQLITE3_FS_LOCKING
233 "unix-dotfile"
234#else
235 nullptr
236#endif
237 );
238
239 if (result != SQLITE_OK)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700240 BOOST_THROW_EXCEPTION(PibImpl::Error("PIB DB cannot be opened/created: " + dir));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700241
242
243 // enable foreign key
244 sqlite3_exec(m_database, "PRAGMA foreign_keys=ON", nullptr, nullptr, nullptr);
245
246 // initialize PIB tables
247 char* errorMessage = nullptr;
248 result = sqlite3_exec(m_database, INITIALIZATION.c_str(), nullptr, nullptr, &errorMessage);
249 if (result != SQLITE_OK && errorMessage != nullptr) {
250 sqlite3_free(errorMessage);
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700251 BOOST_THROW_EXCEPTION(PibImpl::Error("PIB DB cannot be initialized"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700252 }
253}
254
255PibSqlite3::~PibSqlite3()
256{
257 sqlite3_close(m_database);
258}
259
260void
261PibSqlite3::setTpmLocator(const std::string& tpmLocator)
262{
263 Sqlite3Statement statement(m_database, "UPDATE tpmInfo SET tpm_locator=?");
264 statement.bind(1, tpmLocator, SQLITE_TRANSIENT);
265 statement.step();
266
267 // no row is updated, tpm_locator does not exist, insert it directly
268 if (0 == sqlite3_changes(m_database)) {
269 Sqlite3Statement insertStatement(m_database, "INSERT INTO tpmInfo (tpm_locator) values (?)");
270 insertStatement.bind(1, tpmLocator, SQLITE_TRANSIENT);
271 insertStatement.step();
272 }
273}
274
275std::string
276PibSqlite3::getTpmLocator() const
277{
278 Sqlite3Statement statement(m_database, "SELECT tpm_locator FROM tpmInfo");
279 int res = statement.step();
280
281 string tpmLocator;
282 if (res == SQLITE_ROW)
283 return statement.getString(0);
284 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700285 BOOST_THROW_EXCEPTION(Pib::Error("TPM info does not exist"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700286}
287
288bool
289PibSqlite3::hasIdentity(const Name& identity) const
290{
291 Sqlite3Statement statement(m_database, "SELECT id FROM identities WHERE identity=?");
292 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
293 return (statement.step() == SQLITE_ROW);
294}
295
296void
297PibSqlite3::addIdentity(const Name& identity)
298{
299 Sqlite3Statement statement(m_database, "INSERT INTO identities (identity) values (?)");
300 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
301 statement.step();
302}
303
304void
305PibSqlite3::removeIdentity(const Name& identity)
306{
307 Sqlite3Statement statement(m_database, "DELETE FROM identities WHERE identity=?");
308 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
309 statement.step();
310}
311
312std::set<Name>
313PibSqlite3::getIdentities() const
314{
315 std::set<Name> identities;
316 Sqlite3Statement statement(m_database, "SELECT identity FROM identities");
317
318 while (statement.step() == SQLITE_ROW)
319 identities.insert(Name(statement.getBlock(0)));
320
321 return identities;
322}
323
324void
325PibSqlite3::setDefaultIdentity(const Name& identityName)
326{
327 Sqlite3Statement statement(m_database, "UPDATE identities SET is_default=1 WHERE identity=?");
328 statement.bind(1, identityName.wireEncode(), SQLITE_TRANSIENT);
329 statement.step();
330}
331
332Name
333PibSqlite3::getDefaultIdentity() const
334{
335 Sqlite3Statement statement(m_database, "SELECT identity FROM identities WHERE is_default=1");
336
337 if (statement.step() == SQLITE_ROW)
338 return Name(statement.getBlock(0));
339 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700340 BOOST_THROW_EXCEPTION(Pib::Error("No default identity"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700341}
342
343bool
344PibSqlite3::hasKey(const Name& identity, const name::Component& keyId) const
345{
346 Name keyName = getKeyName(identity, keyId);
347
348 Sqlite3Statement statement(m_database, "SELECT id FROM keys WHERE key_name=?");
349 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
350
351 return (statement.step() == SQLITE_ROW);
352}
353
354void
355PibSqlite3::addKey(const Name& identity, const name::Component& keyId, const PublicKey& publicKey)
356{
357 if (hasKey(identity, keyId)) {
358 return;
359 }
360
361 // ensure identity exists
362 addIdentity(identity);
363
364 // add key
365 Name keyName = getKeyName(identity, keyId);
366
367 Sqlite3Statement statement(m_database,
368 "INSERT INTO keys (identity_id, key_name, key_type, key_bits) "
369 "VALUES ((SELECT id FROM identities WHERE identity=?), ?, ?, ?)");
370 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
371 statement.bind(2, keyName.wireEncode(), SQLITE_TRANSIENT);
372 statement.bind(3, publicKey.getKeyType());
373 statement.bind(4, publicKey.get().buf(), publicKey.get().size(), SQLITE_STATIC);
374 statement.step();
375}
376
377void
378PibSqlite3::removeKey(const Name& identity, const name::Component& keyId)
379{
380 Name keyName = getKeyName(identity, keyId);
381
382 Sqlite3Statement statement(m_database, "DELETE FROM keys WHERE key_name=?");
383 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
384 statement.step();
385}
386
387PublicKey
388PibSqlite3::getKeyBits(const Name& identity, const name::Component& keyId) const
389{
390 Name keyName = getKeyName(identity, keyId);
391
392 Sqlite3Statement statement(m_database, "SELECT key_bits FROM keys WHERE key_name=?");
393 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
394
395 if (statement.step() == SQLITE_ROW)
396 return PublicKey(statement.getBlob(0), statement.getSize(0));
397 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700398 BOOST_THROW_EXCEPTION(Pib::Error("Key does not exist"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700399}
400
401std::set<name::Component>
402PibSqlite3::getKeysOfIdentity(const Name& identity) const
403{
404 std::set<name::Component> keyNames;
405
406 Sqlite3Statement statement(m_database,
407 "SELECT key_name "
408 "FROM keys JOIN identities ON keys.identity_id=identities.id "
409 "WHERE identities.identity=?");
410 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
411
412 while (statement.step() == SQLITE_ROW) {
413 Name keyName(statement.getBlock(0));
414 keyNames.insert(keyName.get(-1));
415 }
416
417 return keyNames;
418}
419
420void
421PibSqlite3::setDefaultKeyOfIdentity(const Name& identity, const name::Component& keyId)
422{
423 Name keyName = getKeyName(identity, keyId);
424
425 if (!hasKey(identity, keyId)) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700426 BOOST_THROW_EXCEPTION(Pib::Error("No such key"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700427 }
428
429 Sqlite3Statement statement(m_database, "UPDATE keys SET is_default=1 WHERE key_name=?");
430 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
431 statement.step();
432}
433
434name::Component
435PibSqlite3::getDefaultKeyOfIdentity(const Name& identity) const
436{
437 if (!hasIdentity(identity)) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700438 BOOST_THROW_EXCEPTION(Pib::Error("Identity does not exist"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700439 }
440
441 Sqlite3Statement statement(m_database,
442 "SELECT key_name "
443 "FROM keys JOIN identities ON keys.identity_id=identities.id "
444 "WHERE identities.identity=? AND keys.is_default=1");
445 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
446
447 if (statement.step() == SQLITE_ROW) {
448 Name keyName(statement.getBlock(0));
449 return keyName.get(-1);
450 }
451 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700452 BOOST_THROW_EXCEPTION(Pib::Error("No default key"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700453}
454
455bool
456PibSqlite3::hasCertificate(const Name& certName) const
457{
458 Sqlite3Statement statement(m_database, "SELECT id FROM certificates WHERE certificate_name=?");
459 statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT);
460 return (statement.step() == SQLITE_ROW);
461}
462
463void
464PibSqlite3::addCertificate(const IdentityCertificate& certificate)
465{
466 const Name& certName = certificate.getName();
467 const Name& keyName = certificate.getPublicKeyName();
468
469 name::Component keyId = keyName.get(-1);
470 Name identityName = keyName.getPrefix(-1);
471
472 // ensure key exists
473 addKey(identityName, keyId, certificate.getPublicKeyInfo());
474
475 Sqlite3Statement statement(m_database,
476 "INSERT INTO certificates "
477 "(key_id, certificate_name, certificate_data) "
478 "VALUES ((SELECT id FROM keys WHERE key_name=?), ?, ?)");
479 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
480 statement.bind(2, certName.wireEncode(), SQLITE_TRANSIENT);
481 statement.bind(3, certificate.wireEncode(), SQLITE_STATIC);
482 statement.step();
483}
484
485void
486PibSqlite3::removeCertificate(const Name& certName)
487{
488 Sqlite3Statement statement(m_database, "DELETE FROM certificates WHERE certificate_name=?");
489 statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT);
490 statement.step();
491}
492
493IdentityCertificate
494PibSqlite3::getCertificate(const Name& certName) const
495{
496 Sqlite3Statement statement(m_database,
497 "SELECT certificate_data FROM certificates WHERE certificate_name=?");
498 statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT);
499
500 if (statement.step() == SQLITE_ROW)
501 return IdentityCertificate(statement.getBlock(0));
502 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700503 BOOST_THROW_EXCEPTION(Pib::Error("Certificate does not exit"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700504}
505
506std::set<Name>
507PibSqlite3::getCertificatesOfKey(const Name& identity, const name::Component& keyId) const
508{
509 std::set<Name> certNames;
510
511 Name keyName = getKeyName(identity, keyId);
512
513 Sqlite3Statement statement(m_database,
514 "SELECT certificate_name "
515 "FROM certificates JOIN keys ON certificates.key_id=keys.id "
516 "WHERE keys.key_name=?");
517 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
518
519 while (statement.step() == SQLITE_ROW)
520 certNames.insert(Name(statement.getBlock(0)));
521
522 return certNames;
523}
524
525void
526PibSqlite3::setDefaultCertificateOfKey(const Name& identity, const name::Component& keyId,
527 const Name& certName)
528{
529 if (!hasCertificate(certName)) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700530 BOOST_THROW_EXCEPTION(Pib::Error("Certificate does not exist"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700531 }
532
533 Sqlite3Statement statement(m_database,
534 "UPDATE certificates SET is_default=1 WHERE certificate_name=?");
535 statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT);
536 statement.step();
537}
538
539IdentityCertificate
540PibSqlite3::getDefaultCertificateOfKey(const Name& identity, const name::Component& keyId) const
541{
542 Name keyName = getKeyName(identity, keyId);
543
544 Sqlite3Statement statement(m_database,
545 "SELECT certificate_data "
546 "FROM certificates JOIN keys ON certificates.key_id=keys.id "
547 "WHERE certificates.is_default=1 AND keys.key_name=?");
548 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
549
550 if (statement.step() == SQLITE_ROW)
551 return IdentityCertificate(statement.getBlock(0));
552 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700553 BOOST_THROW_EXCEPTION(Pib::Error("Certificate does not exit"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700554}
555
556} // namespace security
557} // namespace ndn