blob: 3064d84e6a4083f68106fa0122e3c9ee987c2ee0 [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 Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 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 Afanasyeve2dcdfd2014-02-07 15:53:28 -080024#include "common.hpp"
25
Alexander Afanasyev19508852014-01-29 01:01:51 -080026#include "sec-tpm-osx.hpp"
Yingdi Yuf56c68f2014-04-24 21:50:13 -070027#include "public-key.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070028#include "../encoding/oid.hpp"
29#include "../encoding/buffer-stream.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070030#include "cryptopp.hpp"
Jeff Thompson2747dc02013-10-04 19:11:34 -070031
Yingdi Yu2b2b4792014-02-04 16:27:07 -080032#include <pwd.h>
33#include <unistd.h>
34#include <stdlib.h>
35#include <string.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070036
Alexander Afanasyev1c6976d2014-07-13 11:40:50 -070037#include <boost/lexical_cast.hpp>
38
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080039#include <CoreFoundation/CoreFoundation.h>
40#include <Security/Security.h>
Yingdi Yu4b752752014-02-18 12:24:03 -080041#include <Security/SecRandom.h>
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080042#include <CoreServices/CoreServices.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070043
Alexander Afanasyev59d67a52014-04-03 16:09:31 -070044#include <Security/SecDigestTransform.h>
45
Yingdi Yufc40d872014-02-18 12:56:04 -080046namespace ndn {
47
Yingdi Yu7036ce22014-06-19 18:53:37 -070048using std::string;
49
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070050/**
51 * @brief Helper class to wrap CoreFoundation object pointers
52 *
53 * The class is similar in spirit to shared_ptr, but uses CoreFoundation
54 * mechanisms to retain/release object.
55 *
56 * Original implementation by Christopher Hunt and it was borrowed from
57 * http://www.cocoabuilder.com/archive/cocoa/130776-auto-cfrelease-and.html
58 */
59template<class T>
60class CFReleaser
61{
62public:
63 //////////////////////////////
64 // Construction/destruction //
65
66 CFReleaser()
67 : m_typeRef(0)
68 {
69 }
70
71 CFReleaser(const T& typeRef)
72 : m_typeRef(typeRef)
73 {
74 }
75
76 CFReleaser(const CFReleaser& inReleaser)
77 : m_typeRef(0)
78 {
79 retain(inReleaser.m_typeRef);
80 }
81
82 CFReleaser&
83 operator=(const T& typeRef)
84 {
85 if (typeRef != m_typeRef) {
86 release();
87 m_typeRef = typeRef;
88 }
89 return *this;
90 }
91
92 CFReleaser&
93 operator=(const CFReleaser& inReleaser)
94 {
95 retain(inReleaser.m_typeRef);
96 return *this;
97 }
98
99 ~CFReleaser()
100 {
101 release();
102 }
103
104 ////////////
105 // Access //
106
107 // operator const T&() const
108 // {
109 // return m_typeRef;
110 // }
111
112 // operator T&()
113 // {
114 // return m_typeRef;
115 // }
116
117 const T&
118 get() const
119 {
120 return m_typeRef;
121 }
122
123 T&
124 get()
125 {
126 return m_typeRef;
127 }
128
129 ///////////////////
130 // Miscellaneous //
131
132 void
133 retain(const T& typeRef)
134 {
135 if (typeRef != 0) {
136 CFRetain(typeRef);
137 }
138 release();
139 m_typeRef = typeRef;
140 }
141
142 void release()
143 {
144 if (m_typeRef != 0) {
145 CFRelease(m_typeRef);
146 m_typeRef = 0;
147 }
148 };
149
150private:
151 T m_typeRef;
152};
153
154
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700155class SecTpmOsx::Impl
156{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800157public:
158 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -0800159 : m_passwordSet(false)
160 , m_inTerminal(false)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700161 {
162 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700163
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800164 /**
165 * @brief Convert NDN name of a key to internal name of the key.
166 *
Yingdi Yufc40d872014-02-18 12:56:04 -0800167 * @param keyName
168 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800169 * @return the internal key name
170 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700171 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700172 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700173
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800174 /**
175 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -0800176 *
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700177 * @param keyName
Yingdi Yufc40d872014-02-18 12:56:04 -0800178 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800179 * @returns pointer to the key
180 */
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700181 CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700182 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700183
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800184 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800185 * @brief Convert keyType to MAC OS symmetric key key type
186 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800187 * @param keyType
188 * @returns MAC OS key type
189 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300190 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800191 getSymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700192
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800193 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800194 * @brief Convert keyType to MAC OS asymmetirc key type
195 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800196 * @param keyType
197 * @returns MAC OS key type
198 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300199 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800200 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700201
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800202 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800203 * @brief Convert keyClass to MAC OS key class
204 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800205 * @param keyClass
206 * @returns MAC OS key class
207 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300208 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800209 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700210
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800211 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800212 * @brief Convert digestAlgo to MAC OS algorithm id
213 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800214 * @param digestAlgo
215 * @returns MAC OS algorithm id
216 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300217 CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800218 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700219
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800220 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800221 * @brief Get the digest size of the corresponding algorithm
222 *
223 * @param digestAlgo
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800224 * @return digest size
225 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700226 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800227 getDigestSize(DigestAlgorithm digestAlgo);
228
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800229 ///////////////////////////////////////////////
230 // everything here is public, including data //
231 ///////////////////////////////////////////////
232public:
233 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800234 bool m_passwordSet;
235 string m_password;
236 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800237};
238
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800239SecTpmOsx::SecTpmOsx()
240 : m_impl(new Impl)
241{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700242 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700243 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800244 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700245 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800246
Yingdi Yube4150e2014-02-18 13:02:46 -0800247 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700248
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800249 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Yingdi Yube4150e2014-02-18 13:02:46 -0800250 throw Error("No default keychain, create one first!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800251}
252
253SecTpmOsx::~SecTpmOsx(){
254 //TODO: implement
255}
256
Yingdi Yube4150e2014-02-18 13:02:46 -0800257void
258SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
259{
260 m_impl->m_passwordSet = true;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700261 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800262 m_impl->m_password.clear();
263 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
264}
265
266void
267SecTpmOsx::resetTpmPassword()
268{
269 m_impl->m_passwordSet = false;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700270 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800271 m_impl->m_password.clear();
272}
273
274void
275SecTpmOsx::setInTerminal(bool inTerminal)
276{
277 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700278 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700279 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800280 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700281 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800282}
283
284bool
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700285SecTpmOsx::getInTerminal() const
Yingdi Yube4150e2014-02-18 13:02:46 -0800286{
287 return m_impl->m_inTerminal;
288}
289
290bool
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700291SecTpmOsx::isLocked()
Yingdi Yube4150e2014-02-18 13:02:46 -0800292{
293 SecKeychainStatus keychainStatus;
294
295 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700296 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800297 return true;
298 else
299 return ((kSecUnlockStateStatus & keychainStatus) == 0);
300}
301
Yingdi Yu2e57a582014-02-20 23:34:43 -0800302bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800303SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
304{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700305 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800306
307 // If the default key chain is already unlocked, return immediately.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700308 if (!isLocked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800309 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800310
311 // If the default key chain is locked, unlock the key chain.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700312 if (usePassword)
Yingdi Yube4150e2014-02-18 13:02:46 -0800313 {
314 // Use the supplied password.
315 res = SecKeychainUnlock(m_impl->m_keyChainRef,
316 passwordLength,
317 password,
318 true);
319 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700320 else if (m_impl->m_passwordSet)
Yingdi Yube4150e2014-02-18 13:02:46 -0800321 {
322 // If no password supplied, then use the configured password if exists.
323 SecKeychainUnlock(m_impl->m_keyChainRef,
324 m_impl->m_password.size(),
325 m_impl->m_password.c_str(),
326 true);
327 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700328 else if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800329 {
330 // If no configured password, get password from terminal if inTerminal set.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700331 bool isLocked = true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800332 const char* fmt = "Password to unlock the default keychain: ";
333 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700334
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700335 while (isLocked)
Yingdi Yube4150e2014-02-18 13:02:46 -0800336 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700337 if (count > 2)
Yingdi Yube4150e2014-02-18 13:02:46 -0800338 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700339
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700340 char* getPassword = 0;
Yingdi Yube4150e2014-02-18 13:02:46 -0800341 getPassword = getpass(fmt);
342 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700343
Yingdi Yube4150e2014-02-18 13:02:46 -0800344 if (!getPassword)
345 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700346
Yingdi Yube4150e2014-02-18 13:02:46 -0800347 res = SecKeychainUnlock(m_impl->m_keyChainRef,
348 strlen(getPassword),
349 getPassword,
350 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700351
Yingdi Yube4150e2014-02-18 13:02:46 -0800352 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700353
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700354 if (res == errSecSuccess)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800355 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800356 }
357 }
358 else
359 {
360 // If inTerminal is not set, get the password from GUI.
361 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
362 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800363
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700364 return !isLocked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800365}
366
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700367void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700368SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName,
369 const KeyParams& params,
370 bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700371{
372
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700373 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
374 {
375 throw Error("keyName has existed");
376 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800377
378 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
379
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700380 CFReleaser<CFStringRef> keyLabel =
381 CFStringCreateWithCString(0,
382 keyNameUri.c_str(),
383 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800384
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700385 CFReleaser<CFMutableDictionaryRef> attrDict =
386 CFDictionaryCreateMutable(0,
387 3,
388 &kCFTypeDictionaryKeyCallBacks,
389 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700390
Yingdi Yu7036ce22014-06-19 18:53:37 -0700391 KeyType keyType = params.getKeyType();
392 uint32_t keySize;
393 switch (keyType)
394 {
395 case KEY_TYPE_RSA:
396 {
397 const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
398 keySize = rsaParams.getKeySize();
399 break;
400 }
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700401 case KEY_TYPE_ECDSA:
402 {
403 const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
404 keySize = ecdsaParams.getKeySize();
405 break;
406 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700407 default:
408 throw Error("Fail to create a key pair: Unsupported key type");
409 }
410
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700411 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800412
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700413 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
414 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
415 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800416
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700417 CFReleaser<SecKeyRef> publicKey, privateKey;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700418 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700419 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(),
420 &publicKey.get(), &privateKey.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800421
Yingdi Yube4150e2014-02-18 13:02:46 -0800422 if (res == errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800423 {
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800424 return;
425 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700426
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700427 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800428 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700429 if (unlockTpm(0, 0, false))
Yingdi Yu7036ce22014-06-19 18:53:37 -0700430 generateKeyPairInTpmInternal(keyName, params, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800431 else
432 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800433 }
434 else
435 {
Yingdi Yube4150e2014-02-18 13:02:46 -0800436 throw Error("Fail to create a key pair");
437 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800438}
439
440void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700441SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800442{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700443 CFReleaser<CFStringRef> keyLabel =
444 CFStringCreateWithCString(0,
445 keyName.toUri().c_str(),
446 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800447
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700448 CFReleaser<CFMutableDictionaryRef> searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700449 CFDictionaryCreateMutable(0, 5,
450 &kCFTypeDictionaryKeyCallBacks,
451 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800452
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700453 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
454 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
455 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
456 OSStatus res = SecItemDelete(searchDict.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800457
458 if (res == errSecSuccess)
459 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700460
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700461 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800462 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700463 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800464 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800465 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800466}
467
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700468void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700469SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800470{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800471 throw Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700472 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800473 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800474
Yingdi Yu2e57a582014-02-20 23:34:43 -0800475 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800476
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700477 // CFReleaser<CFMutableDictionaryRef> attrDict =
478 // CFDictionaryCreateMutable(kCFAllocatorDefault,
479 // 0,
480 // &kCFTypeDictionaryKeyCallBacks,
481 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800482
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700483 // CFReleaser<CFStringRef> keyLabel =
484 // CFStringCreateWithCString(0,
485 // keyNameUri.c_str(),
486 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800487
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700488 // CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
489
490 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType));
491 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
492 // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue);
493 // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800494
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700495 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800496
Yingdi Yu2e57a582014-02-20 23:34:43 -0800497 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800498
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700499 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800500 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800501}
502
Yingdi Yu2e57a582014-02-20 23:34:43 -0800503shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700504SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800505{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700506 CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
507 if (publicKey.get() == 0)
508 {
509 throw Error("Requested public key [" + keyName.toUri() + "] does not exist in OSX Keychain");
510 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800511
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700512 CFReleaser<CFDataRef> exportedKey;
513 OSStatus res = SecItemExport(publicKey.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800514 kSecFormatOpenSSL,
515 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700516 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700517 &exportedKey.get());
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800518 if (res != errSecSuccess)
519 {
520 throw Error("Cannot export requested public key from OSX Keychain");
521 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800522
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700523 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey.get()),
524 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800525 return key;
526}
527
528ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700529SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800530{
531 using namespace CryptoPP;
532
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700533 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
534 if (privateKey.get() == 0)
535 {
536 /// @todo Can this happen because of keychain is locked?
537 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
538 }
539
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700540 shared_ptr<PublicKey> publicKey = getPublicKeyFromTpm(keyName);
541
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700542 CFReleaser<CFDataRef> exportedKey;
543 OSStatus res = SecItemExport(privateKey.get(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800544 kSecFormatOpenSSL,
545 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700546 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700547 &exportedKey.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800548
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700549 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800550 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700551 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800552 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700553 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700554 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800555 else
556 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800557 }
558 else
559 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800560 }
561
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800562 uint32_t version = 0;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700563 OID algorithm;
564 bool hasParameters = false;
565 OID algorithmParameter;
566 switch (publicKey->getKeyType()) {
567 case KEY_TYPE_RSA:
568 {
569 algorithm = oid::RSA; // "RSA encryption"
570 hasParameters = false;
571 break;
572 }
573 case KEY_TYPE_ECDSA:
574 {
575 // "ECDSA encryption"
576 StringSource src(publicKey->get().buf(), publicKey->get().size(), true);
577 BERSequenceDecoder subjectPublicKeyInfo(src);
578 {
579 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
580 {
581 algorithm.decode(algorithmInfo);
582 algorithmParameter.decode(algorithmInfo);
583 }
584 }
585 hasParameters = true;
586 break;
587 }
588 default:
589 throw Error("Unsupported key type" +
590 boost::lexical_cast<std::string>(publicKey->getKeyType()));
591 }
592
593 OBufferStream pkcs8Os;
594 FileSink sink(pkcs8Os);
595
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800596 SecByteBlock rawKeyBits;
597 // PrivateKeyInfo ::= SEQUENCE {
598 // version INTEGER,
599 // privateKeyAlgorithm SEQUENCE,
600 // privateKey OCTECT STRING}
601 DERSequenceEncoder privateKeyInfo(sink);
602 {
603 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
604 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
605 {
606 algorithm.encode(privateKeyAlgorithm);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700607 if (hasParameters)
608 algorithmParameter.encode(privateKeyAlgorithm);
609 else
610 DEREncodeNull(privateKeyAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800611 }
612 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700613 DEREncodeOctetString(privateKeyInfo,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700614 CFDataGetBytePtr(exportedKey.get()),
615 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800616 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700617 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800618
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700619 return pkcs8Os.buf();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800620}
621
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700622#ifdef __GNUC__
623#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
624#pragma GCC diagnostic push
625#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
626#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
627#endif // __GNUC__
628
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800629bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700630SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700631 const uint8_t* buf, size_t size,
632 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800633{
634 using namespace CryptoPP;
635
636 StringSource privateKeySource(buf, size, true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800637 SecByteBlock rawKeyBits;
638 // PrivateKeyInfo ::= SEQUENCE {
639 // INTEGER,
640 // SEQUENCE,
641 // OCTECT STRING}
642 BERSequenceDecoder privateKeyInfo(privateKeySource);
643 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700644 uint32_t versionNum;
645 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800646 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
647 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700648 OID keyTypeOID;
649 keyTypeOID.decode(sequenceDecoder);
650
651 if (keyTypeOID == oid::RSA)
652 BERDecodeNull(sequenceDecoder);
653 else if (keyTypeOID == oid::ECDSA)
654 {
655 OID parameterOID;
656 parameterOID.decode(sequenceDecoder);
657 }
658 else
659 return false; // Unsupported key type;
660
661
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800662 }
663 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
664 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700665 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800666
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700667 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
668 rawKeyBits.BytePtr(),
669 rawKeyBits.size(),
670 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800671
672 SecExternalFormat externalFormat = kSecFormatOpenSSL;
673 SecExternalItemType externalType = kSecItemTypePrivateKey;
674 SecKeyImportExportParameters keyParams;
675 memset(&keyParams, 0, sizeof(keyParams));
676 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
677 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700678 CFReleaser<SecAccessRef> access;
679 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
680 keyName.toUri().c_str(),
681 kCFStringEncodingUTF8);
682 SecAccessCreate(keyLabel.get(), 0, &access.get());
683 keyParams.accessRef = access.get();
684 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800685
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700686#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700687#pragma clang diagnostic push
688#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700689#endif // __clang__
690
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700691 OSStatus res = SecKeychainItemImport(importedKey.get(),
692 0,
693 &externalFormat,
694 &externalType,
695 0,
696 &keyParams,
697 m_impl->m_keyChainRef,
698 &outItems.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700699
700#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700701#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700702#endif // __clang__
703
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700704 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800705 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700706 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800707 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700708 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700709 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800710 else
711 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800712 }
713 else
714 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800715 }
716
Yingdi Yu7036ce22014-06-19 18:53:37 -0700717 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700718 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800719 SecKeychainAttribute attrs[1]; // maximum number of attributes
720 SecKeychainAttributeList attrList = { 0, attrs };
721 string keyUri = keyName.toUri();
722 {
723 attrs[attrList.count].tag = kSecKeyPrintName;
724 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700725 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800726 attrList.count++;
727 }
728
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700729 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800730 &attrList,
731 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700732 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700733
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700734 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800735 {
736 return false;
737 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700738
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800739 return true;
740}
741
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700742#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
743#pragma GCC diagnostic pop
744#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
745
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800746bool
747SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
748{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700749 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
750 buf,
751 size,
752 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800753
754 SecExternalFormat externalFormat = kSecFormatOpenSSL;
755 SecExternalItemType externalType = kSecItemTypePublicKey;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700756 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800757
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700758 OSStatus res = SecItemImport(importedKey.get(),
759 0,
760 &externalFormat,
761 &externalType,
762 0,
763 0,
764 m_impl->m_keyChainRef,
765 &outItems.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800766
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700767 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800768 return false;
769
Yingdi Yu7036ce22014-06-19 18:53:37 -0700770 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700771 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800772 SecKeychainAttribute attrs[1]; // maximum number of attributes
773 SecKeychainAttributeList attrList = { 0, attrs };
774 string keyUri = keyName.toUri();
775 {
776 attrs[attrList.count].tag = kSecKeyPrintName;
777 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700778 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800779 attrList.count++;
780 }
781
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700782 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800783 &attrList,
784 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700785 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700786
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700787 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800788 return false;
789
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800790 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800791}
792
793Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700794SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
795 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800796{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700797 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
798 data,
799 dataLength,
800 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800801
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700802 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
803 if (privateKey.get() == 0)
804 {
805 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
806 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700807
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700808 CFReleaser<CFErrorRef> error;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700809 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700810 CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
811 &error.get());
812 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700813 throw Error("Fail to create signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800814
815 // Set input
Yingdi Yu7036ce22014-06-19 18:53:37 -0700816 SecTransformSetAttribute(signer.get(),
817 kSecTransformInputAttributeName,
818 dataRef.get(),
819 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700820 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700821 throw Error("Fail to configure input of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800822
823 // Enable use of padding
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700824 SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800825 kSecPaddingKey,
826 kSecPaddingPKCS1Key,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700827 &error.get());
828 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700829 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800830
831 // Set padding type
Yingdi Yu7036ce22014-06-19 18:53:37 -0700832 SecTransformSetAttribute(signer.get(),
833 kSecDigestTypeAttribute,
834 m_impl->getDigestAlgorithm(digestAlgorithm),
835 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700836 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700837 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800838
839 // Set padding attribute
840 long digestSize = m_impl->getDigestSize(digestAlgorithm);
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700841 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700842 SecTransformSetAttribute(signer.get(),
843 kSecDigestLengthAttribute,
844 cfDigestSize.get(),
845 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700846 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700847 throw Error("Fail to configure digest size of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800848
849 // Actually sign
Yingdi Yu7036ce22014-06-19 18:53:37 -0700850 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700851 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
852 if (error.get() != 0)
Yingdi Yube4150e2014-02-18 13:02:46 -0800853 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700854 if (!needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800855 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700856 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800857 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
858 else
859 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800860 }
861 else
862 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700863 CFShow(error.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800864 throw Error("Fail to sign data");
865 }
866 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800867
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700868 if (signature.get() == 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700869 throw Error("Signature is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800870
871 return Block(Tlv::SignatureValue,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700872 make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
873 CFDataGetLength(signature.get())));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800874}
875
876ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700877SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800878{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800879 throw Error("SecTpmOsx::decryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800880
Yingdi Yu2e57a582014-02-20 23:34:43 -0800881 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700882 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800883 // keyClass = KEY_CLASS_SYMMETRIC;
884 // else
885 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800886
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700887 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800888 // reinterpret_cast<const unsigned char*>(data),
889 // dataLength
890 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800891
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700892 // CFReleaser<SecKeyRef> decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
893 // if (decryptKey.get() == 0)
894 // {
895 // /// @todo Can this happen because of keychain is locked?
896 // throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain");
897 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800898
Yingdi Yu2e57a582014-02-20 23:34:43 -0800899 // CFErrorRef error;
900 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
901 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800902
Yingdi Yu2e57a582014-02-20 23:34:43 -0800903 // Boolean set_res = SecTransformSetAttribute(decrypt,
904 // kSecTransformInputAttributeName,
905 // dataRef,
906 // &error);
907 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800908
Yingdi Yu2e57a582014-02-20 23:34:43 -0800909 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
910 // if (error)
911 // {
912 // CFShow(error);
913 // throw Error("Fail to decrypt data");
914 // }
915 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800916
Yingdi Yu2e57a582014-02-20 23:34:43 -0800917 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800918}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700919
Yingdi Yu2e57a582014-02-20 23:34:43 -0800920void
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700921SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800922{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700923 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800924 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700925 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
926 if (privateKey.get() == 0)
927 {
928 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
929 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700930
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700931 CFReleaser<SecAccessRef> accRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700932 SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700933
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700934 CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
935 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700936
Yingdi Yu7036ce22014-06-19 18:53:37 -0700937 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700938 SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700939
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700940 CFReleaser<CFArrayRef> appList;
941 CFReleaser<CFStringRef> description;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800942 SecKeychainPromptSelector promptSelector;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700943 SecACLCopyContents(aclRef,
944 &appList.get(),
945 &description.get(),
946 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700947
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700948 CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
949 0,
950 appList.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700951
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700952 CFReleaser<SecTrustedApplicationRef> trustedApp;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700953 SecTrustedApplicationCreateFromPath(appPath.c_str(),
954 &trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700955
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700956 CFArrayAppendValue(newAppList.get(), trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700957
Yingdi Yu7036ce22014-06-19 18:53:37 -0700958 SecACLSetContents(aclRef,
959 newAppList.get(),
960 description.get(),
961 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700962
Yingdi Yu7036ce22014-06-19 18:53:37 -0700963 SecKeychainItemSetAccess(privateKey.get(), accRef.get());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800964 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800965}
966
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800967ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700968SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800969{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800970 throw Error("SecTpmOsx::encryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800971
Yingdi Yu2e57a582014-02-20 23:34:43 -0800972 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700973 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800974 // keyClass = KEY_CLASS_SYMMETRIC;
975 // else
976 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700977
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700978 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800979 // reinterpret_cast<const unsigned char*>(data),
980 // dataLength
981 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700982
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700983 // CFReleaser<SecKeyRef> encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
984 // if (encryptKey.get() == 0)
985 // {
986 // throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain");
987 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800988
Yingdi Yu2e57a582014-02-20 23:34:43 -0800989 // CFErrorRef error;
990 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
991 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800992
Yingdi Yu2e57a582014-02-20 23:34:43 -0800993 // Boolean set_res = SecTransformSetAttribute(encrypt,
994 // kSecTransformInputAttributeName,
995 // dataRef,
996 // &error);
997 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800998
Yingdi Yu2e57a582014-02-20 23:34:43 -0800999 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
1000 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001001
Yingdi Yu2e57a582014-02-20 23:34:43 -08001002 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001003
Yingdi Yu2e57a582014-02-20 23:34:43 -08001004 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001005}
1006
1007bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001008SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001009{
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001010 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
1011
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001012 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1013 keyNameUri.c_str(),
1014 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001015
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001016 CFReleaser<CFMutableDictionaryRef> attrDict =
1017 CFDictionaryCreateMutable(0,
1018 4,
1019 &kCFTypeDictionaryKeyCallBacks,
1020 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001021
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001022 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1023 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
1024 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1025 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001026
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001027 CFReleaser<SecKeychainItemRef> itemRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001028 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001029 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001030
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001031 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001032 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -08001033 else
1034 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001035
1036}
1037
Yingdi Yu4b752752014-02-18 12:24:03 -08001038bool
1039SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
1040{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001041 return SecRandomCopyBytes(kSecRandomDefault, size, res) == 0;
Yingdi Yu4b752752014-02-18 12:24:03 -08001042}
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001043
1044////////////////////////////////
1045// OSXPrivateKeyStorage::Impl //
1046////////////////////////////////
1047
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001048CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001049SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001050{
1051 string keyNameUri = toInternalKeyName(keyName, keyClass);
1052
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001053 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1054 keyNameUri.c_str(),
1055 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001056
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001057 CFReleaser<CFMutableDictionaryRef> attrDict =
1058 CFDictionaryCreateMutable(0,
1059 5,
1060 &kCFTypeDictionaryKeyCallBacks,
1061 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001062
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001063 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1064 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1065 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
1066 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001067
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001068 CFReleaser<SecKeychainItemRef> keyItem;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001069 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001070 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001071
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001072 if (res != errSecSuccess)
1073 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001074 else
1075 return keyItem;
1076}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001077
1078string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001079SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001080{
1081 string keyUri = keyName.toUri();
1082
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001083 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001084 return keyUri + "/symmetric";
1085 else
1086 return keyUri;
1087}
1088
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001089CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001090SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
1091{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001092 switch (keyType) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001093 case KEY_TYPE_RSA:
1094 return kSecAttrKeyTypeRSA;
Yingdi Yuc8f883c2014-06-20 23:25:22 -07001095 case KEY_TYPE_ECDSA:
1096 return kSecAttrKeyTypeECDSA;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001097 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001098 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001099 }
1100}
1101
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001102CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001103SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
1104{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001105 switch (keyType) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001106 case KEY_TYPE_AES:
1107 return kSecAttrKeyTypeAES;
1108 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::getKeyClass(KeyClass keyClass)
1115{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001116 switch (keyClass) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001117 case KEY_CLASS_PRIVATE:
1118 return kSecAttrKeyClassPrivate;
1119 case KEY_CLASS_PUBLIC:
1120 return kSecAttrKeyClassPublic;
1121 case KEY_CLASS_SYMMETRIC:
1122 return kSecAttrKeyClassSymmetric;
1123 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001124 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001125 }
1126}
1127
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001128CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001129SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
1130{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001131 switch (digestAlgo) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001132 case DIGEST_ALGORITHM_SHA256:
1133 return kSecDigestSHA2;
1134 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001135 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001136 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001137}
Jeff Thompson2747dc02013-10-04 19:11:34 -07001138
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001139long
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001140SecTpmOsx::Impl::getDigestSize(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 256;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001145 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001146 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001147 }
Jeff Thompson2747dc02013-10-04 19:11:34 -07001148}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001149
Yingdi Yufc40d872014-02-18 12:56:04 -08001150} // namespace ndn