blob: 84be0e235c0f5fe0e0cca0667cf6411bb147dd1a [file] [log] [blame]
Jeff Thompson2747dc02013-10-04 19:11:34 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Yingdi Yu <yingdi@cs.ucla.edu>
5 * See COPYING for copyright and distribution information.
6 */
7
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -08008#include "common.hpp"
9
Alexander Afanasyev19508852014-01-29 01:01:51 -080010#include "sec-tpm-osx.hpp"
11
12#include "security/public-key.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070013#include "cryptopp.hpp"
Jeff Thompson2747dc02013-10-04 19:11:34 -070014
Yingdi Yu2b2b4792014-02-04 16:27:07 -080015#include <pwd.h>
16#include <unistd.h>
17#include <stdlib.h>
18#include <string.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070019
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080020#include <CoreFoundation/CoreFoundation.h>
21#include <Security/Security.h>
Yingdi Yu4b752752014-02-18 12:24:03 -080022#include <Security/SecRandom.h>
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080023#include <CoreServices/CoreServices.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070024
Alexander Afanasyev59d67a52014-04-03 16:09:31 -070025#include <Security/SecDigestTransform.h>
26
Jeff Thompson2747dc02013-10-04 19:11:34 -070027using namespace std;
Jeff Thompson2747dc02013-10-04 19:11:34 -070028
Yingdi Yufc40d872014-02-18 12:56:04 -080029namespace ndn {
30
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070031class SecTpmOsx::Impl
32{
Yingdi Yu2b2b4792014-02-04 16:27:07 -080033public:
34 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -080035 : m_passwordSet(false)
36 , m_inTerminal(false)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070037 {
38 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070039
Yingdi Yu2b2b4792014-02-04 16:27:07 -080040 /**
41 * @brief Convert NDN name of a key to internal name of the key.
42 *
Yingdi Yufc40d872014-02-18 12:56:04 -080043 * @param keyName
44 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -080045 * @return the internal key name
46 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070047 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070048 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070049
Yingdi Yu2b2b4792014-02-04 16:27:07 -080050 /**
51 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -080052 *
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070053 * @param keyName
Yingdi Yufc40d872014-02-18 12:56:04 -080054 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -080055 * @returns pointer to the key
56 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070057 SecKeychainItemRef
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070058 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070059
Yingdi Yu2b2b4792014-02-04 16:27:07 -080060 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080061 * @brief Convert keyType to MAC OS symmetric key key type
62 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080063 * @param keyType
64 * @returns MAC OS key type
65 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070066 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080067 getSymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070068
Yingdi Yu2b2b4792014-02-04 16:27:07 -080069 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080070 * @brief Convert keyType to MAC OS asymmetirc key type
71 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080072 * @param keyType
73 * @returns MAC OS key type
74 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070075 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080076 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070077
Yingdi Yu2b2b4792014-02-04 16:27:07 -080078 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080079 * @brief Convert keyClass to MAC OS key class
80 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080081 * @param keyClass
82 * @returns MAC OS key class
83 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070084 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080085 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070086
Yingdi Yu2b2b4792014-02-04 16:27:07 -080087 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080088 * @brief Convert digestAlgo to MAC OS algorithm id
89 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080090 * @param digestAlgo
91 * @returns MAC OS algorithm id
92 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070093 const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080094 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070095
Yingdi Yu2b2b4792014-02-04 16:27:07 -080096 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080097 * @brief Get the digest size of the corresponding algorithm
98 *
99 * @param digestAlgo
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800100 * @return digest size
101 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700102 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800103 getDigestSize(DigestAlgorithm digestAlgo);
104
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800105 ///////////////////////////////////////////////
106 // everything here is public, including data //
107 ///////////////////////////////////////////////
108public:
109 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800110 bool m_passwordSet;
111 string m_password;
112 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800113};
114
115
116SecTpmOsx::SecTpmOsx()
117 : m_impl(new Impl)
118{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700119 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700120 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800121 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700122 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800123
Yingdi Yube4150e2014-02-18 13:02:46 -0800124 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700125
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800126 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Yingdi Yube4150e2014-02-18 13:02:46 -0800127 throw Error("No default keychain, create one first!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800128}
129
130SecTpmOsx::~SecTpmOsx(){
131 //TODO: implement
132}
133
Yingdi Yube4150e2014-02-18 13:02:46 -0800134void
135SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
136{
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);
141}
142
143void
144SecTpmOsx::resetTpmPassword()
145{
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();
149}
150
151void
152SecTpmOsx::setInTerminal(bool inTerminal)
153{
154 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700155 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700156 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800157 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700158 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800159}
160
161bool
162SecTpmOsx::getInTerminal()
163{
164 return m_impl->m_inTerminal;
165}
166
167bool
168SecTpmOsx::locked()
169{
170 SecKeychainStatus keychainStatus;
171
172 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700173 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800174 return true;
175 else
176 return ((kSecUnlockStateStatus & keychainStatus) == 0);
177}
178
Yingdi Yu2e57a582014-02-20 23:34:43 -0800179bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800180SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
181{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700182 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800183
184 // If the default key chain is already unlocked, return immediately.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700185 if (!locked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800186 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800187
188 // If the default key chain is locked, unlock the key chain.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700189 if (usePassword)
Yingdi Yube4150e2014-02-18 13:02:46 -0800190 {
191 // Use the supplied password.
192 res = SecKeychainUnlock(m_impl->m_keyChainRef,
193 passwordLength,
194 password,
195 true);
196 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700197 else if (m_impl->m_passwordSet)
Yingdi Yube4150e2014-02-18 13:02:46 -0800198 {
199 // If no password supplied, then use the configured password if exists.
200 SecKeychainUnlock(m_impl->m_keyChainRef,
201 m_impl->m_password.size(),
202 m_impl->m_password.c_str(),
203 true);
204 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700205 else if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800206 {
207 // If no configured password, get password from terminal if inTerminal set.
208 bool locked = true;
209 const char* fmt = "Password to unlock the default keychain: ";
210 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700211
Yingdi Yube4150e2014-02-18 13:02:46 -0800212 while(locked)
213 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700214 if (count > 2)
Yingdi Yube4150e2014-02-18 13:02:46 -0800215 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700216
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700217 char* getPassword = 0;
Yingdi Yube4150e2014-02-18 13:02:46 -0800218 getPassword = getpass(fmt);
219 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700220
Yingdi Yube4150e2014-02-18 13:02:46 -0800221 if (!getPassword)
222 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700223
Yingdi Yube4150e2014-02-18 13:02:46 -0800224 res = SecKeychainUnlock(m_impl->m_keyChainRef,
225 strlen(getPassword),
226 getPassword,
227 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700228
Yingdi Yube4150e2014-02-18 13:02:46 -0800229 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700230
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700231 if (res == errSecSuccess)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800232 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800233 }
234 }
235 else
236 {
237 // If inTerminal is not set, get the password from GUI.
238 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
239 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800240
241 return !locked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800242}
243
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700244void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700245SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName, KeyType keyType,
246 int keySize, bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700247{
248
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700249 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
250 {
251 throw Error("keyName has existed");
252 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800253
254 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
255
256 SecKeyRef publicKey, privateKey;
257
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700258 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700259 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800260 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700261
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700262 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800263 3,
264 &kCFTypeDictionaryKeyCallBacks,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700265 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800266
267 CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700268 CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(0,
269 kCFNumberIntType,
270 &keySize));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800271 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
272
273 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict, &publicKey, &privateKey);
274
Yingdi Yube4150e2014-02-18 13:02:46 -0800275 if (res == errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800276 {
277 CFRelease(publicKey);
278 CFRelease(privateKey);
279 return;
280 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700281
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700282 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800283 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700284 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800285 generateKeyPairInTpmInternal(keyName, keyType, keySize, true);
286 else
287 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800288 }
289 else
290 {
Yingdi Yube4150e2014-02-18 13:02:46 -0800291 throw Error("Fail to create a key pair");
292 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800293}
294
295void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700296SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800297{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700298 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700299 keyName.toUri().c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800300 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800301
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700302 CFMutableDictionaryRef searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700303 CFDictionaryCreateMutable(0, 5,
304 &kCFTypeDictionaryKeyCallBacks,
305 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800306
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800307 CFDictionaryAddValue(searchDict, kSecClass, kSecClassKey);
308 CFDictionaryAddValue(searchDict, kSecAttrLabel, keyLabel);
309 CFDictionaryAddValue(searchDict, kSecMatchLimit, kSecMatchLimitAll);
Yingdi Yube4150e2014-02-18 13:02:46 -0800310 OSStatus res = SecItemDelete(searchDict);
311
312 if (res == errSecSuccess)
313 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700314
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700315 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800316 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700317 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800318 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800319 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800320}
321
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700322void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700323SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, KeyType keyType, int keySize)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800324{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800325 throw Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700326 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800327 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800328
Yingdi Yu2e57a582014-02-20 23:34:43 -0800329 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800330
Yingdi Yu2e57a582014-02-20 23:34:43 -0800331 // CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
332 // 0,
333 // &kCFTypeDictionaryKeyCallBacks,
334 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800335
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700336 // CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700337 // keyNameUri.c_str(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800338 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800339
Yingdi Yu2e57a582014-02-20 23:34:43 -0800340 // CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getSymKeyType(keyType));
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700341 // CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(kCFAllocatorDefault,
342 // kCFNumberSInt32Type,
343 // &keySize));
Yingdi Yu2e57a582014-02-20 23:34:43 -0800344 // CFDictionaryAddValue(attrDict, kSecAttrIsPermanent, kCFBooleanTrue);
345 // CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800346
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700347 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800348
Yingdi Yu2e57a582014-02-20 23:34:43 -0800349 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800350
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700351 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800352 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800353}
354
Yingdi Yu2e57a582014-02-20 23:34:43 -0800355shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700356SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800357{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800358 SecKeychainItemRef publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
359
360 CFDataRef exportedKey;
361
362 OSStatus res = SecItemExport(publicKey,
363 kSecFormatOpenSSL,
364 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700365 0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800366 &exportedKey);
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800367 if (res != errSecSuccess)
368 {
369 throw Error("Cannot export requested public key from OSX Keychain");
370 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800371
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700372 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey),
373 CFDataGetLength(exportedKey));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800374 CFRelease(exportedKey);
375 return key;
376}
377
378ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700379SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800380{
381 using namespace CryptoPP;
382
383 SecKeychainItemRef privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
384 CFDataRef exportedKey;
385 OSStatus res = SecItemExport(privateKey,
386 kSecFormatOpenSSL,
387 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700388 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800389 &exportedKey);
390
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700391 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800392 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700393 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800394 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700395 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700396 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800397 else
398 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800399 }
400 else
401 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800402 }
403
404 OBufferStream pkcs1Os;
405 FileSink sink(pkcs1Os);
406
407 uint32_t version = 0;
408 OID algorithm("1.2.840.113549.1.1.1");
409 SecByteBlock rawKeyBits;
410 // PrivateKeyInfo ::= SEQUENCE {
411 // version INTEGER,
412 // privateKeyAlgorithm SEQUENCE,
413 // privateKey OCTECT STRING}
414 DERSequenceEncoder privateKeyInfo(sink);
415 {
416 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
417 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
418 {
419 algorithm.encode(privateKeyAlgorithm);
420 DEREncodeNull(privateKeyAlgorithm);
421 }
422 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700423 DEREncodeOctetString(privateKeyInfo,
424 CFDataGetBytePtr(exportedKey),
425 CFDataGetLength(exportedKey));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800426 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700427 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800428
429 CFRelease(exportedKey);
430 return pkcs1Os.buf();
431}
432
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700433#ifdef __GNUC__
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"
438#endif // __GNUC__
439
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800440bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700441SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700442 const uint8_t* buf, size_t size,
443 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800444{
445 using namespace CryptoPP;
446
447 StringSource privateKeySource(buf, size, true);
448 uint32_t tmpNum;
449 OID tmpOID;
450 SecByteBlock rawKeyBits;
451 // PrivateKeyInfo ::= SEQUENCE {
452 // INTEGER,
453 // SEQUENCE,
454 // OCTECT STRING}
455 BERSequenceDecoder privateKeyInfo(privateKeySource);
456 {
457 BERDecodeUnsigned<uint32_t>(privateKeyInfo, tmpNum, INTEGER);
458 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
459 {
460 tmpOID.decode(sequenceDecoder);
461 BERDecodeNull(sequenceDecoder);
462 }
463 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
464 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700465 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800466
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700467 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800468 rawKeyBits.BytePtr(),
469 rawKeyBits.size(),
470 kCFAllocatorNull);
471
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;
478 SecAccessRef access;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700479 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700480 keyName.toUri().c_str(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800481 kCFStringEncodingUTF8);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700482 SecAccessCreate(keyLabel, 0, &access);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800483 keyParams.accessRef = access;
484 CFArrayRef outItems;
485
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700486#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700487#pragma clang diagnostic push
488#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700489#endif // __clang__
490
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800491 OSStatus res = SecKeychainItemImport (importedKey,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700492 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800493 &externalFormat,
494 &externalType,
495 0,
496 &keyParams,
497 m_impl->m_keyChainRef,
498 &outItems);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700499
500#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700501#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700502#endif // __clang__
503
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700504 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800505 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700506 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800507 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700508 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700509 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800510 else
511 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800512 }
513 else
514 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800515 }
516
517 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
518 SecKeychainAttribute attrs[1]; // maximum number of attributes
519 SecKeychainAttributeList attrList = { 0, attrs };
520 string keyUri = keyName.toUri();
521 {
522 attrs[attrList.count].tag = kSecKeyPrintName;
523 attrs[attrList.count].length = keyUri.size();
524 attrs[attrList.count].data = (void *)keyUri.c_str();
525 attrList.count++;
526 }
527
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700528 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800529 &attrList,
530 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700531 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700532
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700533 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800534 {
535 return false;
536 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700537
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800538 CFRelease(importedKey);
539 return true;
540}
541
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700542#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
543#pragma GCC diagnostic pop
544#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
545
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800546bool
547SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
548{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700549 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800550 buf,
551 size,
552 kCFAllocatorNull);
553
554 SecExternalFormat externalFormat = kSecFormatOpenSSL;
555 SecExternalItemType externalType = kSecItemTypePublicKey;
556 CFArrayRef outItems;
557
558 OSStatus res = SecItemImport (importedKey,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700559 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800560 &externalFormat,
561 &externalType,
562 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700563 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800564 m_impl->m_keyChainRef,
565 &outItems);
566
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700567 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800568 return false;
569
570 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
571 SecKeychainAttribute attrs[1]; // maximum number of attributes
572 SecKeychainAttributeList attrList = { 0, attrs };
573 string keyUri = keyName.toUri();
574 {
575 attrs[attrList.count].tag = kSecKeyPrintName;
576 attrs[attrList.count].length = keyUri.size();
577 attrs[attrList.count].data = (void *)keyUri.c_str();
578 attrList.count++;
579 }
580
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700581 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800582 &attrList,
583 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700584 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700585
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700586 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800587 return false;
588
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800589 CFRelease(importedKey);
590 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800591}
592
593Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700594SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
595 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800596{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700597 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800598 data,
599 dataLength,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800600 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800601
602 SecKeyRef privateKey = (SecKeyRef)m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700603
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800604 CFErrorRef error;
605 SecTransformRef signer = SecSignTransformCreate((SecKeyRef)privateKey, &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700606 if (error)
607 throw Error("Fail to create signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800608
609 // Set input
610 Boolean set_res = SecTransformSetAttribute(signer,
611 kSecTransformInputAttributeName,
612 dataRef,
613 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700614 if (error)
615 throw Error("Fail to configure input of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800616
617 // Enable use of padding
Yingdi Yu2e57a582014-02-20 23:34:43 -0800618 SecTransformSetAttribute(signer,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800619 kSecPaddingKey,
620 kSecPaddingPKCS1Key,
621 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700622 if (error)
623 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800624
625 // Set padding type
626 set_res = SecTransformSetAttribute(signer,
627 kSecDigestTypeAttribute,
628 m_impl->getDigestAlgorithm(digestAlgorithm),
629 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700630 if (error)
631 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800632
633 // Set padding attribute
634 long digestSize = m_impl->getDigestSize(digestAlgorithm);
635 set_res = SecTransformSetAttribute(signer,
636 kSecDigestLengthAttribute,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700637 CFNumberCreate(0, kCFNumberLongType, &digestSize),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800638 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700639 if (error)
640 throw Error("Fail to configure digest size of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800641
642 // Actually sign
643 CFDataRef signature = (CFDataRef) SecTransformExecute(signer, &error);
Yingdi Yube4150e2014-02-18 13:02:46 -0800644 if (error)
645 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700646 if (!needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800647 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700648 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800649 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
650 else
651 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800652 }
653 else
654 {
655 CFShow(error);
656 throw Error("Fail to sign data");
657 }
658 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800659
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700660 if (!signature)
661 throw Error("Signature is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800662
663 return Block(Tlv::SignatureValue,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800664 make_shared<Buffer>(CFDataGetBytePtr(signature), CFDataGetLength(signature)));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800665}
666
667ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700668SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800669{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800670 throw Error("SecTpmOsx::decryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800671
Yingdi Yu2e57a582014-02-20 23:34:43 -0800672 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700673 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800674 // keyClass = KEY_CLASS_SYMMETRIC;
675 // else
676 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800677
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700678 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800679 // reinterpret_cast<const unsigned char*>(data),
680 // dataLength
681 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800682
Yingdi Yu2e57a582014-02-20 23:34:43 -0800683 // SecKeyRef decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800684
Yingdi Yu2e57a582014-02-20 23:34:43 -0800685 // CFErrorRef error;
686 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
687 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800688
Yingdi Yu2e57a582014-02-20 23:34:43 -0800689 // Boolean set_res = SecTransformSetAttribute(decrypt,
690 // kSecTransformInputAttributeName,
691 // dataRef,
692 // &error);
693 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800694
Yingdi Yu2e57a582014-02-20 23:34:43 -0800695 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
696 // if (error)
697 // {
698 // CFShow(error);
699 // throw Error("Fail to decrypt data");
700 // }
701 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800702
Yingdi Yu2e57a582014-02-20 23:34:43 -0800703 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800704}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700705
Yingdi Yu2e57a582014-02-20 23:34:43 -0800706void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700707SecTpmOsx::addAppToACL(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800708{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700709 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800710 {
711 SecKeychainItemRef privateKey = m_impl->getKey(keyName, keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700712
Yingdi Yu2e57a582014-02-20 23:34:43 -0800713 SecAccessRef accRef;
714 OSStatus acc_res = SecKeychainItemCopyAccess(privateKey, &accRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700715
Yingdi Yu2e57a582014-02-20 23:34:43 -0800716 CFArrayRef signACL = SecAccessCopyMatchingACLList(accRef,
717 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700718
Yingdi Yu2e57a582014-02-20 23:34:43 -0800719 SecACLRef aclRef = (SecACLRef) CFArrayGetValueAtIndex(signACL, 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700720
Yingdi Yu2e57a582014-02-20 23:34:43 -0800721 CFArrayRef appList;
722 CFStringRef description;
723 SecKeychainPromptSelector promptSelector;
724 OSStatus acl_res = SecACLCopyContents(aclRef,
725 &appList,
726 &description,
727 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700728
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700729 CFMutableArrayRef newAppList = CFArrayCreateMutableCopy(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800730 0,
731 appList);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700732
Yingdi Yu2e57a582014-02-20 23:34:43 -0800733 SecTrustedApplicationRef trustedApp;
734 acl_res = SecTrustedApplicationCreateFromPath(appPath.c_str(),
735 &trustedApp);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700736
Yingdi Yu2e57a582014-02-20 23:34:43 -0800737 CFArrayAppendValue(newAppList, trustedApp);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700738
Yingdi Yu2e57a582014-02-20 23:34:43 -0800739 acl_res = SecACLSetContents(aclRef,
740 newAppList,
741 description,
742 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700743
Yingdi Yu2e57a582014-02-20 23:34:43 -0800744 acc_res = SecKeychainItemSetAccess(privateKey, accRef);
745 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800746}
747
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800748ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700749SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800750{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800751 throw Error("SecTpmOsx::encryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800752
Yingdi Yu2e57a582014-02-20 23:34:43 -0800753 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700754 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800755 // keyClass = KEY_CLASS_SYMMETRIC;
756 // else
757 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700758
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700759 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800760 // reinterpret_cast<const unsigned char*>(data),
761 // dataLength
762 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700763
Yingdi Yu2e57a582014-02-20 23:34:43 -0800764 // SecKeyRef encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800765
Yingdi Yu2e57a582014-02-20 23:34:43 -0800766 // CFErrorRef error;
767 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
768 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800769
Yingdi Yu2e57a582014-02-20 23:34:43 -0800770 // Boolean set_res = SecTransformSetAttribute(encrypt,
771 // kSecTransformInputAttributeName,
772 // dataRef,
773 // &error);
774 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800775
Yingdi Yu2e57a582014-02-20 23:34:43 -0800776 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
777 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800778
Yingdi Yu2e57a582014-02-20 23:34:43 -0800779 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800780
Yingdi Yu2e57a582014-02-20 23:34:43 -0800781 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800782}
783
784bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700785SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800786{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800787 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
788
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700789 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700790 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800791 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700792
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700793 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800794 4,
795 &kCFTypeDictionaryKeyCallBacks,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700796 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800797
798 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800799 // CFDictionaryAddValue(attrDict, kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800800 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
801 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700802
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800803 SecKeychainItemRef itemRef;
804 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict, (CFTypeRef*)&itemRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700805
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700806 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800807 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800808 else
809 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800810
811}
812
Yingdi Yu4b752752014-02-18 12:24:03 -0800813bool
814SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
815{
816 return (SecRandomCopyBytes(kSecRandomDefault, size, res) == 0);
817}
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800818
819////////////////////////////////
820// OSXPrivateKeyStorage::Impl //
821////////////////////////////////
822
823SecKeychainItemRef
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700824SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800825{
826 string keyNameUri = toInternalKeyName(keyName, keyClass);
827
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700828 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700829 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800830 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700831
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700832 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800833 5,
834 &kCFTypeDictionaryKeyCallBacks,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700835 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800836
837 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
838 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
839 CFDictionaryAddValue(attrDict, kSecAttrKeyClass, getKeyClass(keyClass));
840 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700841
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800842 SecKeychainItemRef keyItem;
843
844 OSStatus res = SecItemCopyMatching((CFDictionaryRef) attrDict, (CFTypeRef*)&keyItem);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700845
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700846 if (res != errSecSuccess)
847 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800848 else
849 return keyItem;
850}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700851
852string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700853SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800854{
855 string keyUri = keyName.toUri();
856
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700857 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800858 return keyUri + "/symmetric";
859 else
860 return keyUri;
861}
862
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700863const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800864SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
865{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700866 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800867 case KEY_TYPE_RSA:
868 return kSecAttrKeyTypeRSA;
869 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700870 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800871 }
872}
873
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700874const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800875SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
876{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700877 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800878 case KEY_TYPE_AES:
879 return kSecAttrKeyTypeAES;
880 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700881 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800882 }
883}
884
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700885const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800886SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
887{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700888 switch (keyClass){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800889 case KEY_CLASS_PRIVATE:
890 return kSecAttrKeyClassPrivate;
891 case KEY_CLASS_PUBLIC:
892 return kSecAttrKeyClassPublic;
893 case KEY_CLASS_SYMMETRIC:
894 return kSecAttrKeyClassSymmetric;
895 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700896 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800897 }
898}
899
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700900const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800901SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
902{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700903 switch (digestAlgo){
Jeff Thompson2747dc02013-10-04 19:11:34 -0700904 // case DIGEST_MD2:
905 // return kSecDigestMD2;
906 // case DIGEST_MD5:
907 // return kSecDigestMD5;
908 // case DIGEST_SHA1:
909 // return kSecDigestSHA1;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800910 case DIGEST_ALGORITHM_SHA256:
911 return kSecDigestSHA2;
912 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700913 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700914 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800915}
Jeff Thompson2747dc02013-10-04 19:11:34 -0700916
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700917long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800918SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
919{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700920 switch (digestAlgo){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800921 case DIGEST_ALGORITHM_SHA256:
922 return 256;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700923 // case DIGEST_SHA1:
924 // case DIGEST_MD2:
925 // case DIGEST_MD5:
926 // return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800927 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800928 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700929 }
Jeff Thompson2747dc02013-10-04 19:11:34 -0700930}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700931
Yingdi Yufc40d872014-02-18 12:56:04 -0800932} // namespace ndn