blob: a7e1cd9edc6fc91f0f9cafcba9d3114cd7c3946d [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"
Junxiao Shi482ccc52014-03-31 13:05:24 -070019#include "cryptopp.hpp"
Jeff Thompson2747dc02013-10-04 19:11:34 -070020
Yingdi Yu2b2b4792014-02-04 16:27:07 -080021#include <pwd.h>
22#include <unistd.h>
23#include <stdlib.h>
24#include <string.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070025
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080026#include <CoreFoundation/CoreFoundation.h>
27#include <Security/Security.h>
Yingdi Yu4b752752014-02-18 12:24:03 -080028#include <Security/SecRandom.h>
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080029#include <CoreServices/CoreServices.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070030
Alexander Afanasyev59d67a52014-04-03 16:09:31 -070031#include <Security/SecDigestTransform.h>
32
Jeff Thompson2747dc02013-10-04 19:11:34 -070033using namespace std;
Jeff Thompson2747dc02013-10-04 19:11:34 -070034
Yingdi Yufc40d872014-02-18 12:56:04 -080035namespace ndn {
36
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070037/**
38 * @brief Helper class to wrap CoreFoundation object pointers
39 *
40 * The class is similar in spirit to shared_ptr, but uses CoreFoundation
41 * mechanisms to retain/release object.
42 *
43 * Original implementation by Christopher Hunt and it was borrowed from
44 * http://www.cocoabuilder.com/archive/cocoa/130776-auto-cfrelease-and.html
45 */
46template<class T>
47class CFReleaser
48{
49public:
50 //////////////////////////////
51 // Construction/destruction //
52
53 CFReleaser()
54 : m_typeRef(0)
55 {
56 }
57
58 CFReleaser(const T& typeRef)
59 : m_typeRef(typeRef)
60 {
61 }
62
63 CFReleaser(const CFReleaser& inReleaser)
64 : m_typeRef(0)
65 {
66 retain(inReleaser.m_typeRef);
67 }
68
69 CFReleaser&
70 operator=(const T& typeRef)
71 {
72 if (typeRef != m_typeRef) {
73 release();
74 m_typeRef = typeRef;
75 }
76 return *this;
77 }
78
79 CFReleaser&
80 operator=(const CFReleaser& inReleaser)
81 {
82 retain(inReleaser.m_typeRef);
83 return *this;
84 }
85
86 ~CFReleaser()
87 {
88 release();
89 }
90
91 ////////////
92 // Access //
93
94 // operator const T&() const
95 // {
96 // return m_typeRef;
97 // }
98
99 // operator T&()
100 // {
101 // return m_typeRef;
102 // }
103
104 const T&
105 get() const
106 {
107 return m_typeRef;
108 }
109
110 T&
111 get()
112 {
113 return m_typeRef;
114 }
115
116 ///////////////////
117 // Miscellaneous //
118
119 void
120 retain(const T& typeRef)
121 {
122 if (typeRef != 0) {
123 CFRetain(typeRef);
124 }
125 release();
126 m_typeRef = typeRef;
127 }
128
129 void release()
130 {
131 if (m_typeRef != 0) {
132 CFRelease(m_typeRef);
133 m_typeRef = 0;
134 }
135 };
136
137private:
138 T m_typeRef;
139};
140
141
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700142class SecTpmOsx::Impl
143{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800144public:
145 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -0800146 : m_passwordSet(false)
147 , m_inTerminal(false)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700148 {
149 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700150
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800151 /**
152 * @brief Convert NDN name of a key to internal name of the key.
153 *
Yingdi Yufc40d872014-02-18 12:56:04 -0800154 * @param keyName
155 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800156 * @return the internal key name
157 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700158 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700159 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700160
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800161 /**
162 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -0800163 *
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700164 * @param keyName
Yingdi Yufc40d872014-02-18 12:56:04 -0800165 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800166 * @returns pointer to the key
167 */
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700168 CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700169 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700170
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800171 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800172 * @brief Convert keyType to MAC OS symmetric key key type
173 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800174 * @param keyType
175 * @returns MAC OS key type
176 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700177 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800178 getSymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700179
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800180 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800181 * @brief Convert keyType to MAC OS asymmetirc key type
182 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800183 * @param keyType
184 * @returns MAC OS key type
185 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700186 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800187 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700188
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800189 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800190 * @brief Convert keyClass to MAC OS key class
191 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800192 * @param keyClass
193 * @returns MAC OS key class
194 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700195 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800196 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700197
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800198 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800199 * @brief Convert digestAlgo to MAC OS algorithm id
200 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800201 * @param digestAlgo
202 * @returns MAC OS algorithm id
203 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700204 const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800205 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700206
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800207 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800208 * @brief Get the digest size of the corresponding algorithm
209 *
210 * @param digestAlgo
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800211 * @return digest size
212 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700213 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800214 getDigestSize(DigestAlgorithm digestAlgo);
215
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800216 ///////////////////////////////////////////////
217 // everything here is public, including data //
218 ///////////////////////////////////////////////
219public:
220 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800221 bool m_passwordSet;
222 string m_password;
223 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800224};
225
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800226SecTpmOsx::SecTpmOsx()
227 : m_impl(new Impl)
228{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700229 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700230 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800231 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700232 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800233
Yingdi Yube4150e2014-02-18 13:02:46 -0800234 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700235
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800236 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Yingdi Yube4150e2014-02-18 13:02:46 -0800237 throw Error("No default keychain, create one first!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800238}
239
240SecTpmOsx::~SecTpmOsx(){
241 //TODO: implement
242}
243
Yingdi Yube4150e2014-02-18 13:02:46 -0800244void
245SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
246{
247 m_impl->m_passwordSet = true;
248 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
249 m_impl->m_password.clear();
250 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
251}
252
253void
254SecTpmOsx::resetTpmPassword()
255{
256 m_impl->m_passwordSet = false;
257 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
258 m_impl->m_password.clear();
259}
260
261void
262SecTpmOsx::setInTerminal(bool inTerminal)
263{
264 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700265 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700266 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800267 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700268 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800269}
270
271bool
272SecTpmOsx::getInTerminal()
273{
274 return m_impl->m_inTerminal;
275}
276
277bool
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700278SecTpmOsx::isLocked()
Yingdi Yube4150e2014-02-18 13:02:46 -0800279{
280 SecKeychainStatus keychainStatus;
281
282 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700283 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800284 return true;
285 else
286 return ((kSecUnlockStateStatus & keychainStatus) == 0);
287}
288
Yingdi Yu2e57a582014-02-20 23:34:43 -0800289bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800290SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
291{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700292 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800293
294 // If the default key chain is already unlocked, return immediately.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700295 if (!isLocked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800296 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800297
298 // If the default key chain is locked, unlock the key chain.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700299 if (usePassword)
Yingdi Yube4150e2014-02-18 13:02:46 -0800300 {
301 // Use the supplied password.
302 res = SecKeychainUnlock(m_impl->m_keyChainRef,
303 passwordLength,
304 password,
305 true);
306 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700307 else if (m_impl->m_passwordSet)
Yingdi Yube4150e2014-02-18 13:02:46 -0800308 {
309 // If no password supplied, then use the configured password if exists.
310 SecKeychainUnlock(m_impl->m_keyChainRef,
311 m_impl->m_password.size(),
312 m_impl->m_password.c_str(),
313 true);
314 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700315 else if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800316 {
317 // If no configured password, get password from terminal if inTerminal set.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700318 bool isLocked = true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800319 const char* fmt = "Password to unlock the default keychain: ";
320 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700321
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700322 while (isLocked)
Yingdi Yube4150e2014-02-18 13:02:46 -0800323 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700324 if (count > 2)
Yingdi Yube4150e2014-02-18 13:02:46 -0800325 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700326
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700327 char* getPassword = 0;
Yingdi Yube4150e2014-02-18 13:02:46 -0800328 getPassword = getpass(fmt);
329 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700330
Yingdi Yube4150e2014-02-18 13:02:46 -0800331 if (!getPassword)
332 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700333
Yingdi Yube4150e2014-02-18 13:02:46 -0800334 res = SecKeychainUnlock(m_impl->m_keyChainRef,
335 strlen(getPassword),
336 getPassword,
337 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700338
Yingdi Yube4150e2014-02-18 13:02:46 -0800339 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700340
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700341 if (res == errSecSuccess)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800342 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800343 }
344 }
345 else
346 {
347 // If inTerminal is not set, get the password from GUI.
348 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
349 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800350
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700351 return !isLocked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800352}
353
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700354void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700355SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName, KeyType keyType,
356 int keySize, bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700357{
358
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700359 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
360 {
361 throw Error("keyName has existed");
362 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800363
364 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
365
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700366 CFReleaser<CFStringRef> keyLabel =
367 CFStringCreateWithCString(0,
368 keyNameUri.c_str(),
369 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800370
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700371 CFReleaser<CFMutableDictionaryRef> attrDict =
372 CFDictionaryCreateMutable(0,
373 3,
374 &kCFTypeDictionaryKeyCallBacks,
375 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700376
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700377 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800378
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700379 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
380 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
381 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800382
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700383 CFReleaser<SecKeyRef> publicKey, privateKey;
384 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(),
385 &publicKey.get(), &privateKey.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800386
Yingdi Yube4150e2014-02-18 13:02:46 -0800387 if (res == errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800388 {
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800389 return;
390 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700391
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700392 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800393 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700394 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800395 generateKeyPairInTpmInternal(keyName, keyType, keySize, true);
396 else
397 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800398 }
399 else
400 {
Yingdi Yube4150e2014-02-18 13:02:46 -0800401 throw Error("Fail to create a key pair");
402 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800403}
404
405void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700406SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800407{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700408 CFReleaser<CFStringRef> keyLabel =
409 CFStringCreateWithCString(0,
410 keyName.toUri().c_str(),
411 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800412
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700413 CFReleaser<CFMutableDictionaryRef> searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700414 CFDictionaryCreateMutable(0, 5,
415 &kCFTypeDictionaryKeyCallBacks,
416 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800417
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700418 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
419 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
420 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
421 OSStatus res = SecItemDelete(searchDict.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800422
423 if (res == errSecSuccess)
424 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700425
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700426 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800427 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700428 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800429 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800430 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800431}
432
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700433void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700434SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, KeyType keyType, int keySize)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800435{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800436 throw Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700437 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800438 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800439
Yingdi Yu2e57a582014-02-20 23:34:43 -0800440 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800441
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700442 // CFReleaser<CFMutableDictionaryRef> attrDict =
443 // CFDictionaryCreateMutable(kCFAllocatorDefault,
444 // 0,
445 // &kCFTypeDictionaryKeyCallBacks,
446 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800447
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700448 // CFReleaser<CFStringRef> keyLabel =
449 // CFStringCreateWithCString(0,
450 // keyNameUri.c_str(),
451 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800452
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700453 // CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
454
455 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType));
456 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
457 // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue);
458 // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800459
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700460 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800461
Yingdi Yu2e57a582014-02-20 23:34:43 -0800462 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800463
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700464 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800465 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800466}
467
Yingdi Yu2e57a582014-02-20 23:34:43 -0800468shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700469SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800470{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700471 CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
472 if (publicKey.get() == 0)
473 {
474 throw Error("Requested public key [" + keyName.toUri() + "] does not exist in OSX Keychain");
475 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800476
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700477 CFReleaser<CFDataRef> exportedKey;
478 OSStatus res = SecItemExport(publicKey.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800479 kSecFormatOpenSSL,
480 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700481 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700482 &exportedKey.get());
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800483 if (res != errSecSuccess)
484 {
485 throw Error("Cannot export requested public key from OSX Keychain");
486 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800487
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700488 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey.get()),
489 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800490 return key;
491}
492
493ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700494SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800495{
496 using namespace CryptoPP;
497
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700498 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
499 if (privateKey.get() == 0)
500 {
501 /// @todo Can this happen because of keychain is locked?
502 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
503 }
504
505 CFReleaser<CFDataRef> exportedKey;
506 OSStatus res = SecItemExport(privateKey.get(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800507 kSecFormatOpenSSL,
508 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700509 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700510 &exportedKey.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800511
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700512 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800513 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700514 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800515 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700516 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700517 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800518 else
519 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800520 }
521 else
522 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800523 }
524
525 OBufferStream pkcs1Os;
526 FileSink sink(pkcs1Os);
527
528 uint32_t version = 0;
529 OID algorithm("1.2.840.113549.1.1.1");
530 SecByteBlock rawKeyBits;
531 // PrivateKeyInfo ::= SEQUENCE {
532 // version INTEGER,
533 // privateKeyAlgorithm SEQUENCE,
534 // privateKey OCTECT STRING}
535 DERSequenceEncoder privateKeyInfo(sink);
536 {
537 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
538 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
539 {
540 algorithm.encode(privateKeyAlgorithm);
541 DEREncodeNull(privateKeyAlgorithm);
542 }
543 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700544 DEREncodeOctetString(privateKeyInfo,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700545 CFDataGetBytePtr(exportedKey.get()),
546 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800547 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700548 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800549
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800550 return pkcs1Os.buf();
551}
552
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700553#ifdef __GNUC__
554#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
555#pragma GCC diagnostic push
556#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
557#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
558#endif // __GNUC__
559
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800560bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700561SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700562 const uint8_t* buf, size_t size,
563 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800564{
565 using namespace CryptoPP;
566
567 StringSource privateKeySource(buf, size, true);
568 uint32_t tmpNum;
569 OID tmpOID;
570 SecByteBlock rawKeyBits;
571 // PrivateKeyInfo ::= SEQUENCE {
572 // INTEGER,
573 // SEQUENCE,
574 // OCTECT STRING}
575 BERSequenceDecoder privateKeyInfo(privateKeySource);
576 {
577 BERDecodeUnsigned<uint32_t>(privateKeyInfo, tmpNum, INTEGER);
578 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
579 {
580 tmpOID.decode(sequenceDecoder);
581 BERDecodeNull(sequenceDecoder);
582 }
583 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
584 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700585 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800586
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700587 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
588 rawKeyBits.BytePtr(),
589 rawKeyBits.size(),
590 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800591
592 SecExternalFormat externalFormat = kSecFormatOpenSSL;
593 SecExternalItemType externalType = kSecItemTypePrivateKey;
594 SecKeyImportExportParameters keyParams;
595 memset(&keyParams, 0, sizeof(keyParams));
596 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
597 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700598 CFReleaser<SecAccessRef> access;
599 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
600 keyName.toUri().c_str(),
601 kCFStringEncodingUTF8);
602 SecAccessCreate(keyLabel.get(), 0, &access.get());
603 keyParams.accessRef = access.get();
604 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800605
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700606#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700607#pragma clang diagnostic push
608#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700609#endif // __clang__
610
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700611 OSStatus res = SecKeychainItemImport(importedKey.get(),
612 0,
613 &externalFormat,
614 &externalType,
615 0,
616 &keyParams,
617 m_impl->m_keyChainRef,
618 &outItems.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700619
620#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700621#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700622#endif // __clang__
623
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700624 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800625 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700626 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800627 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700628 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700629 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800630 else
631 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800632 }
633 else
634 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800635 }
636
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700637 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800638 SecKeychainAttribute attrs[1]; // maximum number of attributes
639 SecKeychainAttributeList attrList = { 0, attrs };
640 string keyUri = keyName.toUri();
641 {
642 attrs[attrList.count].tag = kSecKeyPrintName;
643 attrs[attrList.count].length = keyUri.size();
644 attrs[attrList.count].data = (void *)keyUri.c_str();
645 attrList.count++;
646 }
647
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700648 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800649 &attrList,
650 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700651 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700652
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700653 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800654 {
655 return false;
656 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700657
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800658 return true;
659}
660
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700661#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
662#pragma GCC diagnostic pop
663#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
664
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800665bool
666SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
667{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700668 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
669 buf,
670 size,
671 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800672
673 SecExternalFormat externalFormat = kSecFormatOpenSSL;
674 SecExternalItemType externalType = kSecItemTypePublicKey;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700675 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800676
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700677 OSStatus res = SecItemImport(importedKey.get(),
678 0,
679 &externalFormat,
680 &externalType,
681 0,
682 0,
683 m_impl->m_keyChainRef,
684 &outItems.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800685
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700686 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800687 return false;
688
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700689 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800690 SecKeychainAttribute attrs[1]; // maximum number of attributes
691 SecKeychainAttributeList attrList = { 0, attrs };
692 string keyUri = keyName.toUri();
693 {
694 attrs[attrList.count].tag = kSecKeyPrintName;
695 attrs[attrList.count].length = keyUri.size();
696 attrs[attrList.count].data = (void *)keyUri.c_str();
697 attrList.count++;
698 }
699
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700700 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800701 &attrList,
702 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700703 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700704
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700705 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800706 return false;
707
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800708 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800709}
710
711Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700712SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
713 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800714{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700715 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
716 data,
717 dataLength,
718 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800719
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700720 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
721 if (privateKey.get() == 0)
722 {
723 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
724 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700725
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700726 CFReleaser<CFErrorRef> error;
727 CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
728 &error.get());
729 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700730 throw Error("Fail to create signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800731
732 // Set input
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700733 Boolean set_res = SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800734 kSecTransformInputAttributeName,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700735 dataRef.get(),
736 &error.get());
737 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700738 throw Error("Fail to configure input of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800739
740 // Enable use of padding
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700741 SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800742 kSecPaddingKey,
743 kSecPaddingPKCS1Key,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700744 &error.get());
745 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700746 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800747
748 // Set padding type
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700749 set_res = SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800750 kSecDigestTypeAttribute,
751 m_impl->getDigestAlgorithm(digestAlgorithm),
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700752 &error.get());
753 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700754 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800755
756 // Set padding attribute
757 long digestSize = m_impl->getDigestSize(digestAlgorithm);
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700758 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
759 set_res = SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800760 kSecDigestLengthAttribute,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700761 cfDigestSize.get(),
762 &error.get());
763 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700764 throw Error("Fail to configure digest size of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800765
766 // Actually sign
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700767 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
768 if (error.get() != 0)
Yingdi Yube4150e2014-02-18 13:02:46 -0800769 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700770 if (!needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800771 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700772 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800773 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
774 else
775 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800776 }
777 else
778 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700779 CFShow(error.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800780 throw Error("Fail to sign data");
781 }
782 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800783
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700784 if (signature.get() == 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700785 throw Error("Signature is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800786
787 return Block(Tlv::SignatureValue,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700788 make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
789 CFDataGetLength(signature.get())));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800790}
791
792ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700793SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800794{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800795 throw Error("SecTpmOsx::decryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800796
Yingdi Yu2e57a582014-02-20 23:34:43 -0800797 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700798 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800799 // keyClass = KEY_CLASS_SYMMETRIC;
800 // else
801 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800802
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700803 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800804 // reinterpret_cast<const unsigned char*>(data),
805 // dataLength
806 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800807
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700808 // CFReleaser<SecKeyRef> decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
809 // if (decryptKey.get() == 0)
810 // {
811 // /// @todo Can this happen because of keychain is locked?
812 // throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain");
813 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800814
Yingdi Yu2e57a582014-02-20 23:34:43 -0800815 // CFErrorRef error;
816 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
817 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800818
Yingdi Yu2e57a582014-02-20 23:34:43 -0800819 // Boolean set_res = SecTransformSetAttribute(decrypt,
820 // kSecTransformInputAttributeName,
821 // dataRef,
822 // &error);
823 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800824
Yingdi Yu2e57a582014-02-20 23:34:43 -0800825 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
826 // if (error)
827 // {
828 // CFShow(error);
829 // throw Error("Fail to decrypt data");
830 // }
831 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800832
Yingdi Yu2e57a582014-02-20 23:34:43 -0800833 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800834}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700835
Yingdi Yu2e57a582014-02-20 23:34:43 -0800836void
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700837SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800838{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700839 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800840 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700841 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
842 if (privateKey.get() == 0)
843 {
844 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
845 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700846
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700847 CFReleaser<SecAccessRef> accRef;
848 OSStatus acc_res = SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700849
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700850 CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
851 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700852
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700853 SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700854
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700855 CFReleaser<CFArrayRef> appList;
856 CFReleaser<CFStringRef> description;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800857 SecKeychainPromptSelector promptSelector;
858 OSStatus acl_res = SecACLCopyContents(aclRef,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700859 &appList.get(),
860 &description.get(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800861 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700862
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700863 CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
864 0,
865 appList.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700866
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700867 CFReleaser<SecTrustedApplicationRef> trustedApp;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800868 acl_res = SecTrustedApplicationCreateFromPath(appPath.c_str(),
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700869 &trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700870
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700871 CFArrayAppendValue(newAppList.get(), trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700872
Yingdi Yu2e57a582014-02-20 23:34:43 -0800873 acl_res = SecACLSetContents(aclRef,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700874 newAppList.get(),
875 description.get(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800876 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700877
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700878 acc_res = SecKeychainItemSetAccess(privateKey.get(), accRef.get());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800879 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800880}
881
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800882ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700883SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800884{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800885 throw Error("SecTpmOsx::encryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800886
Yingdi Yu2e57a582014-02-20 23:34:43 -0800887 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700888 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800889 // keyClass = KEY_CLASS_SYMMETRIC;
890 // else
891 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700892
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700893 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800894 // reinterpret_cast<const unsigned char*>(data),
895 // dataLength
896 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700897
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700898 // CFReleaser<SecKeyRef> encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
899 // if (encryptKey.get() == 0)
900 // {
901 // throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain");
902 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800903
Yingdi Yu2e57a582014-02-20 23:34:43 -0800904 // CFErrorRef error;
905 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
906 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800907
Yingdi Yu2e57a582014-02-20 23:34:43 -0800908 // Boolean set_res = SecTransformSetAttribute(encrypt,
909 // kSecTransformInputAttributeName,
910 // dataRef,
911 // &error);
912 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800913
Yingdi Yu2e57a582014-02-20 23:34:43 -0800914 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
915 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800916
Yingdi Yu2e57a582014-02-20 23:34:43 -0800917 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800918
Yingdi Yu2e57a582014-02-20 23:34:43 -0800919 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800920}
921
922bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700923SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800924{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800925 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
926
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700927 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
928 keyNameUri.c_str(),
929 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700930
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700931 CFReleaser<CFMutableDictionaryRef> attrDict =
932 CFDictionaryCreateMutable(0,
933 4,
934 &kCFTypeDictionaryKeyCallBacks,
935 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800936
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700937 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
938 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
939 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
940 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700941
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700942 CFReleaser<SecKeychainItemRef> itemRef;
943 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700944
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700945 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800946 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800947 else
948 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800949
950}
951
Yingdi Yu4b752752014-02-18 12:24:03 -0800952bool
953SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
954{
955 return (SecRandomCopyBytes(kSecRandomDefault, size, res) == 0);
956}
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800957
958////////////////////////////////
959// OSXPrivateKeyStorage::Impl //
960////////////////////////////////
961
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700962CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700963SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800964{
965 string keyNameUri = toInternalKeyName(keyName, keyClass);
966
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700967 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
968 keyNameUri.c_str(),
969 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700970
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700971 CFReleaser<CFMutableDictionaryRef> attrDict =
972 CFDictionaryCreateMutable(0,
973 5,
974 &kCFTypeDictionaryKeyCallBacks,
975 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800976
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700977 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
978 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
979 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
980 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700981
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700982 CFReleaser<SecKeychainItemRef> keyItem;
983 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700984
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700985 if (res != errSecSuccess)
986 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800987 else
988 return keyItem;
989}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700990
991string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700992SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800993{
994 string keyUri = keyName.toUri();
995
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700996 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800997 return keyUri + "/symmetric";
998 else
999 return keyUri;
1000}
1001
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001002const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001003SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
1004{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001005 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001006 case KEY_TYPE_RSA:
1007 return kSecAttrKeyTypeRSA;
1008 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001009 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001010 }
1011}
1012
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001013const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001014SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
1015{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001016 switch (keyType){
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001017 case KEY_TYPE_AES:
1018 return kSecAttrKeyTypeAES;
1019 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001020 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001021 }
1022}
1023
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001024const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001025SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
1026{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001027 switch (keyClass){
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001028 case KEY_CLASS_PRIVATE:
1029 return kSecAttrKeyClassPrivate;
1030 case KEY_CLASS_PUBLIC:
1031 return kSecAttrKeyClassPublic;
1032 case KEY_CLASS_SYMMETRIC:
1033 return kSecAttrKeyClassSymmetric;
1034 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001035 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001036 }
1037}
1038
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001039const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001040SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
1041{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001042 switch (digestAlgo){
Jeff Thompson2747dc02013-10-04 19:11:34 -07001043 // case DIGEST_MD2:
1044 // return kSecDigestMD2;
1045 // case DIGEST_MD5:
1046 // return kSecDigestMD5;
1047 // case DIGEST_SHA1:
1048 // return kSecDigestSHA1;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001049 case DIGEST_ALGORITHM_SHA256:
1050 return kSecDigestSHA2;
1051 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001052 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001053 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001054}
Jeff Thompson2747dc02013-10-04 19:11:34 -07001055
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001056long
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001057SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
1058{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001059 switch (digestAlgo){
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001060 case DIGEST_ALGORITHM_SHA256:
1061 return 256;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001062 // case DIGEST_SHA1:
1063 // case DIGEST_MD2:
1064 // case DIGEST_MD5:
1065 // return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001066 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001067 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001068 }
Jeff Thompson2747dc02013-10-04 19:11:34 -07001069}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001070
Yingdi Yufc40d872014-02-18 12:56:04 -08001071} // namespace ndn