blob: cbded5ba6446a591d23a12537137ba8fbe167d38 [file] [log] [blame]
Mickey Sweatt11314b72015-06-10 17:20:19 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev57e00362016-06-23 13:22:54 -07003 * Copyright (c) 2013-2016 Regents of the University of California.
Mickey Sweatt11314b72015-06-10 17:20:19 -07004 *
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 == "") {
Alexander Afanasyev57e00362016-06-23 13:22:54 -0700219#ifdef NDN_CXX_HAVE_TESTS
220 if (getenv("TEST_HOME") != nullptr) {
221 actualDir = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn";
222 }
223 else
224#endif // NDN_CXX_HAVE_TESTS
225 if (getenv("HOME") != nullptr) {
226 actualDir = boost::filesystem::path(getenv("HOME")) / ".ndn";
227 }
228 else {
229 actualDir = boost::filesystem::path(".") / ".ndn";
230 }
Mickey Sweatt11314b72015-06-10 17:20:19 -0700231 }
232 else {
233 actualDir = boost::filesystem::path(dir);
Mickey Sweatt11314b72015-06-10 17:20:19 -0700234 }
Alexander Afanasyev57e00362016-06-23 13:22:54 -0700235 boost::filesystem::create_directories(actualDir);
236
Mickey Sweatt11314b72015-06-10 17:20:19 -0700237 // Open PIB
238 int result = sqlite3_open_v2((actualDir / "pib.db").c_str(), &m_database,
239 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
240#ifdef NDN_CXX_DISABLE_SQLITE3_FS_LOCKING
241 "unix-dotfile"
242#else
243 nullptr
244#endif
245 );
246
247 if (result != SQLITE_OK)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700248 BOOST_THROW_EXCEPTION(PibImpl::Error("PIB DB cannot be opened/created: " + dir));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700249
250
251 // enable foreign key
252 sqlite3_exec(m_database, "PRAGMA foreign_keys=ON", nullptr, nullptr, nullptr);
253
254 // initialize PIB tables
255 char* errorMessage = nullptr;
256 result = sqlite3_exec(m_database, INITIALIZATION.c_str(), nullptr, nullptr, &errorMessage);
257 if (result != SQLITE_OK && errorMessage != nullptr) {
258 sqlite3_free(errorMessage);
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700259 BOOST_THROW_EXCEPTION(PibImpl::Error("PIB DB cannot be initialized"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700260 }
261}
262
263PibSqlite3::~PibSqlite3()
264{
265 sqlite3_close(m_database);
266}
267
268void
269PibSqlite3::setTpmLocator(const std::string& tpmLocator)
270{
271 Sqlite3Statement statement(m_database, "UPDATE tpmInfo SET tpm_locator=?");
272 statement.bind(1, tpmLocator, SQLITE_TRANSIENT);
273 statement.step();
274
275 // no row is updated, tpm_locator does not exist, insert it directly
276 if (0 == sqlite3_changes(m_database)) {
277 Sqlite3Statement insertStatement(m_database, "INSERT INTO tpmInfo (tpm_locator) values (?)");
278 insertStatement.bind(1, tpmLocator, SQLITE_TRANSIENT);
279 insertStatement.step();
280 }
281}
282
283std::string
284PibSqlite3::getTpmLocator() const
285{
286 Sqlite3Statement statement(m_database, "SELECT tpm_locator FROM tpmInfo");
287 int res = statement.step();
288
289 string tpmLocator;
290 if (res == SQLITE_ROW)
291 return statement.getString(0);
292 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700293 BOOST_THROW_EXCEPTION(Pib::Error("TPM info does not exist"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700294}
295
296bool
297PibSqlite3::hasIdentity(const Name& identity) const
298{
299 Sqlite3Statement statement(m_database, "SELECT id FROM identities WHERE identity=?");
300 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
301 return (statement.step() == SQLITE_ROW);
302}
303
304void
305PibSqlite3::addIdentity(const Name& identity)
306{
307 Sqlite3Statement statement(m_database, "INSERT INTO identities (identity) values (?)");
308 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
309 statement.step();
310}
311
312void
313PibSqlite3::removeIdentity(const Name& identity)
314{
315 Sqlite3Statement statement(m_database, "DELETE FROM identities WHERE identity=?");
316 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
317 statement.step();
318}
319
320std::set<Name>
321PibSqlite3::getIdentities() const
322{
323 std::set<Name> identities;
324 Sqlite3Statement statement(m_database, "SELECT identity FROM identities");
325
326 while (statement.step() == SQLITE_ROW)
327 identities.insert(Name(statement.getBlock(0)));
328
329 return identities;
330}
331
332void
333PibSqlite3::setDefaultIdentity(const Name& identityName)
334{
335 Sqlite3Statement statement(m_database, "UPDATE identities SET is_default=1 WHERE identity=?");
336 statement.bind(1, identityName.wireEncode(), SQLITE_TRANSIENT);
337 statement.step();
338}
339
340Name
341PibSqlite3::getDefaultIdentity() const
342{
343 Sqlite3Statement statement(m_database, "SELECT identity FROM identities WHERE is_default=1");
344
345 if (statement.step() == SQLITE_ROW)
346 return Name(statement.getBlock(0));
347 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700348 BOOST_THROW_EXCEPTION(Pib::Error("No default identity"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700349}
350
351bool
352PibSqlite3::hasKey(const Name& identity, const name::Component& keyId) const
353{
354 Name keyName = getKeyName(identity, keyId);
355
356 Sqlite3Statement statement(m_database, "SELECT id FROM keys WHERE key_name=?");
357 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
358
359 return (statement.step() == SQLITE_ROW);
360}
361
362void
363PibSqlite3::addKey(const Name& identity, const name::Component& keyId, const PublicKey& publicKey)
364{
365 if (hasKey(identity, keyId)) {
366 return;
367 }
368
369 // ensure identity exists
370 addIdentity(identity);
371
372 // add key
373 Name keyName = getKeyName(identity, keyId);
374
375 Sqlite3Statement statement(m_database,
376 "INSERT INTO keys (identity_id, key_name, key_type, key_bits) "
377 "VALUES ((SELECT id FROM identities WHERE identity=?), ?, ?, ?)");
378 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
379 statement.bind(2, keyName.wireEncode(), SQLITE_TRANSIENT);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700380 statement.bind(3, static_cast<int>(publicKey.getKeyType()));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700381 statement.bind(4, publicKey.get().buf(), publicKey.get().size(), SQLITE_STATIC);
382 statement.step();
383}
384
385void
386PibSqlite3::removeKey(const Name& identity, const name::Component& keyId)
387{
388 Name keyName = getKeyName(identity, keyId);
389
390 Sqlite3Statement statement(m_database, "DELETE FROM keys WHERE key_name=?");
391 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
392 statement.step();
393}
394
395PublicKey
396PibSqlite3::getKeyBits(const Name& identity, const name::Component& keyId) const
397{
398 Name keyName = getKeyName(identity, keyId);
399
400 Sqlite3Statement statement(m_database, "SELECT key_bits FROM keys WHERE key_name=?");
401 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
402
403 if (statement.step() == SQLITE_ROW)
404 return PublicKey(statement.getBlob(0), statement.getSize(0));
405 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700406 BOOST_THROW_EXCEPTION(Pib::Error("Key does not exist"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700407}
408
409std::set<name::Component>
410PibSqlite3::getKeysOfIdentity(const Name& identity) const
411{
412 std::set<name::Component> keyNames;
413
414 Sqlite3Statement statement(m_database,
415 "SELECT key_name "
416 "FROM keys JOIN identities ON keys.identity_id=identities.id "
417 "WHERE identities.identity=?");
418 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
419
420 while (statement.step() == SQLITE_ROW) {
421 Name keyName(statement.getBlock(0));
422 keyNames.insert(keyName.get(-1));
423 }
424
425 return keyNames;
426}
427
428void
429PibSqlite3::setDefaultKeyOfIdentity(const Name& identity, const name::Component& keyId)
430{
431 Name keyName = getKeyName(identity, keyId);
432
433 if (!hasKey(identity, keyId)) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700434 BOOST_THROW_EXCEPTION(Pib::Error("No such key"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700435 }
436
437 Sqlite3Statement statement(m_database, "UPDATE keys SET is_default=1 WHERE key_name=?");
438 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
439 statement.step();
440}
441
442name::Component
443PibSqlite3::getDefaultKeyOfIdentity(const Name& identity) const
444{
445 if (!hasIdentity(identity)) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700446 BOOST_THROW_EXCEPTION(Pib::Error("Identity does not exist"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700447 }
448
449 Sqlite3Statement statement(m_database,
450 "SELECT key_name "
451 "FROM keys JOIN identities ON keys.identity_id=identities.id "
452 "WHERE identities.identity=? AND keys.is_default=1");
453 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
454
455 if (statement.step() == SQLITE_ROW) {
456 Name keyName(statement.getBlock(0));
457 return keyName.get(-1);
458 }
459 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700460 BOOST_THROW_EXCEPTION(Pib::Error("No default key"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700461}
462
463bool
464PibSqlite3::hasCertificate(const Name& certName) const
465{
466 Sqlite3Statement statement(m_database, "SELECT id FROM certificates WHERE certificate_name=?");
467 statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT);
468 return (statement.step() == SQLITE_ROW);
469}
470
471void
472PibSqlite3::addCertificate(const IdentityCertificate& certificate)
473{
474 const Name& certName = certificate.getName();
475 const Name& keyName = certificate.getPublicKeyName();
476
477 name::Component keyId = keyName.get(-1);
478 Name identityName = keyName.getPrefix(-1);
479
480 // ensure key exists
481 addKey(identityName, keyId, certificate.getPublicKeyInfo());
482
483 Sqlite3Statement statement(m_database,
484 "INSERT INTO certificates "
485 "(key_id, certificate_name, certificate_data) "
486 "VALUES ((SELECT id FROM keys WHERE key_name=?), ?, ?)");
487 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
488 statement.bind(2, certName.wireEncode(), SQLITE_TRANSIENT);
489 statement.bind(3, certificate.wireEncode(), SQLITE_STATIC);
490 statement.step();
491}
492
493void
494PibSqlite3::removeCertificate(const Name& certName)
495{
496 Sqlite3Statement statement(m_database, "DELETE FROM certificates WHERE certificate_name=?");
497 statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT);
498 statement.step();
499}
500
501IdentityCertificate
502PibSqlite3::getCertificate(const Name& certName) const
503{
504 Sqlite3Statement statement(m_database,
505 "SELECT certificate_data FROM certificates WHERE certificate_name=?");
506 statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT);
507
508 if (statement.step() == SQLITE_ROW)
509 return IdentityCertificate(statement.getBlock(0));
510 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700511 BOOST_THROW_EXCEPTION(Pib::Error("Certificate does not exit"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700512}
513
514std::set<Name>
515PibSqlite3::getCertificatesOfKey(const Name& identity, const name::Component& keyId) const
516{
517 std::set<Name> certNames;
518
519 Name keyName = getKeyName(identity, keyId);
520
521 Sqlite3Statement statement(m_database,
522 "SELECT certificate_name "
523 "FROM certificates JOIN keys ON certificates.key_id=keys.id "
524 "WHERE keys.key_name=?");
525 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
526
527 while (statement.step() == SQLITE_ROW)
528 certNames.insert(Name(statement.getBlock(0)));
529
530 return certNames;
531}
532
533void
534PibSqlite3::setDefaultCertificateOfKey(const Name& identity, const name::Component& keyId,
535 const Name& certName)
536{
537 if (!hasCertificate(certName)) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700538 BOOST_THROW_EXCEPTION(Pib::Error("Certificate does not exist"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700539 }
540
541 Sqlite3Statement statement(m_database,
542 "UPDATE certificates SET is_default=1 WHERE certificate_name=?");
543 statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT);
544 statement.step();
545}
546
547IdentityCertificate
548PibSqlite3::getDefaultCertificateOfKey(const Name& identity, const name::Component& keyId) const
549{
550 Name keyName = getKeyName(identity, keyId);
551
552 Sqlite3Statement statement(m_database,
553 "SELECT certificate_data "
554 "FROM certificates JOIN keys ON certificates.key_id=keys.id "
555 "WHERE certificates.is_default=1 AND keys.key_name=?");
556 statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
557
558 if (statement.step() == SQLITE_ROW)
559 return IdentityCertificate(statement.getBlock(0));
560 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700561 BOOST_THROW_EXCEPTION(Pib::Error("Certificate does not exit"));
Mickey Sweatt11314b72015-06-10 17:20:19 -0700562}
563
564} // namespace security
565} // namespace ndn