security: Add NDN Certificate 2.0
Change-Id: I7d779554f53a613e67f283ca44718e57f2f1c771
Refs: #3103
diff --git a/docs/specs/certificate-format.rst b/docs/specs/certificate-format.rst
index 5873a10..9db67b3 100644
--- a/docs/specs/certificate-format.rst
+++ b/docs/specs/certificate-format.rst
@@ -11,7 +11,7 @@
a common certificate format, as it requires additional components. For example,
a certificate may follow a specific naming convention and may need to include
validity period, revocation information, etc. This specification defines
-naming and components of the NDN certificates and is complementary to NDN packet
+naming and structure of the NDN certificates and is complementary to NDN packet
specification.
::
@@ -24,6 +24,9 @@
|+------------------------+|
|| ContentType: KEY(2) ||
|+------------------------+|
+ |+------------------------+|
+ || FreshnessPeriod: >~ 1h ||
+ |+------------------------+|
+--------------------------+
| Content |
|+------------------------+|
@@ -42,6 +45,24 @@
+--------------------------+
+ CertificateV2 ::= DATA-TLV TLV-LENGTH
+ Name (= /<NameSpace>/KEY/[KeyId]/[IssuerId]/[Version])
+ MetaInfo (.ContentType = KEY,
+ .FreshnessPeriod >~ 1h))
+ Content (= X509PublicKeyContent)
+ SignatureInfo (= CertificateV2SignatureInfo)
+ SignatureValue
+
+ X509PublicKeyContent ::= CONTENT-TLV TLV-LENGTH
+ BYTE+ (= public key bits in PKCS#8 format)
+
+ CertificateV2SignatureInfo ::= SIGNATURE-INFO-TYPE TLV-LENGTH
+ SignatureType
+ KeyLocator
+ ValidityPeriod
+ ... optional critical or non-critical extension blocks ...
+
+
Name
----
@@ -49,24 +70,29 @@
::
- /<SubjectName>/[KeyId]/KEY/[IssuerId]/[Version]
+ /<SubjectName>/KEY/[KeyId]/[IssuerId]/[Version]
-A certificate name starts with the subject to which a public key is bound. The
-second part is a single name component, called KeyId, which should uniquely
-identify the key under the subject namespace. The value of KeyId is up to
-the owner of the subject namespace (e.g., 8-byte random number, SHA-256 digest
-of the public key, timestamp, or numerical identifier). A special name
-component ``KEY`` is appended after KeyId, which indicates that the data is a
-certificate. After ``KEY``, there is an IssuerId name component that
-distinguishes different issuers for the same key. How to specify the IssuerId
-is up to the issuer and key owner. The last component is version number.
+A certificate name starts with the subject to which a public key is bound. The following parts
+include the keyword ``KEY`` component, KeyId, IssuerId, and version components.
+
+``KeyId`` is an opaque name component to identify an instance of the public key for the
+certificate namespace. The value of `Key ID` is controlled by the namespace owner and can be
+an 8-byte random number, SHA-256 digest of the public key, timestamp, or a simple numerical
+identifier.
+
+``Issuer Id`` is an opaque name component to identify issuer of the certificate. The value is
+controlled by the certificate issuer and, similar to KeyId, can be an 8-byte random number,
+SHA-256 digest of the issuer's public key, or a simple numerical identifier.
+
+
For example,
::
- /edu/ucla/cs/yingdi/%03%CD...%F1/KEY/%9F%D3...%B7/%FD%d2...%8E
- \_________________/\___________/ \___________/\___________/
- Subject Name Key ID Issuer Id Version
+ /edu/ucla/cs/yingdi/KEY/%03%CD...%F1/%9F%D3...%B7/%FD%d2...%8E
+ \_________________/ \___________/ \___________/\___________/
+ Certificate Namespace Key Id Issuer Id Version
+ (Identity)
MetaInfo
@@ -86,27 +112,15 @@
SignatureInfo
-------------
-Besides, ``SignatureType`` and ``KeyLocator``, the ``SignatureInfo`` field of a
-certificate include more optional fields.
-
-::
-
- SignatureInfo ::= SIGNATURE-INFO-TYPE TLV-LENGTH
- SignatureType
- KeyLocator
- ValidityPeriod?
- ... (SignatureInfo Extension TLVs)
-
-One optional field is ``ValidityPeriod``, which contains two sub TLV fields:
-``NotBefore`` and ``NotAfter``, which are two UTC timestamps in ISO 8601 compact
-format (``yyyymmddTHHMMSS``, e.g., "20020131T235959"). NotBefore indicates
-when the certificate takes effect while NotAfter indicates when the certificate
-expires.
+The SignatureInfo block of a certificate is required to include the ``ValidityPeriod`` field.
+``ValidityPeriod`` includes two sub TLV fields: ``NotBefore`` and ``NotAfter``, which carry two
+UTC timestamps in ISO 8601 compact format (``yyyymmddTHHMMSS``, e.g., "20020131T235959").
+``NotBefore`` indicates when the certificate takes effect while ``NotAfter`` indicates when the
+certificate expires.
.. note::
- Using ISO style string is the convention of specifying validity period of
- certificate, which has been adopted by many certificate systems, such as
- X.509, PGP, and DNSSEC.
+ Using ISO style string is the convention of specifying the validity period of certificate,
+ which has been adopted by many certificate systems, such as X.509, PGP, and DNSSEC.
::
@@ -133,17 +147,13 @@
| NotAfter | 255 | 0xFF |
+---------------------------------------------+-------------------+----------------+
-.. note::
- TLV-TYPE code that falls into [253, 65536) is encoded in
- `3-byte <http://named-data.net/doc/ndn-tlv/tlv.html#variable-size-encoding-for-type-t-and-length-l>`__
-
Extensions
~~~~~~~~~~
A certificate may optionally carry some extensions in SignatureInfo. An extension
-could be either critical or non-critical depends on the TLV-TYPE code convention. An
-critical extension implies that if a validator cannot recognize or cannot parse the
-extension, the validator must reject the certificate. An non-critical extension
+could be either critical or non-critical depends on the TLV-TYPE code convention. A
+critical extension implies that if a validator cannot recognize or parse the
+extension, the validator must reject the certificate. A non-critical extension
implies that if a validator cannot recognize or cannot parse the extension, the
validator may ignore the extension.
@@ -151,42 +161,19 @@
TLV-TYPE code indicates whether the extension is critical or not: ``1`` for critical
while ``0`` for non-critical. If an extension could be either critical or
non-critical, the extension should be allocated with two TLV-TYPE codes which only
-differ at the last bit. For example, TLV-TYPE codes 256 and 257 are allocated to the
-``StatusChecking`` extension, 256 for critical StatusChecking while 257 for
-non-critical StatusChecking.
+differ at the last bit.
+Extensions
+----------
-Proposed Extensions
--------------------
-
-We list the proposed extensions here:
+We list currently defined extensions:
+---------------------------------------------+-------------------+----------------+
| TLV-TYPE | Assigned code | Assigned code |
| | (decimal) | (hexadecimal) |
+=============================================+===================+================+
-| StatusChecking (Non-critical) | 256 | 0x0100 |
+| AdditionalDescription (non-critical) | 258 | 0x0102 |
+---------------------------------------------+-------------------+----------------+
-| StatusChecking (Critical) | 257 | 0x0101 |
-+---------------------------------------------+-------------------+----------------+
-| AdditionalDescription (Non-critical) | 258 | 0x0102 |
-+---------------------------------------------+-------------------+----------------+
-| MultipleSignature (Critical) | 259 | 0x0103 |
-+---------------------------------------------+-------------------+----------------+
-
-.. note::
- TLV-TYPE code that falls into [253, 65536) is encoded in
- `3-byte <http://named-data.net/doc/ndn-tlv/tlv.html#variable-size-encoding-for-type-t-and-length-l>`__
-
-Status Checking
-~~~~~~~~~~~~~~~
-
-TBD
-
-Multiple Signature
-~~~~~~~~~~~~~~~~~~
-
-TBD
AdditionalDescription
~~~~~~~~~~~~~~~~~~~~~
diff --git a/src/security/v2/certificate.cpp b/src/security/v2/certificate.cpp
new file mode 100644
index 0000000..75ee53c
--- /dev/null
+++ b/src/security/v2/certificate.cpp
@@ -0,0 +1,137 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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 Zhiyi Zhang <dreamerbarrychang@gmail.com>
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ */
+
+#include "certificate.hpp"
+#include "../../encoding/block-helpers.hpp"
+
+namespace ndn {
+namespace security {
+namespace v2 {
+
+BOOST_CONCEPT_ASSERT((WireEncodable<Certificate>));
+BOOST_CONCEPT_ASSERT((WireDecodable<Certificate>));
+
+// /<NameSpace>/KEY/[KeyId]/[IssuerId]/[Version]
+
+const ssize_t Certificate::VERSION_OFFSET = -1;
+const ssize_t Certificate::ISSUER_ID_OFFSET = -2;
+const ssize_t Certificate::KEY_ID_OFFSET = -3;
+const ssize_t Certificate::KEY_COMPONENT_OFFSET = -4;
+const size_t Certificate::MIN_CERT_NAME_LENGTH = 4;
+const size_t Certificate::MIN_KEY_NAME_LENGTH = 2;
+const name::Component Certificate::KEY_COMPONENT("KEY");
+
+Certificate::Certificate()
+{
+ setContentType(tlv::ContentTypeValue::ContentType_Key);
+}
+
+Certificate::Certificate(Data&& data)
+ : Data(data)
+{
+ if (!isValidName(getName())) {
+ BOOST_THROW_EXCEPTION(Data::Error("Name does not follow the naming convention for certificate"));
+ }
+ if (getContentType() != tlv::ContentTypeValue::ContentType_Key) {
+ BOOST_THROW_EXCEPTION(Data::Error("ContentType is not KEY"));
+ }
+ if (getFreshnessPeriod() < time::seconds::zero()) {
+ BOOST_THROW_EXCEPTION(Data::Error("FreshnessPeriod is not set"));
+ }
+ if (getContent().value_size() == 0) {
+ BOOST_THROW_EXCEPTION(Data::Error("Content is empty"));
+ }
+}
+
+Certificate::Certificate(const Data& data)
+ : Certificate(Data(data))
+{
+}
+
+Certificate::Certificate(const Block& block)
+ : Certificate(Data(block))
+{
+}
+
+Name
+Certificate::getKeyName() const
+{
+ return getName().getPrefix(KEY_ID_OFFSET + 1);
+}
+
+Name
+Certificate::getIdentity() const
+{
+ return getName().getPrefix(KEY_COMPONENT_OFFSET);
+}
+
+name::Component
+Certificate::getKeyId() const
+{
+ return getName().at(KEY_ID_OFFSET);
+}
+
+name::Component
+Certificate::getIssuerId() const
+{
+ return getName().at(ISSUER_ID_OFFSET);
+}
+
+const Buffer
+Certificate::getPublicKey() const
+{
+ if (getContent().value_size() == 0)
+ BOOST_THROW_EXCEPTION(Data::Error("Content is empty"));
+ return Buffer(getContent().value(), getContent().value_size());
+}
+
+ValidityPeriod
+Certificate::getValidityPeriod() const
+{
+ return getSignature().getSignatureInfo().getValidityPeriod();
+}
+
+bool
+Certificate::isValid(const time::system_clock::TimePoint& ts) const
+{
+ return getSignature().getSignatureInfo().getValidityPeriod().isValid(ts);
+}
+
+const Block&
+Certificate::getExtension(uint32_t type) const
+{
+ return getSignature().getSignatureInfo().getTypeSpecificTlv(type);
+}
+
+bool
+Certificate::isValidName(const Name& certName)
+{
+ // /<NameSpace>/KEY/[KeyId]/[IssuerId]/[Version]
+ return (certName.size() >= Certificate::MIN_CERT_NAME_LENGTH &&
+ certName.get(Certificate::KEY_COMPONENT_OFFSET) == Certificate::KEY_COMPONENT);
+}
+
+} // namespace v2
+} // namespace security
+} // namespace ndn
diff --git a/src/security/v2/certificate.hpp b/src/security/v2/certificate.hpp
new file mode 100644
index 0000000..19d377c
--- /dev/null
+++ b/src/security/v2/certificate.hpp
@@ -0,0 +1,179 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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 Zhiyi Zhang <dreamerbarrychang@gmail.com>
+ * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
+ */
+
+#ifndef NDN_SECURITY_V2_CERTIFICATE_HPP
+#define NDN_SECURITY_V2_CERTIFICATE_HPP
+
+#include "../../data.hpp"
+
+namespace ndn {
+namespace security {
+namespace v2 {
+
+/**
+ * @brief The certificate following the certificate format naming convention
+ *
+ * Overview of NDN certificate format:
+ *
+ * CertificateV2 ::= DATA-TLV TLV-LENGTH
+ * Name (= /<NameSpace>/KEY/[KeyId]/[IssuerId]/[Version])
+ * MetaInfo (.ContentType = KEY)
+ * Content (= X509PublicKeyContent)
+ * SignatureInfo (= CertificateV2SignatureInfo)
+ * SignatureValue
+ *
+ * X509PublicKeyContent ::= CONTENT-TLV TLV-LENGTH
+ * BYTE+ (= public key bits in PKCS#8 format)
+ *
+ * CertificateV2SignatureInfo ::= SIGNATURE-INFO-TYPE TLV-LENGTH
+ * SignatureType
+ * KeyLocator
+ * ValidityPeriod
+ * ... optional critical or non-critical extension blocks ...
+ *
+ * An example of NDN certificate name:
+ *
+ * /edu/ucla/cs/yingdi/KEY/%03%CD...%F1/%9F%D3...%B7/%FD%d2...%8E
+ * \_________________/ \___________/ \___________/\___________/
+ * Certificate Namespace Key Id Issuer Id Version
+ * (Identity)
+ * \__________________________________/
+ * Key Name
+ *
+ * Notes:
+ *
+ * - `Key Id` is opaque name component to identify an instance of the public key for the
+ * certificate namespace. The value of `Key ID` is controlled by the namespace owner. The
+ * library includes helpers for generation of key IDs using 8-byte random number, SHA-256
+ * digest of the public key, timestamp, and the specified numerical identifiers.
+ *
+ * - `Issuer Id` is opaque name component to identify issuer of the certificate. The value is
+ * controlled by the issuer. The library includes helpers to set issuer ID to a 8-byte
+ * random number, SHA-256 digest of the issuer's public key, and the specified numerical
+ * identifiers.
+ *
+ * - `Key Name` is a logical name of the key used for management pursposes. Key Name includes
+ * the certificate namespace, keyword `KEY`, and `KeyId` components.
+ *
+ * @see doc/specs/certificate-format.rst
+ */
+class Certificate : public Data
+{
+public:
+ Certificate();
+
+ /**
+ * @brief Construct certificate from a data object
+ * @throw tlv::Error if data does not follow certificate format
+ */
+ explicit
+ Certificate(Data&& data);
+
+ /**
+ * @brief Construct certificate from a data object
+ * @throw tlv::Error if data does not follow certificate format
+ */
+ explicit
+ Certificate(const Data& data);
+
+ /**
+ * @brief Construct certificate from a wire encoding
+ * @throw tlv::Error if wire encoding is invalid or does not follow certificate format
+ */
+ explicit
+ Certificate(const Block& block);
+
+ /**
+ * @brief Get key name
+ */
+ Name
+ getKeyName() const;
+
+ /**
+ * @brief Get identity name
+ */
+ Name
+ getIdentity() const;
+
+ /**
+ * @brief Get key ID
+ */
+ name::Component
+ getKeyId() const;
+
+ /**
+ * @brief Get issuer ID
+ */
+ name::Component
+ getIssuerId() const;
+
+ /**
+ * @brief Get public key bits (in PKCS#8 format)
+ * @throw Error If content is empty
+ */
+ const Buffer
+ getPublicKey() const;
+
+ /**
+ * @brief Get validity period of the certificate
+ */
+ ValidityPeriod
+ getValidityPeriod() const;
+
+ /**
+ * @brief Check if the certificate is valid at @p ts.
+ */
+ bool
+ isValid(const time::system_clock::TimePoint& ts = time::system_clock::now()) const;
+
+ /**
+ * @brief Get extension with TLV @p type
+ * @throw ndn::SignatureInfo::Error if the specified block type does not exist
+ */
+ const Block&
+ getExtension(uint32_t type) const;
+
+ // @TODO Implement extension enumeration (Issue #3907)
+public:
+ /**
+ * @brief Check if the specified name follows the naming convention for the certificate
+ */
+ static bool
+ isValidName(const Name& certName);
+
+public:
+ static const ssize_t VERSION_OFFSET;
+ static const ssize_t ISSUER_ID_OFFSET;
+ static const ssize_t KEY_COMPONENT_OFFSET;
+ static const ssize_t KEY_ID_OFFSET;
+ static const size_t MIN_CERT_NAME_LENGTH;
+ static const size_t MIN_KEY_NAME_LENGTH;
+ static const name::Component KEY_COMPONENT;
+};
+
+} // namespace v2
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_SECURITY_V2_CERTIFICATE_HPP
diff --git a/tests/unit-tests/security/v2/certificate.t.cpp b/tests/unit-tests/security/v2/certificate.t.cpp
new file mode 100644
index 0000000..8836e05
--- /dev/null
+++ b/tests/unit-tests/security/v2/certificate.t.cpp
@@ -0,0 +1,266 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 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 Zhiyi Zhang <dreamerbarrychang@gmail.com>
+ */
+
+#include "security/v2/certificate.hpp"
+
+#include "boost-test.hpp"
+#include "unit-tests/unit-test-time-fixture.hpp"
+#include <boost/lexical_cast.hpp>
+
+namespace ndn {
+namespace security {
+namespace v2 {
+namespace tests {
+
+using namespace ndn::tests;
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(V2)
+BOOST_FIXTURE_TEST_SUITE(TestCertificate, UnitTestTimeFixture)
+
+const uint8_t PUBLIC_KEY[] = {
+ 0x30, 0x81, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x81, 0x8b, 0x00, 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e,
+ 0x06, 0x3e, 0x47, 0x85, 0xb2, 0x34, 0x37, 0xaa, 0x85, 0x47, 0xac, 0x03, 0x24, 0x83, 0xb5,
+ 0x9c, 0xa8, 0x05, 0x3a, 0x24, 0x1e, 0xeb, 0x89, 0x01, 0xbb, 0xe9, 0x9b, 0xb2, 0xc3, 0x22,
+ 0xac, 0x68, 0xe3, 0xf0, 0x6c, 0x02, 0xce, 0x68, 0xa6, 0xc4, 0xd0, 0xa7, 0x06, 0x90, 0x9c,
+ 0xaa, 0x1b, 0x08, 0x1d, 0x8b, 0x43, 0x9a, 0x33, 0x67, 0x44, 0x6d, 0x21, 0xa3, 0x1b, 0x88,
+ 0x9a, 0x97, 0x5e, 0x59, 0xc4, 0x15, 0x0b, 0xd9, 0x2c, 0xbd, 0x51, 0x07, 0x61, 0x82, 0xad,
+ 0xc1, 0xb8, 0xd7, 0xbf, 0x9b, 0xcf, 0x7d, 0x24, 0xc2, 0x63, 0xf3, 0x97, 0x17, 0xeb, 0xfe,
+ 0x62, 0x25, 0xba, 0x5b, 0x4d, 0x8a, 0xc2, 0x7a, 0xbd, 0x43, 0x8a, 0x8f, 0xb8, 0xf2, 0xf1,
+ 0xc5, 0x6a, 0x30, 0xd3, 0x50, 0x8c, 0xc8, 0x9a, 0xdf, 0xef, 0xed, 0x35, 0xe7, 0x7a, 0x62,
+ 0xea, 0x76, 0x7c, 0xbb, 0x08, 0x26, 0xc7, 0x02, 0x01, 0x11
+};
+
+const uint8_t SIG_INFO[] = {
+ 0x16, 0x55, 0x1B, 0x01, 0x01, 0x1C, 0x26, 0x07, 0x24, 0x08, 0x03, 0x6E, 0x64, 0x6E, 0x08, 0x05,
+ 0x73, 0x69, 0x74, 0x65, 0x31, 0x08, 0x11, 0x6B, 0x73, 0x6B, 0x2D, 0x32, 0x35, 0x31, 0x36, 0x34,
+ 0x32, 0x35, 0x33, 0x37, 0x37, 0x30, 0x39, 0x34, 0x08, 0x03, 0x4B, 0x45, 0x59, 0xFD, 0x00, 0xFD,
+ 0x26, 0xFD, 0x00, 0xFE, 0x0F, 0x32, 0x30, 0x31, 0x35, 0x30, 0x38, 0x31, 0x34, 0x54, 0x32, 0x32,
+ 0x33, 0x37, 0x33, 0x39, 0xFD, 0x00, 0xFF, 0x0F, 0x32, 0x30, 0x31, 0x35, 0x30, 0x38, 0x31, 0x38,
+ 0x54, 0x32, 0x32, 0x33, 0x37, 0x33, 0x38
+};
+
+const uint8_t SIG_VALUE[] = {
+ 0x17, 0x80, // SignatureValue
+ 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec,
+ 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6,
+ 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38,
+ 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc,
+ 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf,
+ 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9,
+ 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8,
+ 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7,
+ 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3,
+ 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1
+};
+
+const uint8_t CERT[] = {
+ 0x06, 0xFD, 0x01, 0xBB, // Data
+ 0x07, 0x33, // Name /ndn/site1/KEY/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B
+ 0x08, 0x03, 0x6E, 0x64, 0x6E,
+ 0x08, 0x05, 0x73, 0x69, 0x74, 0x65, 0x31,
+ 0x08, 0x03, 0x4B, 0x45, 0x59,
+ 0x08, 0x11,
+ 0x6B, 0x73, 0x6B, 0x2D, 0x31, 0x34, 0x31, 0x36, 0x34, 0x32, 0x35, 0x33, 0x37, 0x37, 0x30, 0x39,
+ 0x34,
+ 0x08, 0x04, 0x30, 0x31, 0x32, 0x33,
+ 0x08, 0x07, 0xFD, 0x00, 0x00, 0x01, 0x49, 0xC9, 0x8B,
+ 0x14, 0x09, // MetaInfo
+ 0x18, 0x01, 0x02, // ContentType = Key
+ 0x19, 0x04, 0x00, 0x36, 0xEE, 0x80, // FreshnessPeriod = 3600000 ms
+ 0x15, 0xA0, // Content
+ 0x30, 0x81, 0x9D, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
+ 0x05, 0x00, 0x03, 0x81, 0x8B, 0x00, 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9E, 0x06, 0x3E,
+ 0x47, 0x85, 0xB2, 0x34, 0x37, 0xAA, 0x85, 0x47, 0xAC, 0x03, 0x24, 0x83, 0xB5, 0x9C, 0xA8, 0x05,
+ 0x3A, 0x24, 0x1E, 0xEB, 0x89, 0x01, 0xBB, 0xE9, 0x9B, 0xB2, 0xC3, 0x22, 0xAC, 0x68, 0xE3, 0xF0,
+ 0x6C, 0x02, 0xCE, 0x68, 0xA6, 0xC4, 0xD0, 0xA7, 0x06, 0x90, 0x9C, 0xAA, 0x1B, 0x08, 0x1D, 0x8B,
+ 0x43, 0x9A, 0x33, 0x67, 0x44, 0x6D, 0x21, 0xA3, 0x1B, 0x88, 0x9A, 0x97, 0x5E, 0x59, 0xC4, 0x15,
+ 0x0B, 0xD9, 0x2C, 0xBD, 0x51, 0x07, 0x61, 0x82, 0xAD, 0xC1, 0xB8, 0xD7, 0xBF, 0x9B, 0xCF, 0x7D,
+ 0x24, 0xC2, 0x63, 0xF3, 0x97, 0x17, 0xEB, 0xFE, 0x62, 0x25, 0xBA, 0x5B, 0x4D, 0x8A, 0xC2, 0x7A,
+ 0xBD, 0x43, 0x8A, 0x8F, 0xB8, 0xF2, 0xF1, 0xC5, 0x6A, 0x30, 0xD3, 0x50, 0x8C, 0xC8, 0x9A, 0xDF,
+ 0xEF, 0xED, 0x35, 0xE7, 0x7A, 0x62, 0xEA, 0x76, 0x7C, 0xBB, 0x08, 0x26, 0xC7, 0x02, 0x01, 0x11,
+ 0x16, 0x55, // SignatureInfo
+ 0x1B, 0x01, 0x01, // SignatureType
+ 0x1C, 0x26, // KeyLocator: /ndn/site1/KEY/ksk-2516425377094
+ 0x07, 0x24,
+ 0x08, 0x03, 0x6E, 0x64, 0x6E,
+ 0x08, 0x05, 0x73, 0x69, 0x74, 0x65, 0x31,
+ 0x08, 0x03, 0x4B, 0x45, 0x59,
+ 0x08, 0x11,
+ 0x6B, 0x73, 0x6B, 0x2D, 0x32, 0x35, 0x31, 0x36, 0x34, 0x32, 0x35, 0x33, 0x37, 0x37, 0x30, 0x39,
+ 0x34,
+ 0xFD, 0x00, 0xFD, 0x26, // ValidityPeriod: (20150814T223739, 20150818T223738)
+ 0xFD, 0x00, 0xFE, 0x0F,
+ 0x32, 0x30, 0x31, 0x35, 0x30, 0x38, 0x31, 0x34, 0x54, 0x32, 0x32, 0x33, 0x37, 0x33, 0x39,
+ 0xFD, 0x00, 0xFF, 0x0F,
+ 0x32, 0x30, 0x31, 0x35, 0x30, 0x38, 0x31, 0x38, 0x54, 0x32, 0x32, 0x33, 0x37, 0x33, 0x38,
+ 0x17, 0x80, // SignatureValue
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+Signature
+generateFakeSignature()
+{
+ Block block1(SIG_INFO, sizeof(SIG_INFO));
+ SignatureInfo signatureInfo(block1);
+
+ Name keyLocatorName("/ndn/site1/KEY/ksk-2516425377094");
+ KeyLocator keyLocator(keyLocatorName);
+ signatureInfo.setKeyLocator(keyLocator);
+
+ ValidityPeriod period(time::fromIsoString("20141111T050000"), time::fromIsoString("20141111T060000"));
+ signatureInfo.setValidityPeriod(period);
+
+ Signature signature(signatureInfo);
+ Block block2(SIG_VALUE, sizeof(SIG_VALUE));
+ signature.setValue(block2);
+
+ return signature;
+}
+
+BOOST_AUTO_TEST_CASE(Construction)
+{
+ Block block(CERT, sizeof(CERT));
+ Certificate certificate(block);
+
+ BOOST_CHECK_EQUAL(certificate.getName(), "/ndn/site1/KEY/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B");
+ BOOST_CHECK_EQUAL(certificate.getKeyName(), "/ndn/site1/KEY/ksk-1416425377094");
+ BOOST_CHECK_EQUAL(certificate.getIdentity(), "/ndn/site1");
+ BOOST_CHECK_EQUAL(certificate.getIssuerId(), name::Component("0123"));
+ BOOST_CHECK_EQUAL(certificate.getKeyId(), name::Component("ksk-1416425377094"));
+ BOOST_CHECK_EQUAL(certificate.getSignature().getKeyLocator().getName(), "/ndn/site1/KEY/ksk-2516425377094");
+ BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(certificate.getValidityPeriod()), "(20150814T223739, 20150818T223738)");
+
+ BOOST_CHECK_THROW(certificate.getExtension(12345), ndn::SignatureInfo::Error);
+ BOOST_CHECK_NO_THROW(certificate.getPublicKey());
+
+ Data data(block);
+ Certificate certificate2(std::move(data));
+ BOOST_CHECK_EQUAL(certificate, certificate2);
+}
+
+BOOST_AUTO_TEST_CASE(Setters)
+{
+ Certificate certificate;
+ certificate.setName("/ndn/site1/KEY/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B");
+ certificate.setFreshnessPeriod(time::seconds(3600));
+ certificate.setContent(PUBLIC_KEY, sizeof(PUBLIC_KEY));
+ certificate.setSignature(generateFakeSignature());
+
+ BOOST_CHECK_EQUAL(certificate.getName(), "/ndn/site1/KEY/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B");
+ BOOST_CHECK_EQUAL(certificate.getKeyName(), "/ndn/site1/KEY/ksk-1416425377094");
+ BOOST_CHECK_EQUAL(certificate.getIdentity(), "/ndn/site1");
+ BOOST_CHECK_EQUAL(certificate.getIssuerId(), name::Component("0123"));
+ BOOST_CHECK_EQUAL(certificate.getKeyId(), name::Component("ksk-1416425377094"));
+ BOOST_CHECK_EQUAL(certificate.getSignature().getKeyLocator().getName(), "/ndn/site1/KEY/ksk-2516425377094");
+ BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(certificate.getValidityPeriod()), "(20141111T050000, 20141111T060000)");
+
+ BOOST_CHECK_THROW(certificate.getExtension(12345), ndn::SignatureInfo::Error);
+ BOOST_CHECK_NO_THROW(certificate.getPublicKey());
+}
+
+BOOST_AUTO_TEST_CASE(ValidityPeriodChecking)
+{
+ Certificate certificate;
+ certificate.setName("/ndn/site1/KEY/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B");
+ certificate.setFreshnessPeriod(time::seconds(3600));
+ certificate.setContent(PUBLIC_KEY, sizeof(PUBLIC_KEY));
+ certificate.setSignature(generateFakeSignature());
+
+ BOOST_CHECK_EQUAL(certificate.isValid(), true);
+ BOOST_CHECK_EQUAL(certificate.isValid(time::fromIsoString("20141111T045959")), false);
+ BOOST_CHECK_EQUAL(certificate.isValid(time::fromIsoString("20141111T060001")), false);
+}
+
+// This fixture prepares a well-formed certificate. A test case then modifies one of the
+// fields, and verifies the Certificate class correctly identifies the certificate as
+// malformed.
+class InvalidCertFixture
+{
+public:
+ InvalidCertFixture()
+ {
+ Certificate certBase(Block(CERT, sizeof(CERT)));
+ BOOST_CHECK_NO_THROW((Certificate(certBase)));
+
+ m_certBase = Data(certBase);
+ m_certBase.setSignature(generateFakeSignature());
+
+ BOOST_CHECK_NO_THROW((Certificate(m_certBase)));
+ }
+
+public:
+ Data m_certBase;
+};
+
+BOOST_FIXTURE_TEST_CASE(InvalidName, InvalidCertFixture)
+{
+ Data data(m_certBase);
+ data.setName("/ndn/site1/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B");
+ data.setSignature(generateFakeSignature());
+
+ BOOST_CHECK_THROW((Certificate(data)), Certificate::Error);
+ BOOST_CHECK_THROW((Certificate(std::move(data))), Certificate::Error);
+}
+
+BOOST_FIXTURE_TEST_CASE(InvalidType, InvalidCertFixture)
+{
+ Data data(m_certBase);
+ data.setContentType(tlv::ContentType_Blob);
+ data.setSignature(generateFakeSignature());
+
+ BOOST_CHECK_THROW((Certificate(data)), Certificate::Error);
+ BOOST_CHECK_THROW((Certificate(std::move(data))), Certificate::Error);
+}
+
+BOOST_FIXTURE_TEST_CASE(EmptyContent, InvalidCertFixture)
+{
+ Data data(m_certBase);
+ data.setContent(nullptr, 0);
+ data.setSignature(generateFakeSignature());
+
+ BOOST_CHECK_THROW((Certificate(data)), Certificate::Error);
+ BOOST_CHECK_THROW((Certificate(std::move(data))), Certificate::Error);
+
+ Certificate cert(m_certBase);
+ cert.setContent(nullptr, 0);
+ cert.setSignature(generateFakeSignature());
+ BOOST_CHECK_THROW(cert.getPublicKey(), Certificate::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestCertificate
+BOOST_AUTO_TEST_SUITE_END() // V2
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace v2
+} // namespace security
+} // namespace ndn