security: Make addKey/Cert behavior of PibImpl consistent

Change-Id: I30c6dd0007e9095ee07f7a8eda3b20db4c34c513
Refs: #3351
diff --git a/src/security/pib/pib-sqlite3.cpp b/src/security/pib/pib-sqlite3.cpp
index 8d8c437..b19f32c 100644
--- a/src/security/pib/pib-sqlite3.cpp
+++ b/src/security/pib/pib-sqlite3.cpp
@@ -279,9 +279,15 @@
 void
 PibSqlite3::addIdentity(const Name& identity)
 {
-  Sqlite3Statement statement(m_database, "INSERT INTO identities (identity) values (?)");
-  statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
-  statement.step();
+  if (!hasIdentity(identity)) {
+    Sqlite3Statement statement(m_database, "INSERT INTO identities (identity) values (?)");
+    statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
+    statement.step();
+  }
+
+  if (!hasDefaultIdentity()) {
+    setDefaultIdentity(identity);
+  }
 }
 
 void
@@ -331,6 +337,13 @@
 }
 
 bool
+PibSqlite3::hasDefaultIdentity() const
+{
+  Sqlite3Statement statement(m_database, "SELECT identity FROM identities WHERE is_default=1");
+  return (statement.step() == SQLITE_ROW);
+}
+
+bool
 PibSqlite3::hasKey(const Name& keyName) const
 {
   Sqlite3Statement statement(m_database, "SELECT id FROM keys WHERE key_name=?");
@@ -343,20 +356,29 @@
 PibSqlite3::addKey(const Name& identity, const Name& keyName,
                    const uint8_t* key, size_t keyLen)
 {
-  if (hasKey(keyName)) {
-    return;
-  }
-
   // ensure identity exists
   addIdentity(identity);
 
-  Sqlite3Statement statement(m_database,
-                             "INSERT INTO keys (identity_id, key_name, key_bits) "
-                             "VALUES ((SELECT id FROM identities WHERE identity=?), ?, ?)");
-  statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
-  statement.bind(2, keyName.wireEncode(), SQLITE_TRANSIENT);
-  statement.bind(3, key, keyLen, SQLITE_STATIC);
-  statement.step();
+  if (!hasKey(keyName)) {
+    Sqlite3Statement statement(m_database,
+                               "INSERT INTO keys (identity_id, key_name, key_bits) "
+                               "VALUES ((SELECT id FROM identities WHERE identity=?), ?, ?)");
+    statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
+    statement.bind(2, keyName.wireEncode(), SQLITE_TRANSIENT);
+    statement.bind(3, key, keyLen, SQLITE_STATIC);
+    statement.step();
+  }
+  else {
+    Sqlite3Statement statement(m_database,
+                               "UPDATE keys SET key_bits=? WHERE key_name=?");
+    statement.bind(1, key, keyLen, SQLITE_STATIC);
+    statement.bind(2, keyName.wireEncode(), SQLITE_TRANSIENT);
+    statement.step();
+  }
+
+  if (!hasDefaultKeyOfIdentity(identity)) {
+    setDefaultKeyOfIdentity(identity, keyName);
+  }
 }
 
 void
@@ -430,6 +452,18 @@
 }
 
 bool
+PibSqlite3::hasDefaultKeyOfIdentity(const Name& identity) const
+{
+  Sqlite3Statement statement(m_database,
+                             "SELECT key_name "
+                             "FROM keys JOIN identities ON keys.identity_id=identities.id "
+                             "WHERE identities.identity=? AND keys.is_default=1");
+  statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
+
+  return (statement.step() == SQLITE_ROW);
+}
+
+bool
 PibSqlite3::hasCertificate(const Name& certName) const
 {
   Sqlite3Statement statement(m_database, "SELECT id FROM certificates WHERE certificate_name=?");
@@ -444,14 +478,27 @@
   const Block& content = certificate.getContent();
   addKey(certificate.getIdentity(), certificate.getKeyName(), content.value(), content.value_size());
 
-  Sqlite3Statement statement(m_database,
-                             "INSERT INTO certificates "
-                             "(key_id, certificate_name, certificate_data) "
-                             "VALUES ((SELECT id FROM keys WHERE key_name=?), ?, ?)");
-  statement.bind(1, certificate.getKeyName().wireEncode(), SQLITE_TRANSIENT);
-  statement.bind(2, certificate.getName().wireEncode(), SQLITE_TRANSIENT);
-  statement.bind(3, certificate.wireEncode(), SQLITE_STATIC);
-  statement.step();
+  if (!hasCertificate(certificate.getName())) {
+    Sqlite3Statement statement(m_database,
+                               "INSERT INTO certificates "
+                               "(key_id, certificate_name, certificate_data) "
+                               "VALUES ((SELECT id FROM keys WHERE key_name=?), ?, ?)");
+    statement.bind(1, certificate.getKeyName().wireEncode(), SQLITE_TRANSIENT);
+    statement.bind(2, certificate.getName().wireEncode(), SQLITE_TRANSIENT);
+    statement.bind(3, certificate.wireEncode(), SQLITE_STATIC);
+    statement.step();
+  }
+  else {
+    Sqlite3Statement statement(m_database,
+                               "UPDATE certificates SET certificate_data=? WHERE certificate_name=?");
+    statement.bind(1, certificate.wireEncode(), SQLITE_STATIC);
+    statement.bind(2, certificate.getName().wireEncode(), SQLITE_TRANSIENT);
+    statement.step();
+  }
+
+  if (!hasDefaultCertificateOfKey(certificate.getKeyName())) {
+    setDefaultCertificateOfKey(certificate.getKeyName(), certificate.getName());
+  }
 }
 
 void
@@ -520,6 +567,18 @@
     BOOST_THROW_EXCEPTION(Pib::Error("No default certificate for key `" + keyName.toUri() + "`"));
 }
 
+bool
+PibSqlite3::hasDefaultCertificateOfKey(const Name& keyName) const
+{
+  Sqlite3Statement statement(m_database,
+                             "SELECT certificate_data "
+                             "FROM certificates JOIN keys ON certificates.key_id=keys.id "
+                             "WHERE certificates.is_default=1 AND keys.key_name=?");
+  statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
+
+  return (statement.step() == SQLITE_ROW);
+}
+
 } // namespace pib
 } // namespace security
 } // namespace ndn