security+tools: Allow user to explicitly specify the cert name prefix before 'KEY' component in ndnsec-certgen

Change-Id: I71e137e89b5ab0cd5db7001b39ff76c22a448bd2
Refs: #1659
diff --git a/src/security/key-chain.cpp b/src/security/key-chain.cpp
index fe85472..240bab6 100644
--- a/src/security/key-chain.cpp
+++ b/src/security/key-chain.cpp
@@ -35,6 +35,9 @@
 
 namespace ndn {
 
+// Use a GUID as a magic number of KeyChain::DEFAULT_PREFIX identifier
+const Name KeyChain::DEFAULT_PREFIX("/723821fd-f534-44b3-80d9-44bf5f58bbbb");
+
 KeyChain::KeyChain()
   : m_pib(0)
   , m_tpm(0)
@@ -120,7 +123,32 @@
   const Name& signingIdentity,
   const time::system_clock::TimePoint& notBefore,
   const time::system_clock::TimePoint& notAfter,
-  const std::vector<CertificateSubjectDescription>& subjectDescription)
+  const std::vector<CertificateSubjectDescription>& subjectDescription,
+  const Name& certPrefix)
+{
+  shared_ptr<PublicKey> publicKey;
+  try
+    {
+      publicKey = m_pib->getPublicKey(keyName);
+    }
+  catch (SecPublicInfo::Error& e)
+    {
+      return shared_ptr<IdentityCertificate>();
+    }
+
+  return prepareUnsignedIdentityCertificate(keyName, *publicKey, signingIdentity,
+                                            notBefore, notAfter,
+                                            subjectDescription, certPrefix);
+}
+
+shared_ptr<IdentityCertificate>
+KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
+  const PublicKey& publicKey,
+  const Name& signingIdentity,
+  const time::system_clock::TimePoint& notBefore,
+  const time::system_clock::TimePoint& notAfter,
+  const std::vector<CertificateSubjectDescription>& subjectDescription,
+  const Name& certPrefix)
 {
   if (keyName.size() < 1)
     return shared_ptr<IdentityCertificate>();
@@ -132,37 +160,40 @@
   shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
   Name certName;
 
-  if (signingIdentity.isPrefixOf(keyName))
+  if (certPrefix == KeyChain::DEFAULT_PREFIX)
     {
-      certName.append(signingIdentity)
-        .append("KEY")
-        .append(keyName.getSubName(signingIdentity.size()))
-        .append("ID-CERT")
-        .appendVersion();
+      // No certificate prefix hint, infer the prefix
+      if (signingIdentity.isPrefixOf(keyName))
+        certName.append(signingIdentity)
+          .append("KEY")
+          .append(keyName.getSubName(signingIdentity.size()))
+          .append("ID-CERT")
+          .appendVersion();
+      else
+        certName.append(keyName.getPrefix(-1))
+          .append("KEY")
+          .append(keyName.get(-1))
+          .append("ID-CERT")
+          .appendVersion();
     }
   else
     {
-      certName.append(keyName.getPrefix(-1))
-        .append("KEY")
-        .append(keyName.get(-1))
-        .append("ID-CERT")
-        .appendVersion();
+      // cert prefix hint is supplied, determine the cert name.
+      if (certPrefix.isPrefixOf(keyName) && certPrefix != keyName)
+        certName.append(certPrefix)
+          .append("KEY")
+          .append(keyName.getSubName(certPrefix.size()))
+          .append("ID-CERT")
+          .appendVersion();
+      else
+        return shared_ptr<IdentityCertificate>();
     }
 
+
   certificate->setName(certName);
   certificate->setNotBefore(notBefore);
   certificate->setNotAfter(notAfter);
-
-  shared_ptr<PublicKey> publicKey;
-  try
-    {
-      publicKey = m_pib->getPublicKey(keyName);
-    }
-  catch (SecPublicInfo::Error& e)
-    {
-      return shared_ptr<IdentityCertificate>();
-    }
-  certificate->setPublicKeyInfo(*publicKey);
+  certificate->setPublicKeyInfo(publicKey);
 
   if (subjectDescription.empty())
     {
diff --git a/src/security/key-chain.hpp b/src/security/key-chain.hpp
index 7c95e14..00a2e6b 100644
--- a/src/security/key-chain.hpp
+++ b/src/security/key-chain.hpp
@@ -57,6 +57,8 @@
     }
   };
 
+  static const Name DEFAULT_PREFIX;
+
   KeyChain();
 
   template<class KeyChainTraits>
@@ -116,6 +118,11 @@
    * @param notBefore Refer to IdentityCertificate.
    * @param notAfter Refer to IdentityCertificate.
    * @param subjectDescription Refer to IdentityCertificate.
+   * @param certPrefix Prefix before `KEY` component. By default, KeyChain will infer the
+   *                   certificate name according to the relation between the signingIdentity and
+   *                   the subject identity. If signingIdentity is a prefix of the subject identity,
+   *                   `KEY` will be inserted after the signingIdentity, otherwise `KEY` is inserted
+   *                   after subject identity (i.e., before `ksk-....`).
    * @return IdentityCertificate.
    */
   shared_ptr<IdentityCertificate>
@@ -123,7 +130,33 @@
     const Name& signingIdentity,
     const time::system_clock::TimePoint& notBefore,
     const time::system_clock::TimePoint& notAfter,
-    const std::vector<CertificateSubjectDescription>& subjectDescription);
+    const std::vector<CertificateSubjectDescription>& subjectDescription,
+    const Name& certPrefix = DEFAULT_PREFIX);
+
+  /**
+   * @brief prepare an unsigned identity certificate
+   *
+   * @param keyName Key name, e.g., `/<identity_name>/ksk-123456`.
+   * @param publicKey Public key to sign.
+   * @param signingIdentity The signing identity.
+   * @param notBefore Refer to IdentityCertificate.
+   * @param notAfter Refer to IdentityCertificate.
+   * @param subjectDescription Refer to IdentityCertificate.
+   * @param certPrefix Prefix before `KEY` component. By default, KeyChain will infer the
+   *                   certificate name according to the relation between the signingIdentity and
+   *                   the subject identity. If signingIdentity is a prefix of the subject identity,
+   *                   `KEY` will be inserted after the signingIdentity, otherwise `KEY` is inserted
+   *                   after subject identity (i.e., before `ksk-....`).
+   * @return IdentityCertificate.
+   */
+  shared_ptr<IdentityCertificate>
+  prepareUnsignedIdentityCertificate(const Name& keyName,
+    const PublicKey& publicKey,
+    const Name& signingIdentity,
+    const time::system_clock::TimePoint& notBefore,
+    const time::system_clock::TimePoint& notAfter,
+    const std::vector<CertificateSubjectDescription>& subjectDescription,
+    const Name& certPrefix = DEFAULT_PREFIX);
 
   /**
    * @brief Sign packet with default identity