blob: 1abfcec37e5ff41440529208d28f0afb03e7306d [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 Afanasyevfdbfc6d2014-04-14 15:12:11 -0700331 else if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800332 {
333 // If no configured password, get password from terminal if inTerminal set.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700334 bool isLocked = true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800335 const char* fmt = "Password to unlock the default keychain: ";
336 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700337
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700338 while (isLocked)
Yingdi Yube4150e2014-02-18 13:02:46 -0800339 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700340 if (count > 2)
Yingdi Yube4150e2014-02-18 13:02:46 -0800341 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700342
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700343 char* getPassword = 0;
Yingdi Yube4150e2014-02-18 13:02:46 -0800344 getPassword = getpass(fmt);
345 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700346
Yingdi Yube4150e2014-02-18 13:02:46 -0800347 if (!getPassword)
348 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700349
Yingdi Yube4150e2014-02-18 13:02:46 -0800350 res = SecKeychainUnlock(m_impl->m_keyChainRef,
351 strlen(getPassword),
352 getPassword,
353 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700354
Yingdi Yube4150e2014-02-18 13:02:46 -0800355 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700356
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700357 if (res == errSecSuccess)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800358 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800359 }
360 }
361 else
362 {
363 // If inTerminal is not set, get the password from GUI.
364 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
365 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800366
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700367 return !isLocked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800368}
369
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700370void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700371SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName,
372 const KeyParams& params,
373 bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700374{
375
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700376 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
377 {
378 throw Error("keyName has existed");
379 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800380
381 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
382
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700383 CFReleaser<CFStringRef> keyLabel =
384 CFStringCreateWithCString(0,
385 keyNameUri.c_str(),
386 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800387
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700388 CFReleaser<CFMutableDictionaryRef> attrDict =
389 CFDictionaryCreateMutable(0,
390 3,
391 &kCFTypeDictionaryKeyCallBacks,
392 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700393
Yingdi Yu7036ce22014-06-19 18:53:37 -0700394 KeyType keyType = params.getKeyType();
395 uint32_t keySize;
396 switch (keyType)
397 {
398 case KEY_TYPE_RSA:
399 {
400 const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
401 keySize = rsaParams.getKeySize();
402 break;
403 }
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700404 case KEY_TYPE_ECDSA:
405 {
406 const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
407 keySize = ecdsaParams.getKeySize();
408 break;
409 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700410 default:
411 throw Error("Fail to create a key pair: Unsupported key type");
412 }
413
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700414 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800415
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700416 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
417 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
418 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800419
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700420 CFReleaser<SecKeyRef> publicKey, privateKey;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700421 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700422 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(),
423 &publicKey.get(), &privateKey.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800424
Yingdi Yube4150e2014-02-18 13:02:46 -0800425 if (res == errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800426 {
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800427 return;
428 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700429
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700430 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800431 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700432 if (unlockTpm(0, 0, false))
Yingdi Yu7036ce22014-06-19 18:53:37 -0700433 generateKeyPairInTpmInternal(keyName, params, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800434 else
435 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800436 }
437 else
438 {
Yingdi Yube4150e2014-02-18 13:02:46 -0800439 throw Error("Fail to create a key pair");
440 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800441}
442
443void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700444SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800445{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700446 CFReleaser<CFStringRef> keyLabel =
447 CFStringCreateWithCString(0,
448 keyName.toUri().c_str(),
449 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800450
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700451 CFReleaser<CFMutableDictionaryRef> searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700452 CFDictionaryCreateMutable(0, 5,
453 &kCFTypeDictionaryKeyCallBacks,
454 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800455
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700456 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
457 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
458 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
459 OSStatus res = SecItemDelete(searchDict.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800460
461 if (res == errSecSuccess)
462 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700463
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700464 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800465 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700466 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800467 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800468 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800469}
470
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700471void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700472SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800473{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800474 throw Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700475 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800476 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800477
Yingdi Yu2e57a582014-02-20 23:34:43 -0800478 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800479
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700480 // CFReleaser<CFMutableDictionaryRef> attrDict =
481 // CFDictionaryCreateMutable(kCFAllocatorDefault,
482 // 0,
483 // &kCFTypeDictionaryKeyCallBacks,
484 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800485
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700486 // CFReleaser<CFStringRef> keyLabel =
487 // CFStringCreateWithCString(0,
488 // keyNameUri.c_str(),
489 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800490
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700491 // CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
492
493 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType));
494 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
495 // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue);
496 // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800497
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700498 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800499
Yingdi Yu2e57a582014-02-20 23:34:43 -0800500 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800501
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700502 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800503 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800504}
505
Yingdi Yu2e57a582014-02-20 23:34:43 -0800506shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700507SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800508{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700509 CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
510 if (publicKey.get() == 0)
511 {
512 throw Error("Requested public key [" + keyName.toUri() + "] does not exist in OSX Keychain");
513 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800514
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700515 CFReleaser<CFDataRef> exportedKey;
516 OSStatus res = SecItemExport(publicKey.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800517 kSecFormatOpenSSL,
518 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700519 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700520 &exportedKey.get());
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800521 if (res != errSecSuccess)
522 {
523 throw Error("Cannot export requested public key from OSX Keychain");
524 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800525
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700526 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey.get()),
527 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800528 return key;
529}
530
Yingdi Yu41546342014-11-30 23:37:53 -0800531std::string
532SecTpmOsx::getScheme()
533{
534 return SCHEME;
535}
536
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800537ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700538SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800539{
540 using namespace CryptoPP;
541
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700542 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
543 if (privateKey.get() == 0)
544 {
545 /// @todo Can this happen because of keychain is locked?
546 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
547 }
548
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700549 shared_ptr<PublicKey> publicKey = getPublicKeyFromTpm(keyName);
550
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700551 CFReleaser<CFDataRef> exportedKey;
552 OSStatus res = SecItemExport(privateKey.get(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800553 kSecFormatOpenSSL,
554 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700555 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700556 &exportedKey.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800557
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700558 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800559 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700560 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800561 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700562 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700563 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800564 else
565 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800566 }
567 else
568 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800569 }
570
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800571 uint32_t version = 0;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700572 OID algorithm;
573 bool hasParameters = false;
574 OID algorithmParameter;
575 switch (publicKey->getKeyType()) {
576 case KEY_TYPE_RSA:
577 {
578 algorithm = oid::RSA; // "RSA encryption"
579 hasParameters = false;
580 break;
581 }
582 case KEY_TYPE_ECDSA:
583 {
584 // "ECDSA encryption"
585 StringSource src(publicKey->get().buf(), publicKey->get().size(), true);
586 BERSequenceDecoder subjectPublicKeyInfo(src);
587 {
588 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
589 {
590 algorithm.decode(algorithmInfo);
591 algorithmParameter.decode(algorithmInfo);
592 }
593 }
594 hasParameters = true;
595 break;
596 }
597 default:
598 throw Error("Unsupported key type" +
599 boost::lexical_cast<std::string>(publicKey->getKeyType()));
600 }
601
602 OBufferStream pkcs8Os;
603 FileSink sink(pkcs8Os);
604
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800605 SecByteBlock rawKeyBits;
606 // PrivateKeyInfo ::= SEQUENCE {
607 // version INTEGER,
608 // privateKeyAlgorithm SEQUENCE,
609 // privateKey OCTECT STRING}
610 DERSequenceEncoder privateKeyInfo(sink);
611 {
612 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
613 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
614 {
615 algorithm.encode(privateKeyAlgorithm);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700616 if (hasParameters)
617 algorithmParameter.encode(privateKeyAlgorithm);
618 else
619 DEREncodeNull(privateKeyAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800620 }
621 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700622 DEREncodeOctetString(privateKeyInfo,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700623 CFDataGetBytePtr(exportedKey.get()),
624 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800625 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700626 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800627
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700628 return pkcs8Os.buf();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800629}
630
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700631#ifdef __GNUC__
632#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
633#pragma GCC diagnostic push
634#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
635#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
636#endif // __GNUC__
637
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800638bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700639SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700640 const uint8_t* buf, size_t size,
641 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800642{
643 using namespace CryptoPP;
644
645 StringSource privateKeySource(buf, size, true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800646 SecByteBlock rawKeyBits;
647 // PrivateKeyInfo ::= SEQUENCE {
648 // INTEGER,
649 // SEQUENCE,
650 // OCTECT STRING}
651 BERSequenceDecoder privateKeyInfo(privateKeySource);
652 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700653 uint32_t versionNum;
654 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800655 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
656 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700657 OID keyTypeOID;
658 keyTypeOID.decode(sequenceDecoder);
659
660 if (keyTypeOID == oid::RSA)
661 BERDecodeNull(sequenceDecoder);
662 else if (keyTypeOID == oid::ECDSA)
663 {
664 OID parameterOID;
665 parameterOID.decode(sequenceDecoder);
666 }
667 else
668 return false; // Unsupported key type;
669
670
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800671 }
672 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
673 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700674 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800675
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700676 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
677 rawKeyBits.BytePtr(),
678 rawKeyBits.size(),
679 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800680
681 SecExternalFormat externalFormat = kSecFormatOpenSSL;
682 SecExternalItemType externalType = kSecItemTypePrivateKey;
683 SecKeyImportExportParameters keyParams;
684 memset(&keyParams, 0, sizeof(keyParams));
685 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
686 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700687 CFReleaser<SecAccessRef> access;
688 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
689 keyName.toUri().c_str(),
690 kCFStringEncodingUTF8);
691 SecAccessCreate(keyLabel.get(), 0, &access.get());
692 keyParams.accessRef = access.get();
693 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800694
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700695#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700696#pragma clang diagnostic push
697#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700698#endif // __clang__
699
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700700 OSStatus res = SecKeychainItemImport(importedKey.get(),
701 0,
702 &externalFormat,
703 &externalType,
704 0,
705 &keyParams,
706 m_impl->m_keyChainRef,
707 &outItems.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700708
709#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700710#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700711#endif // __clang__
712
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700713 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800714 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700715 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800716 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700717 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700718 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800719 else
720 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800721 }
722 else
723 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800724 }
725
Yingdi Yu7036ce22014-06-19 18:53:37 -0700726 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700727 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800728 SecKeychainAttribute attrs[1]; // maximum number of attributes
729 SecKeychainAttributeList attrList = { 0, attrs };
730 string keyUri = keyName.toUri();
731 {
732 attrs[attrList.count].tag = kSecKeyPrintName;
733 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700734 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800735 attrList.count++;
736 }
737
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700738 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800739 &attrList,
740 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700741 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700742
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700743 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800744 {
745 return false;
746 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700747
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800748 return true;
749}
750
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700751#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
752#pragma GCC diagnostic pop
753#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
754
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800755bool
756SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
757{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700758 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
759 buf,
760 size,
761 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800762
763 SecExternalFormat externalFormat = kSecFormatOpenSSL;
764 SecExternalItemType externalType = kSecItemTypePublicKey;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700765 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800766
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700767 OSStatus res = SecItemImport(importedKey.get(),
768 0,
769 &externalFormat,
770 &externalType,
771 0,
772 0,
773 m_impl->m_keyChainRef,
774 &outItems.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800775
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700776 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800777 return false;
778
Yingdi Yu7036ce22014-06-19 18:53:37 -0700779 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700780 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800781 SecKeychainAttribute attrs[1]; // maximum number of attributes
782 SecKeychainAttributeList attrList = { 0, attrs };
783 string keyUri = keyName.toUri();
784 {
785 attrs[attrList.count].tag = kSecKeyPrintName;
786 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700787 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800788 attrList.count++;
789 }
790
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700791 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800792 &attrList,
793 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700794 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700795
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700796 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800797 return false;
798
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800799 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800800}
801
802Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700803SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
804 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800805{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700806 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
807 data,
808 dataLength,
809 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800810
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700811 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
812 if (privateKey.get() == 0)
813 {
814 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
815 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700816
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700817 CFReleaser<CFErrorRef> error;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700818 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700819 CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
820 &error.get());
821 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700822 throw Error("Fail to create signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800823
824 // Set input
Yingdi Yu7036ce22014-06-19 18:53:37 -0700825 SecTransformSetAttribute(signer.get(),
826 kSecTransformInputAttributeName,
827 dataRef.get(),
828 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700829 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700830 throw Error("Fail to configure input of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800831
832 // Enable use of padding
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700833 SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800834 kSecPaddingKey,
835 kSecPaddingPKCS1Key,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700836 &error.get());
837 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700838 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800839
840 // Set padding type
Yingdi Yu7036ce22014-06-19 18:53:37 -0700841 SecTransformSetAttribute(signer.get(),
842 kSecDigestTypeAttribute,
843 m_impl->getDigestAlgorithm(digestAlgorithm),
844 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700845 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700846 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800847
848 // Set padding attribute
849 long digestSize = m_impl->getDigestSize(digestAlgorithm);
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700850 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700851 SecTransformSetAttribute(signer.get(),
852 kSecDigestLengthAttribute,
853 cfDigestSize.get(),
854 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700855 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700856 throw Error("Fail to configure digest size of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800857
858 // Actually sign
Yingdi Yu7036ce22014-06-19 18:53:37 -0700859 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700860 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
861 if (error.get() != 0)
Yingdi Yube4150e2014-02-18 13:02:46 -0800862 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700863 if (!needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800864 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700865 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800866 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
867 else
868 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800869 }
870 else
871 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700872 CFShow(error.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800873 throw Error("Fail to sign data");
874 }
875 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800876
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700877 if (signature.get() == 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700878 throw Error("Signature is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800879
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600880 return Block(tlv::SignatureValue,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700881 make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
882 CFDataGetLength(signature.get())));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800883}
884
885ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700886SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800887{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800888 throw Error("SecTpmOsx::decryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800889
Yingdi Yu2e57a582014-02-20 23:34:43 -0800890 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700891 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800892 // keyClass = KEY_CLASS_SYMMETRIC;
893 // else
894 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800895
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700896 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800897 // reinterpret_cast<const unsigned char*>(data),
898 // dataLength
899 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800900
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700901 // CFReleaser<SecKeyRef> decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
902 // if (decryptKey.get() == 0)
903 // {
904 // /// @todo Can this happen because of keychain is locked?
905 // throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain");
906 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800907
Yingdi Yu2e57a582014-02-20 23:34:43 -0800908 // CFErrorRef error;
909 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
910 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800911
Yingdi Yu2e57a582014-02-20 23:34:43 -0800912 // Boolean set_res = SecTransformSetAttribute(decrypt,
913 // kSecTransformInputAttributeName,
914 // dataRef,
915 // &error);
916 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800917
Yingdi Yu2e57a582014-02-20 23:34:43 -0800918 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
919 // if (error)
920 // {
921 // CFShow(error);
922 // throw Error("Fail to decrypt data");
923 // }
924 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800925
Yingdi Yu2e57a582014-02-20 23:34:43 -0800926 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800927}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700928
Yingdi Yu2e57a582014-02-20 23:34:43 -0800929void
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700930SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800931{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700932 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800933 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700934 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
935 if (privateKey.get() == 0)
936 {
937 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
938 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700939
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700940 CFReleaser<SecAccessRef> accRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700941 SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700942
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700943 CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
944 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700945
Yingdi Yu7036ce22014-06-19 18:53:37 -0700946 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700947 SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700948
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700949 CFReleaser<CFArrayRef> appList;
950 CFReleaser<CFStringRef> description;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800951 SecKeychainPromptSelector promptSelector;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700952 SecACLCopyContents(aclRef,
953 &appList.get(),
954 &description.get(),
955 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700956
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700957 CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
958 0,
959 appList.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700960
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700961 CFReleaser<SecTrustedApplicationRef> trustedApp;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700962 SecTrustedApplicationCreateFromPath(appPath.c_str(),
963 &trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700964
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700965 CFArrayAppendValue(newAppList.get(), trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700966
Yingdi Yu7036ce22014-06-19 18:53:37 -0700967 SecACLSetContents(aclRef,
968 newAppList.get(),
969 description.get(),
970 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700971
Yingdi Yu7036ce22014-06-19 18:53:37 -0700972 SecKeychainItemSetAccess(privateKey.get(), accRef.get());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800973 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800974}
975
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800976ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700977SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800978{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800979 throw Error("SecTpmOsx::encryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800980
Yingdi Yu2e57a582014-02-20 23:34:43 -0800981 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700982 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800983 // keyClass = KEY_CLASS_SYMMETRIC;
984 // else
985 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700986
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700987 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800988 // reinterpret_cast<const unsigned char*>(data),
989 // dataLength
990 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700991
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700992 // CFReleaser<SecKeyRef> encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
993 // if (encryptKey.get() == 0)
994 // {
995 // throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain");
996 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800997
Yingdi Yu2e57a582014-02-20 23:34:43 -0800998 // CFErrorRef error;
999 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
1000 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001001
Yingdi Yu2e57a582014-02-20 23:34:43 -08001002 // Boolean set_res = SecTransformSetAttribute(encrypt,
1003 // kSecTransformInputAttributeName,
1004 // dataRef,
1005 // &error);
1006 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001007
Yingdi Yu2e57a582014-02-20 23:34:43 -08001008 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
1009 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001010
Yingdi Yu2e57a582014-02-20 23:34:43 -08001011 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001012
Yingdi Yu2e57a582014-02-20 23:34:43 -08001013 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001014}
1015
1016bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001017SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001018{
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001019 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
1020
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001021 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1022 keyNameUri.c_str(),
1023 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001024
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001025 CFReleaser<CFMutableDictionaryRef> attrDict =
1026 CFDictionaryCreateMutable(0,
1027 4,
1028 &kCFTypeDictionaryKeyCallBacks,
1029 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001030
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001031 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1032 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
1033 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1034 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001035
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001036 CFReleaser<SecKeychainItemRef> itemRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001037 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001038 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001039
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001040 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001041 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -08001042 else
1043 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001044
1045}
1046
Yingdi Yu4b752752014-02-18 12:24:03 -08001047bool
1048SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
1049{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001050 return SecRandomCopyBytes(kSecRandomDefault, size, res) == 0;
Yingdi Yu4b752752014-02-18 12:24:03 -08001051}
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001052
1053////////////////////////////////
1054// OSXPrivateKeyStorage::Impl //
1055////////////////////////////////
1056
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001057CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001058SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001059{
1060 string keyNameUri = toInternalKeyName(keyName, keyClass);
1061
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001062 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1063 keyNameUri.c_str(),
1064 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001065
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001066 CFReleaser<CFMutableDictionaryRef> attrDict =
1067 CFDictionaryCreateMutable(0,
1068 5,
1069 &kCFTypeDictionaryKeyCallBacks,
1070 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001071
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001072 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1073 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1074 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
1075 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001076
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001077 CFReleaser<SecKeychainItemRef> keyItem;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001078 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001079 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001080
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001081 if (res != errSecSuccess)
1082 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001083 else
1084 return keyItem;
1085}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001086
1087string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001088SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001089{
1090 string keyUri = keyName.toUri();
1091
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001092 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001093 return keyUri + "/symmetric";
1094 else
1095 return keyUri;
1096}
1097
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001098CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001099SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
1100{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001101 switch (keyType) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001102 case KEY_TYPE_RSA:
1103 return kSecAttrKeyTypeRSA;
Yingdi Yuc8f883c2014-06-20 23:25:22 -07001104 case KEY_TYPE_ECDSA:
1105 return kSecAttrKeyTypeECDSA;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001106 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001107 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001108 }
1109}
1110
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001111CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001112SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
1113{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001114 switch (keyType) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001115 case KEY_TYPE_AES:
1116 return kSecAttrKeyTypeAES;
1117 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001118 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001119 }
1120}
1121
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001122CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001123SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
1124{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001125 switch (keyClass) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001126 case KEY_CLASS_PRIVATE:
1127 return kSecAttrKeyClassPrivate;
1128 case KEY_CLASS_PUBLIC:
1129 return kSecAttrKeyClassPublic;
1130 case KEY_CLASS_SYMMETRIC:
1131 return kSecAttrKeyClassSymmetric;
1132 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001133 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001134 }
1135}
1136
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001137CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001138SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
1139{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001140 switch (digestAlgo) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001141 case DIGEST_ALGORITHM_SHA256:
1142 return kSecDigestSHA2;
1143 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001144 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001145 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001146}
Jeff Thompson2747dc02013-10-04 19:11:34 -07001147
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001148long
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001149SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
1150{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001151 switch (digestAlgo) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001152 case DIGEST_ALGORITHM_SHA256:
1153 return 256;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001154 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001155 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001156 }
Jeff Thompson2747dc02013-10-04 19:11:34 -07001157}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001158
Yingdi Yufc40d872014-02-18 12:56:04 -08001159} // namespace ndn