tools: export non-default key/cert in ndnsec export
refs #5043
Change-Id: Ida6e3c041b850a132160660a58d1f219defedf22
diff --git a/docs/manpages/ndnsec-export.rst b/docs/manpages/ndnsec-export.rst
index 4d7e277..de232a6 100644
--- a/docs/manpages/ndnsec-export.rst
+++ b/docs/manpages/ndnsec-export.rst
@@ -4,18 +4,32 @@
Synopsis
--------
-**ndnsec-export** [**-h**] [**-o** *file*] [**-P** *passphrase*] *identity*
+**ndnsec-export** [**-h**] [**-o** *file*] [**-P** *passphrase*]
+[**-i**\|\ **-k**\|\ **-c**] *name*
Description
-----------
-:program:`ndnsec-export` exports the default certificate of *identity* and its
-private key to a file. It will ask for a passphrase to encrypt the private key.
+:program:`ndnsec-export` exports a certificate from the **Public Info Base (PIB)** and
+its private key to a file. It will ask for a passphrase to encrypt the private key.
The resulting file can be imported again using :program:`ndnsec-import`.
Options
-------
+.. option:: -i, --identity
+
+ Interpret *name* as an identity name. The default certificate of the identity will be exported.
+ This is the default unless **-k** or **-c** is specified.
+
+.. option:: -k, --key
+
+ Interpret *name* as a key name. The default certificate of the key will be exported.
+
+.. option:: -c, --cert
+
+ Interpret *name* as a certificate name.
+
.. option:: -o <file>, --output <file>
Write to the specified output file instead of the standard output.
@@ -34,6 +48,6 @@
$ ndnsec-export -o alice.ndnkey /ndn/test/alice
-Export an identity's default certificate and private key to the standard output::
+Export a specific certificate and its private key to the standard output::
- $ ndnsec-export /ndn/test/alice
+ $ ndnsec-export -c /ndn/edu/ucla/alice/KEY/1%5D%A7g%90%B2%CF%AA/self/%FD%00%00%01r-%D3%DC%2A
diff --git a/tools/ndnsec/cert-dump.cpp b/tools/ndnsec/cert-dump.cpp
index 38d8ed5..d553822 100644
--- a/tools/ndnsec/cert-dump.cpp
+++ b/tools/ndnsec/cert-dump.cpp
@@ -95,7 +95,8 @@
return 2;
}
- if (isIdentityName + isKeyName + isFileName > 1) {
+ int nIsNameOptions = isIdentityName + isKeyName + isFileName;
+ if (nIsNameOptions > 1) {
std::cerr << "ERROR: at most one of '--identity', '--key', "
"or '--file' may be specified" << std::endl;
return 2;
@@ -106,35 +107,20 @@
return 2;
}
- security::v2::KeyChain keyChain;
-
security::v2::Certificate certificate;
- try {
- if (isIdentityName) {
- certificate = keyChain.getPib()
- .getIdentity(name)
- .getDefaultKey()
- .getDefaultCertificate();
- }
- else if (isKeyName) {
- certificate = keyChain.getPib()
- .getIdentity(security::v2::extractIdentityFromKeyName(name))
- .getKey(name)
- .getDefaultCertificate();
- }
- else if (isFileName) {
+ if (isFileName) {
+ try {
certificate = loadCertificate(name);
}
- else {
- certificate = keyChain.getPib()
- .getIdentity(security::v2::extractIdentityFromCertName(name))
- .getKey(security::v2::extractKeyNameFromCertName(name))
- .getCertificate(name);
+ catch (const CannotLoadCertificate&) {
+ std::cerr << "ERROR: Cannot load the certificate from `" << name << "`" << std::endl;
+ return 1;
}
}
- catch (const CannotLoadCertificate&) {
- std::cerr << "ERROR: Cannot load the certificate from `" << name << "`" << std::endl;
- return 1;
+ else {
+ security::v2::KeyChain keyChain;
+ certificate = getCertificateFromPib(keyChain.getPib(), name,
+ isIdentityName, isKeyName, nIsNameOptions == 0);
}
if (isPretty) {
diff --git a/tools/ndnsec/export.cpp b/tools/ndnsec/export.cpp
index 4429dd4..79bea3d 100644
--- a/tools/ndnsec/export.cpp
+++ b/tools/ndnsec/export.cpp
@@ -35,7 +35,10 @@
{
namespace po = boost::program_options;
- Name identityName;
+ Name name;
+ bool isIdentityName = false;
+ bool isKeyName = false;
+ bool isCertName = false;
std::string output;
std::string password;
@@ -45,46 +48,69 @@
OPENSSL_cleanse(&password.front(), password.size());
} BOOST_SCOPE_EXIT_END
- po::options_description description(
- "Usage: ndnsec export [-h] [-o FILE] [-P PASSPHRASE] [-i] IDENTITY\n"
+ po::options_description visibleOptDesc(
+ "Usage: ndnsec export [-h] [-o FILE] [-P PASSPHRASE] [-i|-k|-c] NAME\n"
"\n"
"Options");
- description.add_options()
+ visibleOptDesc.add_options()
("help,h", "produce help message")
- ("identity,i", po::value<Name>(&identityName), "name of the identity to export")
+ ("identity,i", po::bool_switch(&isIdentityName),
+ "treat the NAME argument as an identity name (e.g., /ndn/edu/ucla/alice)")
+ ("key,k", po::bool_switch(&isKeyName),
+ "treat the NAME argument as a key name (e.g., /ndn/edu/ucla/alice/KEY/1%5D%A7g%90%B2%CF%AA)")
+ ("cert,c", po::bool_switch(&isCertName),
+ "treat the NAME argument as a certificate name "
+ "(e.g., /ndn/edu/ucla/alice/KEY/1%5D%A7g%90%B2%CF%AA/self/%FD%00%00%01r-%D3%DC%2A)")
("output,o", po::value<std::string>(&output)->default_value("-"),
"output file, '-' for stdout (the default)")
("password,P", po::value<std::string>(&password),
"passphrase, will prompt if empty or not specified")
;
- po::positional_options_description p;
- p.add("identity", 1);
+ po::options_description hiddenOptDesc;
+ hiddenOptDesc.add_options()
+ ("name", po::value<Name>(&name));
+
+ po::options_description optDesc;
+ optDesc.add(visibleOptDesc).add(hiddenOptDesc);
+
+ po::positional_options_description optPos;
+ optPos.add("name", 1);
po::variables_map vm;
try {
- po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm);
+ po::store(po::command_line_parser(argc, argv).options(optDesc).positional(optPos).run(), vm);
po::notify(vm);
}
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << "\n\n"
- << description << std::endl;
+ << visibleOptDesc << std::endl;
return 2;
}
if (vm.count("help") > 0) {
- std::cout << description << std::endl;
+ std::cout << visibleOptDesc << std::endl;
return 0;
}
- if (vm.count("identity") == 0) {
- std::cerr << "ERROR: you must specify an identity" << std::endl;
+ if (vm.count("name") == 0) {
+ std::cerr << "ERROR: you must specify a name" << std::endl;
return 2;
}
- security::v2::KeyChain keyChain;
+ int nIsNameOptions = isIdentityName + isKeyName + isCertName;
+ if (nIsNameOptions > 1) {
+ std::cerr << "ERROR: at most one of '--identity', '--key', "
+ "or '--cert' may be specified" << std::endl;
+ return 2;
+ }
+ else if (nIsNameOptions == 0) {
+ isIdentityName = true;
+ }
- auto id = keyChain.getPib().getIdentity(identityName);
+ security::v2::KeyChain keyChain;
+ auto cert = getCertificateFromPib(keyChain.getPib(), name,
+ isIdentityName, isKeyName, isCertName);
if (password.empty()) {
int count = 3;
@@ -97,9 +123,7 @@
}
}
- // TODO: export all certificates, selected key pair, selected certificate
- auto safeBag = keyChain.exportSafeBag(id.getDefaultKey().getDefaultCertificate(),
- password.data(), password.size());
+ auto safeBag = keyChain.exportSafeBag(cert, password.data(), password.size());
if (output == "-")
io::save(*safeBag, std::cout);
diff --git a/tools/ndnsec/util.cpp b/tools/ndnsec/util.cpp
index cb35b52..c07b509 100644
--- a/tools/ndnsec/util.cpp
+++ b/tools/ndnsec/util.cpp
@@ -69,6 +69,28 @@
}
security::v2::Certificate
+getCertificateFromPib(const security::pib::Pib& pib, const Name& name,
+ bool isIdentityName, bool isKeyName, bool isCertName)
+{
+ if (isIdentityName) {
+ return pib.getIdentity(name)
+ .getDefaultKey()
+ .getDefaultCertificate();
+ }
+ else if (isKeyName) {
+ return pib.getIdentity(security::v2::extractIdentityFromKeyName(name))
+ .getKey(name)
+ .getDefaultCertificate();
+ }
+ else if (isCertName) {
+ return pib.getIdentity(security::v2::extractIdentityFromCertName(name))
+ .getKey(security::v2::extractKeyNameFromCertName(name))
+ .getCertificate(name);
+ }
+ NDN_CXX_UNREACHABLE;
+}
+
+security::v2::Certificate
loadCertificate(const std::string& fileName)
{
shared_ptr<security::v2::Certificate> cert;
diff --git a/tools/ndnsec/util.hpp b/tools/ndnsec/util.hpp
index 873f6b0..f069c34 100644
--- a/tools/ndnsec/util.hpp
+++ b/tools/ndnsec/util.hpp
@@ -33,6 +33,22 @@
namespace ndn {
namespace ndnsec {
+/**
+ * @brief Get certificate of given name from PIB.
+ * @param pib PIB instance, obtained from keyChain.getPib().
+ * @param name identity name, key name, or cert name.
+ * @param isIdentityName interpret @p name as identity name.
+ * @param isKeyName interpret @p name as key name.
+ * @param isCertName interpret @p name as certificate name.
+ * @pre exactly one of @p isIdentityName , @p isKeyName , @p isCertName must be true.
+ * @return a certificate.
+ * @throw std::invalid_argument name is invalid.
+ * @throw Pib::Error certificate does not exist.
+ */
+security::v2::Certificate
+getCertificateFromPib(const security::pib::Pib& pib, const Name& name,
+ bool isIdentityName, bool isKeyName, bool isCertName);
+
class CannotLoadCertificate : public std::runtime_error
{
public: