27 #include "../../encoding/oid.hpp" 28 #include "../../encoding/buffer-stream.hpp" 36 #include <boost/lexical_cast.hpp> 38 #include <CoreFoundation/CoreFoundation.h> 39 #include <Security/Security.h> 40 #include <Security/SecRandom.h> 41 #include <CoreServices/CoreServices.h> 43 #include <Security/SecDigestTransform.h> 74 CFReleaser(
const T& typeRef)
79 CFReleaser(
const CFReleaser& inReleaser)
82 retain(inReleaser.m_typeRef);
86 operator=(
const T& typeRef)
88 if (typeRef != m_typeRef) {
96 operator=(
const CFReleaser& inReleaser)
98 retain(inReleaser.m_typeRef);
136 retain(
const T& typeRef)
138 if (typeRef !=
nullptr) {
148 if (m_typeRef !=
nullptr) {
149 CFRelease(m_typeRef);
157 return get() ==
nullptr;
163 return get() !=
nullptr;
171 class SecTpmOsx::Impl
175 : m_passwordSet(false)
176 , m_inTerminal(false)
186 toInternalKeyName(
const Name& keyName,
KeyClass keyClass);
193 CFReleaser<SecKeychainItemRef>
202 getSymKeyType(
KeyType keyType);
240 SecKeychainRef m_keyChainRef;
251 if (m_impl->m_inTerminal)
252 SecKeychainSetUserInteractionAllowed(
false);
254 SecKeychainSetUserInteractionAllowed(
true);
256 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
258 if (res == errSecNoDefaultKeychain)
259 BOOST_THROW_EXCEPTION(
Error(
"No default keychain, please create one first"));
269 m_impl->m_passwordSet =
true;
270 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
271 m_impl->m_password.clear();
272 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
278 m_impl->m_passwordSet =
false;
279 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
280 m_impl->m_password.clear();
286 m_impl->m_inTerminal = inTerminal;
288 SecKeychainSetUserInteractionAllowed(
false);
290 SecKeychainSetUserInteractionAllowed(
true);
296 return m_impl->m_inTerminal;
302 SecKeychainStatus keychainStatus;
304 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
305 if (res != errSecSuccess)
308 return ((kSecUnlockStateStatus & keychainStatus) == 0);
323 res = SecKeychainUnlock(m_impl->m_keyChainRef,
328 else if (m_impl->m_passwordSet) {
330 SecKeychainUnlock(m_impl->m_keyChainRef,
331 m_impl->m_password.size(),
332 m_impl->m_password.c_str(),
335 #ifdef NDN_CXX_HAVE_GETPASS 336 else if (m_impl->m_inTerminal) {
339 const char* fmt =
"Password to unlock the default keychain: ";
346 char* getPassword =
nullptr;
347 getPassword = getpass(fmt);
353 res = SecKeychainUnlock(m_impl->m_keyChainRef,
358 memset(getPassword, 0, strlen(getPassword));
360 if (res == errSecSuccess)
364 #endif // NDN_CXX_HAVE_GETPASS 367 SecKeychainUnlock(m_impl->m_keyChainRef, 0,
nullptr,
false);
380 BOOST_THROW_EXCEPTION(
Error(
"keyName already exists"));
385 CFReleaser<CFStringRef> keyLabel =
386 CFStringCreateWithCString(0,
388 kCFStringEncodingUTF8);
390 CFReleaser<CFMutableDictionaryRef> attrDict =
391 CFDictionaryCreateMutable(0,
393 &kCFTypeDictionaryKeyCallBacks,
397 uint32_t keySize = 0;
412 BOOST_THROW_EXCEPTION(
Error(
"Fail to create a key pair: Unsupported key type"));
415 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
417 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
418 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
419 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
421 CFReleaser<SecKeyRef> publicKey, privateKey;
423 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(),
424 &publicKey.get(), &privateKey.get());
426 if (res == errSecSuccess) {
430 if (res == errSecAuthFailed && !needRetry) {
434 BOOST_THROW_EXCEPTION(
Error(
"Fail to unlock the keychain"));
437 BOOST_THROW_EXCEPTION(
Error(
"Fail to create a key pair"));
444 CFReleaser<CFStringRef> keyLabel =
445 CFStringCreateWithCString(0,
446 keyName.
toUri().c_str(),
447 kCFStringEncodingUTF8);
449 CFReleaser<CFMutableDictionaryRef> searchDict =
450 CFDictionaryCreateMutable(0, 5,
451 &kCFTypeDictionaryKeyCallBacks,
452 &kCFTypeDictionaryValueCallBacks);
454 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
455 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
456 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
457 OSStatus res = SecItemDelete(searchDict.get());
459 if (res == errSecSuccess)
462 if (res == errSecAuthFailed && !needRetry) {
471 BOOST_THROW_EXCEPTION(
Error(
"SecTpmOsx::generateSymmetricKeyInTpm is not supported"));
503 shared_ptr<PublicKey>
506 CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName,
KeyClass::PUBLIC);
507 if (publicKey ==
nullptr) {
508 BOOST_THROW_EXCEPTION(
Error(
"Requested public key [" + keyName.
toUri() +
"] does not exist " 512 CFReleaser<CFDataRef> exportedKey;
513 OSStatus res = SecItemExport(publicKey.get(),
518 if (res != errSecSuccess) {
519 BOOST_THROW_EXCEPTION(
Error(
"Cannot export requested public key from OSX Keychain"));
522 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey.get()),
523 CFDataGetLength(exportedKey.get()));
538 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName,
KeyClass::PRIVATE);
539 if (privateKey ==
nullptr) {
541 BOOST_THROW_EXCEPTION(
Error(
"Private key [" + keyName.
toUri() +
"] does not exist " 547 CFReleaser<CFDataRef> exportedKey;
548 OSStatus res = SecItemExport(privateKey.get(),
554 if (res != errSecSuccess) {
555 if (res == errSecAuthFailed && !needRetry) {
565 uint32_t version = 0;
567 bool hasParameters =
false;
568 Oid algorithmParameter;
569 switch (publicKey->getKeyType()) {
572 hasParameters =
false;
578 StringSource src(publicKey->get().buf(), publicKey->get().size(),
true);
579 BERSequenceDecoder subjectPublicKeyInfo(src);
581 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
583 algorithm.
decode(algorithmInfo);
584 algorithmParameter.
decode(algorithmInfo);
587 hasParameters =
true;
592 BOOST_THROW_EXCEPTION(
Error(
"Unsupported key type" +
593 boost::lexical_cast<std::string>(publicKey->getKeyType())));
597 FileSink sink(pkcs8Os);
599 SecByteBlock rawKeyBits;
604 DERSequenceEncoder privateKeyInfo(sink);
606 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
607 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
609 algorithm.
encode(privateKeyAlgorithm);
611 algorithmParameter.
encode(privateKeyAlgorithm);
613 DEREncodeNull(privateKeyAlgorithm);
615 privateKeyAlgorithm.MessageEnd();
616 DEREncodeOctetString(privateKeyInfo,
617 CFDataGetBytePtr(exportedKey.get()),
618 CFDataGetLength(exportedKey.get()));
620 privateKeyInfo.MessageEnd();
622 return pkcs8Os.buf();
626 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) 627 #pragma GCC diagnostic push 628 #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) 629 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 634 const uint8_t* buf,
size_t size,
639 StringSource privateKeySource(buf, size,
true);
640 SecByteBlock rawKeyBits;
645 BERSequenceDecoder privateKeyInfo(privateKeySource);
648 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
649 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
652 keyTypeOid.
decode(sequenceDecoder);
655 BERDecodeNull(sequenceDecoder);
658 parameterOid.
decode(sequenceDecoder);
663 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
665 privateKeyInfo.MessageEnd();
667 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
668 rawKeyBits.BytePtr(),
672 SecExternalFormat externalFormat = kSecFormatOpenSSL;
673 SecExternalItemType externalType = kSecItemTypePrivateKey;
674 SecKeyImportExportParameters keyParams;
675 memset(&keyParams, 0,
sizeof(keyParams));
676 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
677 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
678 CFReleaser<SecAccessRef> access;
679 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
680 keyName.
toUri().c_str(),
681 kCFStringEncodingUTF8);
682 SecAccessCreate(keyLabel.get(), 0, &access.get());
683 keyParams.accessRef = access.get();
684 CFReleaser<CFArrayRef> outItems;
687 #pragma clang diagnostic push 688 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 691 OSStatus res = SecKeychainItemImport(importedKey.get(),
697 m_impl->m_keyChainRef,
701 #pragma clang diagnostic pop 704 if (res != errSecSuccess) {
705 if (res == errSecAuthFailed && !needRetry) {
716 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
717 SecKeychainAttribute attrs[1];
718 SecKeychainAttributeList attrList = {0, attrs};
719 string keyUri = keyName.
toUri();
721 attrs[attrList.count].tag = kSecKeyPrintName;
722 attrs[attrList.count].length = keyUri.size();
723 attrs[attrList.count].data =
const_cast<char*
>(keyUri.c_str());
727 res = SecKeychainItemModifyAttributesAndData(privateKey,
732 if (res != errSecSuccess) {
739 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) 740 #pragma GCC diagnostic pop 741 #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) 746 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
751 SecExternalFormat externalFormat = kSecFormatOpenSSL;
752 SecExternalItemType externalType = kSecItemTypePublicKey;
753 CFReleaser<CFArrayRef> outItems;
755 OSStatus res = SecItemImport(importedKey.get(),
761 m_impl->m_keyChainRef,
764 if (res != errSecSuccess)
768 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
769 SecKeychainAttribute attrs[1];
770 SecKeychainAttributeList attrList = { 0, attrs };
771 string keyUri = keyName.
toUri();
773 attrs[attrList.count].tag = kSecKeyPrintName;
774 attrs[attrList.count].length = keyUri.size();
775 attrs[attrList.count].data =
const_cast<char*
>(keyUri.c_str());
779 res = SecKeychainItemModifyAttributesAndData(publicKey,
784 if (res != errSecSuccess)
794 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
799 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName,
KeyClass::PRIVATE);
800 if (privateKey ==
nullptr) {
801 BOOST_THROW_EXCEPTION(
Error(
"Private key [" + keyName.
toUri() +
"] does not exist " 805 CFReleaser<CFErrorRef> error;
807 CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
809 if (error !=
nullptr)
810 BOOST_THROW_EXCEPTION(
Error(
"Fail to create signer"));
813 SecTransformSetAttribute(signer.get(),
814 kSecTransformInputAttributeName,
817 if (error !=
nullptr)
818 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure input of signer"));
821 SecTransformSetAttribute(signer.get(),
825 if (error !=
nullptr)
826 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure digest algorithm of signer"));
829 SecTransformSetAttribute(signer.get(),
830 kSecDigestTypeAttribute,
831 m_impl->getDigestAlgorithm(digestAlgorithm),
833 if (error !=
nullptr)
834 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure digest algorithm of signer"));
837 long digestSize = m_impl->getDigestSize(digestAlgorithm);
838 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
839 SecTransformSetAttribute(signer.get(),
840 kSecDigestLengthAttribute,
843 if (error !=
nullptr)
844 BOOST_THROW_EXCEPTION(
Error(
"Fail to configure digest size of signer"));
848 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
849 if (error !=
nullptr) {
854 BOOST_THROW_EXCEPTION(
Error(
"Fail to unlock the keychain"));
858 BOOST_THROW_EXCEPTION(
Error(
"Fail to sign data"));
862 if (signature ==
nullptr)
863 BOOST_THROW_EXCEPTION(
Error(
"Signature is NULL!\n"));
866 make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
867 CFDataGetLength(signature.get())));
873 BOOST_THROW_EXCEPTION(
Error(
"SecTpmOsx::decryptInTpm is not supported"));
918 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
919 if (privateKey ==
nullptr) {
920 BOOST_THROW_EXCEPTION(
Error(
"Private key [" + keyName.
toUri() +
"] does not exist " 924 CFReleaser<SecAccessRef> accRef;
925 SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
927 CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
928 kSecACLAuthorizationSign);
931 SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
933 CFReleaser<CFArrayRef> appList;
934 CFReleaser<CFStringRef> description;
935 SecKeychainPromptSelector promptSelector;
936 SecACLCopyContents(aclRef,
941 CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
945 CFReleaser<SecTrustedApplicationRef> trustedApp;
946 SecTrustedApplicationCreateFromPath(appPath.c_str(),
949 CFArrayAppendValue(newAppList.get(), trustedApp.get());
951 SecACLSetContents(aclRef,
956 SecKeychainItemSetAccess(privateKey.get(), accRef.get());
963 BOOST_THROW_EXCEPTION(
Error(
"SecTpmOsx::encryptInTpm is not supported"));
1003 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
1005 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1007 kCFStringEncodingUTF8);
1009 CFReleaser<CFMutableDictionaryRef> attrDict =
1010 CFDictionaryCreateMutable(0,
1012 &kCFTypeDictionaryKeyCallBacks,
1015 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1017 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1018 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
1020 CFReleaser<SecKeychainItemRef> itemRef;
1022 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
1024 if (res == errSecSuccess)
1034 return SecRandomCopyBytes(kSecRandomDefault, size, res) == 0;
1041 CFReleaser<SecKeychainItemRef>
1042 SecTpmOsx::Impl::getKey(
const Name& keyName,
KeyClass keyClass)
1044 string keyNameUri = toInternalKeyName(keyName, keyClass);
1046 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1048 kCFStringEncodingUTF8);
1050 CFReleaser<CFMutableDictionaryRef> attrDict =
1051 CFDictionaryCreateMutable(0,
1053 &kCFTypeDictionaryKeyCallBacks,
1056 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1057 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1058 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
1059 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
1061 CFReleaser<SecKeychainItemRef> keyItem;
1063 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
1065 if (res != errSecSuccess)
1072 SecTpmOsx::Impl::toInternalKeyName(
const Name& keyName,
KeyClass keyClass)
1074 string keyUri = keyName.
toUri();
1077 return keyUri +
"/symmetric";
1087 return kSecAttrKeyTypeRSA;
1089 return kSecAttrKeyTypeECDSA;
1096 SecTpmOsx::Impl::getSymKeyType(
KeyType keyType)
1100 return kSecAttrKeyTypeAES;
1107 SecTpmOsx::Impl::getKeyClass(
KeyClass keyClass)
1111 return kSecAttrKeyClassPrivate;
1113 return kSecAttrKeyClassPublic;
1115 return kSecAttrKeyClassSymmetric;
1124 switch (digestAlgo) {
1126 return kSecDigestSHA2;
1135 switch (digestAlgo) {
bool importPrivateKeyPkcs8IntoTpmInternal(const Name &keyName, const uint8_t *buf, size_t size, bool needRetry)
void decode(CryptoPP::BufferedTransformation &in)
virtual std::string getScheme()
virtual bool doesKeyExistInTpm(const Name &keyName, KeyClass keyClass)
Check if a particular key exists.
virtual void setTpmPassword(const uint8_t *password, size_t passwordLength)
set password of TPM
const Oid ECDSA("1.2.840.10045.2.1")
Copyright (c) 2013-2017 Regents of the University of California.
Copyright (c) 2013-2017 Regents of the University of California.
KeyType getKeyType() const
uint32_t getKeySize() const
void encode(CryptoPP::BufferedTransformation &out) const
virtual void generateSymmetricKeyInTpm(const Name &keyName, const KeyParams ¶ms)
Generate a symmetric key.
static CFTypeRef getDigestAlgorithm(DigestAlgorithm digestAlgo)
Represents a TLV element of NDN packet format.
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.
bool operator!=(const Data &lhs, const Data &rhs)
std::string toUri() const
Get URI representation of the name.
virtual void resetTpmPassword()
reset password of TPM
static CFTypeRef getAsymKeyType(KeyType keyType)
const Oid RSA("1.2.840.113549.1.1.1")
SecTpmOsx(const std::string &location="")
virtual bool importPublicKeyPkcs1IntoTpm(const Name &keyName, const uint8_t *buf, size_t size)
Import a public key in PKCS#1 formatted buffer of size bufferSize.
virtual bool getInTerminal() const
Get value of inTerminal flag.
virtual ConstBufferPtr decryptInTpm(const uint8_t *data, size_t dataLength, const Name &keyName, bool isSymmetric)
Decrypt data.
static long getDigestSize(DigestAlgorithm digestAlgo)
Use the SHA256 hash of the public key as the key id.
Represents an absolute name.
virtual bool generateRandomBlock(uint8_t *res, size_t size)
Generate a random block.
void generateKeyPairInTpmInternal(const Name &keyName, const KeyParams ¶ms, bool needRetry)
virtual bool unlockTpm(const char *password, size_t passwordLength, bool usePassword)
Unlock the TPM.
virtual void setInTerminal(bool inTerminal)
Set inTerminal flag to inTerminal.
virtual ConstBufferPtr encryptInTpm(const uint8_t *data, size_t dataLength, const Name &keyName, bool isSymmetric)
Encrypt data.
SecTpm is the base class of the TPM classes.
void deleteKeyPairInTpmInternal(const Name &keyName, bool needRetry)
Base class of key parameters.
virtual bool isLocked()
Check if TPM is locked.
bool operator==(const Data &lhs, const Data &rhs)
implements an output stream that constructs ndn::Buffer
shared_ptr< const Buffer > ConstBufferPtr
SimplePublicKeyParams is a template for public keys with only one parameter: size.
static const std::string SCHEME
Block signInTpmInternal(const uint8_t *data, size_t dataLength, const Name &keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
virtual shared_ptr< v1::PublicKey > getPublicKeyFromTpm(const Name &keyName)
Get a public key.