blob: dfb14192308c16518e39c7d1400d21e0d432e4e2 [file] [log] [blame]
Alexander Afanasyev7c6aeb02014-04-10 19:59:19 -07001Security Library Tutorial
2=========================
3
4Key Management
5--------------
6
7Identity, Key and Certificates
8~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9
10All keys, certificates and their corresponding identities are managed by
11KeyChain.
12
13Before signing a packet, you need to assure that the signing key and its
14corresponding identity certificate exist in the KeyChain. The private
15part of the signing key is used to generate signature, while the
16identity certificate is used to constructed the KeyLocator.
17
18In KeyChain, keys and certificates are managed in terms of identities
19which are expressed by namespaces (e.g., ``/ndn/edu/ucla/irl/yingdi``, or
20``/ndn/edu/ucla/boelter\_hall/room\_4805``). Each pair of keys belongs to
21only one identity, and it is named by the identity name appended with a
22key ID (e.g., ``/ndn/edu/ucla/irl/yingdi/ksk-1234567890``, or
23``/ndn/edu/ucla/boelter\_hall/room\_4805/ksk-1357924680``). However, one
24identity may have more than one pair of keys, but only one of them is
25the **default key** of the identity. A key pair without any identity
26certificates is not quite useful. A key pair may have more than one
27identity certificates, but only one of them is the **default
28certificate**. Therefore, for a given identity, there is at only one
29default identity certificate, which is the default certificates of its
30default key.
31
32While keys and certificates can be created offline using NDN security
33tools **ndnsec**, they can be created online using the KeyChain API. The
34simplest way is to call ``KeyChain::createIdentity``.
35
36.. code-block:: cpp
37
38 KeyChain keyChain;
39 Name identity("/ndn/test/alice");
40
41 Name certificateName = keyChain.createIdentity(identity);
42
43``KeyChain::createIdentity`` returns the default certificate name of the
44supplied identity, and always assures that the supplied identity has a
45default key and a default certificate. If the default key of the
46identity does not exist, ``createIdentity`` will create one. If the
47default certificate of the identity does not exist, ``createIdentity``
48will generate a self-signed certificate of the default key as the
49default certificate.
50
51System Default Identity
52~~~~~~~~~~~~~~~~~~~~~~~
53
54There is a default key for a particular identity, and a default identity
55certificate for a particular key. And, there is also a **default
56identity** for the system, which is the user of the system. The default
57identity can be configured using ndnsec tools only. You cannot configure
58through the security library API.
59
60Get and Set Default Keys/Certificates
61~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
62
63If you know the exact names of keys and certificates, you can call
64``KeyChain::getPublicKey`` and ``KeyChain::getCertificate``.
65
66.. code-block:: cpp
67
68 KeyChain keyChain;
69 Name aliceKeyName("/ndn/test/alice/ksk-1394129695025");
70 Name aliceCertName("/ndn/test/KEY/alice/ksk-1394129695025/ID-CERT/%FD%01D%98%9A%F2%3F");
71
72 shared_ptr<PublicKey> aliceKey = keyChain.getPublicKey(aliceKeyName);
73 shared_ptr<IdentityCertificate> aliceCert = keyChain.getCertificate(aliceCertName);
74
75It might be difficult to remember the exact name of keys and
76certificates, but it might be easier to remember identity names. The
77security library provides a list of methods to locate the default key
78name and certificate name of an identity.
79
80.. code-block:: cpp
81
82 KeyChain keyChain;
83 Name alice("/ndn/test/alice");
84
85 Name aliceKeyName = keyChain.getDefaultKeyNameForIdentity(alice);
86 Name aliceCertName = keyChain.getDefaultCertificateNameForKey(aliceKeyName);
87
88 /* following code is equivalent to the two lines above */
89 Name aliceCertName2 = keyChain.getDefaultCertificateNameForIdentity(alice);
90
91You can also manually set default key for an identity and default
92certificate for a key through KeyChain.
93
94.. code-block:: cpp
95
96 KeyChain keyChain;
97
98 Name aliceKeyName("/ndn/test/alice/ksk-1394129695025");
99 Name aliceCertName("/ndn/test/KEY/alice/ksk-1394129695025/ID-CERT/%FD%01D%98%9A%F2%3F");
100
101 keyChain.setDefaultKeyNameForIdentity(aliceKeyName);
102 keyChain.getDefaultCertificateNameForKey(aliceCertName);
103
104Create Keys Manually
105~~~~~~~~~~~~~~~~~~~~
106
107You can call ``KeyChain::generateRSAKeyPair`` to generate an RSA key
108pair. Note that generated key pair is not set as the default key of the
109identity, so you need to set it manually by calling
110``KeyChain::setDefaultKeyNameForIdentity``. There is also a helper
111method "KeyChain::generateRSAKeyPairAsDefault", which combines the two
112steps into one.
113
114.. code-block:: cpp
115
116 KeyChain keyChain;
117 Name alice("/ndn/test/alice");
118
119 Name aliceKeyName = keyChain.generateRSAKeyPair(alice);
120 keyChain.setDefaultKeyNameForIdentity(aliceKeyName);
121
122 Name aliceKeyName2 = keyChain.generateRSAKeyPairAsDefault(alice); // Now the key with the name aliceKeyName2 becomes alice's default key
123
124Create Identity Certificate Manually
125~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
126
127If you have created a key pair, you can generate a self-signed
128certificate for the key by calling ``KeyChain::selfSign``.
129
130.. code-block:: cpp
131
132 KeyChain keyChain;
133 Name aliceKeyName("/ndn/test/alice/ksk-1394129695025");
134
135 shared_ptr<IdentityCertificate> aliceCert = keyChain.selfSign(aliceKeyName);
136
137You can sign a public key using a different key, but this signing
138process may take several steps. Note that this time, the signing key is
139vouching for the signed key, so you need to specify more details, such
140as the validity, subject descriptions. The first step is to prepare the
141unsigned identity certificate by calling
142``KeyChain::prepareUnsignedIdentityCertificate``. And the second step is
143to sign the identity certificate. We will talk about the signing methods
144in `Packet Signing <#packet_signing>`__.
145
146.. code-block:: cpp
147
148 KeyChain keyChain;
149
150 Name signingIdentity("/ndn/test");
151 Name aliceKeyName("/ndn/test/alice/ksk-1394129695025");
152 MillisecondsSince1970 notBefore = getNow();
153 MillisecondsSince1970 notAfter = notBefore + 630720000;
154 vector<CertificateSubjectDescription> subjectDescription;
155 subjectDescription.push_back(CertificateSubjectDescription("2.5.4.41", "Alice")); // push any subject description into the list.
156
157 shared_ptr<IdentityCertificate> = aliceCert
158 keyChain.prepareUnsignedIdentityCertificate(aliceKeyName, signingIdentity, notBefore, notAftersubjectDescription);
159
160 keyChain.signByIdentity(*aliceCert, signingIdentity);
161
162Packet Signing
163--------------
164
165When keys and certificates are ready for use, you can sign packet using
166them. There are two ways to sign a packet:
167
1681. by specifying the name of the identity certificate belonging to the
169 signing key.
1702. by specifying the identity to which the signing key belongs
171
172Sign With Certificate Name
173~~~~~~~~~~~~~~~~~~~~~~~~~~
174
175If we specify the exact certificate name when signing a packet, the
176certificate name (without version number) is put into the KeyLocator TLV
177in the SignatureInfo. KeyChain will look up the corresponding private
178key in the Trusted Platform Module (TPM), and use the private key to
179generate the signature.
180
181.. code-block:: cpp
182
183 KeyChain keyChain;
184
185 Name aliceCertName("/ndn/test/KEY/alice/ksk-1394129695025/ID-CERT/%FD%01D%98%9A%F2%3F");
186 Data data("/ndn/test/alice/test-data");
187
188 keyChain.sign(data, aliceCertName);
189
190When ``KeyChain::sing`` returns, the SignatureInfo and SignatureValue
191TLVs of the supplied data will be set.
192
193Sign With Identity Name
194~~~~~~~~~~~~~~~~~~~~~~~
195
196If we only specify the identity name when signing a packet, the name of
197the identity's default certificate will be put into the KeyLocator TLV
198in the SingatureInfo, and the identity's default key is used to sign the
199packet. Please make sure the default key and certificates of the signing
200identity is initialized correctly before signing, otherwise, KeyChain
201will create key and self-signed certificate for signing (which is not
202quite useful).
203
204.. code-block:: cpp
205
206 KeyChain keyChain;
207
208 Name alice("/ndn/test/alice");
209 Data data("/ndn/test/alice/test-data");
210
211 keyChain.signByIdentity(data, alice);
212
213Sign Interest Packet
214~~~~~~~~~~~~~~~~~~~~
215
216Signing an interest packet is the same as signing a Data packet. The
217only difference is that the SignatureInfo And SignatureValue TLV are
218encoded as the last two components of the interest name.
219
220Packet Validation
221-----------------
222
223Packet validation is done through a **Validator**. Validator is a
224virtual class, two pure virtual methods must be implemented in order to
225construct a working validator:
226
227.. code-block:: cpp
228
229 class Validator {
230 ...
231 protected:
232 virtual void
233 checkPolicy (const Data& data,
234 int stepCount,
235 const OnDataValidated &onValidated,
236 const OnDataValidationFailed &onValidationFailed,
237 std::vector<shared_ptr<ValidationRequest> >& nextSteps) = 0;
238
239 virtual void
240 checkPolicy (const Interest& interest,
241 int stepCount,
242 const OnInterestValidated &onValidated,
243 const OnInterestValidationFailed &onValidationFailed,
244 std::vector<shared_ptr<ValidationRequest> >& nextSteps) = 0;
245 ...
246
247What you need to do inside these two methods is to check whether the
248packet and signer comply with your policies, and whether their signature
249can be verified. If the packet can be validated, you should call the
250``onValidated`` callback function to trigger packet processing,
251otherwise the ``onValidationFailed`` callback should be invoked. If you
252need more information (e.g., other certificates), you can construct
253several ``ValidationRequest`` and push them into nextSteps.
254
255.. code-block:: cpp
256
257 class ValidationRequest {
258 public:
259 Interest m_interest; // An interest packet to fetch the requested data.
260 OnDataValidated m_onValidated; // A callback function if the requested certificate is validated.
261 OnDataValidationFailed m_onDataValidated; // A callback function if the requested certificate validation fails.
262 int m_retry; // The number of retrials when there is an interest timeout.
263 int m_stepCount; // The count of validation steps.
264 };
265
266Security library also provides an ``Validator``, ``ValidatorRegex``
267which has already implemented the two methods (basically for Data policy
268checking, the Interest policy checking method always calls
269``onValidationFailed``).
270
271.. code-block:: cpp
272
273 class ValidatorRegex : public Validator
274 {
275 public:
276 ...
277
278 void
279 addDataVerificationRule(shared_ptr<SecRuleRelative> rule);
280
281 void
282 addTrustAnchor(shared_ptr<IdentityCertificate> certificate);
283
284 ...
285 };
286
287With ``ValidatorRegex``, you can specify the validation rules in terms
288of [[Regex\|NDN Regular Expression]] via
289``ValidatorRegex::addDataVerificationRule``, and set trust anchor via
290``ValidatorRegex::addTrustAnchor``.
291
292How to specify regex-based validation rule
293~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
294
295To specify a ``SecRuleRelative``, you needs to specify two NDN regular
296expressions: one for data name matching, and the other for KeyLocator
297matching. For each regex, you also need to specify the back reference
298pattern to extract parts of the name. Moreover, you need to specify the
299relation between two extracted patterns. For example, a typical
300hierarchical rule can be written as
301
302.. code-block:: cpp
303
304 SecRuleRelative rule("^(<>*)$", "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
305 ">", "\\1", "\\1\\2", true);
306
307This rule indicates that the data name must be under the signer's
308namespace.
309
310How to use validator
311~~~~~~~~~~~~~~~~~~~~
312
313Here is an example of how to use the validator
314
315.. code-block:: cpp
316
317 class Example {
318 public:
319 Example(ndn::shared_ptr<ndn::Face> face>)
320 : m_face(face)
321 {
322 ndn::shared_ptr<ndn::ValidatorRegex> validator(new ndn::ValidatorRegex(m_face));
323 validator->addDataVerificationRule(ndn::make_shared<ndn::SecRuleRelative>("^(<>*)$",
324 "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
325 ">", "\\1", "\\1\\2", true));
326 ndn::shared_ptr<ndn::IdentityCertificate> anchor = ndn::io::load<IdentityCertificate>("ndn-root.cert");
327 validator->addTrustAnchor(anchor);
328 m_validator = validator;
329 }
330
331 virtual
332 ~Example() {}
333
334 void
335 sendInterest()
336 {
337 Interest interest ("/ndn/test/data");
338 m_face->expressInterest(interest,
339 bind(&Example::onData, this, _1, _2),
340 bind(&Example::onTimeout, this, _1));
341 }
342
343 void
344 onData(const ndn::Interest& interest, const ndn::Data& data)
345 {
346 m_validator->validate(data,
347 ndn::bind(&Example::onValidated, this, _1),
348 ndn::bind(&Example::onValidationFailed, this, _1, _2));
349 }
350
351 void onTimeout(const ndn::Interest& interest) {}
352
353 void onValidated(const ndn::shared_ptr<const ndn::Data>& data) {}
354
355 void onValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, const std::string& failInfo) {}
356
357 private:
358 ndn::shared_ptr<ndn::Face> m_face;
359 ndn::shared_ptr<ndn::Validator> m_validator;
360 };