blob: 6a5250cf16cd1906bf3d22d0f4bd2156dc61d83e [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"
13#include "util/logging.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070014#include "cryptopp.hpp"
Jeff Thompson2747dc02013-10-04 19:11:34 -070015
Yingdi Yu2b2b4792014-02-04 16:27:07 -080016#include <pwd.h>
17#include <unistd.h>
18#include <stdlib.h>
19#include <string.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070020
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080021#include <CoreFoundation/CoreFoundation.h>
22#include <Security/Security.h>
Yingdi Yu4b752752014-02-18 12:24:03 -080023#include <Security/SecRandom.h>
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080024#include <CoreServices/CoreServices.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070025
Alexander Afanasyev59d67a52014-04-03 16:09:31 -070026#include <Security/SecDigestTransform.h>
27
Jeff Thompson2747dc02013-10-04 19:11:34 -070028using namespace std;
Jeff Thompson2747dc02013-10-04 19:11:34 -070029
Yingdi Yu21157162014-02-28 13:02:34 -080030INIT_LOGGER("ndn.SecTpmOsx");
Jeff Thompson2747dc02013-10-04 19:11:34 -070031
Yingdi Yufc40d872014-02-18 12:56:04 -080032namespace ndn {
33
Yingdi Yu2b2b4792014-02-04 16:27:07 -080034class SecTpmOsx::Impl {
35public:
36 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -080037 : m_passwordSet(false)
38 , m_inTerminal(false)
Yingdi Yu2b2b4792014-02-04 16:27:07 -080039 {}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070040
Yingdi Yu2b2b4792014-02-04 16:27:07 -080041 /**
42 * @brief Convert NDN name of a key to internal name of the key.
43 *
Yingdi Yufc40d872014-02-18 12:56:04 -080044 * @param keyName
45 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -080046 * @return the internal key name
47 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070048 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070049 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070050
Yingdi Yu2b2b4792014-02-04 16:27:07 -080051 /**
52 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -080053 *
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070054 * @param keyName
Yingdi Yufc40d872014-02-18 12:56:04 -080055 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -080056 * @returns pointer to the key
57 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070058 SecKeychainItemRef
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070059 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070060
Yingdi Yu2b2b4792014-02-04 16:27:07 -080061 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080062 * @brief Convert keyType to MAC OS symmetric key key type
63 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080064 * @param keyType
65 * @returns MAC OS key type
66 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070067 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080068 getSymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070069
Yingdi Yu2b2b4792014-02-04 16:27:07 -080070 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080071 * @brief Convert keyType to MAC OS asymmetirc key type
72 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080073 * @param keyType
74 * @returns MAC OS key type
75 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070076 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080077 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070078
Yingdi Yu2b2b4792014-02-04 16:27:07 -080079 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080080 * @brief Convert keyClass to MAC OS key class
81 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080082 * @param keyClass
83 * @returns MAC OS key class
84 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070085 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080086 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070087
Yingdi Yu2b2b4792014-02-04 16:27:07 -080088 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080089 * @brief Convert digestAlgo to MAC OS algorithm id
90 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080091 * @param digestAlgo
92 * @returns MAC OS algorithm id
93 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070094 const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080095 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070096
Yingdi Yu2b2b4792014-02-04 16:27:07 -080097 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080098 * @brief Get the digest size of the corresponding algorithm
99 *
100 * @param digestAlgo
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800101 * @return digest size
102 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700103 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800104 getDigestSize(DigestAlgorithm digestAlgo);
105
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800106 ///////////////////////////////////////////////
107 // everything here is public, including data //
108 ///////////////////////////////////////////////
109public:
110 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800111 bool m_passwordSet;
112 string m_password;
113 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800114};
115
116
117SecTpmOsx::SecTpmOsx()
118 : m_impl(new Impl)
119{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700120 if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800121 SecKeychainSetUserInteractionAllowed (false);
122 else
123 SecKeychainSetUserInteractionAllowed (true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800124
Yingdi Yube4150e2014-02-18 13:02:46 -0800125 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700126
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800127 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Yingdi Yube4150e2014-02-18 13:02:46 -0800128 throw Error("No default keychain, create one first!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800129}
130
131SecTpmOsx::~SecTpmOsx(){
132 //TODO: implement
133}
134
Yingdi Yube4150e2014-02-18 13:02:46 -0800135void
136SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
137{
138 m_impl->m_passwordSet = true;
139 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
140 m_impl->m_password.clear();
141 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
142}
143
144void
145SecTpmOsx::resetTpmPassword()
146{
147 m_impl->m_passwordSet = false;
148 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
149 m_impl->m_password.clear();
150}
151
152void
153SecTpmOsx::setInTerminal(bool inTerminal)
154{
155 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700156 if (inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800157 SecKeychainSetUserInteractionAllowed (false);
158 else
159 SecKeychainSetUserInteractionAllowed (true);
160}
161
162bool
163SecTpmOsx::getInTerminal()
164{
165 return m_impl->m_inTerminal;
166}
167
168bool
169SecTpmOsx::locked()
170{
171 SecKeychainStatus keychainStatus;
172
173 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700174 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800175 return true;
176 else
177 return ((kSecUnlockStateStatus & keychainStatus) == 0);
178}
179
Yingdi Yu2e57a582014-02-20 23:34:43 -0800180bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800181SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
182{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700183 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800184
185 // If the default key chain is already unlocked, return immediately.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700186 if (!locked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800187 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800188
189 // If the default key chain is locked, unlock the key chain.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700190 if (usePassword)
Yingdi Yube4150e2014-02-18 13:02:46 -0800191 {
192 // Use the supplied password.
193 res = SecKeychainUnlock(m_impl->m_keyChainRef,
194 passwordLength,
195 password,
196 true);
197 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700198 else if (m_impl->m_passwordSet)
Yingdi Yube4150e2014-02-18 13:02:46 -0800199 {
200 // If no password supplied, then use the configured password if exists.
201 SecKeychainUnlock(m_impl->m_keyChainRef,
202 m_impl->m_password.size(),
203 m_impl->m_password.c_str(),
204 true);
205 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700206 else if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800207 {
208 // If no configured password, get password from terminal if inTerminal set.
209 bool locked = true;
210 const char* fmt = "Password to unlock the default keychain: ";
211 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700212
Yingdi Yube4150e2014-02-18 13:02:46 -0800213 while(locked)
214 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700215 if (count > 2)
Yingdi Yube4150e2014-02-18 13:02:46 -0800216 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700217
Yingdi Yube4150e2014-02-18 13:02:46 -0800218 char* getPassword = NULL;
219 getPassword = getpass(fmt);
220 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700221
Yingdi Yube4150e2014-02-18 13:02:46 -0800222 if (!getPassword)
223 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700224
Yingdi Yube4150e2014-02-18 13:02:46 -0800225 res = SecKeychainUnlock(m_impl->m_keyChainRef,
226 strlen(getPassword),
227 getPassword,
228 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700229
Yingdi Yube4150e2014-02-18 13:02:46 -0800230 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700231
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700232 if (res == errSecSuccess)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800233 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800234 }
235 }
236 else
237 {
238 // If inTerminal is not set, get the password from GUI.
239 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
240 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800241
242 return !locked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800243}
244
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700245void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700246SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName, KeyType keyType, int keySize, bool retry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700247{
248
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700249 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC)){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800250 _LOG_DEBUG("keyName has existed");
251 throw Error("keyName has existed");
252 }
253
254 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
255
256 SecKeyRef publicKey, privateKey;
257
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700258 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
259 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800260 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700261
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800262 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
263 3,
264 &kCFTypeDictionaryKeyCallBacks,
265 NULL);
266
267 CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
268 CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(NULL, kCFNumberIntType, &keySize));
269 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
270
271 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict, &publicKey, &privateKey);
272
Yingdi Yube4150e2014-02-18 13:02:46 -0800273 if (res == errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800274 {
275 CFRelease(publicKey);
276 CFRelease(privateKey);
277 return;
278 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700279
Yingdi Yube4150e2014-02-18 13:02:46 -0800280 if (res == errSecAuthFailed && !retry)
281 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700282 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800283 generateKeyPairInTpmInternal(keyName, keyType, keySize, true);
284 else
285 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800286 }
287 else
288 {
289 _LOG_DEBUG("Fail to create a key pair: " << res);
290 throw Error("Fail to create a key pair");
291 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800292}
293
294void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700295SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool retry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800296{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700297 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
298 keyName.toUri().c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800299 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800300
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700301 CFMutableDictionaryRef searchDict =
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800302 CFDictionaryCreateMutable(NULL, 5, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800303
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800304 CFDictionaryAddValue(searchDict, kSecClass, kSecClassKey);
305 CFDictionaryAddValue(searchDict, kSecAttrLabel, keyLabel);
306 CFDictionaryAddValue(searchDict, kSecMatchLimit, kSecMatchLimitAll);
Yingdi Yube4150e2014-02-18 13:02:46 -0800307 OSStatus res = SecItemDelete(searchDict);
308
309 if (res == errSecSuccess)
310 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700311
Yingdi Yube4150e2014-02-18 13:02:46 -0800312 if (res == errSecAuthFailed && !retry)
313 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700314 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800315 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800316 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800317}
318
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700319void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700320SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, KeyType keyType, int keySize)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800321{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800322 throw Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700323 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800324 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800325
Yingdi Yu2e57a582014-02-20 23:34:43 -0800326 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800327
Yingdi Yu2e57a582014-02-20 23:34:43 -0800328 // CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
329 // 0,
330 // &kCFTypeDictionaryKeyCallBacks,
331 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800332
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700333 // CFStringRef keyLabel = CFStringCreateWithCString(NULL,
334 // keyNameUri.c_str(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800335 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800336
Yingdi Yu2e57a582014-02-20 23:34:43 -0800337 // CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getSymKeyType(keyType));
338 // CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &keySize));
339 // CFDictionaryAddValue(attrDict, kSecAttrIsPermanent, kCFBooleanTrue);
340 // CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800341
Yingdi Yu2e57a582014-02-20 23:34:43 -0800342 // CFErrorRef error = NULL;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800343
Yingdi Yu2e57a582014-02-20 23:34:43 -0800344 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800345
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700346 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800347 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800348}
349
Yingdi Yu2e57a582014-02-20 23:34:43 -0800350shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700351SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800352{
353 _LOG_TRACE("OSXPrivateKeyStorage::getPublickey");
354
355 SecKeychainItemRef publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
356
357 CFDataRef exportedKey;
358
359 OSStatus res = SecItemExport(publicKey,
360 kSecFormatOpenSSL,
361 0,
362 NULL,
363 &exportedKey);
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800364 if (res != errSecSuccess)
365 {
366 throw Error("Cannot export requested public key from OSX Keychain");
367 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800368
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800369 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
370 CFRelease(exportedKey);
371 return key;
372}
373
374ConstBufferPtr
Yingdi Yube4150e2014-02-18 13:02:46 -0800375SecTpmOsx::exportPrivateKeyPkcs1FromTpmInternal(const Name& keyName, bool retry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800376{
377 using namespace CryptoPP;
378
379 SecKeychainItemRef privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
380 CFDataRef exportedKey;
381 OSStatus res = SecItemExport(privateKey,
382 kSecFormatOpenSSL,
383 0,
384 NULL,
385 &exportedKey);
386
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700387 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800388 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700389 if (res == errSecAuthFailed && !retry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800390 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700391 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800392 return exportPrivateKeyPkcs1FromTpmInternal(keyName, true);
393 else
394 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800395 }
396 else
397 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800398 }
399
400 OBufferStream pkcs1Os;
401 FileSink sink(pkcs1Os);
402
403 uint32_t version = 0;
404 OID algorithm("1.2.840.113549.1.1.1");
405 SecByteBlock rawKeyBits;
406 // PrivateKeyInfo ::= SEQUENCE {
407 // version INTEGER,
408 // privateKeyAlgorithm SEQUENCE,
409 // privateKey OCTECT STRING}
410 DERSequenceEncoder privateKeyInfo(sink);
411 {
412 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
413 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
414 {
415 algorithm.encode(privateKeyAlgorithm);
416 DEREncodeNull(privateKeyAlgorithm);
417 }
418 privateKeyAlgorithm.MessageEnd();
419 DEREncodeOctetString(privateKeyInfo, CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
420 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700421 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800422
423 CFRelease(exportedKey);
424 return pkcs1Os.buf();
425}
426
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700427#ifdef __GNUC__
428#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
429#pragma GCC diagnostic push
430#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
431#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
432#endif // __GNUC__
433
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800434bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800435SecTpmOsx::importPrivateKeyPkcs1IntoTpmInternal(const Name& keyName, const uint8_t* buf, size_t size, bool retry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800436{
437 using namespace CryptoPP;
438
439 StringSource privateKeySource(buf, size, true);
440 uint32_t tmpNum;
441 OID tmpOID;
442 SecByteBlock rawKeyBits;
443 // PrivateKeyInfo ::= SEQUENCE {
444 // INTEGER,
445 // SEQUENCE,
446 // OCTECT STRING}
447 BERSequenceDecoder privateKeyInfo(privateKeySource);
448 {
449 BERDecodeUnsigned<uint32_t>(privateKeyInfo, tmpNum, INTEGER);
450 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
451 {
452 tmpOID.decode(sequenceDecoder);
453 BERDecodeNull(sequenceDecoder);
454 }
455 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
456 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700457 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800458
459 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(NULL,
460 rawKeyBits.BytePtr(),
461 rawKeyBits.size(),
462 kCFAllocatorNull);
463
464 SecExternalFormat externalFormat = kSecFormatOpenSSL;
465 SecExternalItemType externalType = kSecItemTypePrivateKey;
466 SecKeyImportExportParameters keyParams;
467 memset(&keyParams, 0, sizeof(keyParams));
468 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
469 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
470 SecAccessRef access;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700471 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
472 keyName.toUri().c_str(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800473 kCFStringEncodingUTF8);
474 SecAccessCreate(keyLabel, NULL, &access);
475 keyParams.accessRef = access;
476 CFArrayRef outItems;
477
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700478#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700479#pragma clang diagnostic push
480#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700481#endif // __clang__
482
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800483 OSStatus res = SecKeychainItemImport (importedKey,
484 NULL,
485 &externalFormat,
486 &externalType,
487 0,
488 &keyParams,
489 m_impl->m_keyChainRef,
490 &outItems);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700491
492#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700493#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700494#endif // __clang__
495
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700496 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800497 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700498 if (res == errSecAuthFailed && !retry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800499 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700500 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800501 return importPrivateKeyPkcs1IntoTpmInternal(keyName, buf, size, true);
502 else
503 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800504 }
505 else
506 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800507 }
508
509 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
510 SecKeychainAttribute attrs[1]; // maximum number of attributes
511 SecKeychainAttributeList attrList = { 0, attrs };
512 string keyUri = keyName.toUri();
513 {
514 attrs[attrList.count].tag = kSecKeyPrintName;
515 attrs[attrList.count].length = keyUri.size();
516 attrs[attrList.count].data = (void *)keyUri.c_str();
517 attrList.count++;
518 }
519
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700520 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800521 &attrList,
522 0,
523 NULL);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700524
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700525 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800526 {
527 return false;
528 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700529
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800530 CFRelease(importedKey);
531 return true;
532}
533
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700534#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
535#pragma GCC diagnostic pop
536#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
537
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800538bool
539SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
540{
541 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(NULL,
542 buf,
543 size,
544 kCFAllocatorNull);
545
546 SecExternalFormat externalFormat = kSecFormatOpenSSL;
547 SecExternalItemType externalType = kSecItemTypePublicKey;
548 CFArrayRef outItems;
549
550 OSStatus res = SecItemImport (importedKey,
551 NULL,
552 &externalFormat,
553 &externalType,
554 0,
555 NULL,
556 m_impl->m_keyChainRef,
557 &outItems);
558
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700559 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800560 return false;
561
562 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
563 SecKeychainAttribute attrs[1]; // maximum number of attributes
564 SecKeychainAttributeList attrList = { 0, attrs };
565 string keyUri = keyName.toUri();
566 {
567 attrs[attrList.count].tag = kSecKeyPrintName;
568 attrs[attrList.count].length = keyUri.size();
569 attrs[attrList.count].data = (void *)keyUri.c_str();
570 attrList.count++;
571 }
572
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700573 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800574 &attrList,
575 0,
576 NULL);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700577
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700578 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800579 return false;
580
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800581 CFRelease(importedKey);
582 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800583}
584
585Block
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700586SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength, const Name& keyName, DigestAlgorithm digestAlgorithm, bool retry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800587{
588 _LOG_TRACE("OSXPrivateKeyStorage::Sign");
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700589
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800590 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(NULL,
591 data,
592 dataLength,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800593 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800594
595 SecKeyRef privateKey = (SecKeyRef)m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700596
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800597 CFErrorRef error;
598 SecTransformRef signer = SecSignTransformCreate((SecKeyRef)privateKey, &error);
599 if (error) throw Error("Fail to create signer");
600
601 // Set input
602 Boolean set_res = SecTransformSetAttribute(signer,
603 kSecTransformInputAttributeName,
604 dataRef,
605 &error);
606 if (error) throw Error("Fail to configure input of signer");
607
608 // Enable use of padding
Yingdi Yu2e57a582014-02-20 23:34:43 -0800609 SecTransformSetAttribute(signer,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800610 kSecPaddingKey,
611 kSecPaddingPKCS1Key,
612 &error);
613 if (error) throw Error("Fail to configure digest algorithm of signer");
614
615 // Set padding type
616 set_res = SecTransformSetAttribute(signer,
617 kSecDigestTypeAttribute,
618 m_impl->getDigestAlgorithm(digestAlgorithm),
619 &error);
620 if (error) throw Error("Fail to configure digest algorithm of signer");
621
622 // Set padding attribute
623 long digestSize = m_impl->getDigestSize(digestAlgorithm);
624 set_res = SecTransformSetAttribute(signer,
625 kSecDigestLengthAttribute,
626 CFNumberCreate(NULL, kCFNumberLongType, &digestSize),
627 &error);
628 if (error) throw Error("Fail to configure digest size of signer");
629
630 // Actually sign
631 CFDataRef signature = (CFDataRef) SecTransformExecute(signer, &error);
Yingdi Yube4150e2014-02-18 13:02:46 -0800632 if (error)
633 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700634 if (!retry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800635 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700636 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800637 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
638 else
639 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800640 }
641 else
642 {
643 CFShow(error);
644 throw Error("Fail to sign data");
645 }
646 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800647
648 if (!signature) throw Error("Signature is NULL!\n");
649
650 return Block(Tlv::SignatureValue,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800651 make_shared<Buffer>(CFDataGetBytePtr(signature), CFDataGetLength(signature)));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800652}
653
654ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700655SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800656{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800657 throw Error("SecTpmOsx::decryptInTpm is not supported");
658 // _LOG_TRACE("OSXPrivateKeyStorage::Decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800659
Yingdi Yu2e57a582014-02-20 23:34:43 -0800660 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700661 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800662 // keyClass = KEY_CLASS_SYMMETRIC;
663 // else
664 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800665
Yingdi Yu2e57a582014-02-20 23:34:43 -0800666 // CFDataRef dataRef = CFDataCreate(NULL,
667 // reinterpret_cast<const unsigned char*>(data),
668 // dataLength
669 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800670
Yingdi Yu2e57a582014-02-20 23:34:43 -0800671 // // _LOG_DEBUG("CreateData");
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700672
Yingdi Yu2e57a582014-02-20 23:34:43 -0800673 // SecKeyRef decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800674
Yingdi Yu2e57a582014-02-20 23:34:43 -0800675 // // _LOG_DEBUG("GetKey");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800676
Yingdi Yu2e57a582014-02-20 23:34:43 -0800677 // CFErrorRef error;
678 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
679 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800680
Yingdi Yu2e57a582014-02-20 23:34:43 -0800681 // Boolean set_res = SecTransformSetAttribute(decrypt,
682 // kSecTransformInputAttributeName,
683 // dataRef,
684 // &error);
685 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800686
Yingdi Yu2e57a582014-02-20 23:34:43 -0800687 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
688 // if (error)
689 // {
690 // CFShow(error);
691 // throw Error("Fail to decrypt data");
692 // }
693 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800694
Yingdi Yu2e57a582014-02-20 23:34:43 -0800695 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800696}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700697
Yingdi Yu2e57a582014-02-20 23:34:43 -0800698void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700699SecTpmOsx::addAppToACL(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800700{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700701 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800702 {
703 SecKeychainItemRef privateKey = m_impl->getKey(keyName, keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700704
Yingdi Yu2e57a582014-02-20 23:34:43 -0800705 SecAccessRef accRef;
706 OSStatus acc_res = SecKeychainItemCopyAccess(privateKey, &accRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700707
Yingdi Yu2e57a582014-02-20 23:34:43 -0800708 CFArrayRef signACL = SecAccessCopyMatchingACLList(accRef,
709 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700710
Yingdi Yu2e57a582014-02-20 23:34:43 -0800711 SecACLRef aclRef = (SecACLRef) CFArrayGetValueAtIndex(signACL, 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700712
Yingdi Yu2e57a582014-02-20 23:34:43 -0800713 CFArrayRef appList;
714 CFStringRef description;
715 SecKeychainPromptSelector promptSelector;
716 OSStatus acl_res = SecACLCopyContents(aclRef,
717 &appList,
718 &description,
719 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700720
Yingdi Yu2e57a582014-02-20 23:34:43 -0800721 CFMutableArrayRef newAppList = CFArrayCreateMutableCopy(NULL,
722 0,
723 appList);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700724
Yingdi Yu2e57a582014-02-20 23:34:43 -0800725 SecTrustedApplicationRef trustedApp;
726 acl_res = SecTrustedApplicationCreateFromPath(appPath.c_str(),
727 &trustedApp);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700728
Yingdi Yu2e57a582014-02-20 23:34:43 -0800729 CFArrayAppendValue(newAppList, trustedApp);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700730
Yingdi Yu2e57a582014-02-20 23:34:43 -0800731 acl_res = SecACLSetContents(aclRef,
732 newAppList,
733 description,
734 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700735
Yingdi Yu2e57a582014-02-20 23:34:43 -0800736 acc_res = SecKeychainItemSetAccess(privateKey, accRef);
737 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800738}
739
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800740ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700741SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800742{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800743 throw Error("SecTpmOsx::encryptInTpm is not supported");
744 // _LOG_TRACE("OSXPrivateKeyStorage::Encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800745
Yingdi Yu2e57a582014-02-20 23:34:43 -0800746 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700747 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800748 // keyClass = KEY_CLASS_SYMMETRIC;
749 // else
750 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700751
Yingdi Yu2e57a582014-02-20 23:34:43 -0800752 // CFDataRef dataRef = CFDataCreate(NULL,
753 // reinterpret_cast<const unsigned char*>(data),
754 // dataLength
755 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700756
Yingdi Yu2e57a582014-02-20 23:34:43 -0800757 // SecKeyRef encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800758
Yingdi Yu2e57a582014-02-20 23:34:43 -0800759 // CFErrorRef error;
760 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
761 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800762
Yingdi Yu2e57a582014-02-20 23:34:43 -0800763 // Boolean set_res = SecTransformSetAttribute(encrypt,
764 // kSecTransformInputAttributeName,
765 // dataRef,
766 // &error);
767 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800768
Yingdi Yu2e57a582014-02-20 23:34:43 -0800769 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
770 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800771
Yingdi Yu2e57a582014-02-20 23:34:43 -0800772 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800773
Yingdi Yu2e57a582014-02-20 23:34:43 -0800774 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800775}
776
777bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700778SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800779{
780 _LOG_TRACE("OSXPrivateKeyStorage::doesKeyExist");
781
782 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
783
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700784 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
785 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800786 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700787
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800788 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
789 4,
790 &kCFTypeDictionaryKeyCallBacks,
791 NULL);
792
793 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800794 // CFDictionaryAddValue(attrDict, kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800795 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
796 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700797
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800798 SecKeychainItemRef itemRef;
799 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict, (CFTypeRef*)&itemRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700800
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700801 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800802 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800803 else
804 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800805
806}
807
Yingdi Yu4b752752014-02-18 12:24:03 -0800808bool
809SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
810{
811 return (SecRandomCopyBytes(kSecRandomDefault, size, res) == 0);
812}
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800813
814////////////////////////////////
815// OSXPrivateKeyStorage::Impl //
816////////////////////////////////
817
818SecKeychainItemRef
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700819SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800820{
821 string keyNameUri = toInternalKeyName(keyName, keyClass);
822
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700823 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
824 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800825 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700826
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800827 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
828 5,
829 &kCFTypeDictionaryKeyCallBacks,
830 NULL);
831
832 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
833 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
834 CFDictionaryAddValue(attrDict, kSecAttrKeyClass, getKeyClass(keyClass));
835 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700836
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800837 SecKeychainItemRef keyItem;
838
839 OSStatus res = SecItemCopyMatching((CFDictionaryRef) attrDict, (CFTypeRef*)&keyItem);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700840
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700841 if (res != errSecSuccess){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800842 _LOG_DEBUG("Fail to find the key!");
843 return NULL;
844 }
845 else
846 return keyItem;
847}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700848
849string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700850SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800851{
852 string keyUri = keyName.toUri();
853
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700854 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800855 return keyUri + "/symmetric";
856 else
857 return keyUri;
858}
859
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700860const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800861SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
862{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700863 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800864 case KEY_TYPE_RSA:
865 return kSecAttrKeyTypeRSA;
866 default:
867 _LOG_DEBUG("Unrecognized key type!")
868 return NULL;
869 }
870}
871
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700872const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800873SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
874{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700875 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800876 case KEY_TYPE_AES:
877 return kSecAttrKeyTypeAES;
878 default:
879 _LOG_DEBUG("Unrecognized key type!")
880 return NULL;
881 }
882}
883
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700884const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800885SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
886{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700887 switch (keyClass){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800888 case KEY_CLASS_PRIVATE:
889 return kSecAttrKeyClassPrivate;
890 case KEY_CLASS_PUBLIC:
891 return kSecAttrKeyClassPublic;
892 case KEY_CLASS_SYMMETRIC:
893 return kSecAttrKeyClassSymmetric;
894 default:
895 _LOG_DEBUG("Unrecognized key class!");
896 return NULL;
897 }
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:
913 _LOG_DEBUG("Unrecognized digest algorithm!");
914 return NULL;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700915 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800916}
Jeff Thompson2747dc02013-10-04 19:11:34 -0700917
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700918long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800919SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
920{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700921 switch (digestAlgo){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800922 case DIGEST_ALGORITHM_SHA256:
923 return 256;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700924 // case DIGEST_SHA1:
925 // case DIGEST_MD2:
926 // case DIGEST_MD5:
927 // return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800928 default:
929 _LOG_DEBUG("Unrecognized digest algorithm! Unknown digest size");
930 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700931 }
Jeff Thompson2747dc02013-10-04 19:11:34 -0700932}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700933
Yingdi Yufc40d872014-02-18 12:56:04 -0800934} // namespace ndn