25 #include "../transform/private-key.hpp"
28 #include <CoreServices/CoreServices.h>
29 #include <Security/Security.h>
30 #include <Security/SecRandom.h>
31 #include <Security/SecDigestTransform.h>
57 CFDictionaryCreateMutable(
nullptr, 5, &kCFTypeDictionaryKeyCallBacks,
nullptr);
59 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
60 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.
get());
61 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, kSecAttrKeyClassPrivate);
62 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
66 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
69 if (res != errSecSuccess) {
70 if (res == errSecAuthFailed) {
71 BOOST_THROW_EXCEPTION(
Error(
"Fail to unlock the keychain"));
73 BOOST_THROW_EXCEPTION(std::domain_error(
"Key does not exist"));
90 return kSecAttrKeyTypeRSA;
92 return kSecAttrKeyTypeECDSA;
94 BOOST_THROW_EXCEPTION(
Tpm::Error(
"Unsupported key type"));
101 switch (digestAlgo) {
103 return kSecDigestSHA2;
112 switch (digestAlgo) {
123 SecKeychainSetUserInteractionAllowed(!m_impl->isTerminalMode);
125 OSStatus res = SecKeychainCopyDefault(&m_impl->keyChainRef);
127 if (res == errSecNoDefaultKeychain) {
128 BOOST_THROW_EXCEPTION(
Error(
"No default keychain, create one first"));
137 static std::string scheme =
"tpm-osxkeychain";
144 return m_impl->isTerminalMode;
150 m_impl->isTerminalMode = isTerminal;
151 SecKeychainSetUserInteractionAllowed(!isTerminal);
157 SecKeychainStatus keychainStatus;
159 OSStatus res = SecKeychainGetStatus(m_impl->keyChainRef, &keychainStatus);
160 if (res != errSecSuccess)
163 return ((kSecUnlockStateStatus & keychainStatus) == 0);
173 if (m_impl->isTerminalMode) {
175 SecKeychainUnlock(m_impl->keyChainRef, pwLen, pw,
true);
179 SecKeychainUnlock(m_impl->keyChainRef, 0,
nullptr,
false);
187 const uint8_t* buf,
size_t size)
const
194 if (error !=
nullptr) {
195 BOOST_THROW_EXCEPTION(
Error(
"Fail to create signer"));
199 SecTransformSetAttribute(signer.
get(), kSecTransformInputAttributeName, dataRef.
get(), &error.
get());
200 if (error !=
nullptr) {
201 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure input of signer"));
205 SecTransformSetAttribute(signer.
get(), kSecPaddingKey, kSecPaddingPKCS1Key, &error.
get());
206 if (error !=
nullptr) {
207 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure digest algorithm of signer"));
212 if (error !=
nullptr) {
213 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure digest algorithm of signer"));
219 SecTransformSetAttribute(signer.
get(),
220 kSecDigestLengthAttribute,
223 if (error !=
nullptr) {
224 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure digest size of signer"));
229 if (error !=
nullptr) {
231 BOOST_THROW_EXCEPTION(
Error(
"Fail to sign data"));
234 if (signature ==
nullptr) {
235 BOOST_THROW_EXCEPTION(
Error(
"Signature is NULL!\n"));
238 return make_shared<Buffer>(CFDataGetBytePtr(signature.
get()), CFDataGetLength(signature.
get()));
244 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(
nullptr, cipherText, cipherSize, kCFAllocatorNull);
248 if (error !=
nullptr) {
249 BOOST_THROW_EXCEPTION(
Error(
"Fail to create decrypt"));
252 SecTransformSetAttribute(decryptor.
get(), kSecTransformInputAttributeName, dataRef.
get(), &error.
get());
253 if (error !=
nullptr) {
254 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure decrypt"));
257 SecTransformSetAttribute(decryptor.
get(), kSecPaddingKey, kSecPaddingOAEPKey, &error.
get());
258 if (error !=
nullptr) {
259 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure decrypt #2"));
263 if (error !=
nullptr) {
265 BOOST_THROW_EXCEPTION(
Error(
"Fail to decrypt data"));
268 if (output ==
nullptr) {
269 BOOST_THROW_EXCEPTION(
Error(
"Output is NULL!\n"));
271 return make_shared<Buffer>(CFDataGetBytePtr(output.
get()), CFDataGetLength(output.
get()));
278 OSStatus res = SecItemExport(key.
get(),
284 if (res != errSecSuccess) {
285 if (res == errSecAuthFailed) {
286 BOOST_THROW_EXCEPTION(
Error(
"Fail to unlock the keychain"));
289 BOOST_THROW_EXCEPTION(
Error(
"Fail to export private key"));
294 privateKey.
loadPkcs1(CFDataGetBytePtr(exportedKey.
get()), CFDataGetLength(exportedKey.
get()));
299 BackEndOsx::doHasKey(
const Name& keyName)
const
304 CFDictionaryCreateMutable(
nullptr, 4, &kCFTypeDictionaryKeyCallBacks,
nullptr);
306 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
307 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.
get());
308 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
312 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
315 return (res == errSecSuccess);
318 unique_ptr<KeyHandle>
319 BackEndOsx::doGetKeyHandle(
const Name& keyName)
const
321 CFReleaser<SecKeychainItemRef> keyItem;
323 keyItem = m_impl->getKey(keyName);
325 catch (
const std::domain_error&) {
329 return make_unique<KeyHandleOsx>(*
this, (SecKeyRef)keyItem.get());
332 unique_ptr<KeyHandle>
333 BackEndOsx::doCreateKey(
const Name& identityName,
const KeyParams& params)
335 KeyType keyType = params.getKeyType();
340 keySize = rsaParams.getKeySize();
345 keySize = ecParams.getKeySize();
349 BOOST_THROW_EXCEPTION(Tpm::Error(
"Fail to create a key pair: Unsupported key type"));
352 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(
nullptr, kCFNumberIntType, &keySize);
354 CFReleaser<CFMutableDictionaryRef> attrDict =
355 CFDictionaryCreateMutable(
nullptr, 2, &kCFTypeDictionaryKeyCallBacks,
nullptr);
356 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType,
getAsymKeyType(keyType));
357 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
361 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(), &publicKey.get(), &privateKey.get());
363 BOOST_ASSERT(privateKey !=
nullptr);
368 BOOST_ASSERT(privateKey !=
nullptr);
370 if (res != errSecSuccess) {
371 if (res == errSecAuthFailed) {
372 BOOST_THROW_EXCEPTION(Error(
"Fail to unlock the keychain"));
375 BOOST_THROW_EXCEPTION(Error(
"Fail to create a key pair"));
379 unique_ptr<KeyHandle> keyHandle = make_unique<KeyHandleOsx>(*
this, privateKey.get());
382 SecKeychainAttribute attrs[1];
383 SecKeychainAttributeList attrList = { 0, attrs };
384 std::string keyUri = keyHandle->getKeyName().toUri();
386 attrs[attrList.count].tag = kSecKeyPrintName;
387 attrs[attrList.count].length = keyUri.size();
388 attrs[attrList.count].data =
const_cast<char*
>(keyUri.data());
392 SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)privateKey.get(), &attrList, 0,
nullptr);
393 SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)publicKey.get(), &attrList, 0,
nullptr);
399 BackEndOsx::doDeleteKey(
const Name& keyName)
401 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(
nullptr, keyName.toUri().c_str(), kCFStringEncodingUTF8);
403 CFReleaser<CFMutableDictionaryRef> searchDict =
404 CFDictionaryCreateMutable(
nullptr, 5, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
406 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
407 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
408 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
409 OSStatus res = SecItemDelete(searchDict.get());
411 if (res != errSecSuccess) {
412 if (res == errSecAuthFailed) {
413 BOOST_THROW_EXCEPTION(Error(
"Fail to unlock the keychain"));
415 else if (res != errSecItemNotFound) {
416 BOOST_THROW_EXCEPTION(Error(
"Fail to delete a key pair"));
422 BackEndOsx::doExportKey(
const Name& keyName,
const char* pw,
size_t pwLen)
424 CFReleaser<SecKeychainItemRef> privateKey;
427 privateKey = m_impl->getKey(keyName);
429 catch (
const std::domain_error&) {
430 BOOST_THROW_EXCEPTION(Tpm::Error(
"Private key does not exist in OSX Keychain"));
433 CFReleaser<CFDataRef> exportedKey;
434 SecItemImportExportKeyParameters keyParams;
435 memset(&keyParams, 0,
sizeof(keyParams));
436 CFReleaser<CFStringRef> passphrase =
437 CFStringCreateWithBytes(0, reinterpret_cast<const uint8_t*>(pw), pwLen, kCFStringEncodingUTF8,
false);
438 keyParams.passphrase = passphrase.get();
439 OSStatus res = SecItemExport(privateKey.get(),
440 kSecFormatWrappedPKCS8,
445 if (res != errSecSuccess) {
446 if (res == errSecAuthFailed) {
447 BOOST_THROW_EXCEPTION(Error(
"Fail to unlock the keychain"));
450 BOOST_THROW_EXCEPTION(Error(
"Fail to export private key"));
454 return make_shared<Buffer>(CFDataGetBytePtr(exportedKey.get()), CFDataGetLength(exportedKey.get()));
458 BackEndOsx::doImportKey(
const Name& keyName,
const uint8_t* buf,
size_t size,
459 const char* pw,
size_t pwLen)
461 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(
nullptr, buf, size, kCFAllocatorNull);
463 SecExternalFormat externalFormat = kSecFormatWrappedPKCS8;
464 SecExternalItemType externalType = kSecItemTypePrivateKey;
466 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(
nullptr, keyName.toUri().c_str(), kCFStringEncodingUTF8);
467 CFReleaser<CFStringRef> passphrase =
468 CFStringCreateWithBytes(
nullptr, reinterpret_cast<const uint8_t*>(pw), pwLen, kCFStringEncodingUTF8,
false);
469 CFReleaser<SecAccessRef> access;
470 SecAccessCreate(keyLabel.get(),
nullptr, &access.get());
472 CFArrayRef attributes =
nullptr;
474 const SecItemImportExportKeyParameters keyParams{
475 SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
485 CFReleaser<CFArrayRef> outItems;
486 OSStatus res = SecItemImport(importedKey.get(),
495 if (res != errSecSuccess) {
496 if (res == errSecAuthFailed) {
497 BOOST_THROW_EXCEPTION(Error(
"Fail to unlock the keychain"));
500 BOOST_THROW_EXCEPTION(Error(
"Cannot import the private key"));
505 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
506 SecKeychainAttribute attrs[1];
507 SecKeychainAttributeList attrList = { 0, attrs };
508 std::string keyUri = keyName.toUri();
510 attrs[attrList.count].tag = kSecKeyPrintName;
511 attrs[attrList.count].length = keyUri.size();
512 attrs[attrList.count].data =
const_cast<char*
>(keyUri.c_str());
516 res = SecKeychainItemModifyAttributesAndData(privateKey, &attrList, 0,
nullptr);
bool isTpmLocked() const final
Copyright (c) 2013-2016 Regents of the University of California.
SimplePublicKeyParams< RsaKeyParamsInfo > RsaKeyParams
RsaKeyParams carries parameters for RSA key.
ConstBufferPtr sign(const KeyRefOsx &key, DigestAlgorithm digestAlgorithm, const uint8_t *buf, size_t size) const
Sign buf with key using digestAlgorithm.
SecKeychainRef keyChainRef
bool isTerminalMode() const final
Check if TPM is in terminal mode.
static CFTypeRef getDigestAlgorithm(DigestAlgorithm digestAlgo)
void retain(const T &typeRef)
Helper class to wrap CoreFoundation object pointers.
static const std::string & getScheme()
std::string toUri() const
Encode this name as a URI.
ConstBufferPtr derivePublicKey(const KeyRefOsx &key) const
static CFTypeRef getAsymKeyType(KeyType keyType)
CFReleaser< SecKeyRef > KeyRefOsx
ConstBufferPtr decrypt(const KeyRefOsx &key, const uint8_t *cipherText, size_t cipherSize) const
void setTerminalMode(bool isTerminal) const final
Set the terminal mode of TPM.
BackEndOsx(const std::string &location="")
Create TPM backed based on macOS KeyChain service.
static long getDigestSize(DigestAlgorithm digestAlgo)
Use the SHA256 hash of the public key as the key id.
Name abstraction to represent 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.
SimplePublicKeyParams< EcKeyParamsInfo > EcKeyParams
EcKeyParams carries parameters for EC key.
bool unlockTpm(const char *pw, size_t pwLen) const final
Unlock TPM.
shared_ptr< const Buffer > ConstBufferPtr
CFReleaser< SecKeychainItemRef > getKey(const Name &keyName)
Get private key reference with name keyName.