29 #include <Security/Security.h> 36 namespace cfstring = detail::cfstring;
37 using detail::CFReleaser;
39 class BackEndOsx::Impl
42 SecKeychainRef keyChainRef;
46 static CFReleaser<CFDataRef>
49 return CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buf, buflen, kCFAllocatorNull);
52 static CFReleaser<CFMutableDictionaryRef>
55 return CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
56 &kCFTypeDictionaryKeyCallBacks,
57 &kCFTypeDictionaryValueCallBacks);
63 CFReleaser<CFStringRef> msg = SecCopyErrorMessageString(status,
nullptr);
67 return "<no error message>";
73 CFReleaser<CFStringRef> reason = CFErrorCopyFailureReason(err);
74 if (reason !=
nullptr)
77 return "<unknown reason>";
85 return kSecAttrKeyTypeRSA;
87 return kSecAttrKeyTypeECDSA;
101 return kSecDigestSHA2;
110 switch (digestAlgo) {
133 CFDictionaryAddValue(query.get(), kSecClass, kSecClassKey);
134 CFDictionaryAddValue(query.get(), kSecAttrKeyClass, kSecAttrKeyClassPrivate);
135 CFDictionaryAddValue(query.get(), kSecAttrLabel, keyLabel.get());
136 CFDictionaryAddValue(query.get(), kSecReturnRef, kCFBooleanTrue);
140 OSStatus res = SecItemCopyMatching(query.get(), (CFTypeRef*)&keyRef.get());
143 if (res == errSecSuccess) {
146 else if (res == errSecItemNotFound) {
161 const char pw[] =
"correct horse battery staple";
164 SecItemImportExportKeyParameters keyParams;
165 std::memset(&keyParams, 0,
sizeof(keyParams));
166 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
167 keyParams.passphrase = passphrase.get();
169 CFReleaser<CFDataRef> exportedKey;
170 OSStatus res = SecItemExport(keyRef.
get(),
171 kSecFormatWrappedPKCS8,
176 if (res != errSecSuccess) {
180 outKey.
loadPkcs8(CFDataGetBytePtr(exportedKey.get()), CFDataGetLength(exportedKey.get()),
181 pw, std::strlen(pw));
185 : m_impl(make_unique<Impl>())
187 SecKeychainSetUserInteractionAllowed(!m_impl->isTerminalMode);
189 OSStatus res = SecKeychainCopyDefault(&m_impl->keyChainRef);
190 if (res == errSecNoDefaultKeychain) {
200 static std::string scheme =
"tpm-osxkeychain";
207 return m_impl->isTerminalMode;
213 m_impl->isTerminalMode = isTerminal;
214 SecKeychainSetUserInteractionAllowed(!isTerminal);
220 SecKeychainStatus keychainStatus;
221 OSStatus res = SecKeychainGetStatus(m_impl->keyChainRef, &keychainStatus);
222 if (res != errSecSuccess)
225 return (kSecUnlockStateStatus & keychainStatus) == 0;
235 if (m_impl->isTerminalMode) {
237 SecKeychainUnlock(m_impl->keyChainRef, pwLen, pw,
true);
241 SecKeychainUnlock(m_impl->keyChainRef, 0,
nullptr,
false);
250 CFReleaser<CFErrorRef> error;
251 CFReleaser<SecTransformRef> signer = SecSignTransformCreate(key.
get(), &error.get());
252 if (signer ==
nullptr) {
258 SecTransformSetAttribute(signer.get(), kSecTransformInputAttributeName, data.get(), &error.get());
259 if (error !=
nullptr) {
264 SecTransformSetAttribute(signer.get(), kSecPaddingKey, kSecPaddingPKCS1Key, &error.get());
265 if (error !=
nullptr) {
270 SecTransformSetAttribute(signer.get(), kSecDigestTypeAttribute,
getDigestAlgorithm(digestAlgo), &error.get());
271 if (error !=
nullptr) {
277 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &digestSize);
278 SecTransformSetAttribute(signer.get(), kSecDigestLengthAttribute, cfDigestSize.get(), &error.get());
279 if (error !=
nullptr) {
285 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
286 if (signature ==
nullptr) {
290 return make_shared<Buffer>(CFDataGetBytePtr(signature.get()), CFDataGetLength(signature.get()));
296 CFReleaser<CFErrorRef> error;
297 CFReleaser<SecTransformRef> decryptor = SecDecryptTransformCreate(key.
get(), &error.get());
298 if (decryptor ==
nullptr) {
303 SecTransformSetAttribute(decryptor.get(), kSecTransformInputAttributeName, data.get(), &error.get());
304 if (error !=
nullptr) {
308 SecTransformSetAttribute(decryptor.get(), kSecPaddingKey, kSecPaddingOAEPKey, &error.get());
309 if (error !=
nullptr) {
314 CFReleaser<CFDataRef> plainText = (CFDataRef)SecTransformExecute(decryptor.get(), &error.get());
315 if (plainText ==
nullptr) {
319 return make_shared<Buffer>(CFDataGetBytePtr(plainText.get()), CFDataGetLength(plainText.get()));
331 BackEndOsx::doHasKey(
const Name& keyName)
const 336 unique_ptr<KeyHandle>
337 BackEndOsx::doGetKeyHandle(
const Name& keyName)
const 340 if (keyRef ==
nullptr) {
344 return make_unique<KeyHandleOsx>(keyRef.
get());
347 unique_ptr<KeyHandle>
348 BackEndOsx::doCreateKey(
const Name& identityName,
const KeyParams& params)
367 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize);
370 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType,
getAsymKeyType(keyType));
371 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
374 OSStatus res = SecKeyGeneratePair(attrDict.get(), &publicKey.get(), &privateKey.get());
378 if (res != errSecSuccess) {
382 unique_ptr<KeyHandle> keyHandle = make_unique<KeyHandleOsx>(privateKey.get());
385 SecKeychainAttribute attrs[1];
386 SecKeychainAttributeList attrList = {0, attrs};
387 std::string keyUri = keyHandle->getKeyName().toUri();
389 attrs[attrList.count].tag = kSecKeyPrintName;
390 attrs[attrList.count].length = keyUri.size();
391 attrs[attrList.count].data =
const_cast<char*
>(keyUri.data());
395 SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)privateKey.get(), &attrList, 0,
nullptr);
396 SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)publicKey.get(), &attrList, 0,
nullptr);
402 BackEndOsx::doDeleteKey(
const Name& keyName)
407 CFDictionaryAddValue(query.get(), kSecClass, kSecClassKey);
408 CFDictionaryAddValue(query.get(), kSecAttrLabel, keyLabel.get());
409 CFDictionaryAddValue(query.get(), kSecMatchLimit, kSecMatchLimitAll);
411 OSStatus res = SecItemDelete(query.get());
413 if (res != errSecSuccess && res != errSecItemNotFound) {
419 BackEndOsx::doExportKey(
const Name& keyName,
const char* pw,
size_t pwLen)
422 if (keychainItem ==
nullptr) {
439 BackEndOsx::doImportKey(
const Name& keyName,
const uint8_t* buf,
size_t size,
440 const char* pw,
size_t pwLen)
454 SecExternalFormat externalFormat = kSecFormatOpenSSL;
455 SecExternalItemType externalType = kSecItemTypePrivateKey;
457 auto keyUri = keyName.
toUri();
459 CFReleaser<SecAccessRef> access;
460 OSStatus res = SecAccessCreate(keyLabel.get(),
464 if (res != errSecSuccess) {
468 SecItemImportExportKeyParameters keyParams;
469 std::memset(&keyParams, 0,
sizeof(keyParams));
470 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
471 keyParams.accessRef = access.get();
473 CFReleaser<CFArrayRef> outItems;
474 res = SecItemImport(keyToImport.get(),
483 if (res != errSecSuccess) {
488 SecKeychainItemRef keychainItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
489 SecKeychainAttribute attrs[1];
490 SecKeychainAttributeList attrList = {0, attrs};
492 attrs[attrList.count].tag = kSecKeyPrintName;
493 attrs[attrList.count].length = keyUri.size();
494 attrs[attrList.count].data =
const_cast<char*
>(keyUri.data());
497 SecKeychainItemModifyAttributesAndData(keychainItem, &attrList, 0,
nullptr);
#define NDN_THROW_NESTED(e)
static CFReleaser< CFDataRef > makeCFDataNoCopy(const uint8_t *buf, size_t buflen)
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...
static ConstBufferPtr decrypt(const KeyRefOsx &key, const uint8_t *cipherText, size_t cipherSize)
bool isTpmLocked() const final
Check if the TPM is locked.
std::string toStdString(CFStringRef cfStr)
Convert a CFString to a std::string.
static CFReleaser< CFMutableDictionaryRef > makeCFMutableDictionary()
KeyType getKeyType() const
uint32_t getKeySize() const
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()
std::string toUri() const
Get URI representation of the name.
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 SHA256 hash of the public key as the key id.
Represents an absolute name.
static void setKeyName(KeyHandle &keyHandle, const Name &identity, const KeyParams ¶ms)
Set the key name in keyHandle according to identity and params.
Helper class to wrap CoreFoundation object pointers.
static ConstBufferPtr sign(const KeyRefOsx &key, DigestAlgorithm digestAlgorithm, const uint8_t *buf, size_t size)
Sign buf with key using digestAlgorithm.
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.
Base class of key parameters.
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.
shared_ptr< const Buffer > ConstBufferPtr