diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index fd1a49a..548c9b7 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -55,7 +55,8 @@ jobs: cd ../.. NO_DEPS=1 BISON=$(which bison) make - make test + # test is no longer compliable after b8f9d3c8a2620c1185ca972248f7af39c1eae68c + # make test sudo -E make install cd ../NAC-ABE @@ -169,7 +170,8 @@ jobs: ln -sf /usr/local/opt/openssl@1.1/include/openssl /usr/local/include ln -sf /usr/local/opt/openssl@1.1/lib/lib* /usr/local/lib NO_DEPS=1 BISON="$(brew --prefix bison)/bin/bison" make - make test + # test is no longer compliable after b8f9d3c8a2620c1185ca972248f7af39c1eae68c + # make test sudo -E make install cd ../NAC-ABE env: diff --git a/CMakeLists.txt b/CMakeLists.txt index eb2a770..ae3d263 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(nac-abe DESCRIPTION "NDN Name-based access control - attribute based encryption library") # flags -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) if (HAVE_TESTS) add_compile_definitions(HAVE_TESTS) @@ -15,7 +15,7 @@ endif(HAVE_TESTS) # dependencies find_package(PkgConfig REQUIRED) -pkg_check_modules(NDN_CXX REQUIRED libndn-cxx) +pkg_check_modules(NDN_CXX REQUIRED libndn-cxx>=0.8.1) find_package(OpenSSL REQUIRED) find_library(openabe NAMES openabe REQUIRED) diff --git a/README.md b/README.md index eb7dba5..b36c0da 100644 --- a/README.md +++ b/README.md @@ -113,15 +113,8 @@ To run tests, you must have `-DHAVE_TESTS=True` when you config the project. To run example, you must have `-DBUILD_EXAMPLES=True` when you config the project. ```bash -# in the build directory of NAC-ABE -#run all the tests (including integrate test) -ndnsec key-gen -t r /consumerPrefix1 -ndnsec key-gen /aaPrefix -ndnsec key-gen /producerPrefix - -./examples/kp-aa-example & -./examples/kp-producer-example & -./examples/kp-consumer-example +# in the examples directory of NAC-ABE +bash run-examples.sh ../build ``` ## 3 Documentation diff --git a/examples/run-examples.sh b/examples/run-examples.sh index 91ea664..0710f73 100644 --- a/examples/run-examples.sh +++ b/examples/run-examples.sh @@ -6,8 +6,10 @@ if ndnsec list | grep "/example/consumer\|/example/aa\|/example/producer" then - echo "Make sure you do not have identity /example/consumer, /example/aa, /example/producer in the keychain before try again" - exit 1 + echo "cleaning example identities" + ndnsec delete /example/consumer + ndnsec delete /example/aa + ndnsec delete /example/producer fi export NDN_LOG=*=INFO diff --git a/src/attribute-authority.cpp b/src/attribute-authority.cpp index 3cb9fb3..35d3011 100644 --- a/src/attribute-authority.cpp +++ b/src/attribute-authority.cpp @@ -23,7 +23,6 @@ #include "algo/abe-support.hpp" #include "ndn-crypto/data-enc-dec.hpp" -#include #include namespace ndn { @@ -32,11 +31,12 @@ namespace nacabe { NDN_LOG_INIT(nacabe.AttributeAuthority); AttributeAuthority::AttributeAuthority(const security::Certificate& identityCert, Face& face, - KeyChain& keyChain, const AbeType& abeType) + KeyChain& keyChain, const AbeType& abeType, size_t maxSegmentSize) : m_cert(identityCert) , m_face(face) , m_keyChain(keyChain) , m_abeType(abeType) + , m_maxSegmentSize(maxSegmentSize) { // ABE setup if (m_abeType == ABE_TYPE_CP_ABE) { @@ -77,31 +77,50 @@ AttributeAuthority::~AttributeAuthority() = default; void AttributeAuthority::onDecryptionKeyRequest(const Interest& request) { - // naming: /AA-prefix/DKEY/ - NDN_LOG_INFO("Got DKEY request: " << request.getName()); - Name keyName(request.getName().at(m_cert.getIdentity().size() + 1).blockFromValue()); - NDN_LOG_DEBUG("KeyName --------> " << keyName); - Name identityName = security::extractIdentityFromKeyName(keyName); - - // verify request and generate token - auto optionalCert = m_trustConfig.findCertificate(identityName); - if (!optionalCert) { - NDN_LOG_INFO("DKEY Request Interest cannot be authenticated: no certificate for " << identityName); - return; + // naming1: /AA-prefix/DKEY/ + // naming2: /AA-prefix/DKEY/// + Name requestName = request.getName(); + NDN_LOG_INFO("Got DKEY request: " << requestName); + + Name supposedKeyName(request.getName().at(m_cert.getIdentity().size() + 1).blockFromValue()); + if (requestName.at(-1).isSegment() && requestName.at(-2).isVersion()) { + auto mapIterator = m_segmentMap.find(requestName.getPrefix(-1)); + if (mapIterator != m_segmentMap.end()) { + for (auto data : mapIterator->second) { + if (requestName == data->getName()) { + m_face.put(*data); + } + } + } + } + else if (security::isValidKeyName(supposedKeyName)) { + NDN_LOG_DEBUG("KeyName --------> " << supposedKeyName); + Name identityName = security::extractIdentityFromKeyName(supposedKeyName); + // verify request and generate token + auto optionalCert = m_trustConfig.findCertificate(identityName); + if (!optionalCert) { + NDN_LOG_INFO("DKEY Request Interest cannot be authenticated: no certificate for " << identityName); + return; + } + NDN_LOG_INFO("Find consumer(decryptor) certificate: " << optionalCert->getName()); + auto ABEPrvKey = getPrivateKey(identityName); + auto prvBuffer = ABEPrvKey.toBuffer(); + + // prepare segments + Data result; + Name resultName = Name(request.getName()).appendVersion(); + result.setName(resultName); + result.setFreshnessPeriod(5_s); + Block dkBlock = encryptDataContentWithCK(prvBuffer, optionalCert->getPublicKey()); + span dkSpan = make_span(dkBlock.data(), dkBlock.size()); + // the freshness period should be configurable, but this value shouldn't affect much + auto dkSegments = m_segmenter.segment(dkSpan, resultName, m_maxSegmentSize, 4_s); + m_segmentMap.emplace(resultName, dkSegments); + m_face.put(*dkSegments.at(0)); + } + else { + // ignore } - NDN_LOG_INFO("Find consumer(decryptor) certificate: " << optionalCert->getName()); - - auto ABEPrvKey = getPrivateKey(identityName); - auto prvBuffer = ABEPrvKey.toBuffer(); - - // reply interest with encrypted private key - Data result; - Name resultName = Name(request.getName()).appendVersion(); - result.setName(resultName); - result.setFreshnessPeriod(5_s); - result.setContent(encryptDataContentWithCK(prvBuffer, optionalCert->getPublicKey())); - m_keyChain.sign(result, signingByCertificate(m_cert)); - m_face.put(result); } void @@ -157,8 +176,8 @@ CpAttributeAuthority::getPrivateKey(Name identityName) } KpAttributeAuthority::KpAttributeAuthority(const security::Certificate& identityCert, - Face& face, KeyChain& keyChain) - : AttributeAuthority(identityCert, face, keyChain, ABE_TYPE_KP_ABE) + Face& face, KeyChain& keyChain, size_t maxSegmentSize) + : AttributeAuthority(identityCert, face, keyChain, ABE_TYPE_KP_ABE, maxSegmentSize) { } diff --git a/src/attribute-authority.hpp b/src/attribute-authority.hpp index 82b8b79..09b6e49 100644 --- a/src/attribute-authority.hpp +++ b/src/attribute-authority.hpp @@ -29,6 +29,9 @@ #include #include +#include +#include + namespace ndn { namespace nacabe { @@ -36,7 +39,8 @@ class AttributeAuthority : noncopyable { protected: AttributeAuthority(const security::Certificate& identityCert, Face& m_face, - KeyChain& keyChain, const AbeType& abeType); + KeyChain& keyChain, const AbeType& abeType, + size_t maxSegmentSize = 1500); virtual ~AttributeAuthority(); @@ -56,6 +60,9 @@ class AttributeAuthority : noncopyable Face& m_face; KeyChain& m_keyChain; TrustConfig m_trustConfig; + ssize_t m_maxSegmentSize; + std::map>> m_segmentMap; + util::Segmenter m_segmenter{m_keyChain, signingByCertificate(m_cert)}; PUBLIC_WITH_TESTS_ELSE_PROTECTED: AbeType m_abeType; @@ -104,7 +111,7 @@ class CpAttributeAuthority: public AttributeAuthority class KpAttributeAuthority: public AttributeAuthority { public: - KpAttributeAuthority(const security::Certificate& identityCert, Face& m_face, KeyChain& keyChain); + KpAttributeAuthority(const security::Certificate& identityCert, Face& m_face, KeyChain& keyChain, size_t maxSegmentSize = 1500); /** * @brief Add a new policy into the state. diff --git a/src/consumer.cpp b/src/consumer.cpp index 1dccd43..aba8e1b 100644 --- a/src/consumer.cpp +++ b/src/consumer.cpp @@ -24,6 +24,7 @@ #include "ndn-crypto/data-enc-dec.hpp" #include +#include namespace ndn { namespace nacabe { @@ -62,20 +63,20 @@ Consumer::obtainDecryptionKey() interest.setMustBeFresh(true); interest.setCanBePrefix(true); - m_face.expressInterest(interest, - [this] (auto&&, const Data& keyData) { - NDN_LOG_INFO(m_cert.getIdentity() << " get decrypt key data"); - auto prvBlock = decryptDataContent(keyData.getContent(), m_keyChain.getTpm(), m_cert.getName()); - algo::PrivateKey prv; - prv.fromBuffer(Buffer(prvBlock.data(), prvBlock.size())); - m_keyCache = prv; - }, - [this] (auto&&, const auto& nack) { - NDN_LOG_INFO("Nack for " << m_cert.getIdentity() << " decrypt key data with reason " << nack.getReason()); - }, - [this] (auto&&) { - NDN_LOG_INFO("Timeout for " << m_cert.getIdentity() << " decrypt key data"); - }); + auto fetcher = util::SegmentFetcher::start(m_face, interest, m_validator); + fetcher->afterSegmentValidated.connect([](Data data) { + NDN_LOG_DEBUG("Validated " << data.getName()); + }); + fetcher->onComplete.connect([this] (ConstBufferPtr contentBuffer) { + NDN_LOG_DEBUG("SegmentFetcher completed with total fetched size of " << contentBuffer->size()); + auto prvBlock = decryptDataContent(Block(contentBuffer), m_keyChain.getTpm(), m_cert.getName()); + algo::PrivateKey prv; + prv.fromBuffer(Buffer(prvBlock.data(), prvBlock.size())); + m_keyCache = prv; + }); + fetcher->onError.connect([] (uint32_t errorCode, const std::string& errorMsg) { + NDN_LOG_ERROR("Error occurs in segment fetching: " << errorMsg); + }); } bool @@ -121,11 +122,11 @@ Consumer::consume(const Interest& dataInterest, auto dataCallback = [this, consumptionCb, errorCallback] (const Interest&, const Data& data) { m_validator.validate(data, [this, consumptionCb, errorCallback] (const Data& data) { - NDN_LOG_INFO("Decryption key conforms to trust schema"); + NDN_LOG_INFO("Encrypted data conforms to trust schema"); decryptContent(data, consumptionCb, errorCallback); }, [] (auto&&, const ndn::security::ValidationError& error) { - NDN_THROW(std::runtime_error("Fetched decryption key cannot be authenticated: " + error.getInfo())); + NDN_THROW(std::runtime_error("Encrypted data cannot be authenticated: " + error.getInfo())); } ); }; diff --git a/src/trust-config.cpp b/src/trust-config.cpp index 98e826a..dae5e1e 100644 --- a/src/trust-config.cpp +++ b/src/trust-config.cpp @@ -68,15 +68,15 @@ TrustConfig::addOrUpdateCertificate(const security::Certificate& certificate) } } -optional +std::optional TrustConfig::findCertificate(const Name& identityName) const { auto search = m_knownIdentities.find(identityName); if (search != m_knownIdentities.end()) { - return make_optional(search->second); + return search->second; } else { - return nullopt; + return std::nullopt; } } diff --git a/src/trust-config.hpp b/src/trust-config.hpp index e71830d..61fc9f5 100644 --- a/src/trust-config.hpp +++ b/src/trust-config.hpp @@ -37,7 +37,7 @@ class TrustConfig void addOrUpdateCertificate(const security::Certificate& certificate); - optional + std::optional findCertificate(const Name& identityName) const; private: