コード例 #1
0
ファイル: ndns-label.cpp プロジェクト: cawka/ndns
inline size_t
calculateSkip(const Name& name,
              const Name& hint, const Name& zone)
{
  size_t skip = 0;

  if (!hint.empty()) {
    // These are only asserts. The caller should supply the right parameters
    skip = hint.size() + 1 + zone.size();
    BOOST_ASSERT(name.size() > skip);

    BOOST_ASSERT(name.getPrefix(hint.size()) == hint);
    BOOST_ASSERT(name.get(hint.size()) == FORWARDING_HINT_LABEL);
    BOOST_ASSERT(name.getSubName(hint.size() + 1, zone.size()) == zone);

  }
  else {
    skip = zone.size();
    BOOST_ASSERT(name.size() > skip);
    BOOST_ASSERT(name.getPrefix(zone.size()) == zone);
  }

  BOOST_ASSERT(name.get(skip) == NDNS_ITERATIVE_QUERY ||
               name.get(skip) == NDNS_CERT_QUERY);

  ++skip;
  return skip;
}
コード例 #2
0
bool
IdentityCertificate::isCorrectName(const Name& name)
{
  int i = name.size() - 1;
  
  string idString("ID-CERT");
  for (; i >= 0; i--) {
    if(name.get(i).toEscapedString() == idString)
      break;
  }

  if (i < 0)
    return false;
  
  int keyIdx = 0;
  string keyString("KEY");
  for (; keyIdx < name.size(); keyIdx++) {
    if(name.get(keyIdx).toEscapedString() == keyString)
      break;
  }

  if (keyIdx >= name.size())
    return false;

  return true;
}
コード例 #3
0
ファイル: data.t.cpp プロジェクト: cawka/ndn-cxx
BOOST_FIXTURE_TEST_CASE(FullName, IdentityManagementFixture)
{
  Data d(Name("/local/ndn/prefix"));
  d.setContentType(tlv::ContentType_Blob);
  d.setFreshnessPeriod(10_s);
  d.setContent(CONTENT1, sizeof(CONTENT1));
  BOOST_CHECK_THROW(d.getFullName(), Data::Error); // FullName is unavailable without signing

  m_keyChain.sign(d);
  BOOST_CHECK_EQUAL(d.hasWire(), true);
  Name fullName = d.getFullName(); // FullName is available after signing

  BOOST_CHECK_EQUAL(d.getName().size() + 1, fullName.size());
  BOOST_CHECK_EQUAL_COLLECTIONS(d.getName().begin(), d.getName().end(),
                                fullName.begin(), fullName.end() - 1);
  BOOST_CHECK_EQUAL(fullName.get(-1).value_size(), util::Sha256::DIGEST_SIZE);

  // FullName should be cached, so value() pointer points to same memory location
  BOOST_CHECK_EQUAL(fullName.get(-1).value(), d.getFullName().get(-1).value());

  d.setFreshnessPeriod(100_s); // invalidates FullName
  BOOST_CHECK_THROW(d.getFullName(), Data::Error);

  Data d1(Block(DATA1, sizeof(DATA1)));
  BOOST_CHECK_EQUAL(d1.getFullName(),
    "/local/ndn/prefix/"
    "sha256digest=28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548");
}
コード例 #4
0
Name
IdentityCertificate::certificateNameToPublicKeyName(const Name& certificateName)
{
  int i = certificateName.size() - 1;
  string idString("ID-CERT");
  bool foundIdString = false;
  for (; i >= 0; i--) {
    if (certificateName.get(i).toEscapedString() == idString)
      {
        foundIdString = true;
        break;
      }
  }

  if(!foundIdString)
    throw Error("Incorrect identity certificate name " + certificateName.toUri());
    
  Name tmpName = certificateName.getSubName(0, i);    
  string keyString("KEY");
  bool foundKeyString = false;
  for (i = 0; i < tmpName.size(); i++) {
    if (tmpName.get(i).toEscapedString() == keyString)
      {
        foundKeyString = true;
        break;
      }
  }

  if(!foundKeyString)
    throw Error("Incorrect identity certificate name " + certificateName.toUri());
  
  return tmpName.getSubName(0, i).append(tmpName.getSubName(i + 1, tmpName.size() - i - 1));
}
コード例 #5
0
ファイル: segment-fetcher.hpp プロジェクト: susmit85/ndn-cpp
 /**
  * Check if the last component in the name is a segment number.
  * @param name The name to check.
  * @return True if the name ends with a segment number, otherwise false.
  */
 static bool
 endsWithSegmentNumber(Name name)
 {
   return name.size() >= 1 &&
          name.get(-1).getValue().size() >= 1 &&
          name.get(-1).getValue().buf()[0] == 0;
 }
