31 #include <Security/Security.h> 34 #include <boost/lexical_cast.hpp> 40 namespace cfstring = detail::cfstring;
41 using detail::CFReleaser;
53 return CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buf.data(), buf.size(), kCFAllocatorNull);
59 return CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
60 &kCFTypeDictionaryKeyCallBacks,
61 &kCFTypeDictionaryValueCallBacks);
71 return "<no error message>";
78 if (reason !=
nullptr)
81 return "<unknown reason>";
89 return kSecAttrKeyTypeRSA;
91 return kSecAttrKeyTypeECDSA;
100 switch (digestAlgo) {
105 return kSecDigestSHA2;
114 switch (digestAlgo) {
137 CFDictionaryAddValue(query.get(), kSecClass, kSecClassKey);
138 CFDictionaryAddValue(query.get(), kSecAttrKeyClass, kSecAttrKeyClassPrivate);
139 CFDictionaryAddValue(query.get(), kSecAttrLabel, keyLabel.get());
140 CFDictionaryAddValue(query.get(), kSecReturnRef, kCFBooleanTrue);
144 OSStatus res = SecItemCopyMatching(query.get(), (CFTypeRef*)&keyRef.get());
147 if (res == errSecSuccess) {
150 else if (res == errSecItemNotFound) {
165 const char pw[] =
"correct horse battery staple";
168 SecItemImportExportKeyParameters keyParams;
169 std::memset(&keyParams, 0,
sizeof(keyParams));
170 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
171 keyParams.passphrase = passphrase.get();
174 OSStatus res = SecItemExport(keyRef.
get(),
175 kSecFormatWrappedPKCS8,
180 if (res != errSecSuccess) {
184 auto keyPtr = CFDataGetBytePtr(exportedKey.
get());
185 auto keyLen =
static_cast<size_t>(CFDataGetLength(exportedKey.
get()));
186 outKey.
loadPkcs8({keyPtr, keyLen}, pw, std::strlen(pw));
190 : m_impl(make_unique<
Impl>())
192 SecKeychainSetUserInteractionAllowed(!m_impl->isTerminalMode);
194 OSStatus res = SecKeychainCopyDefault(&m_impl->keyChainRef);
195 if (res == errSecNoDefaultKeychain) {
205 static std::string scheme =
"tpm-osxkeychain";
212 return m_impl->isTerminalMode;
218 m_impl->isTerminalMode = isTerminal;
219 SecKeychainSetUserInteractionAllowed(!isTerminal);
225 SecKeychainStatus keychainStatus;
226 OSStatus res = SecKeychainGetStatus(m_impl->keyChainRef, &keychainStatus);
227 if (res != errSecSuccess)
230 return (kSecUnlockStateStatus & keychainStatus) == 0;
240 if (m_impl->isTerminalMode) {
242 SecKeychainUnlock(m_impl->keyChainRef, pwLen, pw,
true);
246 SecKeychainUnlock(m_impl->keyChainRef, 0,
nullptr,
false);
257 if (signer ==
nullptr) {
267 auto buffer = digestSink.buf();
268 BOOST_ASSERT(buffer->size() * 8 ==
static_cast<size_t>(
getDigestSize(digestAlgo)));
270 SecTransformSetAttribute(signer.
get(), kSecTransformInputAttributeName, data.get(), &error.
get());
271 if (error !=
nullptr) {
276 SecTransformSetAttribute(signer.
get(), kSecInputIsAttributeName, kSecInputIsDigest, &error.
get());
277 if (error !=
nullptr) {
282 SecTransformSetAttribute(signer.
get(), kSecPaddingKey, kSecPaddingPKCS1Key, &error.
get());
283 if (error !=
nullptr) {
289 if (error !=
nullptr) {
296 SecTransformSetAttribute(signer.
get(), kSecDigestLengthAttribute, cfDigestSize.
get(), &error.
get());
297 if (error !=
nullptr) {
304 if (signature ==
nullptr) {
308 return make_shared<Buffer>(CFDataGetBytePtr(signature.get()), CFDataGetLength(signature.get()));
316 if (decryptor ==
nullptr) {
321 SecTransformSetAttribute(decryptor.
get(), kSecTransformInputAttributeName, data.get(), &error.
get());
322 if (error !=
nullptr) {
326 SecTransformSetAttribute(decryptor.
get(), kSecPaddingKey, kSecPaddingOAEPKey, &error.
get());
327 if (error !=
nullptr) {
333 if (plainText ==
nullptr) {
337 return make_shared<Buffer>(CFDataGetBytePtr(plainText.get()), CFDataGetLength(plainText.get()));
349 BackEndOsx::doHasKey(
const Name& keyName)
const 354 unique_ptr<KeyHandle>
355 BackEndOsx::doGetKeyHandle(
const Name& keyName)
const 358 if (keyRef ==
nullptr) {
362 return make_unique<KeyHandleOsx>(keyRef.
get());
365 unique_ptr<KeyHandle>
366 BackEndOsx::doCreateKey(
const Name& identityName,
const KeyParams& params)
382 NDN_THROW(std::invalid_argument(
"macOS-based TPM does not support creating a key of type " +
383 boost::lexical_cast<std::string>(keyType)));
389 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType,
getAsymKeyType(keyType));
390 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.
get());
393 OSStatus res = SecKeyGeneratePair(attrDict.get(), &publicKey.get(), &privateKey.get());
397 if (res != errSecSuccess) {
401 unique_ptr<KeyHandle> keyHandle = make_unique<KeyHandleOsx>(privateKey.get());
403 keyHandle->setKeyName(keyName);
405 SecKeychainAttribute attrs[1];
406 SecKeychainAttributeList attrList = {0, attrs};
407 std::string keyUri = keyName.toUri();
409 attrs[attrList.count].tag = kSecKeyPrintName;
410 attrs[attrList.count].length = keyUri.size();
411 attrs[attrList.count].data =
const_cast<char*
>(keyUri.data());
415 SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)privateKey.get(), &attrList, 0,
nullptr);
416 SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)publicKey.get(), &attrList, 0,
nullptr);
422 BackEndOsx::doDeleteKey(
const Name& keyName)
427 CFDictionaryAddValue(query.get(), kSecClass, kSecClassKey);
428 CFDictionaryAddValue(query.get(), kSecAttrLabel, keyLabel.get());
429 CFDictionaryAddValue(query.get(), kSecMatchLimit, kSecMatchLimitAll);
431 OSStatus res = SecItemDelete(query.get());
433 if (res != errSecSuccess && res != errSecItemNotFound) {
439 BackEndOsx::doExportKey(
const Name& keyName,
const char* pw,
size_t pwLen)
442 if (keychainItem ==
nullptr) {
459 BackEndOsx::doImportKey(
const Name& keyName, span<const uint8_t> pkcs8,
const char* pw,
size_t pwLen)
473 SecExternalFormat externalFormat = kSecFormatOpenSSL;
474 SecExternalItemType externalType = kSecItemTypePrivateKey;
476 auto keyUri = keyName.
toUri();
479 OSStatus res = SecAccessCreate(keyLabel.get(),
483 if (res != errSecSuccess) {
487 SecItemImportExportKeyParameters keyParams;
488 std::memset(&keyParams, 0,
sizeof(keyParams));
489 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
490 keyParams.accessRef = access.
get();
493 res = SecItemImport(keyToImport.get(),
502 if (res != errSecSuccess) {
507 SecKeychainItemRef keychainItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.
get(), 0);
508 SecKeychainAttribute attrs[1];
509 SecKeychainAttributeList attrList = {0, attrs};
511 attrs[attrList.count].tag = kSecKeyPrintName;
512 attrs[attrList.count].length = keyUri.size();
513 attrs[attrList.count].data =
const_cast<char*
>(keyUri.data());
516 SecKeychainItemModifyAttributesAndData(keychainItem, &attrList, 0,
nullptr);
520 BackEndOsx::doImportKey(
const Name& keyName, shared_ptr<transform::PrivateKey> key)
522 NDN_THROW(
Error(
"macOS-based TPM does not support importing a transform::PrivateKey"));
#define NDN_THROW_NESTED(e)
CFReleaser< CFStringRef > fromStdString(const std::string &str)
Create a CFString by copying characters from a std::string.
This file contains utilities to deal with Apple Core Foundation's CFString and related types...
bool isTpmLocked() const final
Check if the TPM is locked.
Copyright (c) 2011-2015 Regents of the University of California.
std::string toStdString(CFStringRef cfStr)
Convert a CFString to a std::string.
static CFReleaser< CFMutableDictionaryRef > makeCFMutableDictionary()
SecKeychainRef keyChainRef
RSA key, supports sign/verify and encrypt/decrypt operations.
static CFTypeRef getDigestAlgorithm(DigestAlgorithm digestAlgo)
static KeyRefOsx getKeyRef(const Name &keyName)
Get reference to private key with name keyName.
static std::string getErrorMessage(OSStatus status)
KeyType
The type of a cryptographic key.
static const std::string & getScheme()
Name constructAsymmetricKeyName(const KeyHandle &key, const Name &identity, const KeyParams ¶ms) const
Construct and return the name of a RSA or EC key, based on identity and params.
bool isTerminalMode() const final
Check if the TPM is in terminal mode.
void setTerminalMode(bool isTerminal) const final
Set the terminal mode of the TPM.
void retain(const T &typeRef)
static CFTypeRef getAsymKeyType(KeyType keyType)
static int getDigestSize(DigestAlgorithm digestAlgo)
static ConstBufferPtr derivePublicKey(const KeyRefOsx &key)
BackEndOsx(const std::string &location="")
Create TPM backed based on macOS Keychain Services.
bool unlockTpm(const char *pw, size_t pwLen) const final
Unlock the TPM.
Elliptic Curve key (e.g. for ECDSA), supports sign/verify operations.
Use the SHA-256 hash of the public key as key id.
Represents an absolute name.
KeyType getKeyType() const
static CFReleaser< CFDataRef > makeCFDataNoCopy(span< const uint8_t > buf)
Helper class to wrap CoreFoundation object pointers.
CFReleaser< CFStringRef > fromBuffer(const uint8_t *buf, size_t buflen)
Create a CFString by copying bytes from a raw buffer.
shared_ptr< Buffer > buf()
Flush written data to the stream and return shared pointer to the underlying buffer.
#define NDN_CXX_UNREACHABLE
Base class for key parameters.
void toUri(std::ostream &os, name::UriFormat format=name::UriFormat::DEFAULT) const
Write URI representation of the name to the output stream.
uint32_t getKeySize() const
static std::string getFailureReason(CFErrorRef err)
implements an output stream that constructs ndn::Buffer
static void exportItem(const KeyRefOsx &keyRef, transform::PrivateKey &outKey)
Export a private key from the Keychain to outKey.
SimplePublicKeyParams is a template for public keys with only one parameter: size.
static ConstBufferPtr decrypt(const KeyRefOsx &key, span< const uint8_t > cipherText)
Decrypt cipherText with key.
static ConstBufferPtr sign(const KeyRefOsx &key, DigestAlgorithm digestAlgorithm, const InputBuffers &bufs)
Sign bufs with key using digestAlgorithm.
shared_ptr< const Buffer > ConstBufferPtr