28 #include <Security/Security.h>
31 #include <boost/lexical_cast.hpp>
37 namespace cfstring = detail::cfstring;
38 using detail::CFReleaser;
50 return CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
buf, buflen, kCFAllocatorNull);
53 static CFReleaser<CFMutableDictionaryRef>
56 return CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
57 &kCFTypeDictionaryKeyCallBacks,
58 &kCFTypeDictionaryValueCallBacks);
68 return "<no error message>";
75 if (reason !=
nullptr)
78 return "<unknown reason>";
86 return kSecAttrKeyTypeRSA;
88 return kSecAttrKeyTypeECDSA;
102 return kSecDigestSHA2;
111 switch (digestAlgo) {
134 CFDictionaryAddValue(query.get(), kSecClass, kSecClassKey);
135 CFDictionaryAddValue(query.get(), kSecAttrKeyClass, kSecAttrKeyClassPrivate);
136 CFDictionaryAddValue(query.get(), kSecAttrLabel, keyLabel.get());
137 CFDictionaryAddValue(query.get(), kSecReturnRef, kCFBooleanTrue);
141 OSStatus res = SecItemCopyMatching(query.get(), (CFTypeRef*)&keyRef.
get());
144 if (res == errSecSuccess) {
147 else if (res == errSecItemNotFound) {
162 const char pw[] =
"correct horse battery staple";
165 SecItemImportExportKeyParameters keyParams;
166 std::memset(&keyParams, 0,
sizeof(keyParams));
167 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
168 keyParams.passphrase = passphrase.get();
171 OSStatus res = SecItemExport(keyRef.
get(),
172 kSecFormatWrappedPKCS8,
177 if (res != errSecSuccess) {
181 outKey.
loadPkcs8(CFDataGetBytePtr(exportedKey.
get()), CFDataGetLength(exportedKey.
get()),
182 pw, std::strlen(pw));
186 : m_impl(make_unique<
Impl>())
188 SecKeychainSetUserInteractionAllowed(!m_impl->isTerminalMode);
190 OSStatus res = SecKeychainCopyDefault(&m_impl->keyChainRef);
191 if (res == errSecNoDefaultKeychain) {
201 static std::string scheme =
"tpm-osxkeychain";
208 return m_impl->isTerminalMode;
214 m_impl->isTerminalMode = isTerminal;
215 SecKeychainSetUserInteractionAllowed(!isTerminal);
221 SecKeychainStatus keychainStatus;
222 OSStatus res = SecKeychainGetStatus(m_impl->keyChainRef, &keychainStatus);
223 if (res != errSecSuccess)
226 return (kSecUnlockStateStatus & keychainStatus) == 0;
236 if (m_impl->isTerminalMode) {
238 SecKeychainUnlock(m_impl->keyChainRef, pwLen, pw,
true);
242 SecKeychainUnlock(m_impl->keyChainRef, 0,
nullptr,
false);
253 if (signer ==
nullptr) {
259 SecTransformSetAttribute(signer.
get(), kSecTransformInputAttributeName, data.get(), &error.
get());
260 if (error !=
nullptr) {
265 SecTransformSetAttribute(signer.
get(), kSecPaddingKey, kSecPaddingPKCS1Key, &error.
get());
266 if (error !=
nullptr) {
272 if (error !=
nullptr) {
279 SecTransformSetAttribute(signer.
get(), kSecDigestLengthAttribute, cfDigestSize.
get(), &error.
get());
280 if (error !=
nullptr) {
287 if (signature ==
nullptr) {
291 return make_shared<Buffer>(CFDataGetBytePtr(signature.
get()), CFDataGetLength(signature.
get()));
299 if (decryptor ==
nullptr) {
304 SecTransformSetAttribute(decryptor.
get(), kSecTransformInputAttributeName, data.get(), &error.
get());
305 if (error !=
nullptr) {
309 SecTransformSetAttribute(decryptor.
get(), kSecPaddingKey, kSecPaddingOAEPKey, &error.
get());
310 if (error !=
nullptr) {
316 if (plainText ==
nullptr) {
320 return make_shared<Buffer>(CFDataGetBytePtr(plainText.
get()), CFDataGetLength(plainText.
get()));
332 BackEndOsx::doHasKey(
const Name& keyName)
const
337 unique_ptr<KeyHandle>
338 BackEndOsx::doGetKeyHandle(
const Name& keyName)
const
341 if (keyRef ==
nullptr) {
345 return make_unique<KeyHandleOsx>(keyRef.get());
348 unique_ptr<KeyHandle>
349 BackEndOsx::doCreateKey(
const Name& identityName,
const KeyParams& params)
351 KeyType keyType = params.getKeyType();
356 keySize = rsaParams.getKeySize();
361 keySize = ecParams.getKeySize();
365 NDN_THROW(std::invalid_argument(
"macOS-based TPM does not support creating a key of type " +
366 boost::lexical_cast<std::string>(keyType)));
369 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize);
372 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType,
getAsymKeyType(keyType));
373 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
376 OSStatus res = SecKeyGeneratePair(attrDict.get(), &publicKey.get(), &privateKey.get());
380 if (res != errSecSuccess) {
384 unique_ptr<KeyHandle> keyHandle = make_unique<KeyHandleOsx>(privateKey.get());
386 keyHandle->setKeyName(keyName);
388 SecKeychainAttribute attrs[1];
389 SecKeychainAttributeList attrList = {0, attrs};
390 std::string keyUri = keyName.toUri();
392 attrs[attrList.count].tag = kSecKeyPrintName;
393 attrs[attrList.count].length = keyUri.size();
394 attrs[attrList.count].data =
const_cast<char*
>(keyUri.data());
398 SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)privateKey.get(), &attrList, 0,
nullptr);
399 SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)publicKey.get(), &attrList, 0,
nullptr);
405 BackEndOsx::doDeleteKey(
const Name& keyName)
410 CFDictionaryAddValue(query.get(), kSecClass, kSecClassKey);
411 CFDictionaryAddValue(query.get(), kSecAttrLabel, keyLabel.get());
412 CFDictionaryAddValue(query.get(), kSecMatchLimit, kSecMatchLimitAll);
414 OSStatus res = SecItemDelete(query.get());
416 if (res != errSecSuccess && res != errSecItemNotFound) {
422 BackEndOsx::doExportKey(
const Name& keyName,
const char* pw,
size_t pwLen)
425 if (keychainItem ==
nullptr) {
433 exportedKey.savePkcs8(pkcs8, pw, pwLen);
435 catch (
const transform::PrivateKey::Error&) {
442 BackEndOsx::doImportKey(
const Name& keyName,
const uint8_t*
buf,
size_t size,
443 const char* pw,
size_t pwLen)
449 privKey.loadPkcs8(
buf, size, pw, pwLen);
450 privKey.savePkcs1(pkcs1);
452 catch (
const transform::PrivateKey::Error&) {
455 auto keyToImport =
makeCFDataNoCopy(pkcs1.buf()->data(), pkcs1.buf()->size());
457 SecExternalFormat externalFormat = kSecFormatOpenSSL;
458 SecExternalItemType externalType = kSecItemTypePrivateKey;
460 auto keyUri = keyName.toUri();
462 CFReleaser<SecAccessRef> access;
463 OSStatus res = SecAccessCreate(keyLabel.get(),
467 if (res != errSecSuccess) {
471 SecItemImportExportKeyParameters keyParams;
472 std::memset(&keyParams, 0,
sizeof(keyParams));
473 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
474 keyParams.accessRef = access.get();
476 CFReleaser<CFArrayRef> outItems;
477 res = SecItemImport(keyToImport.get(),
486 if (res != errSecSuccess) {
491 SecKeychainItemRef keychainItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
492 SecKeychainAttribute attrs[1];
493 SecKeychainAttributeList attrList = {0, attrs};
495 attrs[attrList.count].tag = kSecKeyPrintName;
496 attrs[attrList.count].length = keyUri.size();
497 attrs[attrList.count].data =
const_cast<char*
>(keyUri.data());
500 SecKeychainItemModifyAttributesAndData(keychainItem, &attrList, 0,
nullptr);
504 BackEndOsx::doImportKey(
const Name& keyName, shared_ptr<transform::PrivateKey> key)
506 NDN_THROW(
Error(
"macOS-based TPM does not support importing a transform::PrivateKey"));