コード例 #6
0
ファイル: action-log.cpp プロジェクト: named-data/ChronoShare
ActionItemPtr
ActionLog::AddRemoteAction(shared_ptr<Data> actionData)
{
  Name name = actionData->getName();
  // action name: /<device_name>/<appname>/action/<shared-folder>/<action-seq>

  uint64_t seqno = name.get(-1).toNumber();
  std::string sharedFolder = name.get(-2).toUri();

  if (sharedFolder != m_sharedFolderName) {
    _LOG_ERROR("Action doesn't belong to this shared folder");
    return ActionItemPtr();
  }

  if (name.get(-3).toUri() != "action") {
    _LOG_ERROR("not an action");
    return ActionItemPtr();
  }

  if (name.get(-4) != m_appName) {
    _LOG_ERROR("Action doesn't belong to this application");
    return ActionItemPtr();
  }

  Name deviceName = name.getSubName(0, name.size() - 4);

  _LOG_DEBUG("From [" << name << "] extracted deviceName: " << deviceName << ", sharedFolder: "
                      << sharedFolder
                      << ", seqno: "
                      << seqno);

  return AddRemoteAction(deviceName, seqno, actionData);
}
コード例 #7
0
bool
IdentityCertificate::isCorrectName(const Name& name)
{
  string idString("ID-CERT");
  int i = name.size() - 1;
  for (; i >= 0; i--) {
    if (name.get(i).toUri() == idString)
      break;
  }

  if (i < 0)
    return false;

  string keyString("KEY");
  size_t keyIndex = 0;
  for (; keyIndex < name.size(); keyIndex++) {
    if (name.get(keyIndex).toUri() == keyString)
      break;
  }

  if (keyIndex >= name.size())
    return false;

  return true;
}
/**
 * Use /localhost/nfd/rib/register to register the prefix to the faceId.
 * @param prefix The prefix name to register.
 * @param faceId The face ID.
 * @param face The Face which is used to sign the command interest and call
 * expressInterest.
 * @param enabled On success or error, set enabled[0] = false;
 */
