blob: 440034398c537bdf0d952fbd311eef14e9f59554 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Jeff Thompson2747dc02013-10-04 19:11:34 -07002/**
Alexander Afanasyevaf99f462015-01-19 21:43:09 -08003 * Copyright (c) 2013-2015 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Jeff Thompson2747dc02013-10-04 19:11:34 -070022 */
23
Alexander Afanasyev19508852014-01-29 01:01:51 -080024#include "sec-tpm-osx.hpp"
Yingdi Yuf56c68f2014-04-24 21:50:13 -070025#include "public-key.hpp"
Alexander Afanasyev07113802015-01-15 19:14:36 -080026
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070027#include "../encoding/oid.hpp"
28#include "../encoding/buffer-stream.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070029#include "cryptopp.hpp"
Jeff Thompson2747dc02013-10-04 19:11:34 -070030
Yingdi Yu2b2b4792014-02-04 16:27:07 -080031#include <pwd.h>
32#include <unistd.h>
33#include <stdlib.h>
34#include <string.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070035
Alexander Afanasyev1c6976d2014-07-13 11:40:50 -070036#include <boost/lexical_cast.hpp>
37
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080038#include <CoreFoundation/CoreFoundation.h>
39#include <Security/Security.h>
Yingdi Yu4b752752014-02-18 12:24:03 -080040#include <Security/SecRandom.h>
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080041#include <CoreServices/CoreServices.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070042
Alexander Afanasyev59d67a52014-04-03 16:09:31 -070043#include <Security/SecDigestTransform.h>
44
Yingdi Yufc40d872014-02-18 12:56:04 -080045namespace ndn {
46
Yingdi Yu7036ce22014-06-19 18:53:37 -070047using std::string;
48
Alexander Afanasyev07113802015-01-15 19:14:36 -080049const std::string SecTpmOsx::SCHEME("tpm-osxkeychain");
Yingdi Yu41546342014-11-30 23:37:53 -080050
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070051/**
52 * @brief Helper class to wrap CoreFoundation object pointers
53 *
54 * The class is similar in spirit to shared_ptr, but uses CoreFoundation
55 * mechanisms to retain/release object.
56 *
57 * Original implementation by Christopher Hunt and it was borrowed from
58 * http://www.cocoabuilder.com/archive/cocoa/130776-auto-cfrelease-and.html
59 */
60template<class T>
61class CFReleaser
62{
63public:
64 //////////////////////////////
65 // Construction/destruction //
66
67 CFReleaser()
68 : m_typeRef(0)
69 {
70 }
71
72 CFReleaser(const T& typeRef)
73 : m_typeRef(typeRef)
74 {
75 }
76
77 CFReleaser(const CFReleaser& inReleaser)
78 : m_typeRef(0)
79 {
80 retain(inReleaser.m_typeRef);
81 }
82
83 CFReleaser&
84 operator=(const T& typeRef)
85 {
86 if (typeRef != m_typeRef) {
87 release();
88 m_typeRef = typeRef;
89 }
90 return *this;
91 }
92
93 CFReleaser&
94 operator=(const CFReleaser& inReleaser)
95 {
96 retain(inReleaser.m_typeRef);
97 return *this;
98 }
99
100 ~CFReleaser()
101 {
102 release();
103 }
104
105 ////////////
106 // Access //
107
108 // operator const T&() const
109 // {
110 // return m_typeRef;
111 // }
112
113 // operator T&()
114 // {
115 // return m_typeRef;
116 // }
117
118 const T&
119 get() const
120 {
121 return m_typeRef;
122 }
123
124 T&
125 get()
126 {
127 return m_typeRef;
128 }
129
130 ///////////////////
131 // Miscellaneous //
132
133 void
134 retain(const T& typeRef)
135 {
136 if (typeRef != 0) {
137 CFRetain(typeRef);
138 }
139 release();
140 m_typeRef = typeRef;
141 }
142
143 void release()
144 {
145 if (m_typeRef != 0) {
146 CFRelease(m_typeRef);
147 m_typeRef = 0;
148 }
149 };
150
151private:
152 T m_typeRef;
153};
154
155
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700156class SecTpmOsx::Impl
157{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800158public:
159 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -0800160 : m_passwordSet(false)
161 , m_inTerminal(false)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700162 {
163 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700164
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800165 /**
166 * @brief Convert NDN name of a key to internal name of the key.
167 *
Yingdi Yufc40d872014-02-18 12:56:04 -0800168 * @param keyName
169 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800170 * @return the internal key name
171 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700172 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700173 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700174
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800175 /**
176 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -0800177 *
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700178 * @param keyName
Yingdi Yufc40d872014-02-18 12:56:04 -0800179 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800180 * @returns pointer to the key
181 */
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700182 CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700183 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700184
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800185 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800186 * @brief Convert keyType to MAC OS symmetric key key type
187 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800188 * @param keyType
189 * @returns MAC OS key type
190 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300191 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800192 getSymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700193
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800194 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800195 * @brief Convert keyType to MAC OS asymmetirc key type
196 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800197 * @param keyType
198 * @returns MAC OS key type
199 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300200 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800201 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700202
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800203 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800204 * @brief Convert keyClass to MAC OS key class
205 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800206 * @param keyClass
207 * @returns MAC OS key class
208 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300209 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800210 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700211
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800212 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800213 * @brief Convert digestAlgo to MAC OS algorithm id
214 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800215 * @param digestAlgo
216 * @returns MAC OS algorithm id
217 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300218 CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800219 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700220
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800221 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800222 * @brief Get the digest size of the corresponding algorithm
223 *
224 * @param digestAlgo
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800225 * @return digest size
226 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700227 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800228 getDigestSize(DigestAlgorithm digestAlgo);
229
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800230 ///////////////////////////////////////////////
231 // everything here is public, including data //
232 ///////////////////////////////////////////////
233public:
234 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800235 bool m_passwordSet;
236 string m_password;
237 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800238};
239
Yingdi Yu41546342014-11-30 23:37:53 -0800240SecTpmOsx::SecTpmOsx(const std::string& location)
241 : SecTpm(location)
242 , m_impl(new Impl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800243{
Yingdi Yu41546342014-11-30 23:37:53 -0800244 // TODO: add location support
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700245 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700246 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800247 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700248 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800249
Yingdi Yube4150e2014-02-18 13:02:46 -0800250 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700251
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800252 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Yingdi Yube4150e2014-02-18 13:02:46 -0800253 throw Error("No default keychain, create one first!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800254}
255
Yingdi Yu41546342014-11-30 23:37:53 -0800256SecTpmOsx::~SecTpmOsx()
257{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800258}
259
Yingdi Yube4150e2014-02-18 13:02:46 -0800260void
261SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
262{
263 m_impl->m_passwordSet = true;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700264 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800265 m_impl->m_password.clear();
266 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
267}
268
269void
270SecTpmOsx::resetTpmPassword()
271{
272 m_impl->m_passwordSet = false;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700273 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800274 m_impl->m_password.clear();
275}
276
277void
278SecTpmOsx::setInTerminal(bool inTerminal)
279{
280 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700281 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700282 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800283 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700284 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800285}
286
287bool
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700288SecTpmOsx::getInTerminal() const
Yingdi Yube4150e2014-02-18 13:02:46 -0800289{
290 return m_impl->m_inTerminal;
291}
292
293bool
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700294SecTpmOsx::isLocked()
Yingdi Yube4150e2014-02-18 13:02:46 -0800295{
296 SecKeychainStatus keychainStatus;
297
298 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700299 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800300 return true;
301 else
302 return ((kSecUnlockStateStatus & keychainStatus) == 0);
303}
304
Yingdi Yu2e57a582014-02-20 23:34:43 -0800305bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800306SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
307{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700308 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800309
310 // If the default key chain is already unlocked, return immediately.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700311 if (!isLocked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800312 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800313
314 // If the default key chain is locked, unlock the key chain.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700315 if (usePassword)
Yingdi Yube4150e2014-02-18 13:02:46 -0800316 {
317 // Use the supplied password.
318 res = SecKeychainUnlock(m_impl->m_keyChainRef,
319 passwordLength,
320 password,
321 true);
322 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700323 else if (m_impl->m_passwordSet)
Yingdi Yube4150e2014-02-18 13:02:46 -0800324 {
325 // If no password supplied, then use the configured password if exists.
326 SecKeychainUnlock(m_impl->m_keyChainRef,
327 m_impl->m_password.size(),
328 m_impl->m_password.c_str(),
329 true);
330 }
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800331#ifdef NDN_CXX_HAVE_GETPASS
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700332 else if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800333 {
334 // If no configured password, get password from terminal if inTerminal set.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700335 bool isLocked = true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800336 const char* fmt = "Password to unlock the default keychain: ";
337 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700338
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700339 while (isLocked)
Yingdi Yube4150e2014-02-18 13:02:46 -0800340 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700341 if (count > 2)
Yingdi Yube4150e2014-02-18 13:02:46 -0800342 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700343
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700344 char* getPassword = 0;
Yingdi Yube4150e2014-02-18 13:02:46 -0800345 getPassword = getpass(fmt);
346 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700347
Yingdi Yube4150e2014-02-18 13:02:46 -0800348 if (!getPassword)
349 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700350
Yingdi Yube4150e2014-02-18 13:02:46 -0800351 res = SecKeychainUnlock(m_impl->m_keyChainRef,
352 strlen(getPassword),
353 getPassword,
354 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700355
Yingdi Yube4150e2014-02-18 13:02:46 -0800356 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700357
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700358 if (res == errSecSuccess)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800359 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800360 }
361 }
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800362#endif // NDN_CXX_HAVE_GETPASS
Yingdi Yube4150e2014-02-18 13:02:46 -0800363 else
364 {
365 // If inTerminal is not set, get the password from GUI.
366 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
367 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800368
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700369 return !isLocked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800370}
371
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700372void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700373SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName,
374 const KeyParams& params,
375 bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700376{
377
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700378 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
379 {
380 throw Error("keyName has existed");
381 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800382
383 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
384
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700385 CFReleaser<CFStringRef> keyLabel =
386 CFStringCreateWithCString(0,
387 keyNameUri.c_str(),
388 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800389
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700390 CFReleaser<CFMutableDictionaryRef> attrDict =
391 CFDictionaryCreateMutable(0,
392 3,
393 &kCFTypeDictionaryKeyCallBacks,
394 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700395
Yingdi Yu7036ce22014-06-19 18:53:37 -0700396 KeyType keyType = params.getKeyType();
397 uint32_t keySize;
398 switch (keyType)
399 {
400 case KEY_TYPE_RSA:
401 {
402 const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
403 keySize = rsaParams.getKeySize();
404 break;
405 }
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700406 case KEY_TYPE_ECDSA:
407 {
408 const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
409 keySize = ecdsaParams.getKeySize();
410 break;
411 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700412 default:
413 throw Error("Fail to create a key pair: Unsupported key type");
414 }
415
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700416 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800417
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700418 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
419 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
420 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800421
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700422 CFReleaser<SecKeyRef> publicKey, privateKey;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700423 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700424 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(),
425 &publicKey.get(), &privateKey.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800426
Yingdi Yube4150e2014-02-18 13:02:46 -0800427 if (res == errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800428 {
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800429 return;
430 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700431
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700432 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800433 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700434 if (unlockTpm(0, 0, false))
Yingdi Yu7036ce22014-06-19 18:53:37 -0700435 generateKeyPairInTpmInternal(keyName, params, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800436 else
437 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800438 }
439 else
440 {
Yingdi Yube4150e2014-02-18 13:02:46 -0800441 throw Error("Fail to create a key pair");
442 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800443}
444
445void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700446SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800447{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700448 CFReleaser<CFStringRef> keyLabel =
449 CFStringCreateWithCString(0,
450 keyName.toUri().c_str(),
451 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800452
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700453 CFReleaser<CFMutableDictionaryRef> searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700454 CFDictionaryCreateMutable(0, 5,
455 &kCFTypeDictionaryKeyCallBacks,
456 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800457
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700458 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
459 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
460 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
461 OSStatus res = SecItemDelete(searchDict.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800462
463 if (res == errSecSuccess)
464 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700465
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700466 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800467 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700468 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800469 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800470 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800471}
472
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700473void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700474SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800475{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800476 throw Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700477 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800478 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800479
Yingdi Yu2e57a582014-02-20 23:34:43 -0800480 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800481
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700482 // CFReleaser<CFMutableDictionaryRef> attrDict =
483 // CFDictionaryCreateMutable(kCFAllocatorDefault,
484 // 0,
485 // &kCFTypeDictionaryKeyCallBacks,
486 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800487
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700488 // CFReleaser<CFStringRef> keyLabel =
489 // CFStringCreateWithCString(0,
490 // keyNameUri.c_str(),
491 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800492
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700493 // CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
494
495 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType));
496 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
497 // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue);
498 // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800499
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700500 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800501
Yingdi Yu2e57a582014-02-20 23:34:43 -0800502 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800503
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700504 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800505 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800506}
507
Yingdi Yu2e57a582014-02-20 23:34:43 -0800508shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700509SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800510{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700511 CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
512 if (publicKey.get() == 0)
513 {
514 throw Error("Requested public key [" + keyName.toUri() + "] does not exist in OSX Keychain");
515 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800516
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700517 CFReleaser<CFDataRef> exportedKey;
518 OSStatus res = SecItemExport(publicKey.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800519 kSecFormatOpenSSL,
520 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700521 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700522 &exportedKey.get());
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800523 if (res != errSecSuccess)
524 {
525 throw Error("Cannot export requested public key from OSX Keychain");
526 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800527
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700528 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey.get()),
529 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800530 return key;
531}
532
Yingdi Yu41546342014-11-30 23:37:53 -0800533std::string
534SecTpmOsx::getScheme()
535{
536 return SCHEME;
537}
538
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800539ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700540SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800541{
542 using namespace CryptoPP;
543
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700544 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
545 if (privateKey.get() == 0)
546 {
547 /// @todo Can this happen because of keychain is locked?
548 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
549 }
550
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700551 shared_ptr<PublicKey> publicKey = getPublicKeyFromTpm(keyName);
552
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700553 CFReleaser<CFDataRef> exportedKey;
554 OSStatus res = SecItemExport(privateKey.get(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800555 kSecFormatOpenSSL,
556 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700557 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700558 &exportedKey.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800559
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700560 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800561 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700562 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800563 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700564 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700565 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800566 else
567 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800568 }
569 else
570 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800571 }
572
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800573 uint32_t version = 0;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700574 OID algorithm;
575 bool hasParameters = false;
576 OID algorithmParameter;
577 switch (publicKey->getKeyType()) {
578 case KEY_TYPE_RSA:
579 {
580 algorithm = oid::RSA; // "RSA encryption"
581 hasParameters = false;
582 break;
583 }
584 case KEY_TYPE_ECDSA:
585 {
586 // "ECDSA encryption"
587 StringSource src(publicKey->get().buf(), publicKey->get().size(), true);
588 BERSequenceDecoder subjectPublicKeyInfo(src);
589 {
590 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
591 {
592 algorithm.decode(algorithmInfo);
593 algorithmParameter.decode(algorithmInfo);
594 }
595 }
596 hasParameters = true;
597 break;
598 }
599 default:
600 throw Error("Unsupported key type" +
601 boost::lexical_cast<std::string>(publicKey->getKeyType()));
602 }
603
604 OBufferStream pkcs8Os;
605 FileSink sink(pkcs8Os);
606
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800607 SecByteBlock rawKeyBits;
608 // PrivateKeyInfo ::= SEQUENCE {
609 // version INTEGER,
610 // privateKeyAlgorithm SEQUENCE,
611 // privateKey OCTECT STRING}
612 DERSequenceEncoder privateKeyInfo(sink);
613 {
614 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
615 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
616 {
617 algorithm.encode(privateKeyAlgorithm);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700618 if (hasParameters)
619 algorithmParameter.encode(privateKeyAlgorithm);
620 else
621 DEREncodeNull(privateKeyAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800622 }
623 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700624 DEREncodeOctetString(privateKeyInfo,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700625 CFDataGetBytePtr(exportedKey.get()),
626 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800627 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700628 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800629
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700630 return pkcs8Os.buf();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800631}
632
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700633#ifdef __GNUC__
634#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
635#pragma GCC diagnostic push
636#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
637#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
638#endif // __GNUC__
639
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800640bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700641SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700642 const uint8_t* buf, size_t size,
643 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800644{
645 using namespace CryptoPP;
646
647 StringSource privateKeySource(buf, size, true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800648 SecByteBlock rawKeyBits;
649 // PrivateKeyInfo ::= SEQUENCE {
650 // INTEGER,
651 // SEQUENCE,
652 // OCTECT STRING}
653 BERSequenceDecoder privateKeyInfo(privateKeySource);
654 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700655 uint32_t versionNum;
656 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800657 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
658 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700659 OID keyTypeOID;
660 keyTypeOID.decode(sequenceDecoder);
661
662 if (keyTypeOID == oid::RSA)
663 BERDecodeNull(sequenceDecoder);
664 else if (keyTypeOID == oid::ECDSA)
665 {
666 OID parameterOID;
667 parameterOID.decode(sequenceDecoder);
668 }
669 else
670 return false; // Unsupported key type;
671
672
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800673 }
674 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
675 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700676 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800677
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700678 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
679 rawKeyBits.BytePtr(),
680 rawKeyBits.size(),
681 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800682
683 SecExternalFormat externalFormat = kSecFormatOpenSSL;
684 SecExternalItemType externalType = kSecItemTypePrivateKey;
685 SecKeyImportExportParameters keyParams;
686 memset(&keyParams, 0, sizeof(keyParams));
687 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
688 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700689 CFReleaser<SecAccessRef> access;
690 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
691 keyName.toUri().c_str(),
692 kCFStringEncodingUTF8);
693 SecAccessCreate(keyLabel.get(), 0, &access.get());
694 keyParams.accessRef = access.get();
695 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800696
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700697#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700698#pragma clang diagnostic push
699#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700700#endif // __clang__
701
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700702 OSStatus res = SecKeychainItemImport(importedKey.get(),
703 0,
704 &externalFormat,
705 &externalType,
706 0,
707 &keyParams,
708 m_impl->m_keyChainRef,
709 &outItems.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700710
711#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700712#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700713#endif // __clang__
714
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700715 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800716 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700717 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800718 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700719 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700720 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800721 else
722 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800723 }
724 else
725 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800726 }
727
Yingdi Yu7036ce22014-06-19 18:53:37 -0700728 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700729 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800730 SecKeychainAttribute attrs[1]; // maximum number of attributes
731 SecKeychainAttributeList attrList = { 0, attrs };
732 string keyUri = keyName.toUri();
733 {
734 attrs[attrList.count].tag = kSecKeyPrintName;
735 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700736 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800737 attrList.count++;
738 }
739
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700740 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800741 &attrList,
742 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700743 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700744
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700745 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800746 {
747 return false;
748 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700749
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800750 return true;
751}
752
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700753#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
754#pragma GCC diagnostic pop
755#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
756
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800757bool
758SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
759{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700760 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
761 buf,
762 size,
763 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800764
765 SecExternalFormat externalFormat = kSecFormatOpenSSL;
766 SecExternalItemType externalType = kSecItemTypePublicKey;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700767 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800768
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700769 OSStatus res = SecItemImport(importedKey.get(),
770 0,
771 &externalFormat,
772 &externalType,
773 0,
774 0,
775 m_impl->m_keyChainRef,
776 &outItems.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800777
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700778 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800779 return false;
780
Yingdi Yu7036ce22014-06-19 18:53:37 -0700781 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700782 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800783 SecKeychainAttribute attrs[1]; // maximum number of attributes
784 SecKeychainAttributeList attrList = { 0, attrs };
785 string keyUri = keyName.toUri();
786 {
787 attrs[attrList.count].tag = kSecKeyPrintName;
788 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700789 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800790 attrList.count++;
791 }
792
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700793 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800794 &attrList,
795 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700796 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700797
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700798 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800799 return false;
800
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800801 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800802}
803
804Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700805SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
806 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800807{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700808 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
809 data,
810 dataLength,
811 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800812
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700813 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
814 if (privateKey.get() == 0)
815 {
816 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
817 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700818
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700819 CFReleaser<CFErrorRef> error;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700820 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700821 CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
822 &error.get());
823 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700824 throw Error("Fail to create signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800825
826 // Set input
Yingdi Yu7036ce22014-06-19 18:53:37 -0700827 SecTransformSetAttribute(signer.get(),
828 kSecTransformInputAttributeName,
829 dataRef.get(),
830 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700831 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700832 throw Error("Fail to configure input of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800833
834 // Enable use of padding
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700835 SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800836 kSecPaddingKey,
837 kSecPaddingPKCS1Key,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700838 &error.get());
839 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700840 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800841
842 // Set padding type
Yingdi Yu7036ce22014-06-19 18:53:37 -0700843 SecTransformSetAttribute(signer.get(),
844 kSecDigestTypeAttribute,
845 m_impl->getDigestAlgorithm(digestAlgorithm),
846 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700847 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700848 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800849
850 // Set padding attribute
851 long digestSize = m_impl->getDigestSize(digestAlgorithm);
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700852 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700853 SecTransformSetAttribute(signer.get(),
854 kSecDigestLengthAttribute,
855 cfDigestSize.get(),
856 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700857 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700858 throw Error("Fail to configure digest size of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800859
860 // Actually sign
Yingdi Yu7036ce22014-06-19 18:53:37 -0700861 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700862 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
863 if (error.get() != 0)
Yingdi Yube4150e2014-02-18 13:02:46 -0800864 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700865 if (!needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800866 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700867 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800868 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
869 else
870 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800871 }
872 else
873 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700874 CFShow(error.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800875 throw Error("Fail to sign data");
876 }
877 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800878
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700879 if (signature.get() == 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700880 throw Error("Signature is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800881
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600882 return Block(tlv::SignatureValue,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700883 make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
884 CFDataGetLength(signature.get())));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800885}
886
887ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700888SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800889{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800890 throw Error("SecTpmOsx::decryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800891
Yingdi Yu2e57a582014-02-20 23:34:43 -0800892 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700893 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800894 // keyClass = KEY_CLASS_SYMMETRIC;
895 // else
896 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800897
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700898 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800899 // reinterpret_cast<const unsigned char*>(data),
900 // dataLength
901 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800902
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700903 // CFReleaser<SecKeyRef> decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
904 // if (decryptKey.get() == 0)
905 // {
906 // /// @todo Can this happen because of keychain is locked?
907 // throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain");
908 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800909
Yingdi Yu2e57a582014-02-20 23:34:43 -0800910 // CFErrorRef error;
911 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
912 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800913
Yingdi Yu2e57a582014-02-20 23:34:43 -0800914 // Boolean set_res = SecTransformSetAttribute(decrypt,
915 // kSecTransformInputAttributeName,
916 // dataRef,
917 // &error);
918 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800919
Yingdi Yu2e57a582014-02-20 23:34:43 -0800920 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
921 // if (error)
922 // {
923 // CFShow(error);
924 // throw Error("Fail to decrypt data");
925 // }
926 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800927
Yingdi Yu2e57a582014-02-20 23:34:43 -0800928 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800929}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700930
Yingdi Yu2e57a582014-02-20 23:34:43 -0800931void
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700932SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800933{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700934 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800935 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700936 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
937 if (privateKey.get() == 0)
938 {
939 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
940 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700941
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700942 CFReleaser<SecAccessRef> accRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700943 SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700944
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700945 CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
946 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700947
Yingdi Yu7036ce22014-06-19 18:53:37 -0700948 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700949 SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700950
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700951 CFReleaser<CFArrayRef> appList;
952 CFReleaser<CFStringRef> description;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800953 SecKeychainPromptSelector promptSelector;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700954 SecACLCopyContents(aclRef,
955 &appList.get(),
956 &description.get(),
957 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700958
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700959 CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
960 0,
961 appList.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700962
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700963 CFReleaser<SecTrustedApplicationRef> trustedApp;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700964 SecTrustedApplicationCreateFromPath(appPath.c_str(),
965 &trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700966
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700967 CFArrayAppendValue(newAppList.get(), trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700968
Yingdi Yu7036ce22014-06-19 18:53:37 -0700969 SecACLSetContents(aclRef,
970 newAppList.get(),
971 description.get(),
972 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700973
Yingdi Yu7036ce22014-06-19 18:53:37 -0700974 SecKeychainItemSetAccess(privateKey.get(), accRef.get());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800975 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800976}
977
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800978ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700979SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800980{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800981 throw Error("SecTpmOsx::encryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800982
Yingdi Yu2e57a582014-02-20 23:34:43 -0800983 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700984 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800985 // keyClass = KEY_CLASS_SYMMETRIC;
986 // else
987 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700988
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700989 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800990 // reinterpret_cast<const unsigned char*>(data),
991 // dataLength
992 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700993
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700994 // CFReleaser<SecKeyRef> encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
995 // if (encryptKey.get() == 0)
996 // {
997 // throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain");
998 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800999
Yingdi Yu2e57a582014-02-20 23:34:43 -08001000 // CFErrorRef error;
1001 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
1002 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001003
Yingdi Yu2e57a582014-02-20 23:34:43 -08001004 // Boolean set_res = SecTransformSetAttribute(encrypt,
1005 // kSecTransformInputAttributeName,
1006 // dataRef,
1007 // &error);
1008 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001009
Yingdi Yu2e57a582014-02-20 23:34:43 -08001010 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
1011 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001012
Yingdi Yu2e57a582014-02-20 23:34:43 -08001013 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001014
Yingdi Yu2e57a582014-02-20 23:34:43 -08001015 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001016}
1017
1018bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001019SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001020{
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001021 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
1022
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001023 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1024 keyNameUri.c_str(),
1025 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001026
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001027 CFReleaser<CFMutableDictionaryRef> attrDict =
1028 CFDictionaryCreateMutable(0,
1029 4,
1030 &kCFTypeDictionaryKeyCallBacks,
1031 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001032
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001033 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1034 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
1035 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1036 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001037
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001038 CFReleaser<SecKeychainItemRef> itemRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001039 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001040 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001041
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001042 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001043 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -08001044 else
1045 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001046
1047}
1048
Yingdi Yu4b752752014-02-18 12:24:03 -08001049bool
1050SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
1051{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001052 return SecRandomCopyBytes(kSecRandomDefault, size, res) == 0;
Yingdi Yu4b752752014-02-18 12:24:03 -08001053}
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001054
1055////////////////////////////////
1056// OSXPrivateKeyStorage::Impl //
1057////////////////////////////////
1058
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001059CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001060SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001061{
1062 string keyNameUri = toInternalKeyName(keyName, keyClass);
1063
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001064 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1065 keyNameUri.c_str(),
1066 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001067
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001068 CFReleaser<CFMutableDictionaryRef> attrDict =
1069 CFDictionaryCreateMutable(0,
1070 5,
1071 &kCFTypeDictionaryKeyCallBacks,
1072 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001073
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001074 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1075 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1076 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
1077 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001078
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001079 CFReleaser<SecKeychainItemRef> keyItem;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001080 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001081 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001082
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001083 if (res != errSecSuccess)
1084 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001085 else
1086 return keyItem;
1087}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001088
1089string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001090SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001091{
1092 string keyUri = keyName.toUri();
1093
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001094 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001095 return keyUri + "/symmetric";
1096 else
1097 return keyUri;
1098}
1099
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001100CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001101SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
1102{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001103 switch (keyType) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001104 case KEY_TYPE_RSA:
1105 return kSecAttrKeyTypeRSA;
Yingdi Yuc8f883c2014-06-20 23:25:22 -07001106 case KEY_TYPE_ECDSA:
1107 return kSecAttrKeyTypeECDSA;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001108 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001109 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001110 }
1111}
1112
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001113CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001114SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
1115{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001116 switch (keyType) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001117 case KEY_TYPE_AES:
1118 return kSecAttrKeyTypeAES;
1119 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001120 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001121 }
1122}
1123
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001124CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001125SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
1126{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001127 switch (keyClass) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001128 case KEY_CLASS_PRIVATE:
1129 return kSecAttrKeyClassPrivate;
1130 case KEY_CLASS_PUBLIC:
1131 return kSecAttrKeyClassPublic;
1132 case KEY_CLASS_SYMMETRIC:
1133 return kSecAttrKeyClassSymmetric;
1134 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001135 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001136 }
1137}
1138
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001139CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001140SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
1141{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001142 switch (digestAlgo) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001143 case DIGEST_ALGORITHM_SHA256:
1144 return kSecDigestSHA2;
1145 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001146 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001147 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001148}
Jeff Thompson2747dc02013-10-04 19:11:34 -07001149
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001150long
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001151SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
1152{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001153 switch (digestAlgo) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001154 case DIGEST_ALGORITHM_SHA256:
1155 return 256;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001156 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001157 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001158 }
Jeff Thompson2747dc02013-10-04 19:11:34 -07001159}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001160
Yingdi Yufc40d872014-02-18 12:56:04 -08001161} // namespace ndn