20 #include <CoreFoundation/CoreFoundation.h>
21 #include <Security/Security.h>
22 #include <Security/SecRandom.h>
23 #include <CoreServices/CoreServices.h>
25 #include <Security/SecDigestTransform.h>
35 : m_passwordSet(false)
48 toInternalKeyName(
const Name& keyName,
KeyClass keyClass);
76 getAsymKeyType(
KeyType keyType);
116 SecTpmOsx::SecTpmOsx()
119 if (m_impl->m_inTerminal)
120 SecKeychainSetUserInteractionAllowed(
false);
122 SecKeychainSetUserInteractionAllowed(
true);
124 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
126 if (res == errSecNoDefaultKeychain)
127 throw Error(
"No default keychain, create one first!");
137 m_impl->m_passwordSet =
true;
138 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
139 m_impl->m_password.clear();
140 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
146 m_impl->m_passwordSet =
false;
147 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
148 m_impl->m_password.clear();
154 m_impl->m_inTerminal = inTerminal;
156 SecKeychainSetUserInteractionAllowed(
false);
158 SecKeychainSetUserInteractionAllowed(
true);
164 return m_impl->m_inTerminal;
170 SecKeychainStatus keychainStatus;
172 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
173 if (res != errSecSuccess)
176 return ((kSecUnlockStateStatus & keychainStatus) == 0);
192 res = SecKeychainUnlock(m_impl->m_keyChainRef,
197 else if (m_impl->m_passwordSet)
200 SecKeychainUnlock(m_impl->m_keyChainRef,
201 m_impl->m_password.size(),
202 m_impl->m_password.c_str(),
205 else if (m_impl->m_inTerminal)
209 const char* fmt =
"Password to unlock the default keychain: ";
217 char* getPassword = 0;
218 getPassword = getpass(fmt);
224 res = SecKeychainUnlock(m_impl->m_keyChainRef,
229 memset(getPassword, 0, strlen(getPassword));
231 if (res == errSecSuccess)
238 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0,
false);
246 int keySize,
bool needRetry)
251 throw Error(
"keyName has existed");
256 SecKeyRef publicKey, privateKey;
258 CFStringRef keyLabel = CFStringCreateWithCString(0,
260 kCFStringEncodingUTF8);
262 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
264 &kCFTypeDictionaryKeyCallBacks,
267 CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
268 CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(0,
271 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
273 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict, &publicKey, &privateKey);
275 if (res == errSecSuccess)
277 CFRelease(publicKey);
278 CFRelease(privateKey);
282 if (res == errSecAuthFailed && !needRetry)
287 throw Error(
"Fail to unlock the keychain");
291 throw Error(
"Fail to create a key pair");
298 CFStringRef keyLabel = CFStringCreateWithCString(0,
299 keyName.
toUri().c_str(),
300 kCFStringEncodingUTF8);
302 CFMutableDictionaryRef searchDict =
303 CFDictionaryCreateMutable(0, 5,
304 &kCFTypeDictionaryKeyCallBacks,
305 &kCFTypeDictionaryValueCallBacks);
307 CFDictionaryAddValue(searchDict, kSecClass, kSecClassKey);
308 CFDictionaryAddValue(searchDict, kSecAttrLabel, keyLabel);
309 CFDictionaryAddValue(searchDict, kSecMatchLimit, kSecMatchLimitAll);
310 OSStatus res = SecItemDelete(searchDict);
312 if (res == errSecSuccess)
315 if (res == errSecAuthFailed && !needRetry)
325 throw Error(
"SecTpmOsx::generateSymmetricKeyInTpm is not supported");
355 shared_ptr<PublicKey>
360 CFDataRef exportedKey;
362 OSStatus res = SecItemExport(publicKey,
367 if (res != errSecSuccess)
369 throw Error(
"Cannot export requested public key from OSX Keychain");
372 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey),
373 CFDataGetLength(exportedKey));
374 CFRelease(exportedKey);
381 using namespace CryptoPP;
384 CFDataRef exportedKey;
385 OSStatus res = SecItemExport(privateKey,
391 if (res != errSecSuccess)
393 if (res == errSecAuthFailed && !needRetry)
398 return shared_ptr<Buffer>();
401 return shared_ptr<Buffer>();
405 FileSink sink(pkcs1Os);
407 uint32_t version = 0;
408 OID algorithm(
"1.2.840.113549.1.1.1");
409 SecByteBlock rawKeyBits;
414 DERSequenceEncoder privateKeyInfo(sink);
416 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
417 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
419 algorithm.
encode(privateKeyAlgorithm);
420 DEREncodeNull(privateKeyAlgorithm);
422 privateKeyAlgorithm.MessageEnd();
423 DEREncodeOctetString(privateKeyInfo,
424 CFDataGetBytePtr(exportedKey),
425 CFDataGetLength(exportedKey));
427 privateKeyInfo.MessageEnd();
429 CFRelease(exportedKey);
430 return pkcs1Os.buf();
434 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
435 #pragma GCC diagnostic push
436 #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
437 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
442 const uint8_t* buf,
size_t size,
445 using namespace CryptoPP;
447 StringSource privateKeySource(buf, size,
true);
450 SecByteBlock rawKeyBits;
455 BERSequenceDecoder privateKeyInfo(privateKeySource);
457 BERDecodeUnsigned<uint32_t>(privateKeyInfo, tmpNum, INTEGER);
458 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
460 tmpOID.decode(sequenceDecoder);
461 BERDecodeNull(sequenceDecoder);
463 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
465 privateKeyInfo.MessageEnd();
467 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(0,
468 rawKeyBits.BytePtr(),
472 SecExternalFormat externalFormat = kSecFormatOpenSSL;
473 SecExternalItemType externalType = kSecItemTypePrivateKey;
474 SecKeyImportExportParameters keyParams;
475 memset(&keyParams, 0,
sizeof(keyParams));
476 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
477 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
479 CFStringRef keyLabel = CFStringCreateWithCString(0,
480 keyName.
toUri().c_str(),
481 kCFStringEncodingUTF8);
482 SecAccessCreate(keyLabel, 0, &access);
483 keyParams.accessRef = access;
487 #pragma clang diagnostic push
488 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
491 OSStatus res = SecKeychainItemImport (importedKey,
497 m_impl->m_keyChainRef,
501 #pragma clang diagnostic pop
504 if (res != errSecSuccess)
506 if (res == errSecAuthFailed && !needRetry)
517 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
518 SecKeychainAttribute attrs[1];
519 SecKeychainAttributeList attrList = { 0, attrs };
520 string keyUri = keyName.
toUri();
522 attrs[attrList.count].tag = kSecKeyPrintName;
523 attrs[attrList.count].length = keyUri.size();
524 attrs[attrList.count].data = (
void *)keyUri.c_str();
528 res = SecKeychainItemModifyAttributesAndData(privateKey,
533 if (res != errSecSuccess)
538 CFRelease(importedKey);
542 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
543 #pragma GCC diagnostic pop
544 #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
549 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(0,
554 SecExternalFormat externalFormat = kSecFormatOpenSSL;
555 SecExternalItemType externalType = kSecItemTypePublicKey;
558 OSStatus res = SecItemImport (importedKey,
564 m_impl->m_keyChainRef,
567 if (res != errSecSuccess)
570 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
571 SecKeychainAttribute attrs[1];
572 SecKeychainAttributeList attrList = { 0, attrs };
573 string keyUri = keyName.
toUri();
575 attrs[attrList.count].tag = kSecKeyPrintName;
576 attrs[attrList.count].length = keyUri.size();
577 attrs[attrList.count].data = (
void *)keyUri.c_str();
581 res = SecKeychainItemModifyAttributesAndData(publicKey,
586 if (res != errSecSuccess)
589 CFRelease(importedKey);
597 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(0,
605 SecTransformRef signer = SecSignTransformCreate((SecKeyRef)privateKey, &error);
607 throw Error(
"Fail to create signer");
610 Boolean set_res = SecTransformSetAttribute(signer,
611 kSecTransformInputAttributeName,
615 throw Error(
"Fail to configure input of signer");
618 SecTransformSetAttribute(signer,
623 throw Error(
"Fail to configure digest algorithm of signer");
626 set_res = SecTransformSetAttribute(signer,
627 kSecDigestTypeAttribute,
628 m_impl->getDigestAlgorithm(digestAlgorithm),
631 throw Error(
"Fail to configure digest algorithm of signer");
634 long digestSize = m_impl->getDigestSize(digestAlgorithm);
635 set_res = SecTransformSetAttribute(signer,
636 kSecDigestLengthAttribute,
637 CFNumberCreate(0, kCFNumberLongType, &digestSize),
640 throw Error(
"Fail to configure digest size of signer");
643 CFDataRef signature = (CFDataRef) SecTransformExecute(signer, &error);
651 throw Error(
"Fail to unlock the keychain");
656 throw Error(
"Fail to sign data");
661 throw Error(
"Signature is NULL!\n");
664 make_shared<Buffer>(CFDataGetBytePtr(signature), CFDataGetLength(signature)));
670 throw Error(
"SecTpmOsx::decryptInTpm is not supported");
711 SecKeychainItemRef privateKey = m_impl->getKey(keyName, keyClass);
714 OSStatus acc_res = SecKeychainItemCopyAccess(privateKey, &accRef);
716 CFArrayRef signACL = SecAccessCopyMatchingACLList(accRef,
717 kSecACLAuthorizationSign);
719 SecACLRef aclRef = (SecACLRef) CFArrayGetValueAtIndex(signACL, 0);
722 CFStringRef description;
723 SecKeychainPromptSelector promptSelector;
724 OSStatus acl_res = SecACLCopyContents(aclRef,
729 CFMutableArrayRef newAppList = CFArrayCreateMutableCopy(0,
733 SecTrustedApplicationRef trustedApp;
734 acl_res = SecTrustedApplicationCreateFromPath(appPath.c_str(),
737 CFArrayAppendValue(newAppList, trustedApp);
739 acl_res = SecACLSetContents(aclRef,
744 acc_res = SecKeychainItemSetAccess(privateKey, accRef);
751 throw Error(
"SecTpmOsx::encryptInTpm is not supported");
787 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
789 CFStringRef keyLabel = CFStringCreateWithCString(0,
791 kCFStringEncodingUTF8);
793 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
795 &kCFTypeDictionaryKeyCallBacks,
798 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
800 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
801 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
803 SecKeychainItemRef itemRef;
804 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict, (CFTypeRef*)&itemRef);
806 if (res == errSecSuccess)
816 return (SecRandomCopyBytes(kSecRandomDefault, size, res) == 0);
826 string keyNameUri = toInternalKeyName(keyName, keyClass);
828 CFStringRef keyLabel = CFStringCreateWithCString(0,
830 kCFStringEncodingUTF8);
832 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
834 &kCFTypeDictionaryKeyCallBacks,
837 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
838 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
839 CFDictionaryAddValue(attrDict, kSecAttrKeyClass, getKeyClass(keyClass));
840 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
842 SecKeychainItemRef keyItem;
844 OSStatus res = SecItemCopyMatching((CFDictionaryRef) attrDict, (CFTypeRef*)&keyItem);
846 if (res != errSecSuccess)
855 string keyUri = keyName.
toUri();
858 return keyUri +
"/symmetric";
868 return kSecAttrKeyTypeRSA;
879 return kSecAttrKeyTypeAES;
890 return kSecAttrKeyClassPrivate;
892 return kSecAttrKeyClassPublic;
894 return kSecAttrKeyClassSymmetric;
911 return kSecDigestSHA2;
Class implementing interface similar to ostringstream, but to construct ndn::Buffer.
void deleteKeyPairInTpmInternal(const Name &keyName, bool needRetry)
virtual bool getInTerminal()
get inTerminal flag
const CFStringRef getDigestAlgorithm(DigestAlgorithm digestAlgo)
Convert digestAlgo to MAC OS algorithm id.
virtual ConstBufferPtr encryptInTpm(const uint8_t *data, size_t dataLength, const Name &keyName, bool isSymmetric)
Encrypt data.
virtual bool importPublicKeyPkcs1IntoTpm(const Name &keyName, const uint8_t *buf, size_t size)
Import a public key in PKCS#1 format.
Class representing wire element of the NDN packet.
ConstBufferPtr exportPrivateKeyPkcs8FromTpmInternal(const Name &keyName, bool needRetry)
virtual void addAppToACL(const Name &keyName, KeyClass keyClass, const std::string &appPath, AclType acl)
Add the application into the ACL of a particular key.
void generateKeyPairInTpmInternal(const Name &keyName, KeyType keyType, int keySize, bool needRetry)
virtual void setTpmPassword(const uint8_t *password, size_t passwordLength)
set password of TPM
virtual void resetTpmPassword()
reset password of TPM
std::string toUri() const
Encode this name as a URI.
const CFTypeRef getAsymKeyType(KeyType keyType)
Convert keyType to MAC OS asymmetirc key type.
ptr_lib::shared_ptr< const Buffer > ConstBufferPtr
virtual bool locked()
check if TPM is locked.
virtual void generateSymmetricKeyInTpm(const Name &keyName, KeyType keyType, int keySize)
Generate a symmetric key.
virtual shared_ptr< PublicKey > getPublicKeyFromTpm(const Name &keyName)
Get a public key.
bool importPrivateKeyPkcs8IntoTpmInternal(const Name &keyName, const uint8_t *buf, size_t size, bool needRetry)
const CFTypeRef getKeyClass(KeyClass keyClass)
Convert keyClass to MAC OS key class.
A Name holds an array of Name::Component and represents an NDN name.
virtual ConstBufferPtr decryptInTpm(const uint8_t *data, size_t dataLength, const Name &keyName, bool isSymmetric)
Decrypt data.
std::string toInternalKeyName(const Name &keyName, KeyClass keyClass)
Convert NDN name of a key to internal name of the key.
virtual bool doesKeyExistInTpm(const Name &keyName, KeyClass keyClass)
Check if a particular key exists.
virtual void setInTerminal(bool inTerminal)
set inTerminal flag
long getDigestSize(DigestAlgorithm digestAlgo)
Get the digest size of the corresponding algorithm.
Block signInTpmInternal(const uint8_t *data, size_t dataLength, const Name &keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
SecKeychainRef m_keyChainRef
void encode(CryptoPP::BufferedTransformation &out) const
virtual bool generateRandomBlock(uint8_t *res, size_t size)
Generate a random block.
SecKeychainItemRef getKey(const Name &keyName, KeyClass keyClass)
Get key.
virtual bool unlockTpm(const char *password, size_t passwordLength, bool usePassword)
Unlock the TPM.
const CFTypeRef getSymKeyType(KeyType keyType)
Convert keyType to MAC OS symmetric key key type.