docs: Update of tutorials and other minor fixes
Change-Id: I87d8679d38b3f17f8d4d8dbad3d5f01b3cc4ce7b
diff --git a/docs/RELEASE_NOTES.rst b/docs/RELEASE_NOTES.rst
index 27a0762..60e762e 100644
--- a/docs/RELEASE_NOTES.rst
+++ b/docs/RELEASE_NOTES.rst
@@ -27,7 +27,7 @@
+ Add support for new `NDN naming conventions
<http://named-data.net/doc/tech-memos/naming-conventions.pdf>`_
- (`Issue #1761 <http://redmine.named-data.net/issues/1761>`_)
+ (`Issue #1761 <http://redmine.named-data.net/issues/1761>`_)
- **Security**
@@ -141,7 +141,7 @@
* :ndn-cxx:`Validator::onTimeout <onTimeout>` to process interest timeout
* :ndn-cxx:`Validator::afterCheckPolicy <afterCheckPolicy>` to process validation requests.
- + Fix memory issues in :ndn-cxx:`SecPublicInfoSqlite`
+ + Fix memory issues in :ndn-cxx:`SecPublicInfoSqlite3`
- **Miscellaneous tools**
diff --git a/docs/conf.py b/docs/conf.py
index 93bd384..dbf6a2a 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -254,6 +254,7 @@
('tutorials/security-validator-config', 'ndnsec-validator.conf',
'NDN trust validator configuration file', None, 5),
('manpages/tlvdump', 'tlvdump', 'Decode structure of TLV encoded buffer', None, 1),
+ ('manpages/client.conf', 'client.conf', 'Configuration file for NDN platform', None, 5),
]
diff --git a/docs/examples.rst b/docs/examples.rst
index 793cd89..7e901ec 100644
--- a/docs/examples.rst
+++ b/docs/examples.rst
@@ -1,6 +1,12 @@
Trivial applications
====================
+.. note::
+
+ To successfully run the following examples, please make sure that NFD is properly
+ configured and running. For more information about NFD, refer to `NFD's official
+ homepage <http://named-data.net/doc/NFD/>`_.
+
Trivial consumer
----------------
diff --git a/docs/manpages.rst b/docs/manpages.rst
index ad28cc6..b17844d 100644
--- a/docs/manpages.rst
+++ b/docs/manpages.rst
@@ -2,6 +2,7 @@
========
.. toctree::
+ manpages/client.conf
manpages/ndnsec
ndnsec-list <manpages/ndnsec-list>
ndnsec-get-default <manpages/ndnsec-get-default>
diff --git a/docs/manpages/client.conf.rst b/docs/manpages/client.conf.rst
new file mode 100644
index 0000000..c0c9bd7
--- /dev/null
+++ b/docs/manpages/client.conf.rst
@@ -0,0 +1,67 @@
+client.conf
+===========
+
+System configuration of NDN platform is specified in ``client.conf``.
+Here is an example of ``client.conf`` for current ndn-cxx package:
+
+::
+
+ ; "unix_socket" specifies the location of the NFD unix socket
+ unix_socket=/var/run/nfd.sock
+
+ ; "protocol" determines the protocol for prefix registration
+ ; it has a value of:
+ ; nrd-0.1
+ protocol=nrd-0.1
+
+ ; "pib" determines which Public Info Base (PIB) should used by default in applications.
+ ; If "pib" is not specified, the default PIB will be used.
+ ; Note that default PIB could be different on different system.
+ ; If "pib" is specified, it may have a value of:
+ ; sqlite3
+ ; pib=sqlite3
+
+ ; "tpm" determines which Trusted Platform Module (TPM) should used by default in applications.
+ ; If "tpm" is not specified, the default TPM will be used.
+ ; Note that default TPM could be different on different system.
+ ; If "tpm" is specified, it may have a value of:
+ ; file
+ ; osx-keychain
+ ; tpm=file
+
+NFD
+---
+
+unix_socket
+ The local interface of NFD to applications. By default, the path to the socket is ``/var/run/nfd.sock``.
+
+Prefix Registration
+-------------------
+
+protocol
+ The prefix registration protocol. For now, only one protocol ``nrd-0.1`` is supported.
+ With this protocol, applications send prefix registration requests to NRD.
+ NRD, after authenticating the request, will set up corresponding FIB entries in NFD.
+
+Key Management
+--------------
+
+tpm
+ Trusted Platform Module (TPM) where the private keys are stored.
+ Two options are currently available: ``file`` and ``osx-keychain``.
+ **Users are not supposed to change the ``tpm`` setting once it is configued,
+ otherwise users may face the problem of "Keys are not found".**
+ The default value of ``tpm`` depends on the operating system.
+ For OS X, the default value is ``osx-keychain``.
+ For other systems, the default value is ``file``.
+
+pib
+ The public key information for each private key stored in TPM.
+ There is only one option for ``pib``: ``sqlite3``, which is also the default value of ``pib``.
+
+Users are not supposed to change the configuration of Key Management.
+If changes is inevitable, please clean up the all the existing data (which is usually under ``~/.ndn/``):
+
+::
+
+ rm -rf ~/.ndn/ndnsec-*
diff --git a/docs/tutorials.rst b/docs/tutorials.rst
index 1195ce6..b6e492d 100644
--- a/docs/tutorials.rst
+++ b/docs/tutorials.rst
@@ -7,4 +7,5 @@
tutorials/security-library
tutorials/utils-ndn-regex
tutorials/security-validator-config
+ tutorials/signed-interest
manpages
diff --git a/docs/tutorials/security-library.rst b/docs/tutorials/security-library.rst
index dfb1419..4f88f72 100644
--- a/docs/tutorials/security-library.rst
+++ b/docs/tutorials/security-library.rst
@@ -1,115 +1,141 @@
Security Library Tutorial
=========================
-Key Management
---------------
+.. contents::
Identity, Key and Certificates
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+------------------------------
-All keys, certificates and their corresponding identities are managed by
-KeyChain.
+All keys, certificates and their corresponding identities are managed by :ndn-cxx:`KeyChain`.
-Before signing a packet, you need to assure that the signing key and its
-corresponding identity certificate exist in the KeyChain. The private
-part of the signing key is used to generate signature, while the
-identity certificate is used to constructed the KeyLocator.
+An real world **identity** can be expressed by a namespace. (e.g.,
+``/ndn/edu/ucla/alice``, or ``/ndn/edu/ucla/BoelterHall/4805``).
-In KeyChain, keys and certificates are managed in terms of identities
-which are expressed by namespaces (e.g., ``/ndn/edu/ucla/irl/yingdi``, or
-``/ndn/edu/ucla/boelter\_hall/room\_4805``). Each pair of keys belongs to
-only one identity, and it is named by the identity name appended with a
-key ID (e.g., ``/ndn/edu/ucla/irl/yingdi/ksk-1234567890``, or
-``/ndn/edu/ucla/boelter\_hall/room\_4805/ksk-1357924680``). However, one
-identity may have more than one pair of keys, but only one of them is
-the **default key** of the identity. A key pair without any identity
-certificates is not quite useful. A key pair may have more than one
-identity certificates, but only one of them is the **default
-certificate**. Therefore, for a given identity, there is at only one
-default identity certificate, which is the default certificates of its
-default key.
+**Keys** belonging to an identity are named under the identity's namespace, with a unique
+**KeyId**::
-While keys and certificates can be created offline using NDN security
-tools **ndnsec**, they can be created online using the KeyChain API. The
-simplest way is to call ``KeyChain::createIdentity``.
+ /<identity_name>/[KeyId]
+
+For now, only two types of KeyId are specified: ``ksk-[timestamp]`` and
+``dsk-[timestamp]``. The first type of KeyId is used to denote Key-Signing-Key (KSK)
+which is supposed to have a long lifetime. The second type of KeyId is used to denote
+Data-Signing-Key (DSK) which is supposed to have a short lifetime. Both types of KeyId
+use timestamps (number of milliseconds since unix epoch) to provide relative uniqueness of
+key names. Replacing timestamp with key hash can bring stronger uniqueness but on the
+cost of longer name. Therefore, key hash is not used for now. For example,
+``/ndn/edu/ucla/alice/ksk-1234567890`` or
+``/ndn/edu/ucla/BoelterHall/4805/dsk-1357924680``.
+
+An identity may have more than one keys associated with it. For example, one may have a
+KSK to sign other keys and a DSK to sign data packets, or one may periodically replace its
+expired DSK/KSK with a new key.
+
+The private part of a key ("private key"), is stored in a :ndn-cxx:`Trusted Platform
+Module (TPM) <SecTpm>`. The public part ("public key"), is managed in a
+:ndn-cxx:`Public-key Information Base (PIB) <SecPublicInfo>`. The most important
+information managed by PIB is **certificates** of public keys. A certificate binds a
+public key to its key name or the corresponding identity. The signer (or issuer) of a
+certificate vouches for the binding through its own signature. With different signers
+vouching for the binding, a public key may have more than one certificates.
+
+The certificate name follows the naming convention of `NDNS (NDN Domain Name Service) <http://lasr.cs.ucla.edu/afanasyev/data/files/Afanasyev/afanasyev-phd-thesis.pdf>`_. The
+public key name will be broken into two parts:
+
+- The first part ("authoritative namespace") will be put before a name component ``KEY``
+ which serves as an application tag
+- The second part ("label") will be put between ``KEY`` and ``ID-CERT`` which serves as an
+ indicator of certificate.
+
+A version number of the certificate is appended after ``ID-CERT``. For example,
+``/ndn/edu/ucla/KEY/alice/ksk-1234567890/ID-CERT/%FD%01`` or
+``/ndn/edu/ucla/BoelterHall/4805/KEY/dsk-1357924680/ID-CERT/%FD%44``.
+
+The :ndn-cxx:`NDN certificate <IdentityCertificate>` is just an ordinary `NDN-TLV Data
+packet <http://named-data.net/doc/ndn-tlv/data.html>`_, with the content part in DER
+encoding that resembles X.509 certificate:
+
+.. code-block:: cpp
+
+ // NDN-TLV Encoding
+ Certificate ::= DATA-TLV TLV-LENGTH
+ Name
+ MetaInfo (= CertificateMetaInfo)
+ Content (= CertificateContent)
+ Signature
+
+ CertificateMetaInfo ::= META-INFO-TYPE TLV-LENGTH
+ ContentType (= KEY)
+ FreshnessPeriod (= ?)
+
+
+ CertificateContent ::= CONTENT-TYPE TLV-LENGTH
+ CertificateDerPayload
+
+
+ // DER Encoding
+ CertificateDerPayload ::= SEQUENCE {
+ validity Validity,
+ subject Name,
+ subjectPubKeyInfo SubjectPublicKeyInfo,
+ extension Extensions OPTIONAL }
+
+ Validity ::= SEQUENCE {
+ notBefore Time,
+ notAfter Time }
+
+ Time ::= CHOICE {
+ GeneralizedTime }
+
+ Name ::= CHOICE {
+ RDNSequence }
+
+ RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+
+ RelativeDistinguishedName ::=
+ SET OF AttributeTypeAndValue
+
+ SubjectPublicKeyInfo ::= SEQUENCE {
+ algorithm AlgorithmIdentifier
+ keybits BIT STRING }
+
+ Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+
+See `RFC 3280 <http://www.ietf.org/rfc/rfc3280.txt>`_ for more details about DER field
+definitions.
+
+Signing
+-------
+
+Key Management
+%%%%%%%%%%%%%%
+
+Create Identity/Keys/Certificate
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The simplest way to initialize an identity and its key and certificate is to call
+:ndn-cxx:`KeyChain::createIdentity`
.. code-block:: cpp
KeyChain keyChain;
- Name identity("/ndn/test/alice");
+ Name defaultCertName = keyChain.createIdentity(identity);
- Name certificateName = keyChain.createIdentity(identity);
-
-``KeyChain::createIdentity`` returns the default certificate name of the
-supplied identity, and always assures that the supplied identity has a
-default key and a default certificate. If the default key of the
-identity does not exist, ``createIdentity`` will create one. If the
-default certificate of the identity does not exist, ``createIdentity``
-will generate a self-signed certificate of the default key as the
-default certificate.
-
-System Default Identity
-~~~~~~~~~~~~~~~~~~~~~~~
-
-There is a default key for a particular identity, and a default identity
-certificate for a particular key. And, there is also a **default
-identity** for the system, which is the user of the system. The default
-identity can be configured using ndnsec tools only. You cannot configure
-through the security library API.
-
-Get and Set Default Keys/Certificates
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you know the exact names of keys and certificates, you can call
-``KeyChain::getPublicKey`` and ``KeyChain::getCertificate``.
-
-.. code-block:: cpp
-
- KeyChain keyChain;
- Name aliceKeyName("/ndn/test/alice/ksk-1394129695025");
- Name aliceCertName("/ndn/test/KEY/alice/ksk-1394129695025/ID-CERT/%FD%01D%98%9A%F2%3F");
-
- shared_ptr<PublicKey> aliceKey = keyChain.getPublicKey(aliceKeyName);
- shared_ptr<IdentityCertificate> aliceCert = keyChain.getCertificate(aliceCertName);
-
-It might be difficult to remember the exact name of keys and
-certificates, but it might be easier to remember identity names. The
-security library provides a list of methods to locate the default key
-name and certificate name of an identity.
-
-.. code-block:: cpp
-
- KeyChain keyChain;
- Name alice("/ndn/test/alice");
-
- Name aliceKeyName = keyChain.getDefaultKeyNameForIdentity(alice);
- Name aliceCertName = keyChain.getDefaultCertificateNameForKey(aliceKeyName);
-
- /* following code is equivalent to the two lines above */
- Name aliceCertName2 = keyChain.getDefaultCertificateNameForIdentity(alice);
-
-You can also manually set default key for an identity and default
-certificate for a key through KeyChain.
-
-.. code-block:: cpp
-
- KeyChain keyChain;
-
- Name aliceKeyName("/ndn/test/alice/ksk-1394129695025");
- Name aliceCertName("/ndn/test/KEY/alice/ksk-1394129695025/ID-CERT/%FD%01D%98%9A%F2%3F");
-
- keyChain.setDefaultKeyNameForIdentity(aliceKeyName);
- keyChain.getDefaultCertificateNameForKey(aliceCertName);
+This method guarantees that the default key and certificate of the supplied identity
+always exist in the KeyChain. This method checks if the supplied identity has already had
+a default key and a default certificate and returns the default certificate name if
+exists. If the default certificate is missing, KeyChain will automatically create a
+self-signed certificate of the default key. If the default key is missing, KeyChain will
+automatically create a new key and set it as the default key and create a self-signed
+certificate as well.
Create Keys Manually
~~~~~~~~~~~~~~~~~~~~
-You can call ``KeyChain::generateRSAKeyPair`` to generate an RSA key
-pair. Note that generated key pair is not set as the default key of the
-identity, so you need to set it manually by calling
-``KeyChain::setDefaultKeyNameForIdentity``. There is also a helper
-method "KeyChain::generateRSAKeyPairAsDefault", which combines the two
-steps into one.
+One can call :ndn-cxx:`KeyChain::generateRsaKeyPair` to generate an RSA key pair or
+:ndn-cxx:`KeyChain::generateEcdsaKeyPair` to generate an ECDSA key. Note that generated
+key pair is not set as the default key of the identity, so you need to set it manually by
+calling :ndn-cxx:`KeyChain::setDefaultKeyNameForIdentity`. There is also a helper method
+:ndn-cxx:`KeyChain::generateRsaKeyPairAsDefault`, which combines the two steps into one.
.. code-block:: cpp
@@ -119,13 +145,14 @@
Name aliceKeyName = keyChain.generateRSAKeyPair(alice);
keyChain.setDefaultKeyNameForIdentity(aliceKeyName);
- Name aliceKeyName2 = keyChain.generateRSAKeyPairAsDefault(alice); // Now the key with the name aliceKeyName2 becomes alice's default key
+ // Now the key with the name aliceKeyName2 becomes alice's default key
+ Name aliceKeyName2 = keyChain.generateRSAKeyPairAsDefault(alice);
Create Identity Certificate Manually
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If you have created a key pair, you can generate a self-signed
-certificate for the key by calling ``KeyChain::selfSign``.
+If you have created a key pair, you can generate a self-signed certificate for the key by
+calling :ndn-cxx:`KeyChain::selfSign`.
.. code-block:: cpp
@@ -134,227 +161,199 @@
shared_ptr<IdentityCertificate> aliceCert = keyChain.selfSign(aliceKeyName);
-You can sign a public key using a different key, but this signing
-process may take several steps. Note that this time, the signing key is
-vouching for the signed key, so you need to specify more details, such
-as the validity, subject descriptions. The first step is to prepare the
-unsigned identity certificate by calling
-``KeyChain::prepareUnsignedIdentityCertificate``. And the second step is
-to sign the identity certificate. We will talk about the signing methods
-in `Packet Signing <#packet_signing>`__.
+You can sign a public key using a different key:
.. code-block:: cpp
KeyChain keyChain;
- Name signingIdentity("/ndn/test");
- Name aliceKeyName("/ndn/test/alice/ksk-1394129695025");
- MillisecondsSince1970 notBefore = getNow();
- MillisecondsSince1970 notAfter = notBefore + 630720000;
- vector<CertificateSubjectDescription> subjectDescription;
- subjectDescription.push_back(CertificateSubjectDescription("2.5.4.41", "Alice")); // push any subject description into the list.
+ shared_ptr<IdentityCertificate> certificate =
+ keyChain.prepareUnsignedIdentityCertificate(publicKeyName, publicKey,
+ signingIdentity,
+ notBefore, notAfter,
+ subjectDescription, prefix
- shared_ptr<IdentityCertificate> = aliceCert
- keyChain.prepareUnsignedIdentityCertificate(aliceKeyName, signingIdentity, notBefore, notAfter, subjectDescription);
+ keyChain.signByIdentity(*certificate, signingIdentity);
- keyChain.signByIdentity(*aliceCert, signingIdentity);
+Signing Data
+%%%%%%%%%%%%
-Packet Signing
---------------
+Although the security library does not have the intelligence to automatically determine
+the signing key for each data packet, it still provides a mechanism, called **Default
+Signing Settings**, to facilitate signing process.
-When keys and certificates are ready for use, you can sign packet using
-them. There are two ways to sign a packet:
+The basic signing process in the security library would be like this: create :ndn-cxx:`KeyChain`
+instance and supply the data packet and signing certificate name to :ndn-cxx:`KeyChain::sign`
+method.
-1. by specifying the name of the identity certificate belonging to the
- signing key.
-2. by specifying the identity to which the signing key belongs
+.. code-block:: cpp
-Sign With Certificate Name
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+ KeyChain keyChain;
+ keyChain.sign(dataPacket, signingCertificateName);
-If we specify the exact certificate name when signing a packet, the
-certificate name (without version number) is put into the KeyLocator TLV
-in the SignatureInfo. KeyChain will look up the corresponding private
-key in the Trusted Platform Module (TPM), and use the private key to
-generate the signature.
+The :ndn-cxx:`KeyChain` instance will
+
+- construct ``SignatureInfo`` using the signing certificate name;
+- look up the corresponding private key in :ndn-cxx:`TPM <SecTpm>`;
+- sign the data packet if the private key exists.
+
+The basic process, however, requires application developers to supply the exact
+certificate name. Such a process has two shortages: first, it might be difficult to
+remember the certificate name; second, application developers have to be aware of
+certificate update and key roll-over. Therefore, the security library provides another
+signing process in which application developers only need to supply the signing identity:
+
+.. code-block:: cpp
+
+ KeyChain keyChain;
+ keyChain.signByIdentity(dataPacket, signingIdentity);
+
+The :ndn-cxx:`KeyChain` instance will
+
+- determine the default key of the signing identity;
+- determine the default certificate of the key;
+- construct ``SignatureInfo`` using the default certificate name;
+- look up the corresponding private key in :ndn-cxx:`TPM <SecTpm>`;
+- sign the data packet if the private key exists.
+
+The process above requires that each identity has a default key and that each key has a
+default certificate. All these default settings is managed in :ndn-cxx:`PIB
+<SecPublicInfo>`, one can get/set these default settings through :ndn-cxx:`KeyChain`
+directly:
+
+.. code-block:: cpp
+
+ KeyChain keyChain;
+ Name defaultKeyName = keyChain.getDefaultKeyNameForIdentity(identity);
+ Name defaultCertName = keyChain.getDefaultCertificateNameForKey(keyName);
+
+ keyChain.setDefaultKeyNameForIdentity(keyName);
+ keyChain.setDefaultCertificateNameForKey(certificateName);
+
+There is even a default identity which will be used when no identity information is
+supplied in signing method:
+
+.. code-block:: cpp
+
+ KeyChain keyChain;
+ keyChain.sign(dataPacket);
+
+And default identity can be got/set through :ndn-cxx:`KeyChain` as well:
+
+.. code-block:: cpp
+
+ KeyChain keyChain;
+ Name defaultIdentity = keyChain.getDefaultIdentity();
+ keyChain.setDefaultIdentity(identity);
+
+
+Signing Interests
+%%%%%%%%%%%%%%%%%
+
+The process of signing Interests according to the :doc:`Signed Interest specification
+<signed-interest>` is exactly the same as the process of signing Data packets:
.. code-block:: cpp
KeyChain keyChain;
- Name aliceCertName("/ndn/test/KEY/alice/ksk-1394129695025/ID-CERT/%FD%01D%98%9A%F2%3F");
- Data data("/ndn/test/alice/test-data");
+ keyChain.sign(interest, signingCertName);
+ keyChain.signByIdentity(interest, signingIdentity);
+ keyChain.sign(interest);
- keyChain.sign(data, aliceCertName);
+Validation
+----------
-When ``KeyChain::sing`` returns, the SignatureInfo and SignatureValue
-TLVs of the supplied data will be set.
-
-Sign With Identity Name
-~~~~~~~~~~~~~~~~~~~~~~~
-
-If we only specify the identity name when signing a packet, the name of
-the identity's default certificate will be put into the KeyLocator TLV
-in the SingatureInfo, and the identity's default key is used to sign the
-packet. Please make sure the default key and certificates of the signing
-identity is initialized correctly before signing, otherwise, KeyChain
-will create key and self-signed certificate for signing (which is not
-quite useful).
+Interest and Data validation is done through a **Validator**. :ndn-cxx:`Validator` is a virtual
+class, two pure virtual methods must be implemented in order to construct a working
+validator:
.. code-block:: cpp
- KeyChain keyChain;
-
- Name alice("/ndn/test/alice");
- Data data("/ndn/test/alice/test-data");
-
- keyChain.signByIdentity(data, alice);
-
-Sign Interest Packet
-~~~~~~~~~~~~~~~~~~~~
-
-Signing an interest packet is the same as signing a Data packet. The
-only difference is that the SignatureInfo And SignatureValue TLV are
-encoded as the last two components of the interest name.
-
-Packet Validation
------------------
-
-Packet validation is done through a **Validator**. Validator is a
-virtual class, two pure virtual methods must be implemented in order to
-construct a working validator:
-
-.. code-block:: cpp
-
- class Validator {
+ class Validator
+ {
...
protected:
virtual void
- checkPolicy (const Data& data,
- int stepCount,
- const OnDataValidated &onValidated,
- const OnDataValidationFailed &onValidationFailed,
- std::vector<shared_ptr<ValidationRequest> >& nextSteps) = 0;
+ checkPolicy(const Data& data,
+ int nSteps,
+ const OnDataValidated& onValidated,
+ const OnDataValidationFailed& onValidationFailed,
+ std::vector<shared_ptr<ValidationRequest> >& nextSteps) = 0;
virtual void
- checkPolicy (const Interest& interest,
- int stepCount,
- const OnInterestValidated &onValidated,
- const OnInterestValidationFailed &onValidationFailed,
- std::vector<shared_ptr<ValidationRequest> >& nextSteps) = 0;
- ...
-
-What you need to do inside these two methods is to check whether the
-packet and signer comply with your policies, and whether their signature
-can be verified. If the packet can be validated, you should call the
-``onValidated`` callback function to trigger packet processing,
-otherwise the ``onValidationFailed`` callback should be invoked. If you
-need more information (e.g., other certificates), you can construct
-several ``ValidationRequest`` and push them into nextSteps.
-
-.. code-block:: cpp
-
- class ValidationRequest {
- public:
- Interest m_interest; // An interest packet to fetch the requested data.
- OnDataValidated m_onValidated; // A callback function if the requested certificate is validated.
- OnDataValidationFailed m_onDataValidated; // A callback function if the requested certificate validation fails.
- int m_retry; // The number of retrials when there is an interest timeout.
- int m_stepCount; // The count of validation steps.
+ checkPolicy(const Interest& interest,
+ int nSteps,
+ const OnInterestValidated& onValidated,
+ const OnInterestValidationFailed& onValidationFailed,
+ std::vector<shared_ptr<ValidationRequest> >& nextSteps) = 0;
+ ...
};
-Security library also provides an ``Validator``, ``ValidatorRegex``
-which has already implemented the two methods (basically for Data policy
-checking, the Interest policy checking method always calls
-``onValidationFailed``).
+What should be implemented in these two methods is to check:
+
+- whether the packet and signer comply with trust policies;
+- whether their signature can be verified.
+
+If the packet can be validated, the ``onValidated`` callback should be invoked, otherwise
+the ``onValidationFailed`` callback should be invoked. If more information (e.g., other
+certificates) is needed, express the request for missing information in one or more
+``ValidationRequest`` and push them into ``nextSteps``.
.. code-block:: cpp
- class ValidatorRegex : public Validator
+ class ValidationRequest
{
public:
- ...
-
- void
- addDataVerificationRule(shared_ptr<SecRuleRelative> rule);
-
- void
- addTrustAnchor(shared_ptr<IdentityCertificate> certificate);
-
- ...
+ Interest m_interest; // The Interest for the requested data/certificate.
+ OnDataValidated m_onValidated; // Callback when the retrieved certificate is authenticated.
+ OnDataValidationFailed m_onDataValidated; // Callback when the retrieved certificate cannot be authenticated.
+ int m_nRetries; // The number of retries when the interest times out.
+ int m_nStep; // The number of validation steps that have been performed.
};
-With ``ValidatorRegex``, you can specify the validation rules in terms
-of [[Regex\|NDN Regular Expression]] via
-``ValidatorRegex::addDataVerificationRule``, and set trust anchor via
-``ValidatorRegex::addTrustAnchor``.
-
-How to specify regex-based validation rule
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To specify a ``SecRuleRelative``, you needs to specify two NDN regular
-expressions: one for data name matching, and the other for KeyLocator
-matching. For each regex, you also need to specify the back reference
-pattern to extract parts of the name. Moreover, you need to specify the
-relation between two extracted patterns. For example, a typical
-hierarchical rule can be written as
+Besides the two ``Validator::checkPolicy`` methods, the ``Validator`` also provides three
+hooks to control packet validation in a finer granularity.
.. code-block:: cpp
- SecRuleRelative rule("^(<>*)$", "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
- ">", "\\1", "\\1\\2", true);
+ class Validator
+ {
+ ...
+ protected:
+ virtual shared_ptr<const Data>
+ preCertificateValidation(const Data& data);
-This rule indicates that the data name must be under the signer's
-namespace.
+ virtual void
+ onTimeout(const Interest& interest,
+ int nRemainingRetries,
+ const OnFailure& onFailure,
+ const shared_ptr<ValidationRequest>& validationRequest);
-How to use validator
-~~~~~~~~~~~~~~~~~~~~
-
-Here is an example of how to use the validator
-
-.. code-block:: cpp
-
- class Example {
- public:
- Example(ndn::shared_ptr<ndn::Face> face>)
- : m_face(face)
- {
- ndn::shared_ptr<ndn::ValidatorRegex> validator(new ndn::ValidatorRegex(m_face));
- validator->addDataVerificationRule(ndn::make_shared<ndn::SecRuleRelative>("^(<>*)$",
- "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
- ">", "\\1", "\\1\\2", true));
- ndn::shared_ptr<ndn::IdentityCertificate> anchor = ndn::io::load<IdentityCertificate>("ndn-root.cert");
- validator->addTrustAnchor(anchor);
- m_validator = validator;
- }
-
- virtual
- ~Example() {}
-
- void
- sendInterest()
- {
- Interest interest ("/ndn/test/data");
- m_face->expressInterest(interest,
- bind(&Example::onData, this, _1, _2),
- bind(&Example::onTimeout, this, _1));
- }
-
- void
- onData(const ndn::Interest& interest, const ndn::Data& data)
- {
- m_validator->validate(data,
- ndn::bind(&Example::onValidated, this, _1),
- ndn::bind(&Example::onValidationFailed, this, _1, _2));
- }
-
- void onTimeout(const ndn::Interest& interest) {}
-
- void onValidated(const ndn::shared_ptr<const ndn::Data>& data) {}
-
- void onValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, const std::string& failInfo) {}
-
- private:
- ndn::shared_ptr<ndn::Face> m_face;
- ndn::shared_ptr<ndn::Validator> m_validator;
+ virtual void
+ afterCheckPolicy(const std::vector<shared_ptr<ValidationRequest> >& nextSteps,
+ const OnFailure& onFailure);
+ ...
};
+
+``Validator::preCertificateValidation`` is triggered before validating requested
+certificate. The Data supplied matches the interest in the ``ValidationRequest``. It may
+be certificate or a data encapsulating certificate. This hook returns a data (actually
+certificate) that is will be passed as Data into ``Validator::validate``;
+
+``Validator::onTimeout`` is triggered when interest for certificate times out. The logic
+to handle the timeout can be implemented in this hook. One could invoke onFailure or
+re-express the interest.
+
+``Validator::afterCheckPolicy`` is invoked after ``Validator::checkPolicy`` is done. One
+can implement the logic of how to process the set of ValidationRequests according to its
+trust model.
+
+Configuration-based Validator
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+In most cases, the trust model of applications are simple. However, it is not trivial to
+implement the two ``Validator::checkPolicy`` methods. Therefore, we provide a more
+developer-friendly configuration-based validator, ``ValidatorConfig``. With
+``ValidatorConfig``, one can express the trust model using a policy language in a
+configuration file. See :doc:`security-validator-config` for more details.
diff --git a/docs/tutorials/security-validator-config.rst b/docs/tutorials/security-validator-config.rst
index 905c087..a9ec70e 100644
--- a/docs/tutorials/security-validator-config.rst
+++ b/docs/tutorials/security-validator-config.rst
@@ -1,14 +1,15 @@
Validator Configuration File Format
===================================
-You can set up a ``Validator`` via a configuration file. Next, we will
-show you how to write a configuration file.
+.. contents::
-The configuration file consists of **rules** and **trust-anchors** that
-will be used in validation. **Rules** tell the validator how to validate
-a packet, while **trust-anchors** tell the validator which certificates
-are valid immediately. Here is an example of configuration file
-containing two rules.
+You can set up a ``Validator`` via a configuration file. Next, we will show you how to
+write a configuration file.
+
+The configuration file consists of **rules** and **trust-anchors** that will be used in
+validation. **Rules** tell the validator how to validate a packet, while **trust-anchors**
+tell the validator which certificates are valid immediately. Here is an example of
+configuration file containing two rules.
::
@@ -50,7 +51,8 @@
file-name "testbed-trust-anchor.cert"
}
-- \ **ATTENTION: The order of rules MATTERS!**\
+.. note::
+ **ATTENTION: The order of rules MATTERS!**
A rule can be broken into two parts:
@@ -59,75 +61,63 @@
- The second part is to check whether further validation process is
necessary.
-When receiving a packet, the validator will apply rules in the
-configuration file one-by-one against the packet, until finding a rule
-that the packet qualifies for. And the second part of the matched rule
-will be used to check the validity of the packet. If the packet cannot
-qualify for any rules, it is treated as an invalid packet. Once a packet
-has been matched by a rule, the rest rules will not be applied against
-the packet. Therefore, you should always put the most specific rule to
-the top, otherwise it will become useless.
+When receiving a packet, the validator will apply rules in the configuration file
+one-by-one against the packet, until finding a rule that the packet qualifies for. And the
+second part of the matched rule will be used to check the validity of the packet. If the
+packet cannot qualify for any rules, it is treated as an invalid packet. Once a packet has
+been matched by a rule, the rest rules will not be applied against the packet. Therefore,
+you should always put the most specific rule to the top, otherwise it will become useless.
-In the example configuration, the first rule indicates that all the data
-packets under the name prefix "/localhost/example" must be signed by a
-key whose certificate name is
-"/ndn/edu/ucla/KEY/yingdi/ksk-1234/ID-CERT". If a packet does not have a
-name under prefix "/localhost/example", validator will skip the first
-rule and apply the second rule. The second rule indicates that any data
-packets must be validated along a hierarchy. And a certificate stored in
-a file "testbed-trust-anchor.cert" is valid.
+In the example configuration, the first rule indicates that all the data packets under the
+name prefix ``/localhost/example`` must be signed by a key whose certificate name is
+``/ndn/edu/ucla/KEY/yingdi/ksk-1234/ID-CERT``. If a packet does not have a name under prefix
+``/localhost/example``, validator will skip the first rule and apply the second rule. The
+second rule indicates that any data packets must be validated along a hierarchy. And a
+certificate stored in a file "testbed-trust-anchor.cert" is valid.
Rules in general
----------------
-A rule has four types of properties: **id**, **for**, **filter**, and
-**checker**.
+A rule has four types of properties: **id**, **for**, **filter**, and **checker**.
-The property **id** uniquely identifies the rule in the configuration
-file. As long as being unique, any name can be given to a rule, e.g.,
-"Simple Rule", "Testbed Validation Rule". A rule must have one and only
-one **id** property.
+The property **id** uniquely identifies the rule in the configuration file. As long as
+being unique, any name can be given to a rule, e.g., "Simple Rule", "Testbed Validation
+Rule". A rule must have one and only one **id** property.
-A rule is either used to validate an interest packet or a data packet.
-This information is specified in the property **for**. Only two value
-can be specified: **data** and **interest**. A rule must have one and
-only one **for** property.
+A rule is either used to validate an interest packet or a data packet. This information
+is specified in the property **for**. Only two value can be specified: **data** and
+**interest**. A rule must have one and only one **for** property.
-The property **filter** further constrains the packets that can be
-checked by the rule. Filter property is not required in a rule, in this
-case, the rule will capture all the packets passed to it. A rule may
-contain more than one filters, in this case, a packet can be checked by
-a rule only if the packet satisfies all the filters.
+The property **filter** further constrains the packets that can be checked by the
+rule. Filter property is not required in a rule, in this case, the rule will capture all
+the packets passed to it. A rule may contain more than one filters, in this case, a packet
+can be checked by a rule only if the packet satisfies all the filters.
-- \ **ATTENTION: A packet that satisfies all the filters may not be
- valid**\ .
+.. note::
+ **ATTENTION: A packet that satisfies all the filters may not be valid**.
-The property **checker** defines the conditions that a matched packet
-must fulfill to be treated as a valid packet. A rule must have at least
-one **checker** property, a packet is treated as invalid if it cannot
-pass none of the checkers.
+The property **checker** defines the conditions that a matched packet must fulfill to be
+treated as a valid packet. A rule must have at least one **checker** property, a packet is
+treated as invalid if it cannot pass none of the checkers.
-**filter** and **checker** have their own properties. Next, we will
-introduce them separately.
+**filter** and **checker** have their own properties. Next, we will introduce them
+separately.
Filter Property
---------------
-Filter has its own **type** property. Although a rule may contain more
-than one filters, there is at most one filter of each type. So far, only
-one type of filter is defined: **name**. In other word, only one filter
-can be specified in a rule for now.
+Filter has its own **type** property. Although a rule may contain more than one filters,
+there is at most one filter of each type. So far, only one type of filter is defined:
+**name**. In other word, only one filter can be specified in a rule for now.
Name Filter
~~~~~~~~~~~
-There are two ways to express the conditions on name. The first way is
-to specify a relationship between the packet name and a particular name.
-In this case, two more properties are required: **name** and
-**relation**. A packet can fulfill the condition if the **name** has a
-**relation\* to the packet name. Three types of **\ relation\*\* has
-been defined: **equal**, **is-prefix-of**, **is-strict-prefix-of**. For
-example, a filter
+There are two ways to express the conditions on name. The first way is to specify a
+relationship between the packet name and a particular name. In this case, two more
+properties are required: **name** and **relation**. A packet can fulfill the condition if
+the **name** has a **relation\* to the packet name. Three types of **\ relation\*\* has
+been defined: **equal**, **is-prefix-of**, **is-strict-prefix-of**. For example, a filter
::
@@ -138,7 +128,7 @@
relation equal
}
-shall only capture a packet with the exact name "/localhost/example".
+shall only capture a packet with the exact name ``/localhost/example``.
And a filter
::
@@ -150,9 +140,8 @@
relation is-prefix-of
}
-shall capture a packet with name "/localhost/example" or
-"/localhost/example/data", but cannot catch a packet with name
-"/localhost/another\_example". And a filter
+shall capture a packet with name ``/localhost/example`` or ``/localhost/example/data``, but
+cannot catch a packet with name ``/localhost/another_example``. And a filter
::
@@ -163,12 +152,11 @@
relation is-strict-prefix-of
}
-shall capture a packet with name "/localhost/example/data", but cannot
-catch a packet with name "/localhost/example".
+shall capture a packet with name ``/localhost/example/data``, but cannot catch a packet
+with name ``/localhost/example``.
-The second way is to specify an [[Regex\|NDN Regular Expression]] that
-can match the packet. In this case, only one property **regex** is
-required. For example, a filter
+The second way is to specify an :doc:`utils-ndn-regex` that can match the packet. In this
+case, only one property **regex** is required. For example, a filter
::
@@ -183,18 +171,16 @@
Checker Property
----------------
-Passing all the filters in a rule only indicates that a packet can be
-checked using the rule, and it does not necessarily implies that the
-packet is valid. The validity of a packet is determined by the property
-**checker**, which defines the conditions that a valid packet must
-fulfill.
+Passing all the filters in a rule only indicates that a packet can be checked using the
+rule, and it does not necessarily implies that the packet is valid. The validity of a
+packet is determined by the property **checker**, which defines the conditions that a
+valid packet must fulfill.
-Same as **filter**, **checker** has a property **type**. We have defined
-three types of checkers: **customized**, and **hierarchical**, and
-**fixed-signer**. As suggested by its name, **customized** checker
-allows you to customize the conditions according to specific
-requirements. **hierarchical** checker and **fixed-signer** checker are
-pre-defined shortcuts, which specify specific trust models separately.
+Same as **filter**, **checker** has a property **type**. We have defined three types of
+checkers: **customized**, and **hierarchical**, and **fixed-signer**. As suggested by its
+name, **customized** checker allows you to customize the conditions according to specific
+requirements. **hierarchical** checker and **fixed-signer** checker are pre-defined
+shortcuts, which specify specific trust models separately.
Customized Checker
~~~~~~~~~~~~~~~~~~
@@ -215,20 +201,17 @@
}
}
-The property **sig-type** specifies the acceptable signature type.
-Right now three signature types have been defined: **rsa-sha256** and
-**ecdsa-sha256** (which are strong signature types) and **sha256**
-(which is a weak signature type).
-If sig-type is sha256, then **key-locator** will be ignored. Validator
-will simply calculate the digest of a packet and compare it with the one
-in ``SignatureValue``. If sig-type is rsa-sha256 or ecdsa-sha256, you
-have to further customize the checker with **key-locator**.
+The property **sig-type** specifies the acceptable signature type. Right now three
+signature types have been defined: **rsa-sha256** and **ecdsa-sha256** (which are strong
+signature types) and **sha256** (which is a weak signature type). If sig-type is sha256,
+then **key-locator** will be ignored. Validator will simply calculate the digest of a
+packet and compare it with the one in ``SignatureValue``. If sig-type is rsa-sha256 or
+ecdsa-sha256, you have to further customize the checker with **key-locator**.
-The property **key-locator** which specifies the conditions on
-``KeyLocator``. If the **key-locator** property is specified, it
-requires the existence of the ``KeyLocator`` field in ``SignatureInfo``.
-Although there are more than one types of ``KeyLocator`` defined in the
-`Packet Format <http://named-data.net/doc/ndn-tlv/signature.html>`__,
+The property **key-locator** which specifies the conditions on ``KeyLocator``. If the
+**key-locator** property is specified, it requires the existence of the ``KeyLocator``
+field in ``SignatureInfo``. Although there are more than one types of ``KeyLocator``
+defined in the `Packet Format <http://named-data.net/doc/ndn-tlv/signature.html>`__,
**key-locator** property only supports one type: **name**:
::
@@ -239,10 +222,9 @@
...
}
-Such a key-locator property specifies the conditions on the certificate
-name of the signing key. Since the conditions are about name, they can
-be specified in the same way as the name filter. For example, a checker
-could be:
+Such a key-locator property specifies the conditions on the certificate name of the
+signing key. Since the conditions are about name, they can be specified in the same way as
+the name filter. For example, a checker could be:
::
@@ -258,22 +240,18 @@
}
}
-This checker property requires that the packet must have a rsa-sha256
-signature generated by a key whose certificate name is
-"/ndn/edu/ucla/KEY/yingdi/ksk-1234/ID-CERT".
+This checker property requires that the packet must have a ``rsa-sha256`` signature generated
+by a key whose certificate name is ``/ndn/edu/ucla/KEY/yingdi/ksk-1234/ID-CERT``.
-Besides the two ways to express conditions on the ``KeyLocator`` name
-(name and regex), you can further constrain the ``KeyLocator`` name
-using the information extracted from the packet name. This third type of
-condition is expressed via a property **hyper-relation**. The
-**hyper-relation** property consists of three parts:
+Besides the two ways to express conditions on the ``KeyLocator`` name (name and regex),
+you can further constrain the ``KeyLocator`` name using the information extracted from the
+packet name. This third type of condition is expressed via a property
+**hyper-relation**. The **hyper-relation** property consists of three parts:
-- an NDN regular expression that can extract information from packet
- name
-- an NDN regular expression that can extract information from
- ``KeyLocator`` name
-- relation from the part extracted from ``KeyLocator`` name to the one
- extracted from the packet name
+- an NDN regular expression that can extract information from packet name
+- an NDN regular expression that can extract information from ``KeyLocator`` name
+- relation from the part extracted from ``KeyLocator`` name to the one extracted from the
+ packet name
For example, a checker:
@@ -298,11 +276,10 @@
}
}
-requires the packet name must be under the corresponding namespace of
-the ``KeyLocator`` name.
+requires the packet name must be under the corresponding namespace of the ``KeyLocator``
+name.
-In some cases, you can even customize checker with another property For
-example:
+In some cases, you can even customize checker with another property For example:
::
@@ -327,9 +304,8 @@
Hierarchical Checker
~~~~~~~~~~~~~~~~~~~~
-As implied by its name, hierarchical checker requires that the packet
-name must be under the namespace of the packet signer. A hierarchical
-checker:
+As implied by its name, hierarchical checker requires that the packet name must be under
+the namespace of the packet signer. A hierarchical checker:
::
@@ -364,11 +340,10 @@
Fixed-Signer Checker
~~~~~~~~~~~~~~~~~~~~
-In some cases, you only accept packets signed with pre-trusted
-certificates, i.e. "one-step validation". Such a trust model can be
-expressed with **fixed-signer** checker. And you only need to specify
-the trusted certificate via property **signer**. The definition of
-**signer** is the same as **trust-anchor**. For example:
+In some cases, you only accept packets signed with pre-trusted certificates,
+i.e. "one-step validation". Such a trust model can be expressed with **fixed-signer**
+checker. And you only need to specify the trusted certificate via property **signer**. The
+definition of **signer** is the same as **trust-anchor**. For example:
::
@@ -393,13 +368,11 @@
Trust Anchors
-------------
-Although **trust-anchor** is always not required in the configuration
-file (for example, if fixed-signer checker is used), it is very common
-to have a few trust-anchors in the configuration file, otherwise most
-packets cannot be validated. A configuration file may contain more than
-one trust anchors, but the order of trust anchors does not matter. The
-structure of trust-anchor is same as the **signer** in fixed-signer
-checker, for example:
+Although **trust-anchor** is always not required in the configuration file (for example,
+if fixed-signer checker is used), it is very common to have a few trust-anchors in the
+configuration file, otherwise most packets cannot be validated. A configuration file may
+contain more than one trust anchors, but the order of trust anchors does not matter. The
+structure of trust-anchor is same as the **signer** in fixed-signer checker, for example:
::
@@ -414,9 +387,9 @@
base64-string "Bv0DGwdG...amHFvHIMDw=="
}
-You may also specify a trust-anchor directory. All certificates under this
-directory are taken as trust anchors. For example, if all trust anchors are
-put into ``/usr/local/etc/ndn/keys``.
+You may also specify a trust-anchor directory. All certificates under this directory are
+taken as trust anchors. For example, if all trust anchors are put into
+``/usr/local/etc/ndn/keys``.
::
@@ -426,8 +399,8 @@
file-name /usr/local/etc/ndn/keys
}
-If certificates under the directory might be changed during runtime, you can
-set a refresh period, such as
+If certificates under the directory might be changed during runtime, you can set a refresh
+period, such as
::
@@ -438,13 +411,12 @@
refresh 1h ; refresh certificates every hour, other units include m (for minutes) and s (for seconds)
}
-There is another special trust anchor **any**.
-As long as such a trust-anchor is defined in config file,
-packet validation will be turned off.
+There is another special trust anchor **any**. As long as such a trust-anchor is defined
+in config file, packet validation will be turned off.
-- **ATTENTION: This type of trust anchor is dangerous.
- You should used it only when you want to disable packet validation temporarily
- (e.g, debugging code, building a demo).**
+.. note::
+ **ATTENTION: This type of trust anchor is dangerous. You should used it only when you
+ want to disable packet validation temporarily (e.g, debugging code, building a demo).**
::
@@ -457,8 +429,7 @@
Example Configuration For NLSR
------------------------------
-The trust model of NLSR is semi-hierarchical. An example certificate
-signing hierarchy is:
+The trust model of NLSR is semi-hierarchical. An example certificate signing hierarchy is:
::
@@ -514,17 +485,15 @@
+------------+-------------------------------------------------------------------------------------+
Assume that a typical NLSR data name is
-``/ndn/edu/ucla/%C1.O.R./rt1/NLSR/LSA/LSType.1/%01``. Then, the exception
-of naming hierarchy is "operator-router". So we can write a
-configuration file with three rules. The first one is a customized rule
-that capture the normal NLSR data. The second one is a customized rule
-that handles the exception case of the hierarchy (operator->router). And
-the last one is a hierarchical rule that handles the normal cases of the
-hierarchy.
+``/ndn/edu/ucla/%C1.O.R./rt1/NLSR/LSA/LSType.1/%01``. Then, the exception of naming
+hierarchy is "operator-router". So we can write a configuration file with three rules. The
+first one is a customized rule that capture the normal NLSR data. The second one is a
+customized rule that handles the exception case of the hierarchy (operator->router). And
+the last one is a hierarchical rule that handles the normal cases of the hierarchy.
-We put the NLSR data rule to the first place, because NLSR data packets
-are the most frequently checked. The hierarchical exception rule is put
-to the second, because it is more specific than the last one.
+We put the NLSR data rule to the first place, because NLSR data packets are the most
+frequently checked. The hierarchical exception rule is put to the second, because it is
+more specific than the last one.
And here is the configuration file:
@@ -605,11 +574,12 @@
file-name "testbed-trust-anchor.cert"
}
-Example Configuration For NRD
------------------------------
+Example Configuration For NFD RIB Management
+--------------------------------------------
-Assume NRD allows any valid testbed certificate to register prefix, the
-configuration file could be written as:
+Assume `NFD RIB Management <http://redmine.named-data.net/projects/nfd/wiki/RibMgmt>`_
+allows any valid testbed certificate to register prefix, the configuration file could be
+written as:
::
diff --git a/docs/tutorials/signed-interest.rst b/docs/tutorials/signed-interest.rst
new file mode 100644
index 0000000..093797a
--- /dev/null
+++ b/docs/tutorials/signed-interest.rst
@@ -0,0 +1,129 @@
+Signed Interest
+===============
+
+**Signed Interest** is a mechanism to issue an authenticated interest.
+
+The signature of a signed Interest packet is embedded into the last component of the Interest
+name. The signature covers a continuous block starting from the first name component TLV to the
+penultimate name component TLV:
+
+::
+
+ +-------------+----------+-----------------------------------------------------------------------------------+
+ | Interest | Interest | +------+--------+--------------------------------------------------+ +----------+ |
+ | Type (0x01) | length | | Name | Name | +---------+-- --+---------+---------+---------+| | Other | |
+ | | | | Type | Length | |Component| ... |Component|Component|Component|| | TLVs ... | |
+ | | | | | | | TLV 1 | | TLV n-2 | TLV n-1 | TLV n || | in | |
+ | | | | | | +---------+-- --+---------+---------+---------+| | Interest | |
+ | | | +------+--------+--------------------------------------------------+ +----------+ |
+ +-------------+----------+-----------------------------------------------------------------------------------+
+
+ \ /\ /
+ ---------------- ------------------ --- ---
+ \/ \/
+ Signed portion of Interest Signature
+
+More specifically, the SignedInterest is defined to have four additional components:
+
+- ``<timestamp>``
+- ``<nonce>``
+- ``<SignatureInfo>``
+- ``<SignatureValue>``
+
+For example, for ``/signed/interest/name`` name, CommandInterest will be defined as:
+
+::
+
+ /signed/interest/name/<timestamp>/<random-value>/<SignatureInfo>/<SignatureValue>
+
+ \ /
+ ----------------------------- --------------------------
+ \/
+ Additional components of Signed Interest
+
+Signed Interest specific Name components
+----------------------------------------
+
+Timestamp component (n-3 *th*)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The value of the n-3 *th* component is the interest's timestamp (in terms of millisecond offset
+from UTC 1970-01-01 00:00:00) encoded as
+`nonNegativeInteger <http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding>`__.
+The timestamp may be used to protect against replay attack.
+
+Nonce component (n-2 *th*)
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The value of the n-2 *th* component is random value (encoded as
+`nonNegativeInteger <http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding>`__)
+that adds additional assurances that the interest will be unique.
+
+SignatureInfo component (n-1 *th*)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The value of the n-1 *th* component is actually a
+`SignatureInfo <http://named-data.net/doc/ndn-tlv/signature.html>`__ TLV.
+
+::
+
+ +---------+---------+-------------------+
+ |Component|Component| +---------------+ |
+ | Type | Length | | SignatureInfo | |
+ | | | | TLV | |
+ | | | +---------------+ |
+ +---------+---------+-------------------+
+
+ | |
+ |<---------The n-1 th Component-------->|
+
+SignatureValue component (n *th*)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The value of the n *th* component is actually a
+`SignatureValue <http://named-data.net/doc/ndn-tlv/signature.html>`__ TLV.
+
+::
+
+ +---------+---------+--------------------+
+ |Component|Component| +----------------+ |
+ | Type | Length | | SignatureValue | |
+ | | | | TLV | |
+ | | | +----------------+ |
+ +---------+---------+--------------------+
+
+ | |
+ |<----------The n th Component---------->|
+
+Signed Interest processing
+--------------------------
+
+On receiving an Interest, the producer, according to the Interest name prefix, should be able
+to tell whether the Interest is required to be signed. If the received Interest is supposed to
+be signed, it will be treated as invalid in the following three cases:
+
+- one of the four components above (Timestamp, Nonce, SignatureValue, and SignatureInfo) is
+ missing or cannot be parsed correctly;
+- the key is not trusted for signing the Interest;
+- the signature cannot be verified with the public key pointed by the
+ `KeyLocator <http://named-data.net/doc/ndn-tlv/signature.html#keylocator>`__ in
+ SignatureInfo.
+
+Recipients of a signed interest may further check the timestamp and the uniqueness of the
+signed interest (e.g., when the signed interest carries a command). In this case, a signed
+interest may be treated as invalid if :
+
+- a valid signed Interest whose timestamp is **equal or later** than the timestamp of the
+ received one has been received before.
+
+Note that in order to detect this situation, the recipient needs to maintain a *latest
+timestamp* state for each trusted public key (**Since public key cryptography is used, sharing
+private keys is not recommended. If private key sharing is inevitable, it is the key owner's
+responsibility to keep clock synchronized**). For each trusted public key, the state is
+initialized as the timestamp of the first valid Interest signed by the key. Since then, the
+state will be updated every time when the recipient receives a valid signed Interest.
+
+Note that for the first Interest, the state is not available. To handle this special situation,
+the recipient should check the Interest's timestamp against a grace interval (e.g., 120
+seconds) [current\_timestamp - interval/2, current\_timestamp + interval/2]. The first interest
+is invalid if its timestamp is outside of the interval.