blob: d06cefef0a8aa8d3b5e7b73257e1d802dee5f05a [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
Yingdi Yu2b2b4792014-02-04 16:27:07 -080031class SecTpmOsx::Impl {
32public:
33 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -080034 : m_passwordSet(false)
35 , m_inTerminal(false)
Yingdi Yu2b2b4792014-02-04 16:27:07 -080036 {}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070037
Yingdi Yu2b2b4792014-02-04 16:27:07 -080038 /**
39 * @brief Convert NDN name of a key to internal name of the key.
40 *
Yingdi Yufc40d872014-02-18 12:56:04 -080041 * @param keyName
42 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -080043 * @return the internal key name
44 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070045 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070046 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070047
Yingdi Yu2b2b4792014-02-04 16:27:07 -080048 /**
49 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -080050 *
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070051 * @param keyName
Yingdi Yufc40d872014-02-18 12:56:04 -080052 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -080053 * @returns pointer to the key
54 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070055 SecKeychainItemRef
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070056 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070057
Yingdi Yu2b2b4792014-02-04 16:27:07 -080058 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080059 * @brief Convert keyType to MAC OS symmetric key key type
60 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080061 * @param keyType
62 * @returns MAC OS key type
63 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070064 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080065 getSymKeyType(KeyType keyType);
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 asymmetirc 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 getAsymKeyType(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 keyClass to MAC OS key class
78 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080079 * @param keyClass
80 * @returns MAC OS key class
81 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070082 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080083 getKeyClass(KeyClass keyClass);
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 digestAlgo to MAC OS algorithm id
87 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080088 * @param digestAlgo
89 * @returns MAC OS algorithm id
90 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070091 const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080092 getDigestAlgorithm(DigestAlgorithm digestAlgo);
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 Get the digest size of the corresponding algorithm
96 *
97 * @param digestAlgo
Yingdi Yu2b2b4792014-02-04 16:27:07 -080098 * @return digest size
99 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700100 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800101 getDigestSize(DigestAlgorithm digestAlgo);
102
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800103 ///////////////////////////////////////////////
104 // everything here is public, including data //
105 ///////////////////////////////////////////////
106public:
107 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800108 bool m_passwordSet;
109 string m_password;
110 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800111};
112
113
114SecTpmOsx::SecTpmOsx()
115 : m_impl(new Impl)
116{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700117 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700118 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800119 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700120 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800121
Yingdi Yube4150e2014-02-18 13:02:46 -0800122 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700123
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800124 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Yingdi Yube4150e2014-02-18 13:02:46 -0800125 throw Error("No default keychain, create one first!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800126}
127
128SecTpmOsx::~SecTpmOsx(){
129 //TODO: implement
130}
131
Yingdi Yube4150e2014-02-18 13:02:46 -0800132void
133SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
134{
135 m_impl->m_passwordSet = true;
136 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
137 m_impl->m_password.clear();
138 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
139}
140
141void
142SecTpmOsx::resetTpmPassword()
143{
144 m_impl->m_passwordSet = false;
145 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
146 m_impl->m_password.clear();
147}
148
149void
150SecTpmOsx::setInTerminal(bool inTerminal)
151{
152 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700153 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700154 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800155 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700156 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800157}
158
159bool
160SecTpmOsx::getInTerminal()
161{
162 return m_impl->m_inTerminal;
163}
164
165bool
166SecTpmOsx::locked()
167{
168 SecKeychainStatus keychainStatus;
169
170 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700171 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800172 return true;
173 else
174 return ((kSecUnlockStateStatus & keychainStatus) == 0);
175}
176
Yingdi Yu2e57a582014-02-20 23:34:43 -0800177bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800178SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
179{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700180 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800181
182 // If the default key chain is already unlocked, return immediately.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700183 if (!locked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800184 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800185
186 // If the default key chain is locked, unlock the key chain.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700187 if (usePassword)
Yingdi Yube4150e2014-02-18 13:02:46 -0800188 {
189 // Use the supplied password.
190 res = SecKeychainUnlock(m_impl->m_keyChainRef,
191 passwordLength,
192 password,
193 true);
194 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700195 else if (m_impl->m_passwordSet)
Yingdi Yube4150e2014-02-18 13:02:46 -0800196 {
197 // If no password supplied, then use the configured password if exists.
198 SecKeychainUnlock(m_impl->m_keyChainRef,
199 m_impl->m_password.size(),
200 m_impl->m_password.c_str(),
201 true);
202 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700203 else if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800204 {
205 // If no configured password, get password from terminal if inTerminal set.
206 bool locked = true;
207 const char* fmt = "Password to unlock the default keychain: ";
208 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700209
Yingdi Yube4150e2014-02-18 13:02:46 -0800210 while(locked)
211 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700212 if (count > 2)
Yingdi Yube4150e2014-02-18 13:02:46 -0800213 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700214
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700215 char* getPassword = 0;
Yingdi Yube4150e2014-02-18 13:02:46 -0800216 getPassword = getpass(fmt);
217 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700218
Yingdi Yube4150e2014-02-18 13:02:46 -0800219 if (!getPassword)
220 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700221
Yingdi Yube4150e2014-02-18 13:02:46 -0800222 res = SecKeychainUnlock(m_impl->m_keyChainRef,
223 strlen(getPassword),
224 getPassword,
225 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700226
Yingdi Yube4150e2014-02-18 13:02:46 -0800227 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700228
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700229 if (res == errSecSuccess)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800230 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800231 }
232 }
233 else
234 {
235 // If inTerminal is not set, get the password from GUI.
236 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
237 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800238
239 return !locked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800240}
241
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700242void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700243SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName, KeyType keyType,
244 int keySize, bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700245{
246
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700247 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
248 {
249 throw Error("keyName has existed");
250 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800251
252 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
253
254 SecKeyRef publicKey, privateKey;
255
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700256 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700257 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800258 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700259
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700260 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800261 3,
262 &kCFTypeDictionaryKeyCallBacks,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700263 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800264
265 CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700266 CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(0,
267 kCFNumberIntType,
268 &keySize));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800269 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 Yu4b8c6a22014-04-15 23:00:54 -0700280 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800281 {
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 {
Yingdi Yube4150e2014-02-18 13:02:46 -0800289 throw Error("Fail to create a key pair");
290 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800291}
292
293void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700294SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800295{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700296 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700297 keyName.toUri().c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800298 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800299
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700300 CFMutableDictionaryRef searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700301 CFDictionaryCreateMutable(0, 5,
302 &kCFTypeDictionaryKeyCallBacks,
303 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800304
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800305 CFDictionaryAddValue(searchDict, kSecClass, kSecClassKey);
306 CFDictionaryAddValue(searchDict, kSecAttrLabel, keyLabel);
307 CFDictionaryAddValue(searchDict, kSecMatchLimit, kSecMatchLimitAll);
Yingdi Yube4150e2014-02-18 13:02:46 -0800308 OSStatus res = SecItemDelete(searchDict);
309
310 if (res == errSecSuccess)
311 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700312
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700313 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800314 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700315 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800316 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800317 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800318}
319
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700320void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700321SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, KeyType keyType, int keySize)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800322{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800323 throw Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700324 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800325 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800326
Yingdi Yu2e57a582014-02-20 23:34:43 -0800327 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800328
Yingdi Yu2e57a582014-02-20 23:34:43 -0800329 // CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
330 // 0,
331 // &kCFTypeDictionaryKeyCallBacks,
332 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800333
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700334 // CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700335 // keyNameUri.c_str(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800336 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800337
Yingdi Yu2e57a582014-02-20 23:34:43 -0800338 // CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getSymKeyType(keyType));
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700339 // CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(kCFAllocatorDefault,
340 // kCFNumberSInt32Type,
341 // &keySize));
Yingdi Yu2e57a582014-02-20 23:34:43 -0800342 // CFDictionaryAddValue(attrDict, kSecAttrIsPermanent, kCFBooleanTrue);
343 // CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800344
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700345 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800346
Yingdi Yu2e57a582014-02-20 23:34:43 -0800347 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800348
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700349 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800350 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800351}
352
Yingdi Yu2e57a582014-02-20 23:34:43 -0800353shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700354SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800355{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800356 SecKeychainItemRef publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
357
358 CFDataRef exportedKey;
359
360 OSStatus res = SecItemExport(publicKey,
361 kSecFormatOpenSSL,
362 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700363 0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800364 &exportedKey);
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800365 if (res != errSecSuccess)
366 {
367 throw Error("Cannot export requested public key from OSX Keychain");
368 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800369
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700370 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey),
371 CFDataGetLength(exportedKey));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800372 CFRelease(exportedKey);
373 return key;
374}
375
376ConstBufferPtr
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700377SecTpmOsx::exportPrivateKeyPkcs1FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800378{
379 using namespace CryptoPP;
380
381 SecKeychainItemRef privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
382 CFDataRef exportedKey;
383 OSStatus res = SecItemExport(privateKey,
384 kSecFormatOpenSSL,
385 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700386 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800387 &exportedKey);
388
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700389 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800390 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700391 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800392 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700393 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800394 return exportPrivateKeyPkcs1FromTpmInternal(keyName, true);
395 else
396 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800397 }
398 else
399 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800400 }
401
402 OBufferStream pkcs1Os;
403 FileSink sink(pkcs1Os);
404
405 uint32_t version = 0;
406 OID algorithm("1.2.840.113549.1.1.1");
407 SecByteBlock rawKeyBits;
408 // PrivateKeyInfo ::= SEQUENCE {
409 // version INTEGER,
410 // privateKeyAlgorithm SEQUENCE,
411 // privateKey OCTECT STRING}
412 DERSequenceEncoder privateKeyInfo(sink);
413 {
414 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
415 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
416 {
417 algorithm.encode(privateKeyAlgorithm);
418 DEREncodeNull(privateKeyAlgorithm);
419 }
420 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700421 DEREncodeOctetString(privateKeyInfo,
422 CFDataGetBytePtr(exportedKey),
423 CFDataGetLength(exportedKey));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800424 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700425 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800426
427 CFRelease(exportedKey);
428 return pkcs1Os.buf();
429}
430
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700431#ifdef __GNUC__
432#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
433#pragma GCC diagnostic push
434#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
435#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
436#endif // __GNUC__
437
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800438bool
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700439SecTpmOsx::importPrivateKeyPkcs1IntoTpmInternal(const Name& keyName,
440 const uint8_t* buf, size_t size,
441 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800442{
443 using namespace CryptoPP;
444
445 StringSource privateKeySource(buf, size, true);
446 uint32_t tmpNum;
447 OID tmpOID;
448 SecByteBlock rawKeyBits;
449 // PrivateKeyInfo ::= SEQUENCE {
450 // INTEGER,
451 // SEQUENCE,
452 // OCTECT STRING}
453 BERSequenceDecoder privateKeyInfo(privateKeySource);
454 {
455 BERDecodeUnsigned<uint32_t>(privateKeyInfo, tmpNum, INTEGER);
456 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
457 {
458 tmpOID.decode(sequenceDecoder);
459 BERDecodeNull(sequenceDecoder);
460 }
461 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
462 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700463 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800464
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700465 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800466 rawKeyBits.BytePtr(),
467 rawKeyBits.size(),
468 kCFAllocatorNull);
469
470 SecExternalFormat externalFormat = kSecFormatOpenSSL;
471 SecExternalItemType externalType = kSecItemTypePrivateKey;
472 SecKeyImportExportParameters keyParams;
473 memset(&keyParams, 0, sizeof(keyParams));
474 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
475 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
476 SecAccessRef access;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700477 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700478 keyName.toUri().c_str(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800479 kCFStringEncodingUTF8);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700480 SecAccessCreate(keyLabel, 0, &access);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800481 keyParams.accessRef = access;
482 CFArrayRef outItems;
483
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700484#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700485#pragma clang diagnostic push
486#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700487#endif // __clang__
488
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800489 OSStatus res = SecKeychainItemImport (importedKey,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700490 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800491 &externalFormat,
492 &externalType,
493 0,
494 &keyParams,
495 m_impl->m_keyChainRef,
496 &outItems);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700497
498#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700499#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700500#endif // __clang__
501
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700502 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800503 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700504 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800505 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700506 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800507 return importPrivateKeyPkcs1IntoTpmInternal(keyName, buf, size, true);
508 else
509 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800510 }
511 else
512 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800513 }
514
515 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
516 SecKeychainAttribute attrs[1]; // maximum number of attributes
517 SecKeychainAttributeList attrList = { 0, attrs };
518 string keyUri = keyName.toUri();
519 {
520 attrs[attrList.count].tag = kSecKeyPrintName;
521 attrs[attrList.count].length = keyUri.size();
522 attrs[attrList.count].data = (void *)keyUri.c_str();
523 attrList.count++;
524 }
525
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700526 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800527 &attrList,
528 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700529 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700530
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700531 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800532 {
533 return false;
534 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700535
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800536 CFRelease(importedKey);
537 return true;
538}
539
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700540#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
541#pragma GCC diagnostic pop
542#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
543
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800544bool
545SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
546{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700547 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800548 buf,
549 size,
550 kCFAllocatorNull);
551
552 SecExternalFormat externalFormat = kSecFormatOpenSSL;
553 SecExternalItemType externalType = kSecItemTypePublicKey;
554 CFArrayRef outItems;
555
556 OSStatus res = SecItemImport (importedKey,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700557 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800558 &externalFormat,
559 &externalType,
560 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700561 0,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800562 m_impl->m_keyChainRef,
563 &outItems);
564
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700565 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800566 return false;
567
568 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
569 SecKeychainAttribute attrs[1]; // maximum number of attributes
570 SecKeychainAttributeList attrList = { 0, attrs };
571 string keyUri = keyName.toUri();
572 {
573 attrs[attrList.count].tag = kSecKeyPrintName;
574 attrs[attrList.count].length = keyUri.size();
575 attrs[attrList.count].data = (void *)keyUri.c_str();
576 attrList.count++;
577 }
578
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700579 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800580 &attrList,
581 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700582 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700583
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700584 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800585 return false;
586
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800587 CFRelease(importedKey);
588 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800589}
590
591Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700592SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
593 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800594{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700595 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800596 data,
597 dataLength,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800598 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800599
600 SecKeyRef privateKey = (SecKeyRef)m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700601
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800602 CFErrorRef error;
603 SecTransformRef signer = SecSignTransformCreate((SecKeyRef)privateKey, &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700604 if (error)
605 throw Error("Fail to create signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800606
607 // Set input
608 Boolean set_res = SecTransformSetAttribute(signer,
609 kSecTransformInputAttributeName,
610 dataRef,
611 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700612 if (error)
613 throw Error("Fail to configure input of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800614
615 // Enable use of padding
Yingdi Yu2e57a582014-02-20 23:34:43 -0800616 SecTransformSetAttribute(signer,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800617 kSecPaddingKey,
618 kSecPaddingPKCS1Key,
619 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700620 if (error)
621 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800622
623 // Set padding type
624 set_res = SecTransformSetAttribute(signer,
625 kSecDigestTypeAttribute,
626 m_impl->getDigestAlgorithm(digestAlgorithm),
627 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700628 if (error)
629 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800630
631 // Set padding attribute
632 long digestSize = m_impl->getDigestSize(digestAlgorithm);
633 set_res = SecTransformSetAttribute(signer,
634 kSecDigestLengthAttribute,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700635 CFNumberCreate(0, kCFNumberLongType, &digestSize),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800636 &error);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700637 if (error)
638 throw Error("Fail to configure digest size of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800639
640 // Actually sign
641 CFDataRef signature = (CFDataRef) SecTransformExecute(signer, &error);
Yingdi Yube4150e2014-02-18 13:02:46 -0800642 if (error)
643 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700644 if (!needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800645 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700646 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800647 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
648 else
649 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800650 }
651 else
652 {
653 CFShow(error);
654 throw Error("Fail to sign data");
655 }
656 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800657
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700658 if (!signature)
659 throw Error("Signature is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800660
661 return Block(Tlv::SignatureValue,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800662 make_shared<Buffer>(CFDataGetBytePtr(signature), CFDataGetLength(signature)));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800663}
664
665ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700666SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800667{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800668 throw Error("SecTpmOsx::decryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800669
Yingdi Yu2e57a582014-02-20 23:34:43 -0800670 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700671 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800672 // keyClass = KEY_CLASS_SYMMETRIC;
673 // else
674 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800675
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700676 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800677 // reinterpret_cast<const unsigned char*>(data),
678 // dataLength
679 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800680
Yingdi Yu2e57a582014-02-20 23:34:43 -0800681 // SecKeyRef decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800682
Yingdi Yu2e57a582014-02-20 23:34:43 -0800683 // CFErrorRef error;
684 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
685 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800686
Yingdi Yu2e57a582014-02-20 23:34:43 -0800687 // Boolean set_res = SecTransformSetAttribute(decrypt,
688 // kSecTransformInputAttributeName,
689 // dataRef,
690 // &error);
691 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800692
Yingdi Yu2e57a582014-02-20 23:34:43 -0800693 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
694 // if (error)
695 // {
696 // CFShow(error);
697 // throw Error("Fail to decrypt data");
698 // }
699 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800700
Yingdi Yu2e57a582014-02-20 23:34:43 -0800701 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800702}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700703
Yingdi Yu2e57a582014-02-20 23:34:43 -0800704void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700705SecTpmOsx::addAppToACL(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800706{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700707 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800708 {
709 SecKeychainItemRef privateKey = m_impl->getKey(keyName, keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700710
Yingdi Yu2e57a582014-02-20 23:34:43 -0800711 SecAccessRef accRef;
712 OSStatus acc_res = SecKeychainItemCopyAccess(privateKey, &accRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700713
Yingdi Yu2e57a582014-02-20 23:34:43 -0800714 CFArrayRef signACL = SecAccessCopyMatchingACLList(accRef,
715 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700716
Yingdi Yu2e57a582014-02-20 23:34:43 -0800717 SecACLRef aclRef = (SecACLRef) CFArrayGetValueAtIndex(signACL, 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700718
Yingdi Yu2e57a582014-02-20 23:34:43 -0800719 CFArrayRef appList;
720 CFStringRef description;
721 SecKeychainPromptSelector promptSelector;
722 OSStatus acl_res = SecACLCopyContents(aclRef,
723 &appList,
724 &description,
725 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700726
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700727 CFMutableArrayRef newAppList = CFArrayCreateMutableCopy(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800728 0,
729 appList);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700730
Yingdi Yu2e57a582014-02-20 23:34:43 -0800731 SecTrustedApplicationRef trustedApp;
732 acl_res = SecTrustedApplicationCreateFromPath(appPath.c_str(),
733 &trustedApp);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700734
Yingdi Yu2e57a582014-02-20 23:34:43 -0800735 CFArrayAppendValue(newAppList, trustedApp);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700736
Yingdi Yu2e57a582014-02-20 23:34:43 -0800737 acl_res = SecACLSetContents(aclRef,
738 newAppList,
739 description,
740 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700741
Yingdi Yu2e57a582014-02-20 23:34:43 -0800742 acc_res = SecKeychainItemSetAccess(privateKey, accRef);
743 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800744}
745
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800746ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700747SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800748{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800749 throw Error("SecTpmOsx::encryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800750
Yingdi Yu2e57a582014-02-20 23:34:43 -0800751 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700752 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800753 // keyClass = KEY_CLASS_SYMMETRIC;
754 // else
755 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700756
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700757 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800758 // reinterpret_cast<const unsigned char*>(data),
759 // dataLength
760 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700761
Yingdi Yu2e57a582014-02-20 23:34:43 -0800762 // SecKeyRef encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800763
Yingdi Yu2e57a582014-02-20 23:34:43 -0800764 // CFErrorRef error;
765 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
766 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800767
Yingdi Yu2e57a582014-02-20 23:34:43 -0800768 // Boolean set_res = SecTransformSetAttribute(encrypt,
769 // kSecTransformInputAttributeName,
770 // dataRef,
771 // &error);
772 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800773
Yingdi Yu2e57a582014-02-20 23:34:43 -0800774 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
775 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800776
Yingdi Yu2e57a582014-02-20 23:34:43 -0800777 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800778
Yingdi Yu2e57a582014-02-20 23:34:43 -0800779 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800780}
781
782bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700783SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800784{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800785 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
786
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700787 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700788 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800789 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700790
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700791 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800792 4,
793 &kCFTypeDictionaryKeyCallBacks,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700794 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800795
796 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800797 // CFDictionaryAddValue(attrDict, kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800798 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
799 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700800
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800801 SecKeychainItemRef itemRef;
802 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict, (CFTypeRef*)&itemRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700803
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700804 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800805 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800806 else
807 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800808
809}
810
Yingdi Yu4b752752014-02-18 12:24:03 -0800811bool
812SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
813{
814 return (SecRandomCopyBytes(kSecRandomDefault, size, res) == 0);
815}
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800816
817////////////////////////////////
818// OSXPrivateKeyStorage::Impl //
819////////////////////////////////
820
821SecKeychainItemRef
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700822SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800823{
824 string keyNameUri = toInternalKeyName(keyName, keyClass);
825
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700826 CFStringRef keyLabel = CFStringCreateWithCString(0,
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700827 keyNameUri.c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800828 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700829
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700830 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(0,
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800831 5,
832 &kCFTypeDictionaryKeyCallBacks,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700833 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800834
835 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
836 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
837 CFDictionaryAddValue(attrDict, kSecAttrKeyClass, getKeyClass(keyClass));
838 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700839
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800840 SecKeychainItemRef keyItem;
841
842 OSStatus res = SecItemCopyMatching((CFDictionaryRef) attrDict, (CFTypeRef*)&keyItem);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700843
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700844 if (res != errSecSuccess)
845 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800846 else
847 return keyItem;
848}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700849
850string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700851SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800852{
853 string keyUri = keyName.toUri();
854
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700855 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800856 return keyUri + "/symmetric";
857 else
858 return keyUri;
859}
860
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700861const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800862SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
863{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700864 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800865 case KEY_TYPE_RSA:
866 return kSecAttrKeyTypeRSA;
867 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700868 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800869 }
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:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700879 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800880 }
881}
882
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700883const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800884SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
885{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700886 switch (keyClass){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800887 case KEY_CLASS_PRIVATE:
888 return kSecAttrKeyClassPrivate;
889 case KEY_CLASS_PUBLIC:
890 return kSecAttrKeyClassPublic;
891 case KEY_CLASS_SYMMETRIC:
892 return kSecAttrKeyClassSymmetric;
893 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700894 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800895 }
896}
897
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700898const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800899SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
900{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700901 switch (digestAlgo){
Jeff Thompson2747dc02013-10-04 19:11:34 -0700902 // case DIGEST_MD2:
903 // return kSecDigestMD2;
904 // case DIGEST_MD5:
905 // return kSecDigestMD5;
906 // case DIGEST_SHA1:
907 // return kSecDigestSHA1;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800908 case DIGEST_ALGORITHM_SHA256:
909 return kSecDigestSHA2;
910 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700911 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700912 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800913}
Jeff Thompson2747dc02013-10-04 19:11:34 -0700914
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700915long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800916SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
917{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700918 switch (digestAlgo){
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800919 case DIGEST_ALGORITHM_SHA256:
920 return 256;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700921 // case DIGEST_SHA1:
922 // case DIGEST_MD2:
923 // case DIGEST_MD5:
924 // return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800925 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800926 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700927 }
Jeff Thompson2747dc02013-10-04 19:11:34 -0700928}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700929
Yingdi Yufc40d872014-02-18 12:56:04 -0800930} // namespace ndn