static void
registerRoute(const Name& prefix, boost::uint64_t faceId, Face* face, bool* enabled)
{
  // Use default values;
  boost::uint64_t origin = 255;
  boost::uint64_t cost = 0;
  const boost::uint64_t CHILD_INHERIT = 1;
  boost::uint64_t flags = CHILD_INHERIT;

  ndn_message::ControlParametersTypes_ControlParametersMessage parameters;
  for (size_t i = 0; i < prefix.size(); ++i)
    parameters.mutable_control_parameters()->mutable_name()->add_component
      (prefix.get(i).getValue().buf(), prefix.get(i).getValue().size());
  parameters.mutable_control_parameters()->set_face_id(faceId);
  parameters.mutable_control_parameters()->set_origin(origin);
  parameters.mutable_control_parameters()->set_cost(cost);
  parameters.mutable_control_parameters()->set_flags(flags);
  Blob encodedControlParameters = ProtobufTlv::encode(parameters);

  Interest interest(Name("/localhost/nfd/rib/register"));
  interest.getName().append(encodedControlParameters);
  interest.setInterestLifetimeMilliseconds(10000);

  // Sign and express the interest.
  face->makeCommandInterest(interest);
  face->expressInterest
    (interest,
     bind(&processRegisterResponse, _1, _2, enabled),
     bind(&onTimeout, _1, "Register route command timed out.", enabled));
}
コード例 #9
0
bool
RegexComponentSetMatcher::match(const Name& name, size_t offset, size_t len)
{
  bool isMatched = false;

  /* componentset only matches one component */
  if (len != 1)
    {
      return false;
    }

  for (auto& component : m_components) {
    if (component->match(name, offset, len)) {
      isMatched = true;
      break;
    }
  }

  m_matchResult.clear();

  if (m_isInclusion ? isMatched : !isMatched) {
    m_matchResult.push_back(name.get(offset));
    return true;
  }
  else
    return false;
}
コード例 #10
0
bool
NdnRegexComponentSetMatcher::match(const Name& name, size_t offset, size_t len)
{
  bool isMatched = false;

  // ComponentSet only matches one component.
  if (len != 1)
    return false;

  for (vector<ptr_lib::shared_ptr<NdnRegexComponentMatcher> >::iterator it = components_.begin();
       it != components_.end();
       ++it) {
    if ((*it)->match(name, offset, len)) {
      isMatched = true;
      break;
    }
  }

  matchResult_.clear();

  if (isInclusion_ ? isMatched : !isMatched) {
    matchResult_.push_back(name.get(offset));
    return true;
  }
  else
    return false;
}
コード例 #11
0
ファイル: response.cpp プロジェクト: named-data/ndns
shared_ptr<Data>
Response::toData()
{
  Name name;
  name.append(m_zone)
      .append(m_queryType)
      .append(m_rrLabel)
      .append(m_rrType);

  if (m_version.empty()) {
    name.appendVersion();
    m_version = name.get(-1);
  }
  else {
    name.append(m_version);
  }

  shared_ptr<Data> data = make_shared<Data>(name);

  if (m_contentType != NDNS_BLOB && m_contentType != NDNS_KEY) {
    data->setContent(this->wireEncode());
  }
  else {
    data->setContent(m_appContent);
  }
  data->setFreshnessPeriod(m_freshnessPeriod);
  data->setContentType(m_contentType);

  return data;
}
コード例 #12
0
inline bool
RegexComponentSetMatcher::match(const Name& name, size_t offset, size_t len)
{
  bool isMatched = false;

  /* componentset only matches one component */
  if (len != 1)
    {
      return false;
    }

  for (ComponentsSet::iterator it = m_components.begin();
       it != m_components.end();
       ++it)
    {
      if ((*it)->match(name, offset, len))
        {
          isMatched = true;
          break;
        }
    }

  m_matchResult.clear();

  if (m_isInclusion ? isMatched : !isMatched)
    {
      m_matchResult.push_back(name.get(offset));
      return true;
    }
  else
    return false;
}
コード例 #13
0
Name
IdentityCertificate::certificateNameToPublicKeyName(const Name& certificateName)
{
  int i = certificateName.size() - 1;
  string idString("ID-CERT");
  for (; i >= 0; i--) {
    if (certificateName.get(i).toEscapedString() == idString)
      break;
  }

  Name tmpName = certificateName.getSubName(0, i);
  string keyString("KEY");
  for (i = 0; i < tmpName.size(); i++) {
    if (tmpName.get(i).toEscapedString() == keyString)
      break;
  }

  return tmpName.getSubName(0, i).append(tmpName.getSubName(i + 1, tmpName.size() - i - 1));
}
コード例 #14
0
BOOST_FIXTURE_TEST_CASE(FullName, DataIdentityFixture)
{
  // Encoding pipeline

  ndn::Data d(ndn::Name("/local/ndn/prefix"));
  d.setContentType(tlv::ContentType_Blob);
  d.setFreshnessPeriod(time::seconds(10));

  d.setContent(Content1, sizeof(Content1));

  BOOST_CHECK_THROW(d.getFullName(), Data::Error);

  keyChain.sign(d, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_CERT, certName));

  Name fullName;
  BOOST_REQUIRE_NO_THROW(fullName = d.getFullName());

  BOOST_CHECK_EQUAL(d.getName().hasWire(), true);
  BOOST_CHECK_EQUAL(fullName.hasWire(), false);

  // check if name was properly cached
  BOOST_CHECK_EQUAL(fullName.get(-1).value(), d.getFullName().get(-1).value());

  // check FullName content
  BOOST_REQUIRE_EQUAL(d.getName().size() + 1, fullName.size());
  BOOST_CHECK_EQUAL_COLLECTIONS(d.getName().begin(), d.getName().end(),
                                fullName.begin(), fullName.end() - 1);
  BOOST_CHECK_EQUAL(fullName.get(-1).value_size(), 32);

  // FullName should be reset after the next line
  d.setFreshnessPeriod(time::seconds(100));
  BOOST_CHECK_THROW(d.getFullName(), Data::Error);

  // Decoding pipeline
  d.wireDecode(Block(Data1, sizeof(Data1)));
  BOOST_REQUIRE_NO_THROW(fullName = d.getFullName());

  BOOST_CHECK_EQUAL(fullName.toUri(),
    "/local/ndn/prefix/"
    "sha256digest=28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548");
}
コード例 #15
0
Name
IdentityCertificate::certificateNameToPublicKeyName(const Name& certificateName)
{
  string idString("ID-CERT");
  bool foundIdString = false;
  size_t idCertComponentIndex = certificateName.size() - 1;
  for (; idCertComponentIndex + 1 > 0; --idCertComponentIndex) {
    if (certificateName.get(idCertComponentIndex).toUri() == idString)
      {
        foundIdString = true;
        break;
      }
  }

  if (!foundIdString)
    throw Error("Incorrect identity certificate name " + certificateName.toUri());

  Name tmpName = certificateName.getSubName(0, idCertComponentIndex);
  string keyString("KEY");
  bool foundKeyString = false;
  size_t keyComponentIndex = 0;
  for (; keyComponentIndex < tmpName.size(); keyComponentIndex++) {
    if (tmpName.get(keyComponentIndex).toUri() == keyString)
      {
        foundKeyString = true;
        break;
      }
  }

  if (!foundKeyString)
    throw Error("Incorrect identity certificate name " + certificateName.toUri());

  return tmpName
           .getSubName(0, keyComponentIndex)
           .append(tmpName.getSubName(keyComponentIndex + 1,
                                      tmpName.size() - keyComponentIndex - 1));
}
コード例 #16
0
  void
  keySearchOnEncryptedKeys
    (const vector<ptr_lib::shared_ptr<Data> >& result, int* requestCount,
     Name cKeyName, Name timeMarkerThirdHop, Name expectedInterest)
  {
    ASSERT_EQ(3, *requestCount);
    ASSERT_EQ(1, result.size());

    const Data& keyData = *result[0];
    const Name& keyName = keyData.getName();
    ASSERT_EQ(cKeyName, keyName.getSubName(0, 4));
    ASSERT_EQ(timeMarkerThirdHop.get(0), keyName.get(4));
    ASSERT_EQ(Encryptor::getNAME_COMPONENT_FOR(), keyName.get(5));
    ASSERT_EQ(expectedInterest.append(timeMarkerThirdHop),
              keyName.getSubName(6));
  }
