pib-sqlite3.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
22 #include "pib-sqlite3.hpp"
23 #include "pib.hpp"
24 #include "../security-common.hpp"
25 #include "../../util/sqlite3-statement.hpp"
26 
27 #include <sqlite3.h>
28 #include <boost/filesystem.hpp>
29 #include <boost/algorithm/string.hpp>
30 
31 namespace ndn {
32 namespace security {
33 namespace pib {
34 
35 using util::Sqlite3Statement;
36 
37 static const std::string INITIALIZATION = R"SQL(
38 CREATE TABLE IF NOT EXISTS
39  tpmInfo(
40  tpm_locator BLOB
41  );
42 
43 CREATE TABLE IF NOT EXISTS
44  identities(
45  id INTEGER PRIMARY KEY,
46  identity BLOB NOT NULL,
47  is_default INTEGER DEFAULT 0
48  );
49 
50 CREATE UNIQUE INDEX IF NOT EXISTS
51  identityIndex ON identities(identity);
52 
53 CREATE TRIGGER IF NOT EXISTS
54  identity_default_before_insert_trigger
55  BEFORE INSERT ON identities
56  FOR EACH ROW
57  WHEN NEW.is_default=1
58  BEGIN
59  UPDATE identities SET is_default=0;
60  END;
61 
62 CREATE TRIGGER IF NOT EXISTS
63  identity_default_after_insert_trigger
64  AFTER INSERT ON identities
65  FOR EACH ROW
66  WHEN NOT EXISTS
67  (SELECT id
68  FROM identities
69  WHERE is_default=1)
70  BEGIN
71  UPDATE identities
72  SET is_default=1
73  WHERE identity=NEW.identity;
74  END;
75 
76 CREATE TRIGGER IF NOT EXISTS
77  identity_default_update_trigger
78  BEFORE UPDATE ON identities
79  FOR EACH ROW
80  WHEN NEW.is_default=1 AND OLD.is_default=0
81  BEGIN
82  UPDATE identities SET is_default=0;
83  END;
84 
85 
86 CREATE TABLE IF NOT EXISTS
87  keys(
88  id INTEGER PRIMARY KEY,
89  identity_id INTEGER NOT NULL,
90  key_name BLOB NOT NULL,
91  key_bits BLOB NOT NULL,
92  is_default INTEGER DEFAULT 0,
93  FOREIGN KEY(identity_id)
94  REFERENCES identities(id)
95  ON DELETE CASCADE
96  ON UPDATE CASCADE
97  );
98 
99 CREATE UNIQUE INDEX IF NOT EXISTS
100  keyIndex ON keys(key_name);
101 
102 CREATE TRIGGER IF NOT EXISTS
103  key_default_before_insert_trigger
104  BEFORE INSERT ON keys
105  FOR EACH ROW
106  WHEN NEW.is_default=1
107  BEGIN
108  UPDATE keys
109  SET is_default=0
110  WHERE identity_id=NEW.identity_id;
111  END;
112 
113 CREATE TRIGGER IF NOT EXISTS
114  key_default_after_insert_trigger
115  AFTER INSERT ON keys
116  FOR EACH ROW
117  WHEN NOT EXISTS
118  (SELECT id
119  FROM keys
120  WHERE is_default=1
121  AND identity_id=NEW.identity_id)
122  BEGIN
123  UPDATE keys
124  SET is_default=1
125  WHERE key_name=NEW.key_name;
126  END;
127 
128 CREATE TRIGGER IF NOT EXISTS
129  key_default_update_trigger
130  BEFORE UPDATE ON keys
131  FOR EACH ROW
132  WHEN NEW.is_default=1 AND OLD.is_default=0
133  BEGIN
134  UPDATE keys
135  SET is_default=0
136  WHERE identity_id=NEW.identity_id;
137  END;
138 
139 
140 CREATE TABLE IF NOT EXISTS
141  certificates(
142  id INTEGER PRIMARY KEY,
143  key_id INTEGER NOT NULL,
144  certificate_name BLOB NOT NULL,
145  certificate_data BLOB NOT NULL,
146  is_default INTEGER DEFAULT 0,
147  FOREIGN KEY(key_id)
148  REFERENCES keys(id)
149  ON DELETE CASCADE
150  ON UPDATE CASCADE
151  );
152 
153 CREATE UNIQUE INDEX IF NOT EXISTS
154  certIndex ON certificates(certificate_name);
155 
156 CREATE TRIGGER IF NOT EXISTS
157  cert_default_before_insert_trigger
158  BEFORE INSERT ON certificates
159  FOR EACH ROW
160  WHEN NEW.is_default=1
161  BEGIN
162  UPDATE certificates
163  SET is_default=0
164  WHERE key_id=NEW.key_id;
165  END;
166 
167 CREATE TRIGGER IF NOT EXISTS
168  cert_default_after_insert_trigger
169  AFTER INSERT ON certificates
170  FOR EACH ROW
171  WHEN NOT EXISTS
172  (SELECT id
173  FROM certificates
174  WHERE is_default=1
175  AND key_id=NEW.key_id)
176  BEGIN
177  UPDATE certificates
178  SET is_default=1
179  WHERE certificate_name=NEW.certificate_name;
180  END;
181 
182 CREATE TRIGGER IF NOT EXISTS
183  cert_default_update_trigger
184  BEFORE UPDATE ON certificates
185  FOR EACH ROW
186  WHEN NEW.is_default=1 AND OLD.is_default=0
187  BEGIN
188  UPDATE certificates
189  SET is_default=0
190  WHERE key_id=NEW.key_id;
191  END;
192 )SQL";
193 
194 PibSqlite3::PibSqlite3(const std::string& location)
195 {
196  // Determine the path of PIB DB
197  boost::filesystem::path dbDir;
198  if (!location.empty()) {
199  dbDir = boost::filesystem::path(location);
200  }
201 #ifdef NDN_CXX_HAVE_TESTS
202  else if (getenv("TEST_HOME") != nullptr) {
203  dbDir = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn";
204  }
205 #endif // NDN_CXX_HAVE_TESTS
206  else if (getenv("HOME") != nullptr) {
207  dbDir = boost::filesystem::path(getenv("HOME")) / ".ndn";
208  }
209  else {
210  dbDir = boost::filesystem::current_path() / ".ndn";
211  }
212  boost::filesystem::create_directories(dbDir);
213 
214  // Open PIB
215  int result = sqlite3_open_v2((dbDir / "pib.db").c_str(), &m_database,
216  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
217 #ifdef NDN_CXX_DISABLE_SQLITE3_FS_LOCKING
218  "unix-dotfile"
219 #else
220  nullptr
221 #endif
222  );
223 
224  if (result != SQLITE_OK) {
225  BOOST_THROW_EXCEPTION(PibImpl::Error("PIB database cannot be opened/created in " + location));
226  }
227 
228  // enable foreign key
229  sqlite3_exec(m_database, "PRAGMA foreign_keys=ON", nullptr, nullptr, nullptr);
230 
231  // initialize PIB tables
232  char* errorMessage = nullptr;
233  result = sqlite3_exec(m_database, INITIALIZATION.c_str(), nullptr, nullptr, &errorMessage);
234  if (result != SQLITE_OK && errorMessage != nullptr) {
235  sqlite3_free(errorMessage);
236  BOOST_THROW_EXCEPTION(PibImpl::Error("PIB DB cannot be initialized"));
237  }
238 }
239 
241 {
242  sqlite3_close(m_database);
243 }
244 
245 const std::string&
247 {
248  static std::string scheme = "pib-sqlite3";
249  return scheme;
250 }
251 
252 void
253 PibSqlite3::setTpmLocator(const std::string& tpmLocator)
254 {
255  Sqlite3Statement statement(m_database, "UPDATE tpmInfo SET tpm_locator=?");
256  statement.bind(1, tpmLocator, SQLITE_TRANSIENT);
257  statement.step();
258 
259  if (sqlite3_changes(m_database) == 0) {
260  // no row is updated, tpm_locator does not exist, insert it directly
261  Sqlite3Statement insertStatement(m_database, "INSERT INTO tpmInfo (tpm_locator) values (?)");
262  insertStatement.bind(1, tpmLocator, SQLITE_TRANSIENT);
263  insertStatement.step();
264  }
265 }
266 
267 std::string
269 {
270  Sqlite3Statement statement(m_database, "SELECT tpm_locator FROM tpmInfo");
271  int res = statement.step();
272  if (res == SQLITE_ROW)
273  return statement.getString(0);
274  else
275  return "";
276 }
277 
278 bool
279 PibSqlite3::hasIdentity(const Name& identity) const
280 {
281  Sqlite3Statement statement(m_database, "SELECT id FROM identities WHERE identity=?");
282  statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
283  return (statement.step() == SQLITE_ROW);
284 }
285 
286 void
288 {
289  if (!hasIdentity(identity)) {
290  Sqlite3Statement statement(m_database, "INSERT INTO identities (identity) values (?)");
291  statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
292  statement.step();
293  }
294 
295  if (!hasDefaultIdentity()) {
296  setDefaultIdentity(identity);
297  }
298 }
299 
300 void
302 {
303  Sqlite3Statement statement(m_database, "DELETE FROM identities WHERE identity=?");
304  statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
305  statement.step();
306 }
307 
308 void
310 {
311  Sqlite3Statement statement(m_database, "DELETE FROM identities");
312  statement.step();
313 }
314 
315 std::set<Name>
317 {
318  std::set<Name> identities;
319  Sqlite3Statement statement(m_database, "SELECT identity FROM identities");
320 
321  while (statement.step() == SQLITE_ROW)
322  identities.insert(Name(statement.getBlock(0)));
323 
324  return identities;
325 }
326 
327 void
329 {
330  Sqlite3Statement statement(m_database, "UPDATE identities SET is_default=1 WHERE identity=?");
331  statement.bind(1, identityName.wireEncode(), SQLITE_TRANSIENT);
332  statement.step();
333 }
334 
335 Name
337 {
338  Sqlite3Statement statement(m_database, "SELECT identity FROM identities WHERE is_default=1");
339 
340  if (statement.step() == SQLITE_ROW)
341  return Name(statement.getBlock(0));
342  else
343  BOOST_THROW_EXCEPTION(Pib::Error("No default identity"));
344 }
345 
346 bool
347 PibSqlite3::hasDefaultIdentity() const
348 {
349  Sqlite3Statement statement(m_database, "SELECT identity FROM identities WHERE is_default=1");
350  return (statement.step() == SQLITE_ROW);
351 }
352 
353 bool
354 PibSqlite3::hasKey(const Name& keyName) const
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 
362 void
363 PibSqlite3::addKey(const Name& identity, const Name& keyName,
364  const uint8_t* key, size_t keyLen)
365 {
366  // ensure identity exists
367  addIdentity(identity);
368 
369  if (!hasKey(keyName)) {
370  Sqlite3Statement statement(m_database,
371  "INSERT INTO keys (identity_id, key_name, key_bits) "
372  "VALUES ((SELECT id FROM identities WHERE identity=?), ?, ?)");
373  statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
374  statement.bind(2, keyName.wireEncode(), SQLITE_TRANSIENT);
375  statement.bind(3, key, keyLen, SQLITE_STATIC);
376  statement.step();
377  }
378  else {
379  Sqlite3Statement statement(m_database,
380  "UPDATE keys SET key_bits=? WHERE key_name=?");
381  statement.bind(1, key, keyLen, SQLITE_STATIC);
382  statement.bind(2, keyName.wireEncode(), SQLITE_TRANSIENT);
383  statement.step();
384  }
385 
386  if (!hasDefaultKeyOfIdentity(identity)) {
387  setDefaultKeyOfIdentity(identity, keyName);
388  }
389 }
390 
391 void
393 {
394  Sqlite3Statement statement(m_database, "DELETE FROM keys WHERE key_name=?");
395  statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
396  statement.step();
397 }
398 
399 Buffer
400 PibSqlite3::getKeyBits(const Name& keyName) const
401 {
402  Sqlite3Statement statement(m_database, "SELECT key_bits FROM keys WHERE key_name=?");
403  statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
404 
405  if (statement.step() == SQLITE_ROW)
406  return Buffer(statement.getBlob(0), statement.getSize(0));
407  else
408  BOOST_THROW_EXCEPTION(Pib::Error("Key `" + keyName.toUri() + "` does not exist"));
409 }
410 
411 std::set<Name>
412 PibSqlite3::getKeysOfIdentity(const Name& identity) const
413 {
414  std::set<Name> keyNames;
415 
416  Sqlite3Statement statement(m_database,
417  "SELECT key_name "
418  "FROM keys JOIN identities ON keys.identity_id=identities.id "
419  "WHERE identities.identity=?");
420  statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
421 
422  while (statement.step() == SQLITE_ROW) {
423  keyNames.insert(Name(statement.getBlock(0)));
424  }
425 
426  return keyNames;
427 }
428 
429 void
430 PibSqlite3::setDefaultKeyOfIdentity(const Name& identity, const Name& keyName)
431 {
432  if (!hasKey(keyName)) {
433  BOOST_THROW_EXCEPTION(Pib::Error("Key `" + keyName.toUri() + "` does not exist"));
434  }
435 
436  Sqlite3Statement statement(m_database, "UPDATE keys SET is_default=1 WHERE key_name=?");
437  statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
438  statement.step();
439 }
440 
441 Name
443 {
444  if (!hasIdentity(identity)) {
445  BOOST_THROW_EXCEPTION(Pib::Error("Identity `" + identity.toUri() + "` does not exist"));
446  }
447 
448  Sqlite3Statement statement(m_database,
449  "SELECT key_name "
450  "FROM keys JOIN identities ON keys.identity_id=identities.id "
451  "WHERE identities.identity=? AND keys.is_default=1");
452  statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
453 
454  if (statement.step() == SQLITE_ROW) {
455  return Name(statement.getBlock(0));
456  }
457  else
458  BOOST_THROW_EXCEPTION(Pib::Error("No default key for identity `" + identity.toUri() + "`"));
459 }
460 
461 bool
462 PibSqlite3::hasDefaultKeyOfIdentity(const Name& identity) const
463 {
464  Sqlite3Statement statement(m_database,
465  "SELECT key_name "
466  "FROM keys JOIN identities ON keys.identity_id=identities.id "
467  "WHERE identities.identity=? AND keys.is_default=1");
468  statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
469 
470  return (statement.step() == SQLITE_ROW);
471 }
472 
473 bool
474 PibSqlite3::hasCertificate(const Name& certName) const
475 {
476  Sqlite3Statement statement(m_database, "SELECT id FROM certificates WHERE certificate_name=?");
477  statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT);
478  return (statement.step() == SQLITE_ROW);
479 }
480 
481 void
483 {
484  // ensure key exists
485  const Block& content = certificate.getContent();
486  addKey(certificate.getIdentity(), certificate.getKeyName(), content.value(), content.value_size());
487 
488  if (!hasCertificate(certificate.getName())) {
489  Sqlite3Statement statement(m_database,
490  "INSERT INTO certificates "
491  "(key_id, certificate_name, certificate_data) "
492  "VALUES ((SELECT id FROM keys WHERE key_name=?), ?, ?)");
493  statement.bind(1, certificate.getKeyName().wireEncode(), SQLITE_TRANSIENT);
494  statement.bind(2, certificate.getName().wireEncode(), SQLITE_TRANSIENT);
495  statement.bind(3, certificate.wireEncode(), SQLITE_STATIC);
496  statement.step();
497  }
498  else {
499  Sqlite3Statement statement(m_database,
500  "UPDATE certificates SET certificate_data=? WHERE certificate_name=?");
501  statement.bind(1, certificate.wireEncode(), SQLITE_STATIC);
502  statement.bind(2, certificate.getName().wireEncode(), SQLITE_TRANSIENT);
503  statement.step();
504  }
505 
506  if (!hasDefaultCertificateOfKey(certificate.getKeyName())) {
507  setDefaultCertificateOfKey(certificate.getKeyName(), certificate.getName());
508  }
509 }
510 
511 void
513 {
514  Sqlite3Statement statement(m_database, "DELETE FROM certificates WHERE certificate_name=?");
515  statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT);
516  statement.step();
517 }
518 
520 PibSqlite3::getCertificate(const Name& certName) const
521 {
522  Sqlite3Statement statement(m_database,
523  "SELECT certificate_data FROM certificates WHERE certificate_name=?");
524  statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT);
525 
526  if (statement.step() == SQLITE_ROW)
527  return v2::Certificate(statement.getBlock(0));
528  else
529  BOOST_THROW_EXCEPTION(Pib::Error("Certificate `" + certName.toUri() + "` does not exit"));
530 }
531 
532 std::set<Name>
534 {
535  std::set<Name> certNames;
536 
537  Sqlite3Statement statement(m_database,
538  "SELECT certificate_name "
539  "FROM certificates JOIN keys ON certificates.key_id=keys.id "
540  "WHERE keys.key_name=?");
541  statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
542 
543  while (statement.step() == SQLITE_ROW)
544  certNames.insert(Name(statement.getBlock(0)));
545 
546  return certNames;
547 }
548 
549 void
550 PibSqlite3::setDefaultCertificateOfKey(const Name& keyName, const Name& certName)
551 {
552  if (!hasCertificate(certName)) {
553  BOOST_THROW_EXCEPTION(Pib::Error("Certificate `" + certName.toUri() + "` does not exist"));
554  }
555 
556  Sqlite3Statement statement(m_database,
557  "UPDATE certificates SET is_default=1 WHERE certificate_name=?");
558  statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT);
559  statement.step();
560 }
561 
564 {
565  Sqlite3Statement statement(m_database,
566  "SELECT certificate_data "
567  "FROM certificates JOIN keys ON certificates.key_id=keys.id "
568  "WHERE certificates.is_default=1 AND keys.key_name=?");
569  statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
570 
571  if (statement.step() == SQLITE_ROW)
572  return v2::Certificate(statement.getBlock(0));
573  else
574  BOOST_THROW_EXCEPTION(Pib::Error("No default certificate for key `" + keyName.toUri() + "`"));
575 }
576 
577 bool
578 PibSqlite3::hasDefaultCertificateOfKey(const Name& keyName) const
579 {
580  Sqlite3Statement statement(m_database,
581  "SELECT certificate_data "
582  "FROM certificates JOIN keys ON certificates.key_id=keys.id "
583  "WHERE certificates.is_default=1 AND keys.key_name=?");
584  statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
585 
586  return (statement.step() == SQLITE_ROW);
587 }
588 
589 } // namespace pib
590 } // namespace security
591 } // namespace ndn
represents a non-semantic error
Definition: pib-impl.hpp:48
void removeCertificate(const Name &certName) final
Remove a certificate with name certName.
Copyright (c) 2013-2017 Regents of the University of California.
Definition: common.hpp:66
Name getDefaultKeyOfIdentity(const Name &identity) const final
The certificate following the certificate format naming convention.
Definition: certificate.hpp:81
represents a semantic error
Definition: pib.hpp:56
Name getKeyName() const
Get key name.
Definition: certificate.cpp:81
std::set< Name > getCertificatesOfKey(const Name &keyName) const final
Get a list of certificate names of a key with id keyName.
void clearIdentities() final
Erasing all certificates, keys, and identities.
void addKey(const Name &identity, const Name &keyName, const uint8_t *key, size_t keyLen) final
Add a key.
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Fast encoding or block size estimation.
Definition: name.cpp:131
Represents a TLV element of NDN packet format.
Definition: block.hpp:42
std::set< Name > getIdentities() const final
Get the name of all the identities.
void setTpmLocator(const std::string &tpmLocator) final
Set the corresponding TPM information to tpmLocator.
v2::Certificate getCertificate(const Name &certName) const final
Get a certificate with name certName.
std::string toUri() const
Get URI representation of the name.
Definition: name.cpp:122
std::string getTpmLocator() const final
Get TPM Locator.
size_t wireEncode(EncodingImpl< TAG > &encoder, bool wantUnsignedPortionOnly=false) const
Fast encoding or block size estimation.
Definition: data.cpp:48
Buffer getKeyBits(const Name &keyName) const final
Get the key bits of a key with name keyName.
static const std::string & getScheme()
void removeIdentity(const Name &identity) final
Remove an identity and related keys and certificates.
void setDefaultIdentity(const Name &identityName) final
Set an identity with name identityName as the default identity.
void setDefaultCertificateOfKey(const Name &keyName, const Name &certName) final
Set a cert with name certName as the default of a key with keyName.
Name getDefaultIdentity() const final
Get the default identity.
Name getIdentity() const
Get identity name.
Definition: certificate.cpp:87
Represents an absolute name.
Definition: name.hpp:42
size_t value_size() const
Get size of TLV-VALUE aka TLV-LENGTH.
Definition: block.cpp:317
~PibSqlite3()
Destruct and cleanup internal state.
PibSqlite3(const std::string &location="")
Create sqlite3-based PIB backed.
void addIdentity(const Name &identity) final
Add an identity.
void addCertificate(const v2::Certificate &certificate) final
Add a certificate.
const Name & getName() const
Get name.
Definition: data.hpp:121
v2::Certificate getDefaultCertificateOfKey(const Name &keyName) const final
bool hasKey(const Name &keyName) const final
Check the existence of a key with keyName.
const Block & getContent() const
Get Content.
Definition: data.cpp:185
void removeKey(const Name &keyName) final
Remove a key with keyName and related certificates.
void setDefaultKeyOfIdentity(const Name &identity, const Name &keyName) final
Set an key with keyName as the default key of an identity with name identity.
const uint8_t * value() const
Get pointer to TLV-VALUE.
Definition: block.cpp:311
std::set< Name > getKeysOfIdentity(const Name &identity) const final
Get all the key names of an identity with name identity.
static const std::string INITIALIZATION
Definition: pib-sqlite3.cpp:37
bool hasIdentity(const Name &identity) const final
Check the existence of an identity.
General-purpose automatically managed/resized buffer.
Definition: buffer.hpp:40
bool hasCertificate(const Name &certName) const final
Check the existence of a certificate with name certName.