blob: 5132c3d75bc748c58b23399ca166cf483f395539 [file] [log] [blame]
Jeff Thompson2747dc02013-10-04 19:11:34 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07003 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
11 *
12 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Jeff Thompson2747dc02013-10-04 19:11:34 -070013 */
14
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080015#include "common.hpp"
16
Alexander Afanasyev19508852014-01-29 01:01:51 -080017#include "sec-tpm-osx.hpp"
Yingdi Yuf56c68f2014-04-24 21:50:13 -070018#include "public-key.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070019#include "cryptopp.hpp"
Jeff Thompson2747dc02013-10-04 19:11:34 -070020
Yingdi Yu2b2b4792014-02-04 16:27:07 -080021#include <pwd.h>
22#include <unistd.h>
23#include <stdlib.h>
24#include <string.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070025
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080026#include <CoreFoundation/CoreFoundation.h>
27#include <Security/Security.h>
Yingdi Yu4b752752014-02-18 12:24:03 -080028#include <Security/SecRandom.h>
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080029#include <CoreServices/CoreServices.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070030
Alexander Afanasyev59d67a52014-04-03 16:09:31 -070031#include <Security/SecDigestTransform.h>
32
Jeff Thompson2747dc02013-10-04 19:11:34 -070033using namespace std;
Jeff Thompson2747dc02013-10-04 19:11:34 -070034
Yingdi Yufc40d872014-02-18 12:56:04 -080035namespace ndn {
36
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070037class SecTpmOsx::Impl
38{
Yingdi Yu2b2b4792014-02-04 16:27:07 -080039public:
40 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -080041 : m_passwordSet(false)
42 , m_inTerminal(false)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070043 {
44 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070045
Yingdi Yu2b2b4792014-02-04 16:27:07 -080046 /**
47 * @brief Convert NDN name of a key to internal name of the key.
48 *
Yingdi Yufc40d872014-02-18 12:56:04 -080049 * @param keyName
50 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -080051 * @return the internal key name
52 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070053 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070054 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070055
Yingdi Yu2b2b4792014-02-04 16:27:07 -080056 /**
57 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -080058 *
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070059 * @param keyName
Yingdi Yufc40d872014-02-18 12:56:04 -080060 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -080061 * @returns pointer to the key
62 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070063 SecKeychainItemRef
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070064 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070065
Yingdi Yu2b2b4792014-02-04 16:27:07 -080066 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080067 * @brief Convert keyType to MAC OS symmetric key key type
68 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080069 * @param keyType
70 * @returns MAC OS key type
71 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070072 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080073 getSymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070074
Yingdi Yu2b2b4792014-02-04 16:27:07 -080075 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080076 * @brief Convert keyType to MAC OS asymmetirc key type
77 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080078 * @param keyType
79 * @returns MAC OS key type
80 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070081 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080082 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070083
Yingdi Yu2b2b4792014-02-04 16:27:07 -080084 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080085 * @brief Convert keyClass to MAC OS key class
86 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080087 * @param keyClass
88 * @returns MAC OS key class
89 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070090 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080091 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070092
Yingdi Yu2b2b4792014-02-04 16:27:07 -080093 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080094 * @brief Convert digestAlgo to MAC OS algorithm id
95 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080096 * @param digestAlgo
97 * @returns MAC OS algorithm id
98 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070099 const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800100 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700101
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800102 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800103 * @brief Get the digest size of the corresponding algorithm
104 *
105 * @param digestAlgo
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800106 * @return digest size
107 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700108 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800109 getDigestSize(DigestAlgorithm digestAlgo);
110
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800111 ///////////////////////////////////////////////
112 // everything here is public, including data //
113 ///////////////////////////////////////////////
114public:
115 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800116 bool m_passwordSet;
117 string m_password;
118 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800119};
120
121
122SecTpmOsx::SecTpmOsx()
123 : m_impl(new Impl)
124{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700125 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700126 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800127 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700128 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800129
Yingdi Yube4150e2014-02-18 13:02:46 -0800130 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700131
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800132 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Yingdi Yube4150e2014-02-18 13:02:46 -0800133 throw Error("No default keychain, create one first!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800134}
135
136SecTpmOsx::~SecTpmOsx(){
137 //TODO: implement
138}
139
Yingdi Yube4150e2014-02-18 13:02:46 -0800140void
141SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
142{
143 m_impl->m_passwordSet = true;
144 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
145 m_impl->m_password.clear();
146 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
147}
148
149void
150SecTpmOsx::resetTpmPassword()
151{
152 m_impl->m_passwordSet = false;
153 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
154 m_impl->m_password.clear();
155}
156
157void
158SecTpmOsx::setInTerminal(bool inTerminal)
159{
160 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700161 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700162 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800163 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700164 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800165}
166
167bool
168SecTpmOsx::getInTerminal()
169{
170 return m_impl->m_inTerminal;
171}
172
173bool
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700174SecTpmOsx::isLocked()
Yingdi Yube4150e2014-02-18 13:02:46 -0800175{
176 SecKeychainStatus keychainStatus;
177
178 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700179 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800180 return true;
181 else
182 return ((kSecUnlockStateStatus & keychainStatus) == 0);
183}
184
Yingdi Yu2e57a582014-02-20 23:34:43 -0800185bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800186SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
187{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700188 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800189
190 // If the default key chain is already unlocked, return immediately.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700191 if (!isLocked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800192 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800193
194 // If the default key chain is locked, unlock the key chain.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700195 if (usePassword)
Yingdi Yube4150e2014-02-18 13:02:46 -0800196 {
197 // Use the supplied password.
198 res = SecKeychainUnlock(m_impl->m_keyChainRef,
199 passwordLength,
200 password,
201 true);
202 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700203 else if (m_impl->m_passwordSet)
Yingdi Yube4150e2014-02-18 13:02:46 -0800204 {
205 // If no password supplied, then use the configured password if exists.
206 SecKeychainUnlock(m_impl->m_keyChainRef,
207 m_impl->m_password.size(),
208 m_impl->m_password.c_str(),
209 true);
210 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700211 else if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800212 {
213 // If no configured password, get password from terminal if inTerminal set.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700214 bool isLocked = true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800215 const char* fmt = "Password to unlock the default keychain: ";
216 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700217
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700218 while (isLocked)
Yingdi Yube4150e2014-02-18 13:02:46 -0800219 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700220 if (count > 2)
Yingdi Yube4150e2014-02-18 13:02:46 -0800221 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700222
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700223 char* getPassword = 0;
Yingdi Yube4150e2014-02-18 13:02:46 -0800224 getPassword = getpass(fmt);
225 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700226
Yingdi Yube4150e2014-02-18 13:02:46 -0800227 if (!getPassword)
228 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700229
Yingdi Yube4150e2014-02-18 13:02:46 -0800230 res = SecKeychainUnlock(m_impl->m_keyChainRef,
231 strlen(getPassword),
232 getPassword,
233 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700234
Yingdi Yube4150e2014-02-18 13:02:46 -0800235 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700236
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700237 if (res == errSecSuccess)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800238 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800239 }
240 }
241 else
242 {
243 // If inTerminal is not set, get the password from GUI.
244 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
245 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800246
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700247 return !isLocked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800248}
249
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700250void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700251SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName, KeyType keyType,
252 int keySize, bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700253{
254
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700255 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
256 {
257 throw Error("keyName has existed");
258 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800259
260 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
261
262 SecKeyRef publicKey, privateKey;
263
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700264 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700265 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800266 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700267
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700268 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800269 3,
270 &kCFTypeDictionaryKeyCallBacks,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700271 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800272
273 CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700274 CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(0,
275 kCFNumberIntType,
276 &keySize));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800277 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
278
279 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict, &publicKey, &privateKey);
280
Yingdi Yube4150e2014-02-18 13:02:46 -0800281 if (res == errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800282 {
283 CFRelease(publicKey);
284 CFRelease(privateKey);
285 return;
286 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700287
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700288 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800289 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700290 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800291 generateKeyPairInTpmInternal(keyName, keyType, keySize, true);
292 else
293 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800294 }
295 else
296 {
Yingdi Yube4150e2014-02-18 13:02:46 -0800297 throw Error("Fail to create a key pair");
298 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800299}
300
301void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700302SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800303{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700304 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700305 keyName.toUri().c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800306 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800307
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700308 CFMutableDictionaryRef searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700309 CFDictionaryCreateMutable(0, 5,
310 &kCFTypeDictionaryKeyCallBacks,
311 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800312
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800313 CFDictionaryAddValue(searchDict, kSecClass, kSecClassKey);
314 CFDictionaryAddValue(searchDict, kSecAttrLabel, keyLabel);
315 CFDictionaryAddValue(searchDict, kSecMatchLimit, kSecMatchLimitAll);
Yingdi Yube4150e2014-02-18 13:02:46 -0800316 OSStatus res = SecItemDelete(searchDict);
317
318 if (res == errSecSuccess)
319 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700320
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700321 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800322 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700323 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800324 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800325 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800326}
327
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700328void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700329SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, KeyType keyType, int keySize)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800330{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800331 throw Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700332 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800333 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800334
Yingdi Yu2e57a582014-02-20 23:34:43 -0800335 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800336
Yingdi Yu2e57a582014-02-20 23:34:43 -0800337 // CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
338 // 0,
339 // &kCFTypeDictionaryKeyCallBacks,
340 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800341
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700342 // CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700343 // keyNameUri.c_str(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800344 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800345
Yingdi Yu2e57a582014-02-20 23:34:43 -0800346 // CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getSymKeyType(keyType));
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700347 // CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(kCFAllocatorDefault,
348 // kCFNumberSInt32Type,
349 // &keySize));
Yingdi Yu2e57a582014-02-20 23:34:43 -0800350 // CFDictionaryAddValue(attrDict, kSecAttrIsPermanent, kCFBooleanTrue);
351 // CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800352
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700353 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800354
Yingdi Yu2e57a582014-02-20 23:34:43 -0800355 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800356
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700357 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800358 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800359}
360
Yingdi Yu2e57a582014-02-20 23:34:43 -0800361shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700362SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800363{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800364 SecKeychainItemRef publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
365
366 CFDataRef exportedKey;
367
368 OSStatus res = SecItemExport(publicKey,
369 kSecFormatOpenSSL,
370 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700371 0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800372 &exportedKey);
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800373 if (res != errSecSuccess)
374 {
375 throw Error("Cannot export requested public key from OSX Keychain");
376 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800377
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700378 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey),
379 CFDataGetLength(exportedKey));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800380 CFRelease(exportedKey);
381 return key;
382}
383
384ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700385SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800386{
387 using namespace CryptoPP;
388
389 SecKeychainItemRef privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
390 CFDataRef exportedKey;
391 OSStatus res = SecItemExport(privateKey,
392 kSecFormatOpenSSL,
393 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700394 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800395 &exportedKey);
396
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700397 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800398 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700399 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800400 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700401 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700402 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800403 else
404 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800405 }
406 else
407 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800408 }
409
410 OBufferStream pkcs1Os;
411 FileSink sink(pkcs1Os);
412
413 uint32_t version = 0;
414 OID algorithm("1.2.840.113549.1.1.1");
415 SecByteBlock rawKeyBits;
416 // PrivateKeyInfo ::= SEQUENCE {
417 // version INTEGER,
418 // privateKeyAlgorithm SEQUENCE,
419 // privateKey OCTECT STRING}
420 DERSequenceEncoder privateKeyInfo(sink);
421 {
422 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
423 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
424 {
425 algorithm.encode(privateKeyAlgorithm);
426 DEREncodeNull(privateKeyAlgorithm);
427 }
428 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700429 DEREncodeOctetString(privateKeyInfo,
430 CFDataGetBytePtr(exportedKey),
431 CFDataGetLength(exportedKey));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800432 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700433 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800434
435 CFRelease(exportedKey);
436 return pkcs1Os.buf();
437}
438
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700439#ifdef __GNUC__
440#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
441#pragma GCC diagnostic push
442#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
443#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
444#endif // __GNUC__
445
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800446bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700447SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700448 const uint8_t* buf, size_t size,
449 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800450{
451 using namespace CryptoPP;
452
453 StringSource privateKeySource(buf, size, true);
454 uint32_t tmpNum;
455 OID tmpOID;
456 SecByteBlock rawKeyBits;
457 // PrivateKeyInfo ::= SEQUENCE {
458 // INTEGER,
459 // SEQUENCE,
460 // OCTECT STRING}
461 BERSequenceDecoder privateKeyInfo(privateKeySource);
462 {
463 BERDecodeUnsigned<uint32_t>(privateKeyInfo, tmpNum, INTEGER);
464 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
465 {
466 tmpOID.decode(sequenceDecoder);
467 BERDecodeNull(sequenceDecoder);
468 }
469 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
470 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700471 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800472
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700473 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800474 rawKeyBits.BytePtr(),
475 rawKeyBits.size(),
476 kCFAllocatorNull);
477
478 SecExternalFormat externalFormat = kSecFormatOpenSSL;
479 SecExternalItemType externalType = kSecItemTypePrivateKey;
480 SecKeyImportExportParameters keyParams;
481 memset(&keyParams, 0, sizeof(keyParams));
482 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
483 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
484 SecAccessRef access;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700485 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700486 keyName.toUri().c_str(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800487 kCFStringEncodingUTF8);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700488 SecAccessCreate(keyLabel, 0, &access);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800489 keyParams.accessRef = access;
490 CFArrayRef outItems;
491
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700492#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700493#pragma clang diagnostic push
494#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700495#endif // __clang__
496
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800497 OSStatus res = SecKeychainItemImport (importedKey,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700498 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800499 &externalFormat,
500 &externalType,
501 0,
502 &keyParams,
503 m_impl->m_keyChainRef,
504 &outItems);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700505
506#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700507#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700508#endif // __clang__
509
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700510 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800511 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700512 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800513 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700514 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700515 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800516 else
517 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800518 }
519 else
520 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800521 }
522
523 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
524 SecKeychainAttribute attrs[1]; // maximum number of attributes
525 SecKeychainAttributeList attrList = { 0, attrs };
526 string keyUri = keyName.toUri();
527 {
528 attrs[attrList.count].tag = kSecKeyPrintName;
529 attrs[attrList.count].length = keyUri.size();
530 attrs[attrList.count].data = (void *)keyUri.c_str();
531 attrList.count++;
532 }
533
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700534 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800535 &attrList,
536 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700537 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700538
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700539 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800540 {
541 return false;
542 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700543
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800544 CFRelease(importedKey);
545 return true;
546}
547
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700548#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
549#pragma GCC diagnostic pop
550#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
551
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800552bool
553SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
554{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700555 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800556 buf,
557 size,
558 kCFAllocatorNull);
559
560 SecExternalFormat externalFormat = kSecFormatOpenSSL;
561 SecExternalItemType externalType = kSecItemTypePublicKey;
562 CFArrayRef outItems;
563
564 OSStatus res = SecItemImport (importedKey,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700565 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800566 &externalFormat,
567 &externalType,
568 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700569 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800570 m_impl->m_keyChainRef,
571 &outItems);
572
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700573 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800574 return false;
575
576 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
577 SecKeychainAttribute attrs[1]; // maximum number of attributes
578 SecKeychainAttributeList attrList = { 0, attrs };
579 string keyUri = keyName.toUri();
580 {
581 attrs[attrList.count].tag = kSecKeyPrintName;
582 attrs[attrList.count].length = keyUri.size();
583 attrs[attrList.count].data = (void *)keyUri.c_str();
584 attrList.count++;
585 }
586
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700587 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800588 &attrList,
589 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700590 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700591
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700592 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800593 return false;
594
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800595 CFRelease(importedKey);
596 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800597}
598
599Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700600SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
601 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800602{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700603 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800604 data,
605 dataLength,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800606 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800607
608 SecKeyRef privateKey = (SecKeyRef)m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700609
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800610 CFErrorRef error;
611 SecTransformRef signer = SecSignTransformCreate((SecKeyRef)privateKey, &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700612 if (error)
613 throw Error("Fail to create signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800614
615 // Set input
616 Boolean set_res = SecTransformSetAttribute(signer,
617 kSecTransformInputAttributeName,
618 dataRef,
619 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700620 if (error)
621 throw Error("Fail to configure input of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800622
623 // Enable use of padding
Yingdi Yu2e57a582014-02-20 23:34:43 -0800624 SecTransformSetAttribute(signer,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800625 kSecPaddingKey,
626 kSecPaddingPKCS1Key,
627 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700628 if (error)
629 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800630
631 // Set padding type
632 set_res = SecTransformSetAttribute(signer,
633 kSecDigestTypeAttribute,
634 m_impl->getDigestAlgorithm(digestAlgorithm),
635 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700636 if (error)
637 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800638
639 // Set padding attribute
640 long digestSize = m_impl->getDigestSize(digestAlgorithm);
641 set_res = SecTransformSetAttribute(signer,
642 kSecDigestLengthAttribute,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700643 CFNumberCreate(0, kCFNumberLongType, &digestSize),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800644 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700645 if (error)
646 throw Error("Fail to configure digest size of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800647
648 // Actually sign
649 CFDataRef signature = (CFDataRef) SecTransformExecute(signer, &error);
Yingdi Yube4150e2014-02-18 13:02:46 -0800650 if (error)
651 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700652 if (!needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800653 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700654 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800655 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
656 else
657 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800658 }
659 else
660 {
661 CFShow(error);
662 throw Error("Fail to sign data");
663 }
664 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800665
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700666 if (!signature)
667 throw Error("Signature is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800668
669 return Block(Tlv::SignatureValue,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800670 make_shared<Buffer>(CFDataGetBytePtr(signature), CFDataGetLength(signature)));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800671}
672
673ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700674SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800675{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800676 throw Error("SecTpmOsx::decryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800677
Yingdi Yu2e57a582014-02-20 23:34:43 -0800678 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700679 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800680 // keyClass = KEY_CLASS_SYMMETRIC;
681 // else
682 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800683
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700684 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800685 // reinterpret_cast<const unsigned char*>(data),
686 // dataLength
687 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800688
Yingdi Yu2e57a582014-02-20 23:34:43 -0800689 // SecKeyRef decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800690
Yingdi Yu2e57a582014-02-20 23:34:43 -0800691 // CFErrorRef error;
692 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
693 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800694
Yingdi Yu2e57a582014-02-20 23:34:43 -0800695 // Boolean set_res = SecTransformSetAttribute(decrypt,
696 // kSecTransformInputAttributeName,
697 // dataRef,
698 // &error);
699 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800700
Yingdi Yu2e57a582014-02-20 23:34:43 -0800701 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
702 // if (error)
703 // {
704 // CFShow(error);
705 // throw Error("Fail to decrypt data");
706 // }
707 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800708
Yingdi Yu2e57a582014-02-20 23:34:43 -0800709 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800710}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700711
Yingdi Yu2e57a582014-02-20 23:34:43 -0800712void
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700713SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800714{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700715 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800716 {
717 SecKeychainItemRef privateKey = m_impl->getKey(keyName, keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700718
Yingdi Yu2e57a582014-02-20 23:34:43 -0800719 SecAccessRef accRef;
720 OSStatus acc_res = SecKeychainItemCopyAccess(privateKey, &accRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700721
Yingdi Yu2e57a582014-02-20 23:34:43 -0800722 CFArrayRef signACL = SecAccessCopyMatchingACLList(accRef,
723 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700724
Yingdi Yu2e57a582014-02-20 23:34:43 -0800725 SecACLRef aclRef = (SecACLRef) CFArrayGetValueAtIndex(signACL, 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700726
Yingdi Yu2e57a582014-02-20 23:34:43 -0800727 CFArrayRef appList;
728 CFStringRef description;
729 SecKeychainPromptSelector promptSelector;
730 OSStatus acl_res = SecACLCopyContents(aclRef,
731 &appList,
732 &description,
733 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700734
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700735 CFMutableArrayRef newAppList = CFArrayCreateMutableCopy(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800736 0,
737 appList);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700738
Yingdi Yu2e57a582014-02-20 23:34:43 -0800739 SecTrustedApplicationRef trustedApp;
740 acl_res = SecTrustedApplicationCreateFromPath(appPath.c_str(),
741 &trustedApp);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700742
Yingdi Yu2e57a582014-02-20 23:34:43 -0800743 CFArrayAppendValue(newAppList, trustedApp);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700744
Yingdi Yu2e57a582014-02-20 23:34:43 -0800745 acl_res = SecACLSetContents(aclRef,
746 newAppList,
747 description,
748 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700749
Yingdi Yu2e57a582014-02-20 23:34:43 -0800750 acc_res = SecKeychainItemSetAccess(privateKey, accRef);
751 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800752}
753
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800754ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700755SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800756{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800757 throw Error("SecTpmOsx::encryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800758
Yingdi Yu2e57a582014-02-20 23:34:43 -0800759 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700760 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800761 // keyClass = KEY_CLASS_SYMMETRIC;
762 // else
763 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700764
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700765 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800766 // reinterpret_cast<const unsigned char*>(data),
767 // dataLength
768 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700769
Yingdi Yu2e57a582014-02-20 23:34:43 -0800770 // SecKeyRef encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800771
Yingdi Yu2e57a582014-02-20 23:34:43 -0800772 // CFErrorRef error;
773 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
774 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800775
Yingdi Yu2e57a582014-02-20 23:34:43 -0800776 // Boolean set_res = SecTransformSetAttribute(encrypt,
777 // kSecTransformInputAttributeName,
778 // dataRef,
779 // &error);
780 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800781
Yingdi Yu2e57a582014-02-20 23:34:43 -0800782 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
783 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800784
Yingdi Yu2e57a582014-02-20 23:34:43 -0800785 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800786
Yingdi Yu2e57a582014-02-20 23:34:43 -0800787 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800788}
789
790bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700791SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800792{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800793 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
794
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700795 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700796 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800797 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700798
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700799 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800800 4,
801 &kCFTypeDictionaryKeyCallBacks,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700802 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800803
804 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800805 // CFDictionaryAddValue(attrDict, kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800806 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
807 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700808
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800809 SecKeychainItemRef itemRef;
810 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict, (CFTypeRef*)&itemRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700811
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700812 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800813 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800814 else
815 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800816
817}
818
Yingdi Yu4b752752014-02-18 12:24:03 -0800819bool
820SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
821{
822 return (SecRandomCopyBytes(kSecRandomDefault, size, res) == 0);
823}
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800824
825////////////////////////////////
826// OSXPrivateKeyStorage::Impl //
827////////////////////////////////
828
829SecKeychainItemRef
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700830SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800831{
832 string keyNameUri = toInternalKeyName(keyName, keyClass);
833
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700834 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700835 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800836 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700837
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700838 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800839 5,
840 &kCFTypeDictionaryKeyCallBacks,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700841 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800842
843 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
844 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
845 CFDictionaryAddValue(attrDict, kSecAttrKeyClass, getKeyClass(keyClass));
846 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700847
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800848 SecKeychainItemRef keyItem;
849
850 OSStatus res = SecItemCopyMatching((CFDictionaryRef) attrDict, (CFTypeRef*)&keyItem);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700851
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700852 if (res != errSecSuccess)
853 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800854 else
855 return keyItem;
856}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700857
858string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700859SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800860{
861 string keyUri = keyName.toUri();
862
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700863 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800864 return keyUri + "/symmetric";
865 else
866 return keyUri;
867}
868
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700869const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800870SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
871{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700872 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800873 case KEY_TYPE_RSA:
874 return kSecAttrKeyTypeRSA;
875 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700876 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800877 }
878}
879
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700880const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800881SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
882{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700883 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800884 case KEY_TYPE_AES:
885 return kSecAttrKeyTypeAES;
886 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700887 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800888 }
889}
890
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700891const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800892SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
893{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700894 switch (keyClass){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800895 case KEY_CLASS_PRIVATE:
896 return kSecAttrKeyClassPrivate;
897 case KEY_CLASS_PUBLIC:
898 return kSecAttrKeyClassPublic;
899 case KEY_CLASS_SYMMETRIC:
900 return kSecAttrKeyClassSymmetric;
901 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700902 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800903 }
904}
905
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700906const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800907SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
908{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700909 switch (digestAlgo){
Jeff Thompson2747dc02013-10-04 19:11:34 -0700910 // case DIGEST_MD2:
911 // return kSecDigestMD2;
912 // case DIGEST_MD5:
913 // return kSecDigestMD5;
914 // case DIGEST_SHA1:
915 // return kSecDigestSHA1;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800916 case DIGEST_ALGORITHM_SHA256:
917 return kSecDigestSHA2;
918 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700919 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700920 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800921}
Jeff Thompson2747dc02013-10-04 19:11:34 -0700922
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700923long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800924SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
925{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700926 switch (digestAlgo){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800927 case DIGEST_ALGORITHM_SHA256:
928 return 256;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700929 // case DIGEST_SHA1:
930 // case DIGEST_MD2:
931 // case DIGEST_MD5:
932 // return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800933 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800934 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700935 }
Jeff Thompson2747dc02013-10-04 19:11:34 -0700936}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700937
Yingdi Yufc40d872014-02-18 12:56:04 -0800938} // namespace ndn