access-manager.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2024, Regents of the University of California
4  *
5  * NAC library is free software: you can redistribute it and/or modify it under the
6  * terms of the GNU Lesser General Public License as published by the Free Software
7  * Foundation, either version 3 of the License, or (at your option) any later version.
8  *
9  * NAC library is distributed in the hope that it will be useful, but WITHOUT ANY
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12  *
13  * You should have received copies of the GNU General Public License and GNU Lesser
14  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
15  * <http://www.gnu.org/licenses/>.
16  *
17  * See AUTHORS.md for complete list of NAC library authors and contributors.
18  */
19 
20 #include "access-manager.hpp"
21 #include "encrypted-content.hpp"
22 
23 #include <ndn-cxx/security/signing-helpers.hpp>
24 #include <ndn-cxx/util/logger.hpp>
25 #include <ndn-cxx/util/random.hpp>
26 
27 namespace ndn::nac {
28 
29 NDN_LOG_INIT(nac.AccessManager);
30 
31 AccessManager::AccessManager(const Identity& identity, const Name& dataset,
32  KeyChain& keyChain, Face& face)
33  : m_identity(identity)
34  , m_keyChain(keyChain)
35  , m_face(face)
36 {
37  // NAC Identity: <identity>/NAC/<dataset>
38  // generate NAC key
39  auto nacId = m_keyChain.createIdentity(Name(identity.getName()).append(NAC).append(dataset), RsaKeyParams());
40  m_nacKey = nacId.getDefaultKey();
41  if (m_nacKey.getKeyType() != KeyType::RSA) {
42  NDN_LOG_INFO("Cannot re-use existing KEK/KDK pair, as it is not an RSA key, regenerating");
43  m_nacKey = m_keyChain.createKey(nacId, RsaKeyParams());
44  }
45  auto nacKeyId = m_nacKey.getName().at(-1);
46 
47  auto kekPrefix = Name(m_nacKey.getIdentity()).append(KEK);
48 
49  auto kek = std::make_shared<Data>(m_nacKey.getDefaultCertificate());
50  kek->setName(Name(kekPrefix).append(nacKeyId));
51  kek->setFreshnessPeriod(DEFAULT_KEK_FRESHNESS_PERIOD);
52  m_keyChain.sign(*kek, signingByIdentity(m_identity));
53  // kek looks like a cert, but doesn't have ValidityPeriod
54  m_ims.insert(*kek);
55 
56  auto serveFromIms = [this] (const Name&, const Interest& interest) {
57  auto data = m_ims.find(interest);
58  if (data != nullptr) {
59  NDN_LOG_DEBUG("Serving " << data->getName() << " from InMemoryStorage");
60  m_face.put(*data);
61  }
62  else {
63  NDN_LOG_DEBUG("Didn't find data for " << interest.getName());
64  // send NACK?
65  }
66  };
67 
68  auto handleError = [] (const Name& prefix, const std::string& msg) {
69  NDN_LOG_ERROR("Failed to register prefix " << prefix << ": " << msg);
70  };
71 
72  m_kekReg = m_face.setInterestFilter(kekPrefix, serveFromIms, handleError);
73 
74  auto kdkPrefix = Name(m_nacKey.getIdentity()).append(KDK).append(nacKeyId);
75  m_kdkReg = m_face.setInterestFilter(kdkPrefix, serveFromIms, handleError);
76 }
77 
78 Data
79 AccessManager::addMember(const Certificate& memberCert)
80 {
81  Name kdkName(m_nacKey.getIdentity());
82  kdkName
83  .append(KDK)
84  .append(m_nacKey.getName().at(-1)) // key-id
85  .append(ENCRYPTED_BY)
86  .append(memberCert.getKeyName());
87 
88  const size_t secretLength = 32;
89  uint8_t secret[secretLength + 1];
90  random::generateSecureBytes({secret, secretLength});
91  // because of stupid bug in ndn-cxx, remove all \0 in generated secret, replace with 1
92  for (size_t i = 0; i < secretLength; ++i) {
93  if (secret[i] == 0) {
94  secret[i] = 1;
95  }
96  }
97  secret[secretLength] = 0;
98 
99  auto kdkData = m_keyChain.exportSafeBag(m_nacKey.getDefaultCertificate(),
100  reinterpret_cast<const char*>(secret), secretLength);
101 
102  PublicKey memberKey;
103  memberKey.loadPkcs8(memberCert.getPublicKey());
104 
105  EncryptedContent content;
106  content.setPayload(kdkData->wireEncode());
107  content.setPayloadKey(memberKey.encrypt({secret, secretLength}));
108 
109  auto kdk = std::make_shared<Data>(kdkName);
110  kdk->setContent(content.wireEncode());
111  // FreshnessPeriod can serve as a soft access control for revoking access
112  kdk->setFreshnessPeriod(DEFAULT_KDK_FRESHNESS_PERIOD);
113  m_keyChain.sign(*kdk, signingByIdentity(m_identity));
114 
115  m_ims.insert(*kdk);
116 
117  return *kdk;
118 }
119 
120 void
121 AccessManager::removeMember(const Name& identity)
122 {
123  m_ims.erase(Name(m_nacKey.getName()).append(KDK).append(ENCRYPTED_BY).append(identity));
124 }
125 
126 } // namespace ndn::nac
AccessManager(const Identity &identity, const Name &dataset, KeyChain &keyChain, Face &face)
Data addMember(const Certificate &memberCert)
Authorize a member identified by its certificate memberCert to decrypt data under the policy.
void removeMember(const Name &identity)
Remove member with name identity from the group.
EncryptedContent & setPayloadKey(Block key)
EncryptedContent & setPayload(Block payload)
size_t wireEncode(EncodingImpl< TAG > &block) const
const name::Component KDK
Definition: common.hpp:85
constexpr time::seconds DEFAULT_KEK_FRESHNESS_PERIOD
Definition: common.hpp:91
constexpr time::seconds DEFAULT_KDK_FRESHNESS_PERIOD
Definition: common.hpp:92
const name::Component ENCRYPTED_BY
Definition: common.hpp:82
const name::Component KEK
Definition: common.hpp:84
const name::Component NAC
Definition: common.hpp:83