blob: 2dbe928844a5c1a6132d3809bedfafe8d996ff49 [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"
18
19#include "security/public-key.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070020#include "cryptopp.hpp"
Jeff Thompson2747dc02013-10-04 19:11:34 -070021
Yingdi Yu2b2b4792014-02-04 16:27:07 -080022#include <pwd.h>
23#include <unistd.h>
24#include <stdlib.h>
25#include <string.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070026
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080027#include <CoreFoundation/CoreFoundation.h>
28#include <Security/Security.h>
Yingdi Yu4b752752014-02-18 12:24:03 -080029#include <Security/SecRandom.h>
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080030#include <CoreServices/CoreServices.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070031
Alexander Afanasyev59d67a52014-04-03 16:09:31 -070032#include <Security/SecDigestTransform.h>
33
Jeff Thompson2747dc02013-10-04 19:11:34 -070034using namespace std;
Jeff Thompson2747dc02013-10-04 19:11:34 -070035
Yingdi Yufc40d872014-02-18 12:56:04 -080036namespace ndn {
37
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070038class SecTpmOsx::Impl
39{
Yingdi Yu2b2b4792014-02-04 16:27:07 -080040public:
41 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -080042 : m_passwordSet(false)
43 , m_inTerminal(false)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070044 {
45 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070046
Yingdi Yu2b2b4792014-02-04 16:27:07 -080047 /**
48 * @brief Convert NDN name of a key to internal name of the key.
49 *
Yingdi Yufc40d872014-02-18 12:56:04 -080050 * @param keyName
51 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -080052 * @return the internal key name
53 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070054 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070055 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070056
Yingdi Yu2b2b4792014-02-04 16:27:07 -080057 /**
58 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -080059 *
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070060 * @param keyName
Yingdi Yufc40d872014-02-18 12:56:04 -080061 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -080062 * @returns pointer to the key
63 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070064 SecKeychainItemRef
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070065 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070066
Yingdi Yu2b2b4792014-02-04 16:27:07 -080067 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080068 * @brief Convert keyType to MAC OS symmetric key key type
69 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080070 * @param keyType
71 * @returns MAC OS key type
72 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070073 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080074 getSymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070075
Yingdi Yu2b2b4792014-02-04 16:27:07 -080076 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080077 * @brief Convert keyType to MAC OS asymmetirc key type
78 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080079 * @param keyType
80 * @returns MAC OS key type
81 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070082 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080083 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070084
Yingdi Yu2b2b4792014-02-04 16:27:07 -080085 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080086 * @brief Convert keyClass to MAC OS key class
87 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080088 * @param keyClass
89 * @returns MAC OS key class
90 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070091 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080092 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070093
Yingdi Yu2b2b4792014-02-04 16:27:07 -080094 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080095 * @brief Convert digestAlgo to MAC OS algorithm id
96 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080097 * @param digestAlgo
98 * @returns MAC OS algorithm id
99 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700100 const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800101 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700102
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800103 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800104 * @brief Get the digest size of the corresponding algorithm
105 *
106 * @param digestAlgo
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800107 * @return digest size
108 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700109 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800110 getDigestSize(DigestAlgorithm digestAlgo);
111
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800112 ///////////////////////////////////////////////
113 // everything here is public, including data //
114 ///////////////////////////////////////////////
115public:
116 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800117 bool m_passwordSet;
118 string m_password;
119 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800120};
121
122
123SecTpmOsx::SecTpmOsx()
124 : m_impl(new Impl)
125{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700126 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700127 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800128 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700129 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800130
Yingdi Yube4150e2014-02-18 13:02:46 -0800131 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700132
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800133 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Yingdi Yube4150e2014-02-18 13:02:46 -0800134 throw Error("No default keychain, create one first!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800135}
136
137SecTpmOsx::~SecTpmOsx(){
138 //TODO: implement
139}
140
Yingdi Yube4150e2014-02-18 13:02:46 -0800141void
142SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
143{
144 m_impl->m_passwordSet = true;
145 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
146 m_impl->m_password.clear();
147 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
148}
149
150void
151SecTpmOsx::resetTpmPassword()
152{
153 m_impl->m_passwordSet = false;
154 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
155 m_impl->m_password.clear();
156}
157
158void
159SecTpmOsx::setInTerminal(bool inTerminal)
160{
161 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700162 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700163 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800164 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700165 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800166}
167
168bool
169SecTpmOsx::getInTerminal()
170{
171 return m_impl->m_inTerminal;
172}
173
174bool
175SecTpmOsx::locked()
176{
177 SecKeychainStatus keychainStatus;
178
179 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700180 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800181 return true;
182 else
183 return ((kSecUnlockStateStatus & keychainStatus) == 0);
184}
185
Yingdi Yu2e57a582014-02-20 23:34:43 -0800186bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800187SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
188{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700189 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800190
191 // If the default key chain is already unlocked, return immediately.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700192 if (!locked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800193 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800194
195 // If the default key chain is locked, unlock the key chain.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700196 if (usePassword)
Yingdi Yube4150e2014-02-18 13:02:46 -0800197 {
198 // Use the supplied password.
199 res = SecKeychainUnlock(m_impl->m_keyChainRef,
200 passwordLength,
201 password,
202 true);
203 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700204 else if (m_impl->m_passwordSet)
Yingdi Yube4150e2014-02-18 13:02:46 -0800205 {
206 // If no password supplied, then use the configured password if exists.
207 SecKeychainUnlock(m_impl->m_keyChainRef,
208 m_impl->m_password.size(),
209 m_impl->m_password.c_str(),
210 true);
211 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700212 else if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800213 {
214 // If no configured password, get password from terminal if inTerminal set.
215 bool locked = true;
216 const char* fmt = "Password to unlock the default keychain: ";
217 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700218
Yingdi Yube4150e2014-02-18 13:02:46 -0800219 while(locked)
220 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700221 if (count > 2)
Yingdi Yube4150e2014-02-18 13:02:46 -0800222 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700223
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700224 char* getPassword = 0;
Yingdi Yube4150e2014-02-18 13:02:46 -0800225 getPassword = getpass(fmt);
226 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700227
Yingdi Yube4150e2014-02-18 13:02:46 -0800228 if (!getPassword)
229 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700230
Yingdi Yube4150e2014-02-18 13:02:46 -0800231 res = SecKeychainUnlock(m_impl->m_keyChainRef,
232 strlen(getPassword),
233 getPassword,
234 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700235
Yingdi Yube4150e2014-02-18 13:02:46 -0800236 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700237
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700238 if (res == errSecSuccess)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800239 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800240 }
241 }
242 else
243 {
244 // If inTerminal is not set, get the password from GUI.
245 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
246 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800247
248 return !locked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800249}
250
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700251void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700252SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName, KeyType keyType,
253 int keySize, bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700254{
255
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700256 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
257 {
258 throw Error("keyName has existed");
259 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800260
261 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
262
263 SecKeyRef publicKey, privateKey;
264
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700265 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700266 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800267 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700268
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700269 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800270 3,
271 &kCFTypeDictionaryKeyCallBacks,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700272 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800273
274 CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700275 CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(0,
276 kCFNumberIntType,
277 &keySize));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800278 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
279
280 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict, &publicKey, &privateKey);
281
Yingdi Yube4150e2014-02-18 13:02:46 -0800282 if (res == errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800283 {
284 CFRelease(publicKey);
285 CFRelease(privateKey);
286 return;
287 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700288
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700289 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800290 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700291 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800292 generateKeyPairInTpmInternal(keyName, keyType, keySize, true);
293 else
294 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800295 }
296 else
297 {
Yingdi Yube4150e2014-02-18 13:02:46 -0800298 throw Error("Fail to create a key pair");
299 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800300}
301
302void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700303SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800304{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700305 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700306 keyName.toUri().c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800307 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800308
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700309 CFMutableDictionaryRef searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700310 CFDictionaryCreateMutable(0, 5,
311 &kCFTypeDictionaryKeyCallBacks,
312 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800313
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800314 CFDictionaryAddValue(searchDict, kSecClass, kSecClassKey);
315 CFDictionaryAddValue(searchDict, kSecAttrLabel, keyLabel);
316 CFDictionaryAddValue(searchDict, kSecMatchLimit, kSecMatchLimitAll);
Yingdi Yube4150e2014-02-18 13:02:46 -0800317 OSStatus res = SecItemDelete(searchDict);
318
319 if (res == errSecSuccess)
320 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700321
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700322 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800323 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700324 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800325 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800326 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800327}
328
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700329void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700330SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, KeyType keyType, int keySize)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800331{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800332 throw Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700333 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800334 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800335
Yingdi Yu2e57a582014-02-20 23:34:43 -0800336 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800337
Yingdi Yu2e57a582014-02-20 23:34:43 -0800338 // CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
339 // 0,
340 // &kCFTypeDictionaryKeyCallBacks,
341 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800342
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700343 // CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700344 // keyNameUri.c_str(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800345 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800346
Yingdi Yu2e57a582014-02-20 23:34:43 -0800347 // CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getSymKeyType(keyType));
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700348 // CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(kCFAllocatorDefault,
349 // kCFNumberSInt32Type,
350 // &keySize));
Yingdi Yu2e57a582014-02-20 23:34:43 -0800351 // CFDictionaryAddValue(attrDict, kSecAttrIsPermanent, kCFBooleanTrue);
352 // CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800353
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700354 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800355
Yingdi Yu2e57a582014-02-20 23:34:43 -0800356 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800357
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700358 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800359 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800360}
361
Yingdi Yu2e57a582014-02-20 23:34:43 -0800362shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700363SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800364{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800365 SecKeychainItemRef publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
366
367 CFDataRef exportedKey;
368
369 OSStatus res = SecItemExport(publicKey,
370 kSecFormatOpenSSL,
371 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700372 0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800373 &exportedKey);
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800374 if (res != errSecSuccess)
375 {
376 throw Error("Cannot export requested public key from OSX Keychain");
377 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800378
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700379 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey),
380 CFDataGetLength(exportedKey));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800381 CFRelease(exportedKey);
382 return key;
383}
384
385ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700386SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800387{
388 using namespace CryptoPP;
389
390 SecKeychainItemRef privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
391 CFDataRef exportedKey;
392 OSStatus res = SecItemExport(privateKey,
393 kSecFormatOpenSSL,
394 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700395 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800396 &exportedKey);
397
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700398 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800399 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700400 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800401 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700402 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700403 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800404 else
405 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800406 }
407 else
408 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800409 }
410
411 OBufferStream pkcs1Os;
412 FileSink sink(pkcs1Os);
413
414 uint32_t version = 0;
415 OID algorithm("1.2.840.113549.1.1.1");
416 SecByteBlock rawKeyBits;
417 // PrivateKeyInfo ::= SEQUENCE {
418 // version INTEGER,
419 // privateKeyAlgorithm SEQUENCE,
420 // privateKey OCTECT STRING}
421 DERSequenceEncoder privateKeyInfo(sink);
422 {
423 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
424 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
425 {
426 algorithm.encode(privateKeyAlgorithm);
427 DEREncodeNull(privateKeyAlgorithm);
428 }
429 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700430 DEREncodeOctetString(privateKeyInfo,
431 CFDataGetBytePtr(exportedKey),
432 CFDataGetLength(exportedKey));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800433 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700434 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800435
436 CFRelease(exportedKey);
437 return pkcs1Os.buf();
438}
439
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700440#ifdef __GNUC__
441#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
442#pragma GCC diagnostic push
443#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
444#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
445#endif // __GNUC__
446
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800447bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700448SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700449 const uint8_t* buf, size_t size,
450 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800451{
452 using namespace CryptoPP;
453
454 StringSource privateKeySource(buf, size, true);
455 uint32_t tmpNum;
456 OID tmpOID;
457 SecByteBlock rawKeyBits;
458 // PrivateKeyInfo ::= SEQUENCE {
459 // INTEGER,
460 // SEQUENCE,
461 // OCTECT STRING}
462 BERSequenceDecoder privateKeyInfo(privateKeySource);
463 {
464 BERDecodeUnsigned<uint32_t>(privateKeyInfo, tmpNum, INTEGER);
465 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
466 {
467 tmpOID.decode(sequenceDecoder);
468 BERDecodeNull(sequenceDecoder);
469 }
470 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
471 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700472 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800473
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700474 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800475 rawKeyBits.BytePtr(),
476 rawKeyBits.size(),
477 kCFAllocatorNull);
478
479 SecExternalFormat externalFormat = kSecFormatOpenSSL;
480 SecExternalItemType externalType = kSecItemTypePrivateKey;
481 SecKeyImportExportParameters keyParams;
482 memset(&keyParams, 0, sizeof(keyParams));
483 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
484 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
485 SecAccessRef access;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700486 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700487 keyName.toUri().c_str(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800488 kCFStringEncodingUTF8);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700489 SecAccessCreate(keyLabel, 0, &access);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800490 keyParams.accessRef = access;
491 CFArrayRef outItems;
492
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700493#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700494#pragma clang diagnostic push
495#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700496#endif // __clang__
497
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800498 OSStatus res = SecKeychainItemImport (importedKey,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700499 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800500 &externalFormat,
501 &externalType,
502 0,
503 &keyParams,
504 m_impl->m_keyChainRef,
505 &outItems);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700506
507#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700508#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700509#endif // __clang__
510
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700511 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800512 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700513 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800514 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700515 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700516 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800517 else
518 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800519 }
520 else
521 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800522 }
523
524 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
525 SecKeychainAttribute attrs[1]; // maximum number of attributes
526 SecKeychainAttributeList attrList = { 0, attrs };
527 string keyUri = keyName.toUri();
528 {
529 attrs[attrList.count].tag = kSecKeyPrintName;
530 attrs[attrList.count].length = keyUri.size();
531 attrs[attrList.count].data = (void *)keyUri.c_str();
532 attrList.count++;
533 }
534
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700535 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800536 &attrList,
537 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700538 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700539
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700540 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800541 {
542 return false;
543 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700544
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800545 CFRelease(importedKey);
546 return true;
547}
548
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700549#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
550#pragma GCC diagnostic pop
551#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
552
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800553bool
554SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
555{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700556 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800557 buf,
558 size,
559 kCFAllocatorNull);
560
561 SecExternalFormat externalFormat = kSecFormatOpenSSL;
562 SecExternalItemType externalType = kSecItemTypePublicKey;
563 CFArrayRef outItems;
564
565 OSStatus res = SecItemImport (importedKey,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700566 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800567 &externalFormat,
568 &externalType,
569 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700570 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800571 m_impl->m_keyChainRef,
572 &outItems);
573
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700574 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800575 return false;
576
577 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
578 SecKeychainAttribute attrs[1]; // maximum number of attributes
579 SecKeychainAttributeList attrList = { 0, attrs };
580 string keyUri = keyName.toUri();
581 {
582 attrs[attrList.count].tag = kSecKeyPrintName;
583 attrs[attrList.count].length = keyUri.size();
584 attrs[attrList.count].data = (void *)keyUri.c_str();
585 attrList.count++;
586 }
587
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700588 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800589 &attrList,
590 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700591 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700592
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700593 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800594 return false;
595
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800596 CFRelease(importedKey);
597 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800598}
599
600Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700601SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
602 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800603{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700604 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800605 data,
606 dataLength,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800607 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800608
609 SecKeyRef privateKey = (SecKeyRef)m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700610
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800611 CFErrorRef error;
612 SecTransformRef signer = SecSignTransformCreate((SecKeyRef)privateKey, &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700613 if (error)
614 throw Error("Fail to create signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800615
616 // Set input
617 Boolean set_res = SecTransformSetAttribute(signer,
618 kSecTransformInputAttributeName,
619 dataRef,
620 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700621 if (error)
622 throw Error("Fail to configure input of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800623
624 // Enable use of padding
Yingdi Yu2e57a582014-02-20 23:34:43 -0800625 SecTransformSetAttribute(signer,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800626 kSecPaddingKey,
627 kSecPaddingPKCS1Key,
628 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700629 if (error)
630 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800631
632 // Set padding type
633 set_res = SecTransformSetAttribute(signer,
634 kSecDigestTypeAttribute,
635 m_impl->getDigestAlgorithm(digestAlgorithm),
636 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700637 if (error)
638 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800639
640 // Set padding attribute
641 long digestSize = m_impl->getDigestSize(digestAlgorithm);
642 set_res = SecTransformSetAttribute(signer,
643 kSecDigestLengthAttribute,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700644 CFNumberCreate(0, kCFNumberLongType, &digestSize),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800645 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700646 if (error)
647 throw Error("Fail to configure digest size of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800648
649 // Actually sign
650 CFDataRef signature = (CFDataRef) SecTransformExecute(signer, &error);
Yingdi Yube4150e2014-02-18 13:02:46 -0800651 if (error)
652 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700653 if (!needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800654 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700655 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800656 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
657 else
658 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800659 }
660 else
661 {
662 CFShow(error);
663 throw Error("Fail to sign data");
664 }
665 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800666
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700667 if (!signature)
668 throw Error("Signature is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800669
670 return Block(Tlv::SignatureValue,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800671 make_shared<Buffer>(CFDataGetBytePtr(signature), CFDataGetLength(signature)));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800672}
673
674ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700675SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800676{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800677 throw Error("SecTpmOsx::decryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800678
Yingdi Yu2e57a582014-02-20 23:34:43 -0800679 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700680 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800681 // keyClass = KEY_CLASS_SYMMETRIC;
682 // else
683 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800684
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700685 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800686 // reinterpret_cast<const unsigned char*>(data),
687 // dataLength
688 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800689
Yingdi Yu2e57a582014-02-20 23:34:43 -0800690 // SecKeyRef decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800691
Yingdi Yu2e57a582014-02-20 23:34:43 -0800692 // CFErrorRef error;
693 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
694 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800695
Yingdi Yu2e57a582014-02-20 23:34:43 -0800696 // Boolean set_res = SecTransformSetAttribute(decrypt,
697 // kSecTransformInputAttributeName,
698 // dataRef,
699 // &error);
700 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800701
Yingdi Yu2e57a582014-02-20 23:34:43 -0800702 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
703 // if (error)
704 // {
705 // CFShow(error);
706 // throw Error("Fail to decrypt data");
707 // }
708 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800709
Yingdi Yu2e57a582014-02-20 23:34:43 -0800710 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800711}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700712
Yingdi Yu2e57a582014-02-20 23:34:43 -0800713void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700714SecTpmOsx::addAppToACL(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800715{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700716 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800717 {
718 SecKeychainItemRef privateKey = m_impl->getKey(keyName, keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700719
Yingdi Yu2e57a582014-02-20 23:34:43 -0800720 SecAccessRef accRef;
721 OSStatus acc_res = SecKeychainItemCopyAccess(privateKey, &accRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700722
Yingdi Yu2e57a582014-02-20 23:34:43 -0800723 CFArrayRef signACL = SecAccessCopyMatchingACLList(accRef,
724 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700725
Yingdi Yu2e57a582014-02-20 23:34:43 -0800726 SecACLRef aclRef = (SecACLRef) CFArrayGetValueAtIndex(signACL, 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700727
Yingdi Yu2e57a582014-02-20 23:34:43 -0800728 CFArrayRef appList;
729 CFStringRef description;
730 SecKeychainPromptSelector promptSelector;
731 OSStatus acl_res = SecACLCopyContents(aclRef,
732 &appList,
733 &description,
734 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700735
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700736 CFMutableArrayRef newAppList = CFArrayCreateMutableCopy(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800737 0,
738 appList);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700739
Yingdi Yu2e57a582014-02-20 23:34:43 -0800740 SecTrustedApplicationRef trustedApp;
741 acl_res = SecTrustedApplicationCreateFromPath(appPath.c_str(),
742 &trustedApp);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700743
Yingdi Yu2e57a582014-02-20 23:34:43 -0800744 CFArrayAppendValue(newAppList, trustedApp);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700745
Yingdi Yu2e57a582014-02-20 23:34:43 -0800746 acl_res = SecACLSetContents(aclRef,
747 newAppList,
748 description,
749 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700750
Yingdi Yu2e57a582014-02-20 23:34:43 -0800751 acc_res = SecKeychainItemSetAccess(privateKey, accRef);
752 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800753}
754
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800755ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700756SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800757{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800758 throw Error("SecTpmOsx::encryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800759
Yingdi Yu2e57a582014-02-20 23:34:43 -0800760 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700761 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800762 // keyClass = KEY_CLASS_SYMMETRIC;
763 // else
764 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700765
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700766 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800767 // reinterpret_cast<const unsigned char*>(data),
768 // dataLength
769 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700770
Yingdi Yu2e57a582014-02-20 23:34:43 -0800771 // SecKeyRef encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800772
Yingdi Yu2e57a582014-02-20 23:34:43 -0800773 // CFErrorRef error;
774 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
775 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800776
Yingdi Yu2e57a582014-02-20 23:34:43 -0800777 // Boolean set_res = SecTransformSetAttribute(encrypt,
778 // kSecTransformInputAttributeName,
779 // dataRef,
780 // &error);
781 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800782
Yingdi Yu2e57a582014-02-20 23:34:43 -0800783 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
784 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800785
Yingdi Yu2e57a582014-02-20 23:34:43 -0800786 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800787
Yingdi Yu2e57a582014-02-20 23:34:43 -0800788 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800789}
790
791bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700792SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800793{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800794 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
795
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700796 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700797 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800798 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700799
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700800 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800801 4,
802 &kCFTypeDictionaryKeyCallBacks,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700803 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800804
805 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800806 // CFDictionaryAddValue(attrDict, kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800807 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
808 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700809
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800810 SecKeychainItemRef itemRef;
811 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict, (CFTypeRef*)&itemRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700812
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700813 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800814 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800815 else
816 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800817
818}
819
Yingdi Yu4b752752014-02-18 12:24:03 -0800820bool
821SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
822{
823 return (SecRandomCopyBytes(kSecRandomDefault, size, res) == 0);
824}
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800825
826////////////////////////////////
827// OSXPrivateKeyStorage::Impl //
828////////////////////////////////
829
830SecKeychainItemRef
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700831SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800832{
833 string keyNameUri = toInternalKeyName(keyName, keyClass);
834
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700835 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700836 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800837 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700838
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700839 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800840 5,
841 &kCFTypeDictionaryKeyCallBacks,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700842 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800843
844 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
845 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
846 CFDictionaryAddValue(attrDict, kSecAttrKeyClass, getKeyClass(keyClass));
847 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700848
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800849 SecKeychainItemRef keyItem;
850
851 OSStatus res = SecItemCopyMatching((CFDictionaryRef) attrDict, (CFTypeRef*)&keyItem);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700852
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700853 if (res != errSecSuccess)
854 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800855 else
856 return keyItem;
857}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700858
859string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700860SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800861{
862 string keyUri = keyName.toUri();
863
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700864 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800865 return keyUri + "/symmetric";
866 else
867 return keyUri;
868}
869
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700870const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800871SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
872{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700873 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800874 case KEY_TYPE_RSA:
875 return kSecAttrKeyTypeRSA;
876 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700877 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800878 }
879}
880
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700881const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800882SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
883{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700884 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800885 case KEY_TYPE_AES:
886 return kSecAttrKeyTypeAES;
887 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700888 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800889 }
890}
891
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700892const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800893SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
894{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700895 switch (keyClass){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800896 case KEY_CLASS_PRIVATE:
897 return kSecAttrKeyClassPrivate;
898 case KEY_CLASS_PUBLIC:
899 return kSecAttrKeyClassPublic;
900 case KEY_CLASS_SYMMETRIC:
901 return kSecAttrKeyClassSymmetric;
902 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700903 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800904 }
905}
906
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700907const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800908SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
909{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700910 switch (digestAlgo){
Jeff Thompson2747dc02013-10-04 19:11:34 -0700911 // case DIGEST_MD2:
912 // return kSecDigestMD2;
913 // case DIGEST_MD5:
914 // return kSecDigestMD5;
915 // case DIGEST_SHA1:
916 // return kSecDigestSHA1;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800917 case DIGEST_ALGORITHM_SHA256:
918 return kSecDigestSHA2;
919 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700920 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700921 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800922}
Jeff Thompson2747dc02013-10-04 19:11:34 -0700923
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700924long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800925SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
926{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700927 switch (digestAlgo){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800928 case DIGEST_ALGORITHM_SHA256:
929 return 256;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700930 // case DIGEST_SHA1:
931 // case DIGEST_MD2:
932 // case DIGEST_MD5:
933 // return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800934 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800935 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700936 }
Jeff Thompson2747dc02013-10-04 19:11:34 -0700937}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700938
Yingdi Yufc40d872014-02-18 12:56:04 -0800939} // namespace ndn