From d1b6f95864d9ca6a60d632e4f0565d665578a048 Mon Sep 17 00:00:00 2001 From: Alexander Afanasyev Date: Tue, 13 Jul 2021 15:05:43 -0400 Subject: [PATCH] examples: Extend example with basic trust schema (validator-config) Change-Id: Iaf9f4abd57563e52cb167b55ba3b27d8ecc1ecd7 --- .gitignore | 1 + docs/examples.rst | 6 ++-- examples/README.md | 61 +++++++++++++++++++------------- examples/consumer-with-timer.cpp | 2 -- examples/consumer.cpp | 19 ++++++++-- examples/producer.cpp | 24 +++++++++++-- examples/trust-schema.conf | 34 ++++++++++++++++++ 7 files changed, 112 insertions(+), 35 deletions(-) create mode 100644 examples/trust-schema.conf diff --git a/.gitignore b/.gitignore index 8850587a..724f671d 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ __pycache__/ # Other /VERSION.info +/examples/example-trust-anchor.cert diff --git a/docs/examples.rst b/docs/examples.rst index 0d89e20c..7f0b2b4c 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -18,7 +18,7 @@ callbacks to be called when Data/Nack is retrieved or Interest times out. .. literalinclude:: ../examples/consumer.cpp :language: c++ :linenos: - :emphasize-lines: 39-45,48,59,65,71 + :emphasize-lines: 43-49,52-55,63,77,83 Trivial producer ---------------- @@ -41,7 +41,7 @@ using :ndn-cxx:`Face::put` method. .. literalinclude:: ../examples/producer.cpp :language: c++ :linenos: - :emphasize-lines: 41,50,57-59,62,70,74 + :emphasize-lines: 39-42,55,62-64,79,87,91 Consumer that uses Scheduler ---------------------------- @@ -64,4 +64,4 @@ Interest approximately 3 seconds after the first one. .. literalinclude:: ../examples/consumer-with-timer.cpp :language: c++ :linenos: - :emphasize-lines: 39-40,56,62,93,106,114-116 + :emphasize-lines: 37-38,54-57,60,91,104-107,112-114 diff --git a/examples/README.md b/examples/README.md index 22b71ac1..f1f829ca 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,22 +1,22 @@ -ndn-cxx examples -================ +# ndn-cxx examples -By default, examples in `examples/` folder are not built. To enable them, use +By default, the examples in `examples/` folder are not built. To enable them, use `--with-examples` configure option. For example: ./waf configure --with-examples ./waf -There are two ways to add new examples, depending on their complexity: +There are two ways to add new examples, depending on their complexity. -1. Examples with a single translation unit +1. **Examples with a single translation unit** - For simple examples that have a single translation unit, the `.cpp` file can be directly put - in `examples/` folder and it will be automatically compiled on the next run of `./waf`. Name - of the compiled binary will be determined by the base name of the `.cpp` file. For example, - `examples/foo.cpp` will be compiled into binary `foo` in `/examples` folder: + For simple examples that have a single translation unit, the `.cpp` file can be directly put + in the `examples/` folder and it will be automatically compiled on the next run of `./waf`. + The name of the compiled executable will be determined by the base name of the `.cpp` file. + For instance, `examples/foo.cpp` will be compiled into an executable named `foo` inside the + `build/examples` folder: - echo "int main() { return 0; }" > examples/foo.cpp + echo 'int main() { return 0; }' > examples/foo.cpp ./waf # ... Compiling examples/foo.cpp # ... Linking build/examples/foo @@ -24,25 +24,23 @@ There are two ways to add new examples, depending on their complexity: # To run the example ./build/examples/foo -2. Examples with multiple translation units +2. **Examples with multiple translation units** - For more complex examples that contain multiple translation units, one can use - the following directory structure: + For more complex examples that contain multiple translation units, one can use + the following directory structure: - - Create a directory under `examples/` folder (e.g., `examples/bar`). - The name of this directory will determine the name of the compiled binary - (`/examples/bar/bar`) + - Create a directory under the `examples/` folder (e.g., `examples/bar`). The name of this + directory will determine the name of the compiled executable (`build/examples/bar/bar`). + - Place any number of translation units (e.g., `examples/bar/a.cpp`, `examples/bar/b.cpp`, + ...) in this directory. All `.cpp` files in this directory will be compiled and linked + together to produce the binary executable of the example. One of the .cpp files must + contain the `main()` function. - - Place any number of translation units (e.g., `examples/bar/a.cpp`, `examples/bar/b.cpp`, - ...) in this directory. All `.cpp` files in this directory will be compiled and linked - together to produce the binary of the example. One of the .cpp files should contain - the `main()` function. - - For example: + For example: mkdir examples/bar - echo "int bar(); int main() { return bar(); }" > examples/bar/a.cpp - echo "int bar() { return 10; } " > examples/bar/b.cpp + echo 'int bar(); int main() { return bar(); }' > examples/bar/a.cpp + echo 'int bar() { return 10; }' > examples/bar/b.cpp ./waf # ... Compiling examples/bar/a.cpp # ... Compiling examples/bar/b.cpp @@ -50,3 +48,18 @@ There are two ways to add new examples, depending on their complexity: # To run the example ./build/examples/bar/bar + +## Security configuration for example apps + +In order for the ``consumer`` example app to be able to properly authenticate data packets +created by the ``producer`` app, you must configure the following parameters. + +1. Generate example trust anchor: + + ndnsec key-gen /example + ndnsec cert-dump -i /example > example-trust-anchor.cert + +2. Create a key for the producer and sign it with the example trust anchor: + + ndnsec key-gen /example/testApp + ndnsec sign-req /example/testApp | ndnsec cert-gen -s /example -i example | ndnsec cert-install - diff --git a/examples/consumer-with-timer.cpp b/examples/consumer-with-timer.cpp index 2f9c4d4f..985b77e4 100644 --- a/examples/consumer-with-timer.cpp +++ b/examples/consumer-with-timer.cpp @@ -17,8 +17,6 @@ * . * * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Alexander Afanasyev */ #include diff --git a/examples/consumer.cpp b/examples/consumer.cpp index 5808c997..66438121 100644 --- a/examples/consumer.cpp +++ b/examples/consumer.cpp @@ -17,11 +17,10 @@ * . * * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Alexander Afanasyev */ #include +#include #include @@ -33,6 +32,11 @@ namespace examples { class Consumer { public: + Consumer() + { + m_validator.load("trust-schema.conf"); + } + void run() { @@ -56,9 +60,17 @@ public: private: void - onData(const Interest&, const Data& data) const + onData(const Interest&, const Data& data) { std::cout << "Received Data " << data << std::endl; + + m_validator.validate(data, + [] (const Data&) { + std::cout << "Data conforms to trust schema" << std::endl; + }, + [] (const Data&, const security::ValidationError& error) { + std::cout << "Error authenticating data: " << error << std::endl; + }); } void @@ -75,6 +87,7 @@ private: private: Face m_face; + ValidatorConfig m_validator{m_face}; }; } // namespace examples diff --git a/examples/producer.cpp b/examples/producer.cpp index d88cc866..16356ffc 100644 --- a/examples/producer.cpp +++ b/examples/producer.cpp @@ -17,8 +17,6 @@ * . * * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Alexander Afanasyev */ #include @@ -38,10 +36,17 @@ public: void run() { - m_face.setInterestFilter("/example/testApp", + m_face.setInterestFilter("/example/testApp/randomData", std::bind(&Producer::onInterest, this, _1, _2), nullptr, // RegisterPrefixSuccessCallback is optional std::bind(&Producer::onRegisterFailed, this, _1, _2)); + + auto cert = m_keyChain.getPib().getDefaultIdentity().getDefaultKey().getDefaultCertificate(); + m_certServeHandle = m_face.setInterestFilter(security::extractIdentityFromCertName(cert.getName()), + [this, cert] (auto&&...) { + m_face.put(cert); + }, + std::bind(&Producer::onRegisterFailed, this, _1, _2)); m_face.processEvents(); } @@ -58,6 +63,18 @@ private: data->setFreshnessPeriod(10_s); data->setContent(reinterpret_cast(content.data()), content.size()); + // in order for the consumer application to be able to validate the packet, you need to setup + // the following keys: + // 1. Generate example trust anchor + // + // ndnsec key-gen /example + // ndnsec cert-dump -i /example > example-trust-anchor.cert + // + // 2. Create a key for the producer and sign it with the example trust anchor + // + // ndnsec key-gen /example/testApp + // ndnsec sign-req /example/testApp | ndnsec cert-gen -s /example -i example | ndnsec cert-install - + // Sign Data packet with default identity m_keyChain.sign(*data); // m_keyChain.sign(*data, signingByIdentity()); @@ -81,6 +98,7 @@ private: private: Face m_face; KeyChain m_keyChain; + ScopedRegisteredPrefixHandle m_certServeHandle; }; } // namespace examples diff --git a/examples/trust-schema.conf b/examples/trust-schema.conf new file mode 100644 index 00000000..aade06c1 --- /dev/null +++ b/examples/trust-schema.conf @@ -0,0 +1,34 @@ +rule +{ + id "Example rule" + for data + filter + { + type name + name /example/testApp + relation is-prefix-of + } + checker + { + type customized + sig-type ecdsa-sha256 + key-locator + { + type name + hyper-relation + { + k-regex ^(<>*)<><>?<>?$ + k-expand \\1 + h-relation is-prefix-of + p-regex ^(<>*)<>*$ + p-expand \\1 + } + } + } +} + +trust-anchor +{ + type file + file-name "example-trust-anchor.cert" +}