blob: 200ff7470df88a131a4b6c72eb84c7276d9be160 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2018, Regents of the University of California
*
* This file is part of NAC (Name-Based Access Control for NDN).
* See AUTHORS.md for complete list of NAC authors and contributors.
*
* NAC is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NAC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NAC, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Zhiyi Zhang <zhiyi@cs.ucla.edu>
*/
#include "group-manager.hpp"
#include "boost-test.hpp"
#include "encrypted-content.hpp"
#include "algo/aes.hpp"
#include "algo/rsa.hpp"
#include <ndn-cxx/encoding/buffer-stream.hpp>
#include <boost/filesystem.hpp>
#include <string>
namespace ndn {
namespace nac {
namespace tests {
using namespace boost::posix_time;
const uint8_t SIG_INFO[] = {0x16, 0x1b, // SignatureInfo
0x1b, 0x01, // SignatureType
0x01, 0x1c, 0x16, // KeyLocator
0x07, 0x14, // Name
0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x03, 0x6b, 0x65,
0x79, 0x08, 0x07, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72};
const uint8_t SIG_VALUE[] = {0x17, 0x80, // SignatureValue
0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31,
0xec, 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9,
0xb3, 0xc6, 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8,
0xb3, 0x6a, 0x38, 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6,
0x4d, 0x10, 0x1d, 0xdc, 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96,
0x5e, 0xc0, 0x62, 0x0b, 0xcf, 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41,
0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d,
0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, 0x55, 0xf6, 0x1c, 0x19, 0x0b,
0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, 0xaa, 0x0d, 0x14, 0x58,
0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, 0xfc, 0x90, 0x7a,
0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1};
class GroupManagerFixture
{
public:
GroupManagerFixture()
: tmpPath(boost::filesystem::path(TMP_TESTS_PATH))
{
boost::filesystem::create_directories(tmpPath);
// generate the certificate public key
RsaKeyParams params;
DecryptKey<algo::Rsa> memberDecryptKey = algo::Rsa::generateKey(params);
decryptKeyBuf = memberDecryptKey.getKeyBits();
EncryptKey<algo::Rsa> memberEncryptKey = algo::Rsa::deriveEncryptKey(decryptKeyBuf);
encryptKeyBuf = memberEncryptKey.getKeyBits();
// generate certificate
cert.setName(Name("/ndn/memberA/KEY/ksk-123/ID-CERT/123"));
cert.setContent(encryptKeyBuf.data(), encryptKeyBuf.size());
Block sigInfoBlock(SIG_INFO, sizeof(SIG_INFO));
Block sigValueBlock(SIG_VALUE, sizeof(SIG_VALUE));
Signature sig(sigInfoBlock, sigValueBlock);
cert.setSignature(sig);
auto dataBlock = cert.wireEncode();
}
void
setManager(GroupManager& manager)
{
// set the first schedule
Schedule schedule1;
RepetitiveInterval interval11(from_iso_string("20150825T000000"),
from_iso_string("20150827T000000"),
5,
10,
2,
RepetitiveInterval::RepeatUnit::DAY);
RepetitiveInterval interval12(from_iso_string("20150825T000000"),
from_iso_string("20150827T000000"),
6,
8,
1,
RepetitiveInterval::RepeatUnit::DAY);
RepetitiveInterval interval13(from_iso_string("20150827T000000"),
from_iso_string("20150827T000000"),
7,
8);
schedule1.addWhiteInterval(interval11);
schedule1.addWhiteInterval(interval12);
schedule1.addBlackInterval(interval13);
// set the second schedule
Schedule schedule2;
RepetitiveInterval interval21(from_iso_string("20150825T000000"),
from_iso_string("20150827T000000"),
9,
12,
1,
RepetitiveInterval::RepeatUnit::DAY);
RepetitiveInterval interval22(from_iso_string("20150827T000000"),
from_iso_string("20150827T000000"),
6,
8);
RepetitiveInterval interval23(from_iso_string("20150827T000000"),
from_iso_string("20150827T000000"),
2,
4);
schedule2.addWhiteInterval(interval21);
schedule2.addWhiteInterval(interval22);
schedule2.addBlackInterval(interval23);
// add to the group manager db
manager.addSchedule("schedule1", schedule1);
manager.addSchedule("schedule2", schedule2);
// do some adaptions to certificate
Block dataBlock = cert.wireEncode();
Data memberA(dataBlock);
memberA.setName(Name("/ndn/memberA/KEY/ksk-123/ID-CERT/123"));
Data memberB(dataBlock);
memberB.setName(Name("/ndn/memberB/KEY/ksk-123/ID-CERT/123"));
Data memberC(dataBlock);
memberC.setName(Name("/ndn/memberC/KEY/ksk-123/ID-CERT/123"));
// add members to the database
manager.addMember("schedule1", memberA);
manager.addMember("schedule1", memberB);
manager.addMember("schedule2", memberC);
}
~GroupManagerFixture()
{
boost::filesystem::remove_all(tmpPath);
}
public:
boost::filesystem::path tmpPath;
Buffer decryptKeyBuf;
Buffer encryptKeyBuf;
Certificate cert;
};
BOOST_FIXTURE_TEST_SUITE(TestGroupManager, GroupManagerFixture)
BOOST_AUTO_TEST_CASE(CreateDKeyData)
{
// create the group manager database
std::string dbDir = tmpPath.c_str();
dbDir += "/manager-d-key-test.db";
GroupManager manager(Name("Alice"), Name("data_type"), dbDir, 2048, 1);
Block newCertBlock = cert.wireEncode();
Certificate newCert(newCertBlock);
// encrypt D-KEY
Data data = manager.createDKeyData("20150825T000000",
"20150827T000000",
Name("/ndn/memberA/KEY"),
decryptKeyBuf,
Buffer(newCert.getContent().value(),
newCert.getContent().value_size()));
// verify encrypted D-KEY
Block dataContent = data.getContent();
dataContent.parse();
BOOST_CHECK_EQUAL(dataContent.elements_size(), 2);
// get nonce key
Block::element_const_iterator contentIterator = dataContent.elements_begin();
Block nonceContent(*contentIterator);
BOOST_CHECK_EQUAL(nonceContent.type(), tlv::EncryptedContent);
EncryptedContent encryptedNonce(nonceContent);
BOOST_CHECK_EQUAL(encryptedNonce.getInitialVector().size(), 0);
BOOST_CHECK_EQUAL(encryptedNonce.getAlgorithmType(), tlv::AlgorithmRsaOaep);
const Buffer& bufferNonce = encryptedNonce.getPayload();
Buffer nonce = algo::Rsa::decrypt(decryptKeyBuf.data(),
decryptKeyBuf.size(),
bufferNonce.data(),
bufferNonce.size());
// get D-KEY
contentIterator++;
Block payloadContent(*contentIterator);
BOOST_CHECK_EQUAL(payloadContent.type(), tlv::EncryptedContent);
EncryptedContent encryptedPayload(payloadContent);
BOOST_CHECK_EQUAL(encryptedPayload.getInitialVector().size(), 16);
BOOST_CHECK_EQUAL(encryptedPayload.getAlgorithmType(), tlv::AlgorithmAesCbc);
algo::EncryptParams decryptParams(tlv::AlgorithmAesCbc);
decryptParams.setIV(encryptedPayload.getInitialVector().data(),
encryptedPayload.getInitialVector().size());
const Buffer& bufferPayload = encryptedPayload.getPayload();
Buffer largePayload = algo::Aes::decrypt(nonce.data(),
nonce.size(),
bufferPayload.data(),
bufferPayload.size(),
decryptParams);
BOOST_CHECK_EQUAL_COLLECTIONS(largePayload.begin(),
largePayload.end(),
decryptKeyBuf.begin(),
decryptKeyBuf.end());
}
BOOST_AUTO_TEST_CASE(CreateEKeyData)
{
// create the group manager database
std::string dbDir = tmpPath.c_str();
dbDir += "/manager-e-key-test.db";
// create group manager
GroupManager manager(Name("Alice"), Name("data_type"), dbDir, 1024, 1);
setManager(manager);
Data data = manager.createEKeyData("20150825T090000", "20150825T110000", encryptKeyBuf);
BOOST_CHECK_EQUAL(data.getName().toUri(),
"/Alice/READ/data_type/E-KEY/20150825T090000/20150825T110000");
Buffer contentBuf(data.getContent().value(), data.getContent().value_size());
BOOST_CHECK_EQUAL_COLLECTIONS(encryptKeyBuf.begin(),
encryptKeyBuf.end(),
contentBuf.begin(),
contentBuf.end());
}
BOOST_AUTO_TEST_CASE(CalculateInterval)
{
// create the group manager database
std::string dbDir = tmpPath.c_str();
dbDir += "/manager-interval-test.db";
// create group manager
GroupManager manager(Name("Alice"), Name("data_type"), dbDir, 1024, 1);
setManager(manager);
std::map<Name, Buffer> memberKeys;
Interval result;
TimeStamp tp1(from_iso_string("20150825T093000"));
result = manager.calculateInterval(tp1, memberKeys);
BOOST_CHECK_EQUAL(to_iso_string(result.getStartTime()), "20150825T090000");
BOOST_CHECK_EQUAL(to_iso_string(result.getEndTime()), "20150825T100000");
TimeStamp tp2(from_iso_string("20150827T073000"));
result = manager.calculateInterval(tp2, memberKeys);
BOOST_CHECK_EQUAL(to_iso_string(result.getStartTime()), "20150827T070000");
BOOST_CHECK_EQUAL(to_iso_string(result.getEndTime()), "20150827T080000");
TimeStamp tp3(from_iso_string("20150827T043000"));
result = manager.calculateInterval(tp3, memberKeys);
BOOST_CHECK_EQUAL(result.isValid(), false);
TimeStamp tp4(from_iso_string("20150827T053000"));
result = manager.calculateInterval(tp4, memberKeys);
BOOST_CHECK_EQUAL(to_iso_string(result.getStartTime()), "20150827T050000");
BOOST_CHECK_EQUAL(to_iso_string(result.getEndTime()), "20150827T060000");
}
BOOST_AUTO_TEST_CASE(GetGroupKey)
{
// create the group manager database
std::string dbDir = tmpPath.c_str();
dbDir += "/manager-group-key-test.db";
// create group manager
GroupManager manager(Name("Alice"), Name("data_type"), dbDir, 1024, 1);
setManager(manager);
// get data list from group manager
TimeStamp tp1(from_iso_string("20150825T093000"));
std::list<Data> result = manager.getGroupKey(tp1);
BOOST_CHECK_EQUAL(result.size(), 4);
// first data contain the group encrypt key(public key)
std::list<Data>::iterator dataIterator = result.begin();
BOOST_CHECK_EQUAL(dataIterator->getName().toUri(),
"/Alice/READ/data_type/E-KEY/20150825T090000/20150825T100000");
EncryptKey<algo::Rsa> groupEKey(
Buffer(dataIterator->getContent().value(), dataIterator->getContent().value_size()));
// second data and decrypt
dataIterator++;
BOOST_CHECK_EQUAL(dataIterator->getName().toUri(),
"/Alice/READ/data_type/D-KEY/20150825T090000/20150825T100000/FOR/ndn/memberA/KEY/ksk-123");
//////////////////////////////////////////////////////////////////////// start decryption
Block dataContent = dataIterator->getContent();
dataContent.parse();
BOOST_CHECK_EQUAL(dataContent.elements_size(), 2);
// get nonce key
Block::element_const_iterator contentIterator = dataContent.elements_begin();
Block nonceContent(*contentIterator);
BOOST_CHECK_EQUAL(nonceContent.type(), tlv::EncryptedContent);
EncryptedContent encryptedNonce(nonceContent);
BOOST_CHECK_EQUAL(encryptedNonce.getInitialVector().size(), 0);
BOOST_CHECK_EQUAL(encryptedNonce.getAlgorithmType(), tlv::AlgorithmRsaOaep);
const Buffer& bufferNonce = encryptedNonce.getPayload();
Buffer nonce = algo::Rsa::decrypt(decryptKeyBuf.data(),
decryptKeyBuf.size(),
bufferNonce.data(),
bufferNonce.size());
// get buffer payload
contentIterator++;
Block payloadContent(*contentIterator);
BOOST_CHECK_EQUAL(payloadContent.type(), tlv::EncryptedContent);
EncryptedContent encryptedPayload(payloadContent);
BOOST_CHECK_EQUAL(encryptedPayload.getInitialVector().size(), 16);
BOOST_CHECK_EQUAL(encryptedPayload.getAlgorithmType(), tlv::AlgorithmAesCbc);
algo::EncryptParams decryptParams(tlv::AlgorithmAesCbc);
decryptParams.setIV(encryptedPayload.getInitialVector().data(),
encryptedPayload.getInitialVector().size());
const Buffer& bufferPayload = encryptedPayload.getPayload();
Buffer largePayload = algo::Aes::decrypt(nonce.data(),
nonce.size(),
bufferPayload.data(),
bufferPayload.size(),
decryptParams);
// get group D-KEY
DecryptKey<algo::Rsa> groupDKey(Buffer(largePayload.data(), largePayload.size()));
/////////////////////////////////////////////////////////////////////// end decryption
// check the D-KEY
EncryptKey<algo::Rsa> derivedGroupEKey = algo::Rsa::deriveEncryptKey(groupDKey.getKeyBits());
BOOST_CHECK_EQUAL_COLLECTIONS(groupEKey.getKeyBits().begin(),
groupEKey.getKeyBits().end(),
derivedGroupEKey.getKeyBits().begin(),
derivedGroupEKey.getKeyBits().end());
// third data and decrypt
dataIterator++;
BOOST_CHECK_EQUAL(dataIterator->getName().toUri(),
"/Alice/READ/data_type/D-KEY/20150825T090000/20150825T100000/FOR/ndn/memberB/KEY/ksk-123");
// second data and decrypt
dataIterator++;
BOOST_CHECK_EQUAL(dataIterator->getName().toUri(),
"/Alice/READ/data_type/D-KEY/20150825T090000/20150825T100000/FOR/ndn/memberC/KEY/ksk-123");
// invalid time stamp to get group key
TimeStamp tp2(from_iso_string("20150826T083000"));
BOOST_CHECK_EQUAL(manager.getGroupKey(tp2).size(), 0);
TimeStamp tp3(from_iso_string("20150827T023000"));
BOOST_CHECK_EQUAL(manager.getGroupKey(tp3).size(), 0);
}
BOOST_AUTO_TEST_CASE(GetGroupKeyWithoutRegeneration)
{
// create the group manager database
std::string dbDir = tmpPath.c_str();
dbDir += "/manager-group-key-test.db";
// create group manager
GroupManager manager(Name("Alice"), Name("data_type"), dbDir, 1024, 1);
setManager(manager);
// get data list from group manager
TimeStamp tp1(from_iso_string("20150825T093000"));
std::list<Data> result1 = manager.getGroupKey(tp1);
BOOST_CHECK_EQUAL(result1.size(), 4);
// first data contain the group encrypt key(public key)
std::list<Data>::iterator dataIterator1 = result1.begin();
BOOST_CHECK_EQUAL(dataIterator1->getName().toUri(),
"/Alice/READ/data_type/E-KEY/20150825T090000/20150825T100000");
EncryptKey<algo::Rsa> groupEKey1(
Buffer(dataIterator1->getContent().value(), dataIterator1->getContent().value_size()));
// second data
dataIterator1++;
BOOST_CHECK_EQUAL(dataIterator1->getName().toUri(),
"/Alice/READ/data_type/D-KEY/20150825T090000/20150825T100000/FOR/ndn/memberA/KEY/ksk-123");
// add new members to the database
Block dataBlock = cert.wireEncode();
Data memberD(dataBlock);
memberD.setName(Name("/ndn/memberD/KEY/ksk-123/ID-CERT/123"));
manager.addMember("schedule1", memberD);
std::list<Data> result2 = manager.getGroupKey(tp1, false);
BOOST_CHECK_EQUAL(result2.size(), 5);
// check the new EKey is the same with the previous one
std::list<Data>::iterator dataIterator2 = result2.begin();
BOOST_CHECK_EQUAL(dataIterator2->getName().toUri(),
"/Alice/READ/data_type/E-KEY/20150825T090000/20150825T100000");
EncryptKey<algo::Rsa> groupEKey2(
Buffer(dataIterator2->getContent().value(), dataIterator2->getContent().value_size()));
BOOST_CHECK_EQUAL_COLLECTIONS(groupEKey1.getKeyBits().begin(),
groupEKey1.getKeyBits().end(),
groupEKey2.getKeyBits().begin(),
groupEKey2.getKeyBits().end());
// second data
dataIterator2++;
BOOST_CHECK_EQUAL(dataIterator2->getName().toUri(),
"/Alice/READ/data_type/D-KEY/20150825T090000/20150825T100000/FOR/ndn/memberA/KEY/ksk-123");
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
} // namespace nac
} // namespace ndn