25 #include "../transform/private-key.hpp" 26 #include "../../util/cf-string-osx.hpp" 28 #include <Security/Security.h> 35 namespace cfstring = util::cfstring;
36 using util::CFReleaser;
38 class BackEndOsx::Impl
41 SecKeychainRef keyChainRef;
45 static CFReleaser<CFDataRef>
48 return CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buf, buflen, kCFAllocatorNull);
51 static CFReleaser<CFMutableDictionaryRef>
54 return CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
55 &kCFTypeDictionaryKeyCallBacks,
56 &kCFTypeDictionaryValueCallBacks);
62 CFReleaser<CFStringRef> msg = SecCopyErrorMessageString(status,
nullptr);
66 return "<no error message>";
72 CFReleaser<CFStringRef> reason = CFErrorCopyFailureReason(err);
73 if (reason !=
nullptr)
76 return "<unknown reason>";
84 return kSecAttrKeyTypeRSA;
86 return kSecAttrKeyTypeECDSA;
88 BOOST_THROW_EXCEPTION(
Tpm::Error(
"Unsupported key type"));
100 return kSecDigestSHA2;
109 switch (digestAlgo) {
132 CFDictionaryAddValue(query.get(), kSecClass, kSecClassKey);
133 CFDictionaryAddValue(query.get(), kSecAttrKeyClass, kSecAttrKeyClassPrivate);
134 CFDictionaryAddValue(query.get(), kSecAttrLabel, keyLabel.get());
135 CFDictionaryAddValue(query.get(), kSecReturnRef, kCFBooleanTrue);
139 OSStatus res = SecItemCopyMatching(query.get(), (CFTypeRef*)&keyRef.get());
142 if (res == errSecSuccess) {
145 else if (res == errSecItemNotFound) {
154 : m_impl(make_unique<Impl>())
156 SecKeychainSetUserInteractionAllowed(!m_impl->isTerminalMode);
158 OSStatus res = SecKeychainCopyDefault(&m_impl->keyChainRef);
159 if (res == errSecNoDefaultKeychain) {
160 BOOST_THROW_EXCEPTION(
Error(
"No default keychain, create one first"));
169 static std::string scheme =
"tpm-osxkeychain";
176 return m_impl->isTerminalMode;
182 m_impl->isTerminalMode = isTerminal;
183 SecKeychainSetUserInteractionAllowed(!isTerminal);
189 SecKeychainStatus keychainStatus;
190 OSStatus res = SecKeychainGetStatus(m_impl->keyChainRef, &keychainStatus);
191 if (res != errSecSuccess)
194 return (kSecUnlockStateStatus & keychainStatus) == 0;
204 if (m_impl->isTerminalMode) {
206 SecKeychainUnlock(m_impl->keyChainRef, pwLen, pw,
true);
210 SecKeychainUnlock(m_impl->keyChainRef, 0,
nullptr,
false);
219 CFReleaser<CFErrorRef> error;
220 CFReleaser<SecTransformRef> signer = SecSignTransformCreate(key.
get(), &error.get());
221 if (signer ==
nullptr) {
227 SecTransformSetAttribute(signer.get(), kSecTransformInputAttributeName, data.get(), &error.get());
228 if (error !=
nullptr) {
229 BOOST_THROW_EXCEPTION(
Error(
"Failed to configure input of sign transform: " +
234 SecTransformSetAttribute(signer.get(), kSecPaddingKey, kSecPaddingPKCS1Key, &error.get());
235 if (error !=
nullptr) {
236 BOOST_THROW_EXCEPTION(
Error(
"Failed to configure padding of sign transform: " +
241 SecTransformSetAttribute(signer.get(), kSecDigestTypeAttribute,
getDigestAlgorithm(digestAlgo), &error.get());
242 if (error !=
nullptr) {
243 BOOST_THROW_EXCEPTION(
Error(
"Failed to configure digest type of sign transform: " +
249 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &digestSize);
250 SecTransformSetAttribute(signer.get(), kSecDigestLengthAttribute, cfDigestSize.get(), &error.get());
251 if (error !=
nullptr) {
252 BOOST_THROW_EXCEPTION(
Error(
"Failed to configure digest length of sign transform: " +
258 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
259 if (signature ==
nullptr) {
263 return make_shared<Buffer>(CFDataGetBytePtr(signature.get()), CFDataGetLength(signature.get()));
269 CFReleaser<CFErrorRef> error;
270 CFReleaser<SecTransformRef> decryptor = SecDecryptTransformCreate(key.
get(), &error.get());
271 if (decryptor ==
nullptr) {
272 BOOST_THROW_EXCEPTION(
Error(
"Failed to create decrypt transform: " +
getFailureReason(error.get())));
276 SecTransformSetAttribute(decryptor.get(), kSecTransformInputAttributeName, data.get(), &error.get());
277 if (error !=
nullptr) {
278 BOOST_THROW_EXCEPTION(
Error(
"Failed to configure input of decrypt transform: " +
282 SecTransformSetAttribute(decryptor.get(), kSecPaddingKey, kSecPaddingOAEPKey, &error.get());
283 if (error !=
nullptr) {
284 BOOST_THROW_EXCEPTION(
Error(
"Failed to configure padding of decrypt transform: " +
289 CFReleaser<CFDataRef> plainText = (CFDataRef)SecTransformExecute(decryptor.get(), &error.get());
290 if (plainText ==
nullptr) {
294 return make_shared<Buffer>(CFDataGetBytePtr(plainText.get()), CFDataGetLength(plainText.get()));
300 CFReleaser<CFDataRef> exportedKey;
301 OSStatus res = SecItemExport(key.
get(),
307 if (res != errSecSuccess) {
312 privateKey.
loadPkcs1(CFDataGetBytePtr(exportedKey.get()), CFDataGetLength(exportedKey.get()));
317 BackEndOsx::doHasKey(
const Name& keyName)
const 322 unique_ptr<KeyHandle>
323 BackEndOsx::doGetKeyHandle(
const Name& keyName)
const 326 if (keyRef ==
nullptr) {
330 return make_unique<KeyHandleOsx>(keyRef.
get());
333 unique_ptr<KeyHandle>
334 BackEndOsx::doCreateKey(
const Name& identityName,
const KeyParams& params)
350 BOOST_THROW_EXCEPTION(
Tpm::Error(
"Failed to generate key pair: Unsupported key type"));
353 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize);
356 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType,
getAsymKeyType(keyType));
357 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
360 OSStatus res = SecKeyGeneratePair(attrDict.get(), &publicKey.get(), &privateKey.get());
364 if (res != errSecSuccess) {
368 unique_ptr<KeyHandle> keyHandle = make_unique<KeyHandleOsx>(privateKey.get());
371 SecKeychainAttribute attrs[1];
372 SecKeychainAttributeList attrList = {0, attrs};
373 std::string keyUri = keyHandle->getKeyName().toUri();
375 attrs[attrList.count].tag = kSecKeyPrintName;
376 attrs[attrList.count].length = keyUri.size();
377 attrs[attrList.count].data =
const_cast<char*
>(keyUri.data());
381 SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)privateKey.get(), &attrList, 0,
nullptr);
382 SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)publicKey.get(), &attrList, 0,
nullptr);
388 BackEndOsx::doDeleteKey(
const Name& keyName)
393 CFDictionaryAddValue(query.get(), kSecClass, kSecClassKey);
394 CFDictionaryAddValue(query.get(), kSecAttrLabel, keyLabel.get());
395 CFDictionaryAddValue(query.get(), kSecMatchLimit, kSecMatchLimitAll);
397 OSStatus res = SecItemDelete(query.get());
399 if (res != errSecSuccess && res != errSecItemNotFound) {
405 BackEndOsx::doExportKey(
const Name& keyName,
const char* pw,
size_t pwLen)
408 if (keychainItem ==
nullptr) {
409 BOOST_THROW_EXCEPTION(
Error(
"Failed to export private key: " +
getErrorMessage(errSecItemNotFound)));
413 SecItemImportExportKeyParameters keyParams;
414 std::memset(&keyParams, 0,
sizeof(keyParams));
415 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
416 keyParams.passphrase = passphrase.get();
418 CFReleaser<CFDataRef> exportedKey;
419 OSStatus res = SecItemExport(keychainItem.
get(),
420 kSecFormatWrappedPKCS8,
425 if (res != errSecSuccess) {
429 return make_shared<Buffer>(CFDataGetBytePtr(exportedKey.get()), CFDataGetLength(exportedKey.get()));
433 BackEndOsx::doImportKey(
const Name& keyName,
const uint8_t* buf,
size_t size,
434 const char* pw,
size_t pwLen)
438 SecExternalFormat externalFormat = kSecFormatWrappedPKCS8;
439 SecExternalItemType externalType = kSecItemTypePrivateKey;
443 CFReleaser<SecAccessRef> access;
444 SecAccessCreate(keyLabel.get(),
nullptr, &access.get());
446 SecItemImportExportKeyParameters keyParams;
447 std::memset(&keyParams, 0,
sizeof(keyParams));
448 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
449 keyParams.passphrase = passphrase.get();
450 keyParams.accessRef = access.get();
452 CFReleaser<CFArrayRef> outItems;
453 OSStatus res = SecItemImport(importedKey.get(),
462 if (res != errSecSuccess) {
467 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
468 SecKeychainAttribute attrs[1];
469 SecKeychainAttributeList attrList = {0, attrs};
470 std::string keyUri = keyName.
toUri();
472 attrs[attrList.count].tag = kSecKeyPrintName;
473 attrs[attrList.count].length = keyUri.size();
474 attrs[attrList.count].data =
const_cast<char*
>(keyUri.data());
478 SecKeychainItemModifyAttributesAndData(privateKey, &attrList, 0,
nullptr);
static CFReleaser< CFDataRef > makeCFDataNoCopy(const uint8_t *buf, size_t buflen)
static ConstBufferPtr decrypt(const KeyRefOsx &key, const uint8_t *cipherText, size_t cipherSize)
bool isTpmLocked() const final
Check if the TPM is locked.
Copyright (c) 2013-2017 Regents of the University of California.
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.
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.
std::string toStdString(CFStringRef cfStr)
Convert a CFString to a std::string.
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 > fromStdString(const std::string &str)
Create a CFString by copying characters from a std::string.
CFReleaser< CFStringRef > fromBuffer(const uint8_t *buf, size_t buflen)
Create a CFString by copying bytes from a raw buffer.
void retain(const T &typeRef)
Base class of key parameters.
static std::string getFailureReason(CFErrorRef err)
SimplePublicKeyParams is a template for public keys with only one parameter: size.
shared_ptr< const Buffer > ConstBufferPtr