コード例 #17
0
ファイル: pib.cpp プロジェクト: CSUL/ndn-tools
shared_ptr<IdentityCertificate>
Pib::prepareCertificate(const Name& keyName, const KeyParams& keyParams,
                        const time::system_clock::TimePoint& notBefore,
                        const time::system_clock::TimePoint& notAfter,
                        const Name& signerName)
{
  // Generate mgmt key
  m_tpm->generateKeyPairInTpm(keyName, keyParams);
  shared_ptr<PublicKey> publicKey = m_tpm->getPublicKeyFromTpm(keyName);

  // Set mgmt cert
  auto certificate = make_shared<IdentityCertificate>();
  Name certName = keyName.getPrefix(-1);
  certName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
  certificate->setName(certName);
  certificate->setNotBefore(notBefore);
  certificate->setNotAfter(notAfter);
  certificate->setPublicKeyInfo(*publicKey);
  CertificateSubjectDescription subjectName(oid::ATTRIBUTE_NAME, keyName.getPrefix(-1).toUri());
  certificate->addSubjectDescription(subjectName);
  certificate->encode();


  Name signingKeyName;
  KeyLocator keyLocator;
  if (signerName == EMPTY_SIGNER_NAME) {
    // Self-sign mgmt cert
    keyLocator = KeyLocator(certificate->getName().getPrefix(-1));
    signingKeyName = keyName;
  }
  else {
    keyLocator = KeyLocator(signerName.getPrefix(-1));
    signingKeyName = IdentityCertificate::certificateNameToPublicKeyName(signerName);
  }

  SignatureSha256WithRsa signature(keyLocator);
  certificate->setSignature(signature);
  EncodingBuffer encoder;
  certificate->wireEncode(encoder, true);
  Block signatureValue = m_tpm->signInTpm(encoder.buf(), encoder.size(),
                                          signingKeyName, DIGEST_ALGORITHM_SHA256);
  certificate->wireEncode(encoder, signatureValue);

  return certificate;
}
コード例 #18
0
Blob
Tlv0_2WireFormat::encodeName(const Name& name)
{
  struct ndn_NameComponent nameComponents[100];
  NameLite nameLite
    (nameComponents, sizeof(nameComponents) / sizeof(nameComponents[0]));
  name.get(nameLite);

  DynamicUInt8Vector output(256);
  ndn_Error error;
  size_t dummyBeginOffset, dummyEndOffset, encodingLength;
  if ((error = Tlv0_2WireFormatLite::encodeName
       (nameLite, &dummyBeginOffset, &dummyEndOffset,
        DynamicUInt8ArrayLite::downCast(output), &encodingLength)))
    throw runtime_error(ndn_getErrorString(error));

  return output.finish(encodingLength);
}
コード例 #19
0
Name
IdentityManager::getKeyNameFromCertificatePrefix(const Name & certificatePrefix)
{
  Name result;

  string keyString("KEY");
  int i = 0;
  for(; i < certificatePrefix.size(); i++) {
    if (certificatePrefix.get(i).toEscapedString() == keyString)
      break;
  }

  if (i >= certificatePrefix.size())
    throw SecurityException("Identity Certificate Prefix does not have a KEY component");

  result.append(certificatePrefix.getSubName(0, i));
  result.append(certificatePrefix.getSubName(i + 1, certificatePrefix.size()-i-1));

  return result;
}
コード例 #20
0
ptr_lib::shared_ptr<IdentityCertificate>
IdentityManager::selfSign(const Name& keyName)
{
  ptr_lib::shared_ptr<IdentityCertificate> certificate(new IdentityCertificate());

  Blob keyBlob = identityStorage_->getKey(keyName);
  ptr_lib::shared_ptr<PublicKey> publicKey(new PublicKey(keyBlob));

#if NDN_CPP_HAVE_GMTIME_SUPPORT
  time_t nowSeconds = time(NULL);
  struct tm current = *gmtime(&nowSeconds);
  current.tm_hour = 0;
  current.tm_min  = 0;
  current.tm_sec  = 0;
  MillisecondsSince1970 notBefore = timegm(&current) * 1000.0;
  current.tm_year = current.tm_year + 2;
  MillisecondsSince1970 notAfter = timegm(&current) * 1000.0;

  certificate->setNotBefore(notBefore);
  certificate->setNotAfter(notAfter);
#else
  // Don't really expect this to happen.
  throw SecurityException("selfSign: Can't set certificate validity because time functions are not supported by the standard library.");
#endif

  Name certificateName = keyName.getPrefix(-1).append("KEY").append
    (keyName.get(-1)).append("ID-CERT").append
    (Name::Component::fromNumber((uint64_t)ndn_getNowMilliseconds()));
  certificate->setName(certificateName);

  certificate->setPublicKeyInfo(*publicKey);
  certificate->addSubjectDescription(CertificateSubjectDescription("2.5.4.41", keyName.toUri()));
  certificate->encode();

  signByCertificate(*certificate, certificate->getName());

  return certificate;
}
コード例 #21
0
ファイル: forwarder.cpp プロジェクト: ljjgithub/ndnSIM
void
Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
{
  int level = inFace.getLevel();

  Name prefix;
  Name interestName = interest.getName();

  if(level>=0 && level+2<interestName.size()){
    if(hasLeft(interestName.get(level+1).toUri())){

      Name pitEntryNameToDivide;
      for(int i=level+1;i<interestName.size()-1;++i)
        pitEntryNameToDivide.append(interestName.get(i));
      std::string nameString = pitEntryNameToDivide.toUri();
      nameString = nameString.substr(4,nameString.length()-7);std::cout<<nameString<<std::endl;

      Name pitEntryNameToDivideNew(nameString);
      int bracketCount = 0;
      int begin = 0;
      for(int i=0;i<pitEntryNameToDivideNew.size();++i){

        if(hasLeft(pitEntryNameToDivideNew.get(i).toUri())){
          bracketCount+=hasLeft(pitEntryNameToDivideNew.get(i).toUri());
        }

        if(hasRight(pitEntryNameToDivideNew.get(i).toUri())){
          bracketCount-=hasRight(pitEntryNameToDivideNew.get(i).toUri());
        }

        if(hasDot(pitEntryNameToDivideNew.get(i).toUri()) || i==pitEntryNameToDivideNew.size()-1){
          if(bracketCount==0){
            Name subPrefix;
            for(int j=0;j<=level;++j){
              subPrefix.append(interestName.get(j));
            }
            for(int j=begin;j<i;++j){
              subPrefix.append(pitEntryNameToDivideNew.get(j));
            }
            begin = i+1;
            if(hasDot(pitEntryNameToDivideNew.get(i).toUri())){
              subPrefix.append(pitEntryNameToDivideNew.get(i).toUri().substr(0,pitEntryNameToDivideNew.get(i).size()-3));
            }else{
              subPrefix.append(pitEntryNameToDivideNew.get(i).toUri().substr(0,pitEntryNameToDivideNew.get(i).size()));
            }
            

            std::cout<<"subPrefix: "<<subPrefix<<" "<<subPrefix.get(level+1)<<std::endl;
            std::cout<<"interest name: "<<interest.getName()<<std::endl;

            Interest interestNew(interest);
            subPrefix.append(interest.getName().get(interest.getName().size()-1));
            interestNew.setName(subPrefix);
            prefix.append(subPrefix.get(level+1));
            onIncomingSubInterest(inFace, interestNew, prefix);
          }
        }
      }
    }else{
      prefix.append(interestName.get(level+1));
      onIncomingSubInterest(inFace,interest,prefix);
    }

  }else if(level+2==interestName.size()){
    onIncomingSubInterest(inFace,interest,prefix);
  }
  
}
コード例 #22
0
int
ndnsec_cert_gen(int argc, char** argv)
{
  using boost::tokenizer;
  using boost::escaped_list_separator;

  using namespace ndn;
  using namespace ndn::time;
  namespace po = boost::program_options;

  std::string notBeforeStr;
  std::string notAfterStr;
  std::string subjectName;
  std::string requestFile("-");
  std::string signId;
  std::string subjectInfo;
  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");
  description.add_options()
    ("help,h", "produce help message")
    ("not-before,S", po::value<std::string>(&notBeforeStr), "certificate starting date, YYYYMMDDhhmmss")
    ("not-after,E", po::value<std::string>(&notAfterStr), "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")
    ;

  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("sign-id") != 0)
    {
      hasSignId = true;
    }

  if (vm.count("nack") != 0)
    {
      isNack = true;
    }

  std::vector<CertificateSubjectDescription> otherSubDescrypt;
  tokenizer<escaped_list_separator<char> > subjectInfoItems
    (subjectInfo, escaped_list_separator<char> ("\\", " \t", "'\""));

  tokenizer<escaped_list_separator<char> >::iterator it =
    subjectInfoItems.begin();

  while (it != subjectInfoItems.end())
    {
      std::string oid = *it;

      it++;
      if (it == subjectInfoItems.end())
        {
          std::cerr << "ERROR: unmatched info for oid [" << oid << "]" << std::endl;
          return 1;
        }

      std::string value = *it;

      otherSubDescrypt.push_back(CertificateSubjectDescription(oid, value));

      it++;
    }

  system_clock::TimePoint notBefore;
  system_clock::TimePoint notAfter;

  if (vm.count("not-before") == 0)
    {
      notBefore = system_clock::now();
    }
  else
    {
      notBefore = fromIsoString(notBeforeStr.substr(0, 8) + "T" +
                                notBeforeStr.substr(8, 6));
    }

  if (vm.count("not-after") == 0)
    {
      notAfter = notBefore + days(365);
    }
  else
    {
      notAfter = fromIsoString(notAfterStr.substr(0, 8) + "T" +
                               notAfterStr.substr(8, 6));

      if (notAfter < notBefore)
        {
          std::cerr << "not-before is later than not-after" << std::endl;
          return 1;
        }
    }

  if (vm.count("request") == 0)
    {
      std::cerr << "request file must be specified" << std::endl;
      return 1;
    }

  shared_ptr<IdentityCertificate> selfSignedCertificate
    = getIdentityCertificate(requestFile);

  if (!static_cast<bool>(selfSignedCertificate))
    {
      std::cerr << "ERROR: input error" << std::endl;
      return 1;
    }

  KeyChain keyChain;

  Name keyName = selfSignedCertificate->getPublicKeyName();
  Name signIdName;
  Name certName;

  if (!hasSignId)
    signIdName = keyChain.getDefaultIdentity();
  else
    signIdName = Name(signId);


  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();
    }

  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();
    }

  try
    {
      using namespace CryptoPP;
      StringSource ss(wire.wire(), wire.size(), true,
                      new Base64Encoder(new FileSink(std::cout), true, 64));
    }
  catch (const CryptoPP::Exception& e)
    {
      std::cerr << "ERROR: " << e.what() << std::endl;
      return 1;
    }

  return 0;
}