docs: Update of tutorials and other minor fixes
Change-Id: I87d8679d38b3f17f8d4d8dbad3d5f01b3cc4ce7b
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.