tools: ndnsec-cert-revoke command

Change-Id: Id4b43460345015794650f9bc2191869c687a7c46
Refs: #1666
diff --git a/docs/conf.py b/docs/conf.py
index 3fe24dd..93bd384 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -239,6 +239,7 @@
     ('manpages/ndnsec', 'ndnsec', u'NDN security tools', None, 1),
     ('manpages/ndnsec-cert-dump',    'ndnsec-cert-dump',   'part of NDN security tools', None, 1),
     ('manpages/ndnsec-cert-gen',     'ndnsec-cert-gen',    'part of NDN security tools', None, 1),
+    ('manpages/ndnsec-cert-revoke',  'ndnsec-cert-revoke', 'part of NDN security tools', None, 1),
     ('manpages/ndnsec-cert-install', 'ndnsec-cert-instal', 'part of NDN security tools', None, 1),
     ('manpages/ndnsec-delete',       'ndnsec-delete',      'part of NDN security tools', None, 1),
     ('manpages/ndnsec-export',       'ndnsec-export',      'part of NDN security tools', None, 1),
diff --git a/docs/manpages.rst b/docs/manpages.rst
index 6907bee..ad28cc6 100644
--- a/docs/manpages.rst
+++ b/docs/manpages.rst
@@ -9,6 +9,7 @@
     ndnsec-key-gen      <manpages/ndnsec-key-gen>
     ndnsec-sign-req     <manpages/ndnsec-sign-req>
     ndnsec-cert-gen     <manpages/ndnsec-cert-gen>
+    ndnsec-cert-revoke  <manpages/ndnsec-cert-revoke>
     ndnsec-cert-install <manpages/ndnsec-cert-install>
     ndnsec-cert-dump    <manpages/ndnsec-cert-dump>
     ndnsec-delete       <manpages/ndnsec-delete>
diff --git a/docs/manpages/ndnsec-cert-revoke.rst b/docs/manpages/ndnsec-cert-revoke.rst
new file mode 100644
index 0000000..5136fe1
--- /dev/null
+++ b/docs/manpages/ndnsec-cert-revoke.rst
@@ -0,0 +1,36 @@
+ndnsec-cert-revoke
+==================
+
+``ndnsec-cert-revoke`` is a tool to generate a certificate revocation data.
+
+Usage
+-----
+
+::
+
+    $ ndnsec-cert-revoke [-h] request
+
+Description
+-----------
+
+This command takes an identity ertificate as input.
+The tool will check whether user is the issuer of the certificate (by checking whether user has the key pointed by the KeyLocator of the certificate).
+If so, the tool will generate an empty packet named by the certificate name appended with "REVOKED" as a revocation data.
+If user is not the issuer of the certificate, the command will return error.
+
+This tool generates a revocation Data.
+It does not actually revoke a certificate.
+How to publish and use the revocation Data is not finalized yet.
+
+Options
+-------
+
+``request``
+  request is file name of the certificate to revoke (``-`` for standard input)
+
+Examples
+--------
+
+::
+
+    $ ndnsec-cert-revoke some-cert-to-revoke.ndncert
diff --git a/tools/ndnsec-cert-revoke.hpp b/tools/ndnsec-cert-revoke.hpp
new file mode 100644
index 0000000..ab618a5
--- /dev/null
+++ b/tools/ndnsec-cert-revoke.hpp
@@ -0,0 +1,153 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ */
+
+#ifndef NDNSEC_CERT_REVOKE_HPP
+#define NDNSEC_CERT_REVOKE_HPP
+
+#include "ndnsec-util.hpp"
+
+int
+ndnsec_cert_revoke(int argc, char** argv)
+{
+  using namespace ndn;
+  namespace po = boost::program_options;
+
+  std::string requestFile("-");
+
+  po::options_description description("General Usage\n  ndnsec cert-revoke [-h] request\nGeneral options");
+  description.add_options()
+    ("help,h", "produce help message")
+    ("request,r", po::value<std::string>(&requestFile), "file name of the certificate to revoke, - for stdin")
+    ;
+
+  po::positional_options_description p;
+  p.add("request", 1);
+
+  po::variables_map vm;
+  try
+    {
+      po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(),
+                vm);
+      po::notify(vm);
+    }
+  catch (const std::exception& e)
+    {
+      std::cerr << "ERROR: " << e.what() << std::endl;
+      return 1;
+    }
+
+  if (vm.count("help") != 0)
+    {
+      std::cerr << description << std::endl;
+      return 0;
+    }
+
+  if (vm.count("request") == 0)
+    {
+      std::cerr << "request file must be specified" << std::endl;
+      return 1;
+    }
+
+  shared_ptr<IdentityCertificate> revokedCertificate
+    = getIdentityCertificate(requestFile);
+
+  if (!static_cast<bool>(revokedCertificate))
+    {
+      std::cerr << "ERROR: input error" << std::endl;
+      return 1;
+    }
+
+  KeyChain keyChain;
+  Block wire;
+
+  try
+    {
+      Name certName = revokedCertificate->getName();
+      certName.append("REVOKED");
+
+      Data revocationCert;
+      revocationCert.setName(certName);
+
+      Name keyName;
+
+      const Signature& signature = revokedCertificate->getSignature();
+      if (signature.getType() == Signature::Sha256WithRsa)
+        {
+          SignatureSha256WithRsa sigSha256Rsa(signature);
+          Name keyLocatorName = sigSha256Rsa.getKeyLocator().getName();
+
+          keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocatorName);
+        }
+      else
+        {
+          std::cerr << "ERROR: Unsupported Signature Type!" << std::endl;
+          return 1;
+        }
+
+      if (keyChain.doesPublicKeyExist(keyName))
+        {
+          Name signingCertificateName = keyChain.getDefaultCertificateNameForKey(keyName);
+          keyChain.sign(revocationCert, signingCertificateName);
+        }
+      else
+        {
+          std::cerr << "ERROR: Cannot find the signing key!" << std::endl;
+          return 1;
+        }
+
+      wire = revocationCert.wireEncode();
+    }
+  catch (Signature::Error& e)
+    {
+      std::cerr << "ERROR: No valid signature!" << std::endl;
+      return 1;
+    }
+  catch (KeyLocator::Error& e)
+    {
+      std::cerr << "ERROR: No valid KeyLocator!" << std::endl;
+      return 1;
+    }
+  catch (IdentityCertificate::Error& e)
+    {
+      std::cerr << "ERROR: Cannot determine the signing key!" << std::endl;
+      return 1;
+    }
+
+  try
+    {
+      using namespace CryptoPP;
+      // StringSource ss(wire.wire(), wire.size(), true,
+      //                 new Base64Encoder(new FileSink(std::cout), true, 64));
+      StringSource ss(wire.wire(), wire.size(), true,
+                      new FileSink(std::cout));
+    }
+  catch (const CryptoPP::Exception& e)
+    {
+      std::cerr << "ERROR: " << e.what() << std::endl;
+      return 1;
+    }
+
+  return 0;
+}
+
+#endif //NDNSEC_CERT_REVOKE_HPP
diff --git a/tools/ndnsec.cpp b/tools/ndnsec.cpp
index f8e9140..23bc332 100644
--- a/tools/ndnsec.cpp
+++ b/tools/ndnsec.cpp
@@ -30,6 +30,7 @@
 #include "ndnsec-dsk-gen.hpp"
 #include "ndnsec-sign-req.hpp"
 #include "ndnsec-cert-gen.hpp"
+#include "ndnsec-cert-revoke.hpp"
 #include "ndnsec-cert-dump.hpp"
 #include "ndnsec-cert-install.hpp"
 #include "ndnsec-export.hpp"
@@ -51,6 +52,7 @@
   key-gen      Generate a Key-Signing-Key for an identity.\n\
   sign-req     Generate a certificate signing request.\n\
   cert-gen     Generate an identity certificate.\n\
+  cert-revoke  Revoke an identity certificate.\n\
   cert-dump    Dump a certificate from PublicInfo.\n\
   cert-install Install a certificate into PublicInfo.\n\
   delete       Delete identity/key/certificate.\n\
@@ -84,6 +86,7 @@
       else if (command == "key-gen")      { return ndnsec_key_gen(argc - 1, argv + 1); }
       else if (command == "sign-req")     { return ndnsec_sign_req(argc - 1, argv + 1); }
       else if (command == "cert-gen")     { return ndnsec_cert_gen(argc - 1, argv + 1); }
+      else if (command == "cert-revoke")  { return ndnsec_cert_revoke(argc - 1, argv + 1); }
       else if (command == "cert-dump")    { return ndnsec_cert_dump(argc - 1, argv + 1); }
       else if (command == "cert-install") { return ndnsec_cert_install(argc - 1, argv + 1); }
       else if (command == "delete")       { return ndnsec_delete(argc - 1, argv + 1); }
diff --git a/tools/wrapper/ndnsec-cert-revoke.sh b/tools/wrapper/ndnsec-cert-revoke.sh
new file mode 100644
index 0000000..9c610b5
--- /dev/null
+++ b/tools/wrapper/ndnsec-cert-revoke.sh
@@ -0,0 +1,3 @@
+#!@SH@
+
+`dirname "$0"`/ndnsec cert-revoke "$@"