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;
    52   CFReleaser<SecKeychainItemRef>
    55     CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(
nullptr, keyName.
toUri().c_str(),
    56                                                                  kCFStringEncodingUTF8);
    58     CFReleaser<CFMutableDictionaryRef> attrDict =
    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);
    66     CFReleaser<SecKeychainItemRef> keyItem;
    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);
   199   CFReleaser<CFErrorRef> error;
   200   CFReleaser<SecTransformRef> signer = SecSignTransformCreate(key.
get(), &error.get());
   201   if (error != 
nullptr) {
   202     BOOST_THROW_EXCEPTION(
Error(
"Fail to create signer"));
   206   CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(
nullptr, buf, size, kCFAllocatorNull);
   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"));
   219   SecTransformSetAttribute(signer.get(), kSecDigestTypeAttribute, 
getDigestAlgorithm(digestAlgo), &error.get());
   220   if (error != 
nullptr) {
   221     BOOST_THROW_EXCEPTION(
Error(
"Fail to configure digest type of signer"));
   226   CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(
nullptr, kCFNumberLongType, &digestSize);
   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"));
   234   CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
   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()));
   250   CFReleaser<CFErrorRef> error;
   251   CFReleaser<SecTransformRef> decryptor = SecDecryptTransformCreate(key.
get(), &error.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"));
   267   CFReleaser<CFDataRef> output = (CFDataRef)SecTransformExecute(decryptor.get(), &error.get());
   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()));
   283   CFReleaser<CFDataRef> exportedKey;
   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   307   CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(
nullptr, keyName.
toUri().c_str(),
   308                                                                kCFStringEncodingUTF8);
   310   CFReleaser<CFMutableDictionaryRef> attrDict =
   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);
   317   CFReleaser<SecKeychainItemRef> itemRef;
   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)
   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. 
 
KeyType getKeyType() const 
 
uint32_t getKeySize() const 
 
SecKeychainRef keyChainRef
 
RSA key, supports sign/verify and encrypt/decrypt operations. 
 
unique_ptr< T > make_unique(Args &&...args)
 
static CFTypeRef getDigestAlgorithm(DigestAlgorithm digestAlgo)
 
Catch-all error for security policy errors that don't fit in other categories. 
 
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 TPM is in terminal mode. 
 
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. 
 
static ConstBufferPtr sign(const KeyRefOsx &key, DigestAlgorithm digestAlgorithm, const uint8_t *buf, size_t size)
Sign buf with key using digestAlgorithm. 
 
Base class of key parameters. 
 
SimplePublicKeyParams is a template for public keys with only one parameter: size. 
 
CFReleaser< SecKeychainItemRef > getKey(const Name &keyName)
Get private key reference with name keyName. 
 
shared_ptr< const Buffer > ConstBufferPtr