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/docs/doxygen.conf.in b/docs/doxygen.conf.in
index 24b3de7..7b79b1e 100644
--- a/docs/doxygen.conf.in
+++ b/docs/doxygen.conf.in
@@ -1888,7 +1888,7 @@
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-MACRO_EXPANSION = NO
+MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and
diff --git a/docs/manpages/ndnsec-cert-gen.rst b/docs/manpages/ndnsec-cert-gen.rst
index 3c2eff8..923c936 100644
--- a/docs/manpages/ndnsec-cert-gen.rst
+++ b/docs/manpages/ndnsec-cert-gen.rst
@@ -8,7 +8,7 @@
::
- $ ndnsec-cert-gen [-h] [-S timestamp] [-E timestamp] [-N name] [-I info] [-s sign-id] request
+ $ ndnsec-cert-gen [-h] [-S timestamp] [-E timestamp] [-N name] [-I info] [-s sign-id] [-p cert-prefix] request
Description
-----------
@@ -45,6 +45,15 @@
Signing identity. The default key/certificate of ``sign-id`` will be used to sign the requested
certificate. If this option is not specified, the system default identity will be used.
+``-p cert-prefix``
+ The certificate prefix, which is the part of certificate name before ``KEY`` component.
+
+ By default, the certificate prefix will be inferred from the certificate name according
+ to the relation between the signing identity and the subject identity. If the signing
+ identity 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-....``).
+
Examples
--------
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
diff --git a/tests/unit-tests/security/test-keychain.cpp b/tests/unit-tests/security/test-keychain.cpp
index 9a2300d..1149dce 100644
--- a/tests/unit-tests/security/test-keychain.cpp
+++ b/tests/unit-tests/security/test-keychain.cpp
@@ -163,6 +163,15 @@
BOOST_CHECK(idCert->getName().getPrefix(5) ==
Name().append(identity).append("KEY").append("Lower"));
+ shared_ptr<IdentityCertificate> idCert11 =
+ keyChain.prepareUnsignedIdentityCertificate(lowerKeyName, identity,
+ time::system_clock::now(),
+ time::system_clock::now() + time::days(365),
+ subjectDescription,
+ lowerIdentity);
+ BOOST_CHECK(static_cast<bool>(idCert11));
+ BOOST_CHECK(idCert11->getName().getPrefix(6) ==
+ Name().append(lowerIdentity).append("KEY"));
Name anotherIdentity("/TestKeyChain/PrepareIdentityCertificate/Another/");
anotherIdentity.appendVersion();
diff --git a/tools/ndnsec-cert-gen.hpp b/tools/ndnsec-cert-gen.hpp
index 1b81fc5..c2b0333 100644
--- a/tools/ndnsec-cert-gen.hpp
+++ b/tools/ndnsec-cert-gen.hpp
@@ -42,19 +42,33 @@
std::string requestFile("-");
std::string signId;
std::string subjectInfo;
+ std::string certPrefix;
bool hasSignId = false;
- bool isNack = false;
- po::options_description description("General Usage\n ndnsec cert-gen [-h] [-S date] [-E date] [-N subject-name] [-I subject-info] [-s sign-id] request\nGeneral options");
+ po::options_description description(
+ "General Usage\n"
+ " ndnsec cert-gen [-h] [-S date] [-E date] [-N subject-name] [-I subject-info] "
+ "[-s sign-id] [-p cert-prefix] request\n"
+ "General options");
+
description.add_options()
("help,h", "produce help message")
- ("not-before,S", po::value<std::string>(¬BeforeStr), "certificate starting date, YYYYMMDDhhmmss")
- ("not-after,E", po::value<std::string>(¬AfterStr), "certificate ending date, YYYYMMDDhhmmss")
- ("subject-name,N", po::value<std::string>(&subjectName), "subject name")
- ("subject-info,I", po::value<std::string>(&subjectInfo), "subject info, pairs of OID and string description: \"2.5.4.10 'University of California, Los Angeles'\"")
- ("nack", "Generate revocation certificate (NACK)")
- ("sign-id,s", po::value<std::string>(&signId), "signing Identity, system default identity if not specified")
- ("request,r", po::value<std::string>(&requestFile), "request file name, - for stdin")
+ ("not-before,S", po::value<std::string>(¬BeforeStr),
+ "certificate starting date, YYYYMMDDhhmmss")
+ ("not-after,E", po::value<std::string>(¬AfterStr),
+ "certificate ending date, YYYYMMDDhhmmss")
+ ("subject-name,N", po::value<std::string>(&subjectName),
+ "subject name")
+ ("subject-info,I", po::value<std::string>(&subjectInfo),
+ "subject info, pairs of OID and string description: "
+ "\"2.5.4.10 'University of California, Los Angeles'\"")
+ ("sign-id,s", po::value<std::string>(&signId),
+ "signing Identity, system default identity if not specified")
+ ("cert-prefix,p", po::value<std::string>(&certPrefix),
+ "cert prefix, which is the part of certificate name before "
+ "KEY component")
+ ("request,r", po::value<std::string>(&requestFile),
+ "request file name, - for stdin")
;
po::positional_options_description p;
@@ -84,12 +98,15 @@
hasSignId = true;
}
- if (vm.count("nack") != 0)
+ if (vm.count("subject-name") == 0)
{
- isNack = true;
+ std::cerr << "subject_name must be specified" << std::endl;
+ return 1;
}
- std::vector<CertificateSubjectDescription> otherSubDescrypt;
+ std::vector<CertificateSubjectDescription> subjectDescription;
+ subjectDescription.push_back(CertificateSubjectDescription("2.5.4.41", subjectName));
+
tokenizer<escaped_list_separator<char> > subjectInfoItems
(subjectInfo, escaped_list_separator<char> ("\\", " \t", "'\""));
@@ -109,7 +126,7 @@
std::string value = *it;
- otherSubDescrypt.push_back(CertificateSubjectDescription(oid, value));
+ subjectDescription.push_back(CertificateSubjectDescription(oid, value));
it++;
}
@@ -162,76 +179,23 @@
Name keyName = selfSignedCertificate->getPublicKeyName();
Name signIdName;
- Name certName;
+ Name prefix(certPrefix);
if (!hasSignId)
signIdName = keyChain.getDefaultIdentity();
else
signIdName = Name(signId);
+ shared_ptr<IdentityCertificate> certificate =
+ keyChain.prepareUnsignedIdentityCertificate(keyName, selfSignedCertificate->getPublicKeyInfo(),
+ signIdName, notBefore, notAfter,
+ subjectDescription, prefix);
- if (signIdName.isPrefixOf(keyName))
- {
- // if signee's namespace is a sub-namespace of signer, for example, signer's namespace is
- // /ndn/test, signee's namespace is /ndn/test/alice, the generated certificate name is
- // /ndn/test/KEY/alice/ksk-1234/ID-CERT/%01%02
- certName.append(signIdName)
- .append("KEY")
- .append(keyName.getSubName(signIdName.size()))
- .append("ID-CERT")
- .appendVersion();
- }
- else
- {
- // if signee's namespace is not a sub-namespace of signer, for example, signer's namespace is
- // /ndn/test, signee's namespace is /ndn/ucla/bob, the generated certificate name is
- // /ndn/ucla/bob/KEY/ksk-1234/ID-CERT/%01%02
- certName.append(keyName.getPrefix(-1))
- .append("KEY")
- .append(keyName.get(-1))
- .append("ID-CERT")
- .appendVersion();
- }
+ keyChain.createIdentity(signIdName);
+ Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(signIdName);
+ keyChain.sign(*certificate, signingCertificateName);
- Block wire;
-
- if (!isNack)
- {
- if (vm.count("subject-name") == 0)
- {
- std::cerr << "subject_name must be specified" << std::endl;
- return 1;
- }
-
- CertificateSubjectDescription subDescryptName("2.5.4.41", subjectName);
- IdentityCertificate certificate;
- certificate.setName(certName);
- certificate.setNotBefore(notBefore);
- certificate.setNotAfter(notAfter);
- certificate.setPublicKeyInfo(selfSignedCertificate->getPublicKeyInfo());
- certificate.addSubjectDescription(subDescryptName);
- for (size_t i = 0; i < otherSubDescrypt.size(); i++)
- certificate.addSubjectDescription(otherSubDescrypt[i]);
- certificate.encode();
-
- keyChain.createIdentity(signIdName);
- Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(signIdName);
- keyChain.sign(certificate, signingCertificateName);
-
- wire = certificate.wireEncode();
- }
- else
- {
- Data revocationCert;
- // revocationCert.setContent(void*, 0); // empty content
- revocationCert.setName(certName);
-
- keyChain.createIdentity(signIdName);
- Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(signIdName);
- keyChain.sign(revocationCert, signingCertificateName);
-
- wire = revocationCert.wireEncode();
- }
+ Block wire = certificate->wireEncode();
try
{