blob: cda3633fa2ac3d7062f9748ff3006f91cc954502 [file] [log] [blame]
Jeff Thompson2747dc02013-10-04 19:11:34 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07003 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
11 *
12 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Jeff Thompson2747dc02013-10-04 19:11:34 -070013 */
14
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080015#include "common.hpp"
16
Alexander Afanasyev19508852014-01-29 01:01:51 -080017#include "sec-tpm-osx.hpp"
Yingdi Yuf56c68f2014-04-24 21:50:13 -070018#include "public-key.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070019#include "../encoding/oid.hpp"
20#include "../encoding/buffer-stream.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070021#include "cryptopp.hpp"
Jeff Thompson2747dc02013-10-04 19:11:34 -070022
Yingdi Yu2b2b4792014-02-04 16:27:07 -080023#include <pwd.h>
24#include <unistd.h>
25#include <stdlib.h>
26#include <string.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070027
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080028#include <CoreFoundation/CoreFoundation.h>
29#include <Security/Security.h>
Yingdi Yu4b752752014-02-18 12:24:03 -080030#include <Security/SecRandom.h>
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080031#include <CoreServices/CoreServices.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070032
Alexander Afanasyev59d67a52014-04-03 16:09:31 -070033#include <Security/SecDigestTransform.h>
34
Jeff Thompson2747dc02013-10-04 19:11:34 -070035using namespace std;
Jeff Thompson2747dc02013-10-04 19:11:34 -070036
Yingdi Yufc40d872014-02-18 12:56:04 -080037namespace ndn {
38
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070039/**
40 * @brief Helper class to wrap CoreFoundation object pointers
41 *
42 * The class is similar in spirit to shared_ptr, but uses CoreFoundation
43 * mechanisms to retain/release object.
44 *
45 * Original implementation by Christopher Hunt and it was borrowed from
46 * http://www.cocoabuilder.com/archive/cocoa/130776-auto-cfrelease-and.html
47 */
48template<class T>
49class CFReleaser
50{
51public:
52 //////////////////////////////
53 // Construction/destruction //
54
55 CFReleaser()
56 : m_typeRef(0)
57 {
58 }
59
60 CFReleaser(const T& typeRef)
61 : m_typeRef(typeRef)
62 {
63 }
64
65 CFReleaser(const CFReleaser& inReleaser)
66 : m_typeRef(0)
67 {
68 retain(inReleaser.m_typeRef);
69 }
70
71 CFReleaser&
72 operator=(const T& typeRef)
73 {
74 if (typeRef != m_typeRef) {
75 release();
76 m_typeRef = typeRef;
77 }
78 return *this;
79 }
80
81 CFReleaser&
82 operator=(const CFReleaser& inReleaser)
83 {
84 retain(inReleaser.m_typeRef);
85 return *this;
86 }
87
88 ~CFReleaser()
89 {
90 release();
91 }
92
93 ////////////
94 // Access //
95
96 // operator const T&() const
97 // {
98 // return m_typeRef;
99 // }
100
101 // operator T&()
102 // {
103 // return m_typeRef;
104 // }
105
106 const T&
107 get() const
108 {
109 return m_typeRef;
110 }
111
112 T&
113 get()
114 {
115 return m_typeRef;
116 }
117
118 ///////////////////
119 // Miscellaneous //
120
121 void
122 retain(const T& typeRef)
123 {
124 if (typeRef != 0) {
125 CFRetain(typeRef);
126 }
127 release();
128 m_typeRef = typeRef;
129 }
130
131 void release()
132 {
133 if (m_typeRef != 0) {
134 CFRelease(m_typeRef);
135 m_typeRef = 0;
136 }
137 };
138
139private:
140 T m_typeRef;
141};
142
143
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700144class SecTpmOsx::Impl
145{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800146public:
147 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -0800148 : m_passwordSet(false)
149 , m_inTerminal(false)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700150 {
151 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700152
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800153 /**
154 * @brief Convert NDN name of a key to internal name of the key.
155 *
Yingdi Yufc40d872014-02-18 12:56:04 -0800156 * @param keyName
157 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800158 * @return the internal key name
159 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700160 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700161 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700162
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800163 /**
164 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -0800165 *
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700166 * @param keyName
Yingdi Yufc40d872014-02-18 12:56:04 -0800167 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800168 * @returns pointer to the key
169 */
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700170 CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700171 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700172
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800173 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800174 * @brief Convert keyType to MAC OS symmetric key key type
175 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800176 * @param keyType
177 * @returns MAC OS key type
178 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700179 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800180 getSymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700181
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800182 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800183 * @brief Convert keyType to MAC OS asymmetirc key type
184 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800185 * @param keyType
186 * @returns MAC OS key type
187 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700188 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800189 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700190
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800191 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800192 * @brief Convert keyClass to MAC OS key class
193 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800194 * @param keyClass
195 * @returns MAC OS key class
196 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700197 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800198 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700199
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800200 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800201 * @brief Convert digestAlgo to MAC OS algorithm id
202 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800203 * @param digestAlgo
204 * @returns MAC OS algorithm id
205 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700206 const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800207 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700208
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800209 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800210 * @brief Get the digest size of the corresponding algorithm
211 *
212 * @param digestAlgo
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800213 * @return digest size
214 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700215 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800216 getDigestSize(DigestAlgorithm digestAlgo);
217
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800218 ///////////////////////////////////////////////
219 // everything here is public, including data //
220 ///////////////////////////////////////////////
221public:
222 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800223 bool m_passwordSet;
224 string m_password;
225 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800226};
227
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800228SecTpmOsx::SecTpmOsx()
229 : m_impl(new Impl)
230{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700231 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700232 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800233 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700234 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800235
Yingdi Yube4150e2014-02-18 13:02:46 -0800236 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700237
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800238 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Yingdi Yube4150e2014-02-18 13:02:46 -0800239 throw Error("No default keychain, create one first!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800240}
241
242SecTpmOsx::~SecTpmOsx(){
243 //TODO: implement
244}
245
Yingdi Yube4150e2014-02-18 13:02:46 -0800246void
247SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
248{
249 m_impl->m_passwordSet = true;
250 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
251 m_impl->m_password.clear();
252 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
253}
254
255void
256SecTpmOsx::resetTpmPassword()
257{
258 m_impl->m_passwordSet = false;
259 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
260 m_impl->m_password.clear();
261}
262
263void
264SecTpmOsx::setInTerminal(bool inTerminal)
265{
266 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700267 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700268 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800269 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700270 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800271}
272
273bool
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700274SecTpmOsx::getInTerminal() const
Yingdi Yube4150e2014-02-18 13:02:46 -0800275{
276 return m_impl->m_inTerminal;
277}
278
279bool
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700280SecTpmOsx::isLocked()
Yingdi Yube4150e2014-02-18 13:02:46 -0800281{
282 SecKeychainStatus keychainStatus;
283
284 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700285 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800286 return true;
287 else
288 return ((kSecUnlockStateStatus & keychainStatus) == 0);
289}
290
Yingdi Yu2e57a582014-02-20 23:34:43 -0800291bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800292SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
293{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700294 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800295
296 // If the default key chain is already unlocked, return immediately.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700297 if (!isLocked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800298 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800299
300 // If the default key chain is locked, unlock the key chain.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700301 if (usePassword)
Yingdi Yube4150e2014-02-18 13:02:46 -0800302 {
303 // Use the supplied password.
304 res = SecKeychainUnlock(m_impl->m_keyChainRef,
305 passwordLength,
306 password,
307 true);
308 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700309 else if (m_impl->m_passwordSet)
Yingdi Yube4150e2014-02-18 13:02:46 -0800310 {
311 // If no password supplied, then use the configured password if exists.
312 SecKeychainUnlock(m_impl->m_keyChainRef,
313 m_impl->m_password.size(),
314 m_impl->m_password.c_str(),
315 true);
316 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700317 else if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800318 {
319 // If no configured password, get password from terminal if inTerminal set.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700320 bool isLocked = true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800321 const char* fmt = "Password to unlock the default keychain: ";
322 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700323
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700324 while (isLocked)
Yingdi Yube4150e2014-02-18 13:02:46 -0800325 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700326 if (count > 2)
Yingdi Yube4150e2014-02-18 13:02:46 -0800327 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700328
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700329 char* getPassword = 0;
Yingdi Yube4150e2014-02-18 13:02:46 -0800330 getPassword = getpass(fmt);
331 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700332
Yingdi Yube4150e2014-02-18 13:02:46 -0800333 if (!getPassword)
334 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700335
Yingdi Yube4150e2014-02-18 13:02:46 -0800336 res = SecKeychainUnlock(m_impl->m_keyChainRef,
337 strlen(getPassword),
338 getPassword,
339 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700340
Yingdi Yube4150e2014-02-18 13:02:46 -0800341 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700342
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700343 if (res == errSecSuccess)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800344 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800345 }
346 }
347 else
348 {
349 // If inTerminal is not set, get the password from GUI.
350 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
351 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800352
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700353 return !isLocked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800354}
355
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700356void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700357SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName, KeyType keyType,
358 int keySize, bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700359{
360
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700361 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
362 {
363 throw Error("keyName has existed");
364 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800365
366 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
367
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700368 CFReleaser<CFStringRef> keyLabel =
369 CFStringCreateWithCString(0,
370 keyNameUri.c_str(),
371 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800372
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700373 CFReleaser<CFMutableDictionaryRef> attrDict =
374 CFDictionaryCreateMutable(0,
375 3,
376 &kCFTypeDictionaryKeyCallBacks,
377 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700378
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700379 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800380
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700381 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
382 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
383 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800384
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700385 CFReleaser<SecKeyRef> publicKey, privateKey;
386 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(),
387 &publicKey.get(), &privateKey.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800388
Yingdi Yube4150e2014-02-18 13:02:46 -0800389 if (res == errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800390 {
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800391 return;
392 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700393
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700394 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800395 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700396 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800397 generateKeyPairInTpmInternal(keyName, keyType, keySize, true);
398 else
399 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800400 }
401 else
402 {
Yingdi Yube4150e2014-02-18 13:02:46 -0800403 throw Error("Fail to create a key pair");
404 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800405}
406
407void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700408SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800409{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700410 CFReleaser<CFStringRef> keyLabel =
411 CFStringCreateWithCString(0,
412 keyName.toUri().c_str(),
413 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800414
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700415 CFReleaser<CFMutableDictionaryRef> searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700416 CFDictionaryCreateMutable(0, 5,
417 &kCFTypeDictionaryKeyCallBacks,
418 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800419
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700420 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
421 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
422 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
423 OSStatus res = SecItemDelete(searchDict.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800424
425 if (res == errSecSuccess)
426 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700427
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700428 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800429 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700430 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800431 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800432 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800433}
434
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700435void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700436SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, KeyType keyType, int keySize)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800437{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800438 throw Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700439 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800440 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800441
Yingdi Yu2e57a582014-02-20 23:34:43 -0800442 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800443
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700444 // CFReleaser<CFMutableDictionaryRef> attrDict =
445 // CFDictionaryCreateMutable(kCFAllocatorDefault,
446 // 0,
447 // &kCFTypeDictionaryKeyCallBacks,
448 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800449
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700450 // CFReleaser<CFStringRef> keyLabel =
451 // CFStringCreateWithCString(0,
452 // keyNameUri.c_str(),
453 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800454
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700455 // CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
456
457 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType));
458 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
459 // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue);
460 // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800461
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700462 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800463
Yingdi Yu2e57a582014-02-20 23:34:43 -0800464 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800465
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700466 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800467 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800468}
469
Yingdi Yu2e57a582014-02-20 23:34:43 -0800470shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700471SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800472{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700473 CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
474 if (publicKey.get() == 0)
475 {
476 throw Error("Requested public key [" + keyName.toUri() + "] does not exist in OSX Keychain");
477 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800478
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700479 CFReleaser<CFDataRef> exportedKey;
480 OSStatus res = SecItemExport(publicKey.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800481 kSecFormatOpenSSL,
482 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700483 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700484 &exportedKey.get());
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800485 if (res != errSecSuccess)
486 {
487 throw Error("Cannot export requested public key from OSX Keychain");
488 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800489
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700490 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey.get()),
491 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800492 return key;
493}
494
495ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700496SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800497{
498 using namespace CryptoPP;
499
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700500 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
501 if (privateKey.get() == 0)
502 {
503 /// @todo Can this happen because of keychain is locked?
504 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
505 }
506
507 CFReleaser<CFDataRef> exportedKey;
508 OSStatus res = SecItemExport(privateKey.get(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800509 kSecFormatOpenSSL,
510 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700511 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700512 &exportedKey.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800513
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700514 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800515 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700516 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800517 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700518 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700519 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800520 else
521 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800522 }
523 else
524 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800525 }
526
527 OBufferStream pkcs1Os;
528 FileSink sink(pkcs1Os);
529
530 uint32_t version = 0;
531 OID algorithm("1.2.840.113549.1.1.1");
532 SecByteBlock rawKeyBits;
533 // PrivateKeyInfo ::= SEQUENCE {
534 // version INTEGER,
535 // privateKeyAlgorithm SEQUENCE,
536 // privateKey OCTECT STRING}
537 DERSequenceEncoder privateKeyInfo(sink);
538 {
539 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
540 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
541 {
542 algorithm.encode(privateKeyAlgorithm);
543 DEREncodeNull(privateKeyAlgorithm);
544 }
545 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700546 DEREncodeOctetString(privateKeyInfo,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700547 CFDataGetBytePtr(exportedKey.get()),
548 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800549 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700550 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800551
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800552 return pkcs1Os.buf();
553}
554
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700555#ifdef __GNUC__
556#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
557#pragma GCC diagnostic push
558#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
559#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
560#endif // __GNUC__
561
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800562bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700563SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700564 const uint8_t* buf, size_t size,
565 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800566{
567 using namespace CryptoPP;
568
569 StringSource privateKeySource(buf, size, true);
570 uint32_t tmpNum;
571 OID tmpOID;
572 SecByteBlock rawKeyBits;
573 // PrivateKeyInfo ::= SEQUENCE {
574 // INTEGER,
575 // SEQUENCE,
576 // OCTECT STRING}
577 BERSequenceDecoder privateKeyInfo(privateKeySource);
578 {
579 BERDecodeUnsigned<uint32_t>(privateKeyInfo, tmpNum, INTEGER);
580 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
581 {
582 tmpOID.decode(sequenceDecoder);
583 BERDecodeNull(sequenceDecoder);
584 }
585 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
586 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700587 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800588
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700589 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
590 rawKeyBits.BytePtr(),
591 rawKeyBits.size(),
592 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800593
594 SecExternalFormat externalFormat = kSecFormatOpenSSL;
595 SecExternalItemType externalType = kSecItemTypePrivateKey;
596 SecKeyImportExportParameters keyParams;
597 memset(&keyParams, 0, sizeof(keyParams));
598 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
599 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700600 CFReleaser<SecAccessRef> access;
601 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
602 keyName.toUri().c_str(),
603 kCFStringEncodingUTF8);
604 SecAccessCreate(keyLabel.get(), 0, &access.get());
605 keyParams.accessRef = access.get();
606 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800607
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700608#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700609#pragma clang diagnostic push
610#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700611#endif // __clang__
612
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700613 OSStatus res = SecKeychainItemImport(importedKey.get(),
614 0,
615 &externalFormat,
616 &externalType,
617 0,
618 &keyParams,
619 m_impl->m_keyChainRef,
620 &outItems.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700621
622#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700623#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700624#endif // __clang__
625
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700626 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800627 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700628 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800629 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700630 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700631 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800632 else
633 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800634 }
635 else
636 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800637 }
638
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700639 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800640 SecKeychainAttribute attrs[1]; // maximum number of attributes
641 SecKeychainAttributeList attrList = { 0, attrs };
642 string keyUri = keyName.toUri();
643 {
644 attrs[attrList.count].tag = kSecKeyPrintName;
645 attrs[attrList.count].length = keyUri.size();
646 attrs[attrList.count].data = (void *)keyUri.c_str();
647 attrList.count++;
648 }
649
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700650 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800651 &attrList,
652 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700653 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700654
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700655 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800656 {
657 return false;
658 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700659
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800660 return true;
661}
662
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700663#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
664#pragma GCC diagnostic pop
665#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
666
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800667bool
668SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
669{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700670 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
671 buf,
672 size,
673 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800674
675 SecExternalFormat externalFormat = kSecFormatOpenSSL;
676 SecExternalItemType externalType = kSecItemTypePublicKey;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700677 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800678
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700679 OSStatus res = SecItemImport(importedKey.get(),
680 0,
681 &externalFormat,
682 &externalType,
683 0,
684 0,
685 m_impl->m_keyChainRef,
686 &outItems.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800687
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700688 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800689 return false;
690
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700691 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800692 SecKeychainAttribute attrs[1]; // maximum number of attributes
693 SecKeychainAttributeList attrList = { 0, attrs };
694 string keyUri = keyName.toUri();
695 {
696 attrs[attrList.count].tag = kSecKeyPrintName;
697 attrs[attrList.count].length = keyUri.size();
698 attrs[attrList.count].data = (void *)keyUri.c_str();
699 attrList.count++;
700 }
701
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700702 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800703 &attrList,
704 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700705 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700706
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700707 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800708 return false;
709
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800710 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800711}
712
713Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700714SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
715 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800716{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700717 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
718 data,
719 dataLength,
720 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800721
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700722 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
723 if (privateKey.get() == 0)
724 {
725 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
726 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700727
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700728 CFReleaser<CFErrorRef> error;
729 CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
730 &error.get());
731 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700732 throw Error("Fail to create signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800733
734 // Set input
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700735 Boolean set_res = SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800736 kSecTransformInputAttributeName,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700737 dataRef.get(),
738 &error.get());
739 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700740 throw Error("Fail to configure input of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800741
742 // Enable use of padding
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700743 SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800744 kSecPaddingKey,
745 kSecPaddingPKCS1Key,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700746 &error.get());
747 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700748 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800749
750 // Set padding type
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700751 set_res = SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800752 kSecDigestTypeAttribute,
753 m_impl->getDigestAlgorithm(digestAlgorithm),
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700754 &error.get());
755 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700756 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800757
758 // Set padding attribute
759 long digestSize = m_impl->getDigestSize(digestAlgorithm);
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700760 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
761 set_res = SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800762 kSecDigestLengthAttribute,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700763 cfDigestSize.get(),
764 &error.get());
765 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700766 throw Error("Fail to configure digest size of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800767
768 // Actually sign
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700769 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
770 if (error.get() != 0)
Yingdi Yube4150e2014-02-18 13:02:46 -0800771 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700772 if (!needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800773 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700774 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800775 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
776 else
777 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800778 }
779 else
780 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700781 CFShow(error.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800782 throw Error("Fail to sign data");
783 }
784 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800785
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700786 if (signature.get() == 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700787 throw Error("Signature is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800788
789 return Block(Tlv::SignatureValue,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700790 make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
791 CFDataGetLength(signature.get())));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800792}
793
794ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700795SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800796{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800797 throw Error("SecTpmOsx::decryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800798
Yingdi Yu2e57a582014-02-20 23:34:43 -0800799 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700800 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800801 // keyClass = KEY_CLASS_SYMMETRIC;
802 // else
803 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800804
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700805 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800806 // reinterpret_cast<const unsigned char*>(data),
807 // dataLength
808 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800809
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700810 // CFReleaser<SecKeyRef> decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
811 // if (decryptKey.get() == 0)
812 // {
813 // /// @todo Can this happen because of keychain is locked?
814 // throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain");
815 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800816
Yingdi Yu2e57a582014-02-20 23:34:43 -0800817 // CFErrorRef error;
818 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
819 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800820
Yingdi Yu2e57a582014-02-20 23:34:43 -0800821 // Boolean set_res = SecTransformSetAttribute(decrypt,
822 // kSecTransformInputAttributeName,
823 // dataRef,
824 // &error);
825 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800826
Yingdi Yu2e57a582014-02-20 23:34:43 -0800827 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
828 // if (error)
829 // {
830 // CFShow(error);
831 // throw Error("Fail to decrypt data");
832 // }
833 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800834
Yingdi Yu2e57a582014-02-20 23:34:43 -0800835 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800836}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700837
Yingdi Yu2e57a582014-02-20 23:34:43 -0800838void
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700839SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800840{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700841 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800842 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700843 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
844 if (privateKey.get() == 0)
845 {
846 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
847 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700848
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700849 CFReleaser<SecAccessRef> accRef;
850 OSStatus acc_res = SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700851
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700852 CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
853 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700854
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700855 SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700856
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700857 CFReleaser<CFArrayRef> appList;
858 CFReleaser<CFStringRef> description;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800859 SecKeychainPromptSelector promptSelector;
860 OSStatus acl_res = SecACLCopyContents(aclRef,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700861 &appList.get(),
862 &description.get(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800863 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700864
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700865 CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
866 0,
867 appList.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700868
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700869 CFReleaser<SecTrustedApplicationRef> trustedApp;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800870 acl_res = SecTrustedApplicationCreateFromPath(appPath.c_str(),
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700871 &trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700872
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700873 CFArrayAppendValue(newAppList.get(), trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700874
Yingdi Yu2e57a582014-02-20 23:34:43 -0800875 acl_res = SecACLSetContents(aclRef,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700876 newAppList.get(),
877 description.get(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800878 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700879
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700880 acc_res = SecKeychainItemSetAccess(privateKey.get(), accRef.get());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800881 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800882}
883
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800884ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700885SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800886{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800887 throw Error("SecTpmOsx::encryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800888
Yingdi Yu2e57a582014-02-20 23:34:43 -0800889 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700890 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800891 // keyClass = KEY_CLASS_SYMMETRIC;
892 // else
893 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700894
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700895 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800896 // reinterpret_cast<const unsigned char*>(data),
897 // dataLength
898 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700899
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700900 // CFReleaser<SecKeyRef> encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
901 // if (encryptKey.get() == 0)
902 // {
903 // throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain");
904 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800905
Yingdi Yu2e57a582014-02-20 23:34:43 -0800906 // CFErrorRef error;
907 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
908 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800909
Yingdi Yu2e57a582014-02-20 23:34:43 -0800910 // Boolean set_res = SecTransformSetAttribute(encrypt,
911 // kSecTransformInputAttributeName,
912 // dataRef,
913 // &error);
914 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800915
Yingdi Yu2e57a582014-02-20 23:34:43 -0800916 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
917 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800918
Yingdi Yu2e57a582014-02-20 23:34:43 -0800919 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800920
Yingdi Yu2e57a582014-02-20 23:34:43 -0800921 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800922}
923
924bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700925SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800926{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800927 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
928
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700929 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
930 keyNameUri.c_str(),
931 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700932
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700933 CFReleaser<CFMutableDictionaryRef> attrDict =
934 CFDictionaryCreateMutable(0,
935 4,
936 &kCFTypeDictionaryKeyCallBacks,
937 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800938
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700939 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
940 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
941 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
942 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700943
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700944 CFReleaser<SecKeychainItemRef> itemRef;
945 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700946
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700947 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800948 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800949 else
950 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800951
952}
953
Yingdi Yu4b752752014-02-18 12:24:03 -0800954bool
955SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
956{
957 return (SecRandomCopyBytes(kSecRandomDefault, size, res) == 0);
958}
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800959
960////////////////////////////////
961// OSXPrivateKeyStorage::Impl //
962////////////////////////////////
963
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700964CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700965SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800966{
967 string keyNameUri = toInternalKeyName(keyName, keyClass);
968
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700969 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
970 keyNameUri.c_str(),
971 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700972
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700973 CFReleaser<CFMutableDictionaryRef> attrDict =
974 CFDictionaryCreateMutable(0,
975 5,
976 &kCFTypeDictionaryKeyCallBacks,
977 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800978
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700979 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
980 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
981 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
982 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700983
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700984 CFReleaser<SecKeychainItemRef> keyItem;
985 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700986
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700987 if (res != errSecSuccess)
988 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800989 else
990 return keyItem;
991}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700992
993string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700994SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800995{
996 string keyUri = keyName.toUri();
997
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700998 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800999 return keyUri + "/symmetric";
1000 else
1001 return keyUri;
1002}
1003
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001004const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001005SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
1006{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001007 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001008 case KEY_TYPE_RSA:
1009 return kSecAttrKeyTypeRSA;
1010 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001011 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001012 }
1013}
1014
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001015const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001016SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
1017{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001018 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001019 case KEY_TYPE_AES:
1020 return kSecAttrKeyTypeAES;
1021 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001022 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001023 }
1024}
1025
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001026const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001027SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
1028{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001029 switch (keyClass){
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001030 case KEY_CLASS_PRIVATE:
1031 return kSecAttrKeyClassPrivate;
1032 case KEY_CLASS_PUBLIC:
1033 return kSecAttrKeyClassPublic;
1034 case KEY_CLASS_SYMMETRIC:
1035 return kSecAttrKeyClassSymmetric;
1036 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001037 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001038 }
1039}
1040
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001041const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001042SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
1043{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001044 switch (digestAlgo){
Jeff Thompson2747dc02013-10-04 19:11:34 -07001045 // case DIGEST_MD2:
1046 // return kSecDigestMD2;
1047 // case DIGEST_MD5:
1048 // return kSecDigestMD5;
1049 // case DIGEST_SHA1:
1050 // return kSecDigestSHA1;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001051 case DIGEST_ALGORITHM_SHA256:
1052 return kSecDigestSHA2;
1053 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001054 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001055 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001056}
Jeff Thompson2747dc02013-10-04 19:11:34 -07001057
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001058long
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001059SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
1060{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001061 switch (digestAlgo){
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001062 case DIGEST_ALGORITHM_SHA256:
1063 return 256;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001064 // case DIGEST_SHA1:
1065 // case DIGEST_MD2:
1066 // case DIGEST_MD5:
1067 // return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001068 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001069 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001070 }
Jeff Thompson2747dc02013-10-04 19:11:34 -07001071}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001072
Yingdi Yufc40d872014-02-18 12:56:04 -08001073} // namespace ndn