25 #include "../transform/private-key.hpp" 27 #include <CoreServices/CoreServices.h> 28 #include <Security/SecDigestTransform.h> 29 #include <Security/SecRandom.h> 30 #include <Security/Security.h> 36 using util::CFReleaser;
56 kCFStringEncodingUTF8);
59 CFDictionaryCreateMutable(
nullptr, 5, &kCFTypeDictionaryKeyCallBacks,
nullptr);
61 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
62 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.
get());
63 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, kSecAttrKeyClassPrivate);
64 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
68 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
71 if (res != errSecSuccess) {
72 if (res == errSecAuthFailed) {
73 BOOST_THROW_EXCEPTION(
Error(
"Fail to unlock the keychain"));
75 BOOST_THROW_EXCEPTION(std::domain_error(
"Key does not exist"));
92 return kSecAttrKeyTypeRSA;
94 return kSecAttrKeyTypeECDSA;
96 BOOST_THROW_EXCEPTION(
Tpm::Error(
"Unsupported key type"));
103 switch (digestAlgo) {
108 return kSecDigestSHA2;
117 switch (digestAlgo) {
134 SecKeychainSetUserInteractionAllowed(!m_impl->isTerminalMode);
136 OSStatus res = SecKeychainCopyDefault(&m_impl->keyChainRef);
138 if (res == errSecNoDefaultKeychain) {
139 BOOST_THROW_EXCEPTION(
Error(
"No default keychain, create one first"));
148 static std::string scheme =
"tpm-osxkeychain";
155 return m_impl->isTerminalMode;
161 m_impl->isTerminalMode = isTerminal;
162 SecKeychainSetUserInteractionAllowed(!isTerminal);
168 SecKeychainStatus keychainStatus;
170 OSStatus res = SecKeychainGetStatus(m_impl->keyChainRef, &keychainStatus);
171 if (res != errSecSuccess)
174 return ((kSecUnlockStateStatus & keychainStatus) == 0);
184 if (m_impl->isTerminalMode) {
186 SecKeychainUnlock(m_impl->keyChainRef, pwLen, pw,
true);
190 SecKeychainUnlock(m_impl->keyChainRef, 0,
nullptr,
false);
201 if (error !=
nullptr) {
202 BOOST_THROW_EXCEPTION(
Error(
"Fail to create signer"));
207 SecTransformSetAttribute(signer.
get(), kSecTransformInputAttributeName, dataRef.
get(), &error.
get());
208 if (error !=
nullptr) {
209 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure input of signer"));
213 SecTransformSetAttribute(signer.
get(), kSecPaddingKey, kSecPaddingPKCS1Key, &error.
get());
214 if (error !=
nullptr) {
215 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure padding of signer"));
220 if (error !=
nullptr) {
221 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure digest type of signer"));
227 SecTransformSetAttribute(signer.
get(), kSecDigestLengthAttribute, cfDigestSize.
get(), &error.
get());
228 if (error !=
nullptr) {
229 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure digest length of signer"));
235 if (error !=
nullptr) {
237 BOOST_THROW_EXCEPTION(
Error(
"Fail to sign data"));
240 if (signature ==
nullptr) {
241 BOOST_THROW_EXCEPTION(
Error(
"Signature is null"));
244 return make_shared<Buffer>(CFDataGetBytePtr(signature.
get()), CFDataGetLength(signature.
get()));
252 if (error !=
nullptr) {
253 BOOST_THROW_EXCEPTION(
Error(
"Fail to create decryptor"));
256 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(
nullptr, cipherText, cipherSize, kCFAllocatorNull);
257 SecTransformSetAttribute(decryptor.
get(), kSecTransformInputAttributeName, dataRef.
get(), &error.
get());
258 if (error !=
nullptr) {
259 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure decryptor input"));
262 SecTransformSetAttribute(decryptor.
get(), kSecPaddingKey, kSecPaddingOAEPKey, &error.
get());
263 if (error !=
nullptr) {
264 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure decryptor padding"));
268 if (error !=
nullptr) {
270 BOOST_THROW_EXCEPTION(
Error(
"Fail to decrypt data"));
273 if (output ==
nullptr) {
274 BOOST_THROW_EXCEPTION(
Error(
"Output is null"));
277 return make_shared<Buffer>(CFDataGetBytePtr(output.
get()), CFDataGetLength(output.
get()));
284 OSStatus res = SecItemExport(key.
get(),
290 if (res != errSecSuccess) {
291 if (res == errSecAuthFailed) {
292 BOOST_THROW_EXCEPTION(
Error(
"Fail to unlock the keychain"));
295 BOOST_THROW_EXCEPTION(
Error(
"Fail to export private key"));
300 privateKey.
loadPkcs1(CFDataGetBytePtr(exportedKey.
get()), CFDataGetLength(exportedKey.
get()));
305 BackEndOsx::doHasKey(
const Name& keyName)
const 308 kCFStringEncodingUTF8);
311 CFDictionaryCreateMutable(
nullptr, 4, &kCFTypeDictionaryKeyCallBacks,
nullptr);
313 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
314 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.
get());
315 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
319 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
322 return res == errSecSuccess;
325 unique_ptr<KeyHandle>
326 BackEndOsx::doGetKeyHandle(
const Name& keyName)
const 328 CFReleaser<SecKeychainItemRef> keyItem;
330 keyItem = m_impl->getKey(keyName);
332 catch (
const std::domain_error&) {
336 return make_unique<KeyHandleOsx>((SecKeyRef)keyItem.get());
339 unique_ptr<KeyHandle>
340 BackEndOsx::doCreateKey(
const Name& identityName,
const KeyParams& params)
342 KeyType keyType = params.getKeyType();
347 keySize = rsaParams.getKeySize();
352 keySize = ecParams.getKeySize();
356 BOOST_THROW_EXCEPTION(Tpm::Error(
"Fail to create a key pair: Unsupported key type"));
359 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(
nullptr, kCFNumberIntType, &keySize);
361 CFReleaser<CFMutableDictionaryRef> attrDict =
362 CFDictionaryCreateMutable(
nullptr, 2, &kCFTypeDictionaryKeyCallBacks,
nullptr);
363 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType,
getAsymKeyType(keyType));
364 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
368 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(), &publicKey.get(), &privateKey.get());
370 BOOST_ASSERT(privateKey !=
nullptr);
375 BOOST_ASSERT(privateKey !=
nullptr);
377 if (res != errSecSuccess) {
378 if (res == errSecAuthFailed) {
379 BOOST_THROW_EXCEPTION(Error(
"Fail to unlock the keychain"));
382 BOOST_THROW_EXCEPTION(Error(
"Fail to create a key pair"));
386 unique_ptr<KeyHandle> keyHandle = make_unique<KeyHandleOsx>(privateKey.get());
389 SecKeychainAttribute attrs[1];
390 SecKeychainAttributeList attrList = { 0, attrs };
391 std::string keyUri = keyHandle->getKeyName().toUri();
393 attrs[attrList.count].tag = kSecKeyPrintName;
394 attrs[attrList.count].length = keyUri.size();
395 attrs[attrList.count].data =
const_cast<char*
>(keyUri.data());
399 SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)privateKey.get(), &attrList, 0,
nullptr);
400 SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)publicKey.get(), &attrList, 0,
nullptr);
406 BackEndOsx::doDeleteKey(
const Name& keyName)
408 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(
nullptr, keyName.toUri().c_str(),
409 kCFStringEncodingUTF8);
411 CFReleaser<CFMutableDictionaryRef> searchDict =
412 CFDictionaryCreateMutable(
nullptr, 5, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
414 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
415 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
416 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
417 OSStatus res = SecItemDelete(searchDict.get());
419 if (res != errSecSuccess) {
420 if (res == errSecAuthFailed) {
421 BOOST_THROW_EXCEPTION(Error(
"Fail to unlock the keychain"));
423 else if (res != errSecItemNotFound) {
424 BOOST_THROW_EXCEPTION(Error(
"Fail to delete a key pair"));
430 BackEndOsx::doExportKey(
const Name& keyName,
const char* pw,
size_t pwLen)
432 CFReleaser<SecKeychainItemRef> privateKey;
435 privateKey = m_impl->getKey(keyName);
437 catch (
const std::domain_error&) {
438 BOOST_THROW_EXCEPTION(Tpm::Error(
"Private key does not exist in OSX Keychain"));
441 CFReleaser<CFDataRef> exportedKey;
442 SecItemImportExportKeyParameters keyParams;
443 memset(&keyParams, 0,
sizeof(keyParams));
444 CFReleaser<CFStringRef> passphrase =
445 CFStringCreateWithBytes(0, reinterpret_cast<const uint8_t*>(pw), pwLen, kCFStringEncodingUTF8,
false);
446 keyParams.passphrase = passphrase.get();
447 OSStatus res = SecItemExport(privateKey.get(),
448 kSecFormatWrappedPKCS8,
453 if (res != errSecSuccess) {
454 if (res == errSecAuthFailed) {
455 BOOST_THROW_EXCEPTION(Error(
"Fail to unlock the keychain"));
458 BOOST_THROW_EXCEPTION(Error(
"Fail to export private key"));
462 return make_shared<Buffer>(CFDataGetBytePtr(exportedKey.get()), CFDataGetLength(exportedKey.get()));
466 BackEndOsx::doImportKey(
const Name& keyName,
const uint8_t* buf,
size_t size,
467 const char* pw,
size_t pwLen)
469 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(
nullptr, buf, size, kCFAllocatorNull);
471 SecExternalFormat externalFormat = kSecFormatWrappedPKCS8;
472 SecExternalItemType externalType = kSecItemTypePrivateKey;
474 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(
nullptr, keyName.toUri().c_str(),
475 kCFStringEncodingUTF8);
476 CFReleaser<CFStringRef> passphrase =
477 CFStringCreateWithBytes(
nullptr, reinterpret_cast<const uint8_t*>(pw), pwLen, kCFStringEncodingUTF8,
false);
478 CFReleaser<SecAccessRef> access;
479 SecAccessCreate(keyLabel.get(),
nullptr, &access.get());
481 CFArrayRef attributes =
nullptr;
483 const SecItemImportExportKeyParameters keyParams{
484 SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
494 CFReleaser<CFArrayRef> outItems;
495 OSStatus res = SecItemImport(importedKey.get(),
504 if (res != errSecSuccess) {
505 if (res == errSecAuthFailed) {
506 BOOST_THROW_EXCEPTION(Error(
"Fail to unlock the keychain"));
509 BOOST_THROW_EXCEPTION(Error(
"Cannot import the private key"));
514 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
515 SecKeychainAttribute attrs[1];
516 SecKeychainAttributeList attrList = { 0, attrs };
517 std::string keyUri = keyName.toUri();
519 attrs[attrList.count].tag = kSecKeyPrintName;
520 attrs[attrList.count].length = keyUri.size();
521 attrs[attrList.count].data =
const_cast<char*
>(keyUri.data());
525 res = SecKeychainItemModifyAttributesAndData(privateKey, &attrList, 0,
nullptr);
static ConstBufferPtr decrypt(const KeyRefOsx &key, const uint8_t *cipherText, size_t cipherSize)
bool isTpmLocked() const final
Copyright (c) 2011-2015 Regents of the University of California.
std::string toUri() const
Get URI representation of the name.
util::CFReleaser< SecKeyRef > KeyRefOsx
SecKeychainRef keyChainRef
RSA key, supports sign/verify and encrypt/decrypt operations.
static CFTypeRef getDigestAlgorithm(DigestAlgorithm digestAlgo)
SimplePublicKeyParams< detail::RsaKeyParamsInfo > RsaKeyParams
RsaKeyParams carries parameters for RSA key.
KeyType
The type of a cryptographic key.
static const std::string & getScheme()
bool isTerminalMode() const final
Check if TPM is in terminal mode.
SimplePublicKeyParams< detail::EcKeyParamsInfo > EcKeyParams
EcKeyParams carries parameters for EC key.
void setTerminalMode(bool isTerminal) const final
Set the terminal mode of TPM.
static CFTypeRef getAsymKeyType(KeyType keyType)
static ConstBufferPtr derivePublicKey(const KeyRefOsx &key)
BackEndOsx(const std::string &location="")
Create TPM backed based on macOS KeyChain service.
bool unlockTpm(const char *pw, size_t pwLen) const final
Unlock TPM.
static long getDigestSize(DigestAlgorithm digestAlgo)
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.
void retain(const T &typeRef)
unique_ptr< T > make_unique(Args &&... args)
CFReleaser< SecKeychainItemRef > getKey(const Name &keyName)
Get private key reference with name keyName.
shared_ptr< const Buffer > ConstBufferPtr