26 #include "ndn-cxx/security/pib/impl/pib-memory.hpp"
27 #include "ndn-cxx/security/pib/impl/pib-sqlite3.hpp"
29 #include "ndn-cxx/security/tpm/impl/back-end-file.hpp"
30 #include "ndn-cxx/security/tpm/impl/back-end-mem.hpp"
31 #ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS
32 #include "ndn-cxx/security/tpm/impl/back-end-osx.hpp"
46 #include <boost/lexical_cast.hpp>
63 #ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS
72 KeyChain::PibFactories&
73 KeyChain::getPibFactories()
75 static PibFactories pibFactories;
79 KeyChain::TpmFactories&
80 KeyChain::getTpmFactories()
82 static TpmFactories tpmFactories;
89 return pib::PibSqlite3::getScheme();
95 #ifdef NDN_CXX_WITH_OSX_KEYCHAIN
96 return tpm::BackEndOsx::getScheme();
98 return tpm::BackEndFile::getScheme();
111 class KeyChain::Locator
115 empty() const noexcept
117 return scheme.empty();
120 [[nodiscard]] std::string
123 return scheme +
':' + location;
127 operator==(
const Locator& lhs,
const Locator& rhs) noexcept
129 return lhs.scheme == rhs.scheme && lhs.location == rhs.location;
134 std::string location;
137 KeyChain::Locator KeyChain::s_defaultPibLocator;
138 KeyChain::Locator KeyChain::s_defaultTpmLocator;
143 :
KeyChain(getDefaultPibLocator(), getDefaultTpmLocator(), true)
148 :
KeyChain(parseAndCheckPibLocator(pibLocator),
149 parseAndCheckTpmLocator(tpmLocator),
157 auto pibFactory = getPibFactories().find(pibLocator.scheme);
158 BOOST_ASSERT(pibFactory != getPibFactories().end());
159 m_pib.reset(
new Pib(pibLocator.canonical(), pibFactory->second(pibLocator.location)));
162 std::string oldTpmLocator = m_pib->getTpmLocator();
163 if (pibLocator == getDefaultPibLocator()) {
165 if (!oldTpmLocator.empty() && oldTpmLocator != getDefaultTpmLocator().canonical()) {
167 tpmLocator = getDefaultTpmLocator();
172 if (!oldTpmLocator.empty() && oldTpmLocator != tpmLocator.canonical()) {
176 NDN_THROW(LocatorMismatchError(
"Supplied TPM locator (" + tpmLocator.canonical() +
177 ") does not match TPM locator in PIB (" + oldTpmLocator +
")"));
185 auto tpmFactory = getTpmFactories().find(tpmLocator.scheme);
186 BOOST_ASSERT(tpmFactory != getTpmFactories().end());
187 m_tpm.reset(
new Tpm(tpmLocator.canonical(), tpmFactory->second(tpmLocator.location)));
190 m_pib->setTpmLocator(tpmLocator.canonical());
200 NDN_LOG_DEBUG(
"Requesting creation of identity " << identityName);
201 Identity id = m_pib->addIdentity(identityName);
205 key =
id.getDefaultKey();
215 NDN_LOG_DEBUG(
"No default certificate for " << key <<
", requesting self-signing");
230 NDN_LOG_DEBUG(
"Requesting deletion of identity " << identityName);
232 for (
const auto& key : identity.
getKeys()) {
233 m_tpm->deleteKey(key.getName());
236 m_pib->removeIdentity(identityName);
242 BOOST_ASSERT(identity);
244 m_pib->setDefaultIdentity(identity.
getName());
250 BOOST_ASSERT(identity);
253 Name keyName = m_tpm->createKey(identity.
getName(), params);
256 Key key = identity.addKey(*m_tpm->getPublicKey(keyName), keyName);
258 NDN_LOG_DEBUG(
"Requesting self-signing for newly created key " << key);
267 return m_tpm->createKey(prefix, params);
273 BOOST_ASSERT(identity);
279 identity.removeKey(keyName);
280 m_tpm->deleteKey(keyName);
286 BOOST_ASSERT(identity);
289 identity.setDefaultKey(key.
getName());
297 key.addCertificate(certificate);
305 key.removeCertificate(certName);
313 key.setDefaultCertificate(cert);
323 encryptedKey = m_tpm->exportPrivateKey(keyName, pw, pwLen);
329 return make_shared<SafeBag>(certificate, *encryptedKey);
340 if (m_tpm->hasKey(keyName)) {
346 m_pib->getIdentity(identity).getKey(keyName);
354 m_tpm->importPrivateKey(keyName, safeBag.
getEncryptedKey(), pw, pwLen);
362 const auto msg = make_span(
reinterpret_cast<const uint8_t*
>(&r),
sizeof(r));
367 catch (
const std::runtime_error&) {
368 m_tpm->deleteKey(keyName);
372 m_tpm->deleteKey(keyName);
374 "and private key `" + keyName.
toUri() +
"` do not match"));
377 Identity id = m_pib->addIdentity(identity);
379 key.addCertificate(cert);
385 if (m_tpm->hasKey(keyName)) {
390 m_tpm->importPrivateKey(keyName, std::move(key));
402 auto [keyName, sigInfo] = prepareSignatureInfo(params);
415 auto [keyName, sigInfo] = prepareSignatureInfo(params);
429 signedName.
append(sigInfoBlock);
434 signedName.
append(sigValue);
457 NDN_THROW_NESTED(std::invalid_argument(
"Certificate request contains invalid public key"));
465 static std::tuple<std::string, std::string>
466 parseLocatorUri(
const std::string& uri)
468 if (
auto pos = uri.find(
':'); pos != std::string::npos) {
469 return {uri.substr(0, pos), uri.substr(pos + 1)};
477 KeyChain::parseAndCheckPibLocator(
const std::string& pibLocator)
479 auto [pibScheme, pibLocation] = parseLocatorUri(pibLocator);
480 if (pibScheme.empty()) {
481 pibScheme = getDefaultPibScheme();
484 auto pibFactory = getPibFactories().find(pibScheme);
485 if (pibFactory == getPibFactories().end()) {
486 NDN_THROW(Error(
"PIB scheme `" + pibScheme +
"` is not supported"));
489 return {pibScheme, pibLocation};
493 KeyChain::parseAndCheckTpmLocator(
const std::string& tpmLocator)
495 auto [tpmScheme, tpmLocation] = parseLocatorUri(tpmLocator);
496 if (tpmScheme.empty()) {
497 tpmScheme = getDefaultTpmScheme();
500 auto tpmFactory = getTpmFactories().find(tpmScheme);
501 if (tpmFactory == getTpmFactories().end()) {
502 NDN_THROW(Error(
"TPM scheme `" + tpmScheme +
"` is not supported"));
505 return {tpmScheme, tpmLocation};
508 const KeyChain::Locator&
509 KeyChain::getDefaultPibLocator()
511 if (!s_defaultPibLocator.empty())
512 return s_defaultPibLocator;
515 const char* pibEnv = std::getenv(
"NDN_CLIENT_PIB");
516 if (pibEnv !=
nullptr) {
521 input = config.getParsedConfiguration().get<std::string>(
"pib", getDefaultPibScheme());
524 s_defaultPibLocator = parseAndCheckPibLocator(input);
525 BOOST_ASSERT(!s_defaultPibLocator.empty());
526 return s_defaultPibLocator;
529 const KeyChain::Locator&
530 KeyChain::getDefaultTpmLocator()
532 if (!s_defaultTpmLocator.empty())
533 return s_defaultTpmLocator;
536 const char* tpmEnv = std::getenv(
"NDN_CLIENT_TPM");
537 if (tpmEnv !=
nullptr) {
542 input = config.getParsedConfiguration().get<std::string>(
"tpm", getDefaultTpmScheme());
545 s_defaultTpmLocator = parseAndCheckTpmLocator(input);
546 BOOST_ASSERT(!s_defaultTpmLocator.empty());
547 return s_defaultTpmLocator;
550 #ifdef NDN_CXX_WITH_TESTS
552 KeyChain::resetDefaultLocators()
554 s_defaultPibLocator = {};
555 s_defaultTpmLocator = {};
563 SigningInfo params,
const MakeCertificateOptions& opts)
565 if (opts.freshnessPeriod <= 0_ms) {
568 NDN_THROW(std::invalid_argument(
"FreshnessPeriod is not positive"));
572 name.append(opts.issuerId);
573 name.appendVersion(opts.version);
578 data.setFreshnessPeriod(opts.freshnessPeriod);
579 data.setContent(publicKey);
581 auto sigInfo = params.getSignatureInfo();
586 params.setSignatureInfo(sigInfo);
590 return Certificate(std::move(data));
594 KeyChain::selfSign(Key& key)
596 MakeCertificateOptions opts;
597 opts.issuerId =
SELF;
603 key.addCertificate(cert);
607 std::tuple<Name, SignatureInfo>
608 KeyChain::prepareSignatureInfo(
const SigningInfo& params)
610 switch (params.getSignerType()) {
612 pib::Identity identity;
614 identity = m_pib->getDefaultIdentity();
616 catch (
const Pib::Error&) {
617 return prepareSignatureInfoSha256(params);
619 return prepareSignatureInfoWithIdentity(params, identity);
622 auto identity = params.getPibIdentity();
624 auto identityName = params.getSignerName();
626 identity = m_pib->getIdentity(identityName);
628 catch (
const Pib::Error&) {
630 identityName.toUri() +
"` does not exist"));
634 NDN_THROW(InvalidSigningInfoError(
"Cannot determine signing parameters"));
636 return prepareSignatureInfoWithIdentity(params, identity);
639 auto key = params.getPibKey();
641 auto keyName = params.getSignerName();
644 key = m_pib->getIdentity(identityName).getKey(keyName);
646 catch (
const Pib::Error&) {
648 keyName.toUri() +
"` does not exist"));
652 NDN_THROW(InvalidSigningInfoError(
"Cannot determine signing parameters"));
654 return prepareSignatureInfoWithKey(params, key);
657 auto certName = params.getSignerName();
662 key = m_pib->getIdentity(identityName).getKey(keyName);
664 catch (
const Pib::Error&) {
666 certName.toUri() +
"` does not exist"));
668 return prepareSignatureInfoWithKey(params, key, certName);
671 return prepareSignatureInfoSha256(params);
674 return prepareSignatureInfoHmac(params, *m_tpm);
677 NDN_THROW(InvalidSigningInfoError(
"Unrecognized signer type " +
681 std::tuple<Name, SignatureInfo>
682 KeyChain::prepareSignatureInfoSha256(
const SigningInfo& params)
684 auto sigInfo = params.getSignatureInfo();
691 std::tuple<Name, SignatureInfo>
692 KeyChain::prepareSignatureInfoHmac(
const SigningInfo& params, Tpm& tpm)
694 const Name& keyName = params.getSignerName();
695 if (!tpm.hasKey(keyName)) {
696 tpm.importPrivateKey(keyName, params.getHmacKey());
699 auto sigInfo = params.getSignatureInfo();
700 sigInfo.setSignatureType(getSignatureType(
KeyType::HMAC, params.getDigestAlgorithm()));
701 sigInfo.setKeyLocator(keyName);
704 return {keyName, sigInfo};
707 std::tuple<Name, SignatureInfo>
708 KeyChain::prepareSignatureInfoWithIdentity(
const SigningInfo& params,
const pib::Identity& identity)
712 key = identity.getDefaultKey();
714 catch (
const Pib::Error&) {
715 NDN_THROW_NESTED(InvalidSigningInfoError(
"Signing identity `" + identity.getName().toUri() +
716 "` does not have a default key"));
718 return prepareSignatureInfoWithKey(params, key);
721 std::tuple<Name, SignatureInfo>
722 KeyChain::prepareSignatureInfoWithKey(
const SigningInfo& params,
const pib::Key& key,
723 const std::optional<Name>& certName)
725 auto sigInfo = params.getSignatureInfo();
726 sigInfo.setSignatureType(getSignatureType(key.getKeyType(), params.getDigestAlgorithm()));
727 if (!sigInfo.hasKeyLocator()) {
729 sigInfo.setKeyLocator(certName);
732 Name klName = key.getName();
734 klName = key.getDefaultCertificate().getName();
736 catch (
const Pib::Error&) {
738 sigInfo.setKeyLocator(klName);
743 return {key.getName(), sigInfo};
749 using namespace transform;
757 auto signature = m_tpm->sign(
bufs, keyName, digestAlgorithm);
759 NDN_THROW(InvalidSigningInfoError(
"TPM signing failed for key `" + keyName.toUri() +
"` "
760 "(e.g., PIB contains info about the key, but TPM is missing "
761 "the corresponding private key)"));
778 NDN_THROW(Error(
"Unsupported key type " + boost::lexical_cast<std::string>(keyType)));
Represents a TLV element of the NDN packet format.
void encode()
Encode sub-elements into TLV-VALUE.
Represents a Data packet.
size_t wireEncode(EncodingImpl< TAG > &encoder, bool wantUnsignedPortionOnly=false) const
Prepend wire encoding to encoder.
const Name & getName() const noexcept
Get the Data name.
Data & setSignatureInfo(const SignatureInfo &info)
Set the SignatureInfo element.
Represents an Interest packet.
const Name & getName() const noexcept
Get the Interest name.
Interest & setSignatureValue(span< const uint8_t > value)
Set InterestSignatureValue by copying from a contiguous sequence of bytes.
InputBuffers extractSignedRanges() const
Extract ranges of Interest covered by the signature.
Interest & setName(const Name &name)
Set the Interest name.
Interest & setSignatureInfo(const SignatureInfo &info)
Set the InterestSignatureInfo element.
Base class for key parameters.
Represents an absolute name.
Name & append(const Component &component)
Append a name component.
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Prepend wire encoding to encoder.
void toUri(std::ostream &os, name::UriFormat format=name::UriFormat::DEFAULT) const
Write URI representation of the name to the output stream.
SimplePublicKeyParams is a template for public keys with only one parameter: size.
SimpleSymmetricKeyParams is a template for symmetric keys with only one parameter: size.
Represents a name component.
Represents an NDN certificate.
span< const uint8_t > getPublicKey() const noexcept
Return the public key as a DER-encoded SubjectPublicKeyInfo structure, i.e., exactly as it appears in...
Name getKeyName() const
Get key name.
Name getIdentity() const
Get identity name.
The main interface for signing key management.
void sign(Data &data, const SigningInfo ¶ms=SigningInfo())
Sign a Data packet according to the supplied signing information.
void setDefaultCertificate(const Key &key, const Certificate &cert)
Set cert as the default certificate of key.
void addCertificate(const Key &key, const Certificate &cert)
Add a certificate cert for key.
void importPrivateKey(const Name &keyName, shared_ptr< transform::PrivateKey > key)
Import a private key into the TPM.
void importSafeBag(const SafeBag &safeBag, const char *pw, size_t pwLen)
Import a certificate and its corresponding private key from a SafeBag.
static const KeyParams & getDefaultKeyParams()
shared_ptr< SafeBag > exportSafeBag(const Certificate &certificate, const char *pw, size_t pwLen)
Export a certificate and its corresponding private key.
void deleteIdentity(const Identity &identity)
Delete identity from this KeyChain.
Key createKey(const Identity &identity, const KeyParams ¶ms=getDefaultKeyParams())
Create a new key for identity.
void setDefaultIdentity(const Identity &identity)
Set identity as the default identity.
void setDefaultKey(const Identity &identity, const Key &key)
Set key as the default key of identity.
Name createHmacKey(const Name &prefix=SigningInfo::getHmacIdentity(), const HmacKeyParams ¶ms=HmacKeyParams())
Create a new HMAC key.
KeyChain()
Constructor to create KeyChain with default PIB and TPM.
Certificate makeCertificate(const pib::Key &publicKey, const SigningInfo ¶ms=SigningInfo(), const MakeCertificateOptions &opts={})
Create and sign a certificate packet.
Identity createIdentity(const Name &identityName, const KeyParams ¶ms=getDefaultKeyParams())
Create an identity identityName.
void deleteKey(const Identity &identity, const Key &key)
Delete key from identity.
void deleteCertificate(const Key &key, const Name &certName)
Delete a certificate with name certName from key.
A secured container for sensitive information (certificate, private key)
span< const uint8_t > getEncryptedKey() const
Get the private key in PKCS #8 format from safe bag.
const Data & getCertificate() const
Get the certificate data packet from safe bag.
Signing parameters passed to KeyChain.
static const Name & getDigestSha256Identity()
A localhost identity to indicate that the signature is generated using SHA-256.
@ SIGNER_TYPE_CERT
Signer is a certificate, use it directly.
@ SIGNER_TYPE_SHA256
Use a SHA-256 digest only, no signer needs to be specified.
@ SIGNER_TYPE_HMAC
Signer is a HMAC key.
@ SIGNER_TYPE_NULL
No signer is specified, use default setting or follow the trust schema.
@ SIGNER_TYPE_ID
Signer is an identity, use its default key and default certificate.
@ SIGNER_TYPE_KEY
Signer is a key, use its default certificate.
SignedInterestFormat getSignedInterestFormat() const
Get the signed Interest format.
DigestAlgorithm getDigestAlgorithm() const
Get the digest algorithm for signing operations.
static ValidityPeriod makeRelative(time::seconds validFrom, time::seconds validUntil, const time::system_clock::time_point &now=time::system_clock::now())
Construct ValidityPeriod relative to a timepoint.
Frontend handle for an identity in the PIB.
const KeyContainer & getKeys() const
Return all the keys of this identity.
const Name & getName() const
Return the name of the identity.
Frontend handle for a key in the PIB.
const Certificate & getDefaultCertificate() const
Return the default certificate for this key.
span< const uint8_t > getPublicKey() const
Return the raw public key bits.
const Name & getName() const
Return the name of the key.
Represents a semantic error.
Frontend to the Public Information Base.
#define NDN_THROW_NESTED(e)
#define NDN_CXX_KEYCHAIN_REGISTER_PIB_BACKEND(PibType)
Register Pib backend class in KeyChain.
#define NDN_CXX_KEYCHAIN_REGISTER_TPM_BACKEND(TpmType)
Register Tpm backend class in KeyChain.
#define NDN_LOG_DEBUG(expression)
Log at DEBUG level.
#define NDN_LOG_TRACE(expression)
Log at TRACE level.
#define NDN_LOG_INIT(name)
Define a non-member log module.
EncodingImpl< EncoderTag > EncodingBuffer
std::string to_string(const errinfo_stacktrace &x)
uint64_t generateWord64()
Generate a non-cryptographically-secure random integer in the range [0, 2^64).
Contains the ndn-cxx security framework.
Name extractIdentityFromKeyName(const Name &keyName)
Extract identity namespace from the key name keyName.
SigningInfo signingByKey(const Name &keyName)
Return a SigningInfo for signing with a key.
bool verifySignature(const InputBuffers &blobs, span< const uint8_t > sig, const transform::PublicKey &key)
Verify blobs using key against sig.
const name::Component SELF
Name extractIdentityFromCertName(const Name &certName)
Extract identity namespace from the certificate name certName.
@ V03
Sign Interest using Packet Specification v0.3 semantics.
Name extractKeyNameFromCertName(const Name &certName)
Extract key name from the certificate name certName.
@ ContentType_Key
public key, certificate
SignatureTypeValue
SignatureType values.
@ SignatureHmacWithSha256
@ SignatureSha256WithEcdsa
bool operator==(const Data &lhs, const Data &rhs)
KeyType
The type of a cryptographic key.
@ EC
Elliptic Curve key (e.g. for ECDSA), supports sign/verify operations.
@ RSA
RSA key, supports sign/verify and encrypt/decrypt operations.
@ HMAC
HMAC key, supports sign/verify operations.
std::shared_ptr< const Buffer > ConstBufferPtr
Options to KeyChain::makeCertificate().