blob: 92c6addab9aeadaec9035fb99b36dbb05b754f21 [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/**
Yingdi Yu99b2a002015-08-12 12:47:44 -07003 * Copyright (c) 2013-2016 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()
Yingdi Yu99b2a002015-08-12 12:47:44 -070068 : m_typeRef(nullptr)
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070069 {
70 }
71
72 CFReleaser(const T& typeRef)
73 : m_typeRef(typeRef)
74 {
75 }
76
77 CFReleaser(const CFReleaser& inReleaser)
Yingdi Yu99b2a002015-08-12 12:47:44 -070078 : m_typeRef(nullptr)
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070079 {
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 {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700136 if (typeRef != nullptr) {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700137 CFRetain(typeRef);
138 }
139 release();
140 m_typeRef = typeRef;
141 }
142
Yingdi Yu99b2a002015-08-12 12:47:44 -0700143 void
144 release()
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700145 {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700146 if (m_typeRef != nullptr) {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700147 CFRelease(m_typeRef);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700148 m_typeRef = nullptr;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700149 }
150 };
151
Yingdi Yu99b2a002015-08-12 12:47:44 -0700152 bool
153 operator==(std::nullptr_t)
154 {
155 return get() == nullptr;
156 }
157
158 bool
159 operator!=(std::nullptr_t)
160 {
161 return get() != nullptr;
162 }
163
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700164private:
165 T m_typeRef;
166};
167
168
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700169class SecTpmOsx::Impl
170{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800171public:
172 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -0800173 : m_passwordSet(false)
174 , m_inTerminal(false)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700175 {
176 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700177
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800178 /**
179 * @brief Convert NDN name of a key to internal name of the key.
180 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800181 * @return the internal key name
182 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700183 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700184 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700185
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800186 /**
187 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -0800188 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800189 * @returns pointer to the key
190 */
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700191 CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700192 getKey(const Name& keyName, KeyClass keyClass);
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 symmetric key key type
196 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800197 * @returns MAC OS key type
198 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300199 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800200 getSymKeyType(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 keyType to MAC OS asymmetirc key type
204 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800205 * @returns MAC OS key type
206 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300207 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800208 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700209
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800210 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800211 * @brief Convert keyClass to MAC OS key class
212 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800213 * @returns MAC OS key class
214 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300215 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800216 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700217
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800218 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800219 * @brief Convert digestAlgo to MAC OS algorithm id
220 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800221 * @returns MAC OS algorithm id
222 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300223 CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800224 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700225
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800226 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800227 * @brief Get the digest size of the corresponding algorithm
228 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800229 * @return digest size
230 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700231 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800232 getDigestSize(DigestAlgorithm digestAlgo);
233
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800234 ///////////////////////////////////////////////
235 // everything here is public, including data //
236 ///////////////////////////////////////////////
237public:
238 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800239 bool m_passwordSet;
240 string m_password;
241 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800242};
243
Yingdi Yu41546342014-11-30 23:37:53 -0800244SecTpmOsx::SecTpmOsx(const std::string& location)
245 : SecTpm(location)
246 , m_impl(new Impl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800247{
Yingdi Yu41546342014-11-30 23:37:53 -0800248 // TODO: add location support
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700249 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700250 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800251 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700252 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800253
Yingdi Yube4150e2014-02-18 13:02:46 -0800254 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700255
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800256 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700257 BOOST_THROW_EXCEPTION(Error("No default keychain, please create one first"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800258}
259
Yingdi Yu41546342014-11-30 23:37:53 -0800260SecTpmOsx::~SecTpmOsx()
261{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800262}
263
Yingdi Yube4150e2014-02-18 13:02:46 -0800264void
265SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
266{
267 m_impl->m_passwordSet = true;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700268 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800269 m_impl->m_password.clear();
270 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
271}
272
273void
274SecTpmOsx::resetTpmPassword()
275{
276 m_impl->m_passwordSet = false;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700277 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800278 m_impl->m_password.clear();
279}
280
281void
282SecTpmOsx::setInTerminal(bool inTerminal)
283{
284 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700285 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700286 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800287 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700288 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800289}
290
291bool
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700292SecTpmOsx::getInTerminal() const
Yingdi Yube4150e2014-02-18 13:02:46 -0800293{
294 return m_impl->m_inTerminal;
295}
296
297bool
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700298SecTpmOsx::isLocked()
Yingdi Yube4150e2014-02-18 13:02:46 -0800299{
300 SecKeychainStatus keychainStatus;
301
302 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700303 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800304 return true;
305 else
306 return ((kSecUnlockStateStatus & keychainStatus) == 0);
307}
308
Yingdi Yu2e57a582014-02-20 23:34:43 -0800309bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800310SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
311{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700312 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800313
314 // If the default key chain is already unlocked, return immediately.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700315 if (!isLocked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800316 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800317
318 // If the default key chain is locked, unlock the key chain.
Yingdi Yu99b2a002015-08-12 12:47:44 -0700319 if (usePassword) {
320 // Use the supplied password.
321 res = SecKeychainUnlock(m_impl->m_keyChainRef,
322 passwordLength,
323 password,
324 true);
325 }
326 else if (m_impl->m_passwordSet) {
327 // If no password supplied, then use the configured password if exists.
328 SecKeychainUnlock(m_impl->m_keyChainRef,
329 m_impl->m_password.size(),
330 m_impl->m_password.c_str(),
331 true);
332 }
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800333#ifdef NDN_CXX_HAVE_GETPASS
Yingdi Yu99b2a002015-08-12 12:47:44 -0700334 else if (m_impl->m_inTerminal) {
335 // If no configured password, get password from terminal if inTerminal set.
336 bool isLocked = true;
337 const char* fmt = "Password to unlock the default keychain: ";
338 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700339
Yingdi Yu99b2a002015-08-12 12:47:44 -0700340 while (isLocked) {
341 if (count > 2)
342 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700343
Yingdi Yu99b2a002015-08-12 12:47:44 -0700344 char* getPassword = nullptr;
345 getPassword = getpass(fmt);
346 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700347
Yingdi Yu99b2a002015-08-12 12:47:44 -0700348 if (!getPassword)
349 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700350
Yingdi Yu99b2a002015-08-12 12:47:44 -0700351 res = SecKeychainUnlock(m_impl->m_keyChainRef,
352 strlen(getPassword),
353 getPassword,
354 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700355
Yingdi Yu99b2a002015-08-12 12:47:44 -0700356 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700357
Yingdi Yu99b2a002015-08-12 12:47:44 -0700358 if (res == errSecSuccess)
359 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800360 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700361 }
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800362#endif // NDN_CXX_HAVE_GETPASS
Yingdi Yu99b2a002015-08-12 12:47:44 -0700363 else {
364 // If inTerminal is not set, get the password from GUI.
365 SecKeychainUnlock(m_impl->m_keyChainRef, 0, nullptr, false);
366 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800367
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700368 return !isLocked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800369}
370
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700371void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700372SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName,
373 const KeyParams& params,
374 bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700375{
376
Yingdi Yu99b2a002015-08-12 12:47:44 -0700377 if (doesKeyExistInTpm(keyName, KeyClass::PUBLIC)) {
378 BOOST_THROW_EXCEPTION(Error("keyName already exists"));
379 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800380
Yingdi Yu99b2a002015-08-12 12:47:44 -0700381 string keyNameUri = m_impl->toInternalKeyName(keyName, KeyClass::PUBLIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800382
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();
Yingdi Yu99b2a002015-08-12 12:47:44 -0700395 uint32_t keySize = 0;
396 switch (keyType) {
397 case KeyType::RSA: {
398 const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
399 keySize = rsaParams.getKeySize();
400 break;
401 }
402
403 case KeyType::EC: {
404 const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
405 keySize = ecdsaParams.getKeySize();
406 break;
407 }
408
Yingdi Yu7036ce22014-06-19 18:53:37 -0700409 default:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700410 BOOST_THROW_EXCEPTION(Error("Fail to create a key pair: Unsupported key type"));
Yingdi Yu99b2a002015-08-12 12:47:44 -0700411 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700412
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700413 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800414
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700415 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
416 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
417 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800418
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700419 CFReleaser<SecKeyRef> publicKey, privateKey;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700420 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700421 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(),
422 &publicKey.get(), &privateKey.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800423
Yingdi Yu99b2a002015-08-12 12:47:44 -0700424 if (res == errSecSuccess) {
425 return;
426 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700427
Yingdi Yu99b2a002015-08-12 12:47:44 -0700428 if (res == errSecAuthFailed && !needRetry) {
429 if (unlockTpm(nullptr, 0, false))
430 generateKeyPairInTpmInternal(keyName, params, true);
431 else
432 BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
433 }
434 else {
435 BOOST_THROW_EXCEPTION(Error("Fail to create a key pair"));
436 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800437}
438
439void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700440SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800441{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700442 CFReleaser<CFStringRef> keyLabel =
443 CFStringCreateWithCString(0,
444 keyName.toUri().c_str(),
445 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800446
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700447 CFReleaser<CFMutableDictionaryRef> searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700448 CFDictionaryCreateMutable(0, 5,
449 &kCFTypeDictionaryKeyCallBacks,
450 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800451
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700452 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
453 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
454 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
455 OSStatus res = SecItemDelete(searchDict.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800456
457 if (res == errSecSuccess)
458 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700459
Yingdi Yu99b2a002015-08-12 12:47:44 -0700460 if (res == errSecAuthFailed && !needRetry) {
461 if (unlockTpm(nullptr, 0, false))
462 deleteKeyPairInTpmInternal(keyName, true);
463 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800464}
465
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700466void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700467SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800468{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700469 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported"));
Yingdi Yu99b2a002015-08-12 12:47:44 -0700470 // if (doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800471 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800472
Yingdi Yu99b2a002015-08-12 12:47:44 -0700473 // string keyNameUri = m_impl->toInternalKeyName(keyName, KeyClass::SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800474
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700475 // CFReleaser<CFMutableDictionaryRef> attrDict =
476 // CFDictionaryCreateMutable(kCFAllocatorDefault,
477 // 0,
478 // &kCFTypeDictionaryKeyCallBacks,
479 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800480
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700481 // CFReleaser<CFStringRef> keyLabel =
482 // CFStringCreateWithCString(0,
483 // keyNameUri.c_str(),
484 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800485
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700486 // CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
487
488 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType));
489 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
490 // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue);
491 // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800492
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700493 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800494
Yingdi Yu2e57a582014-02-20 23:34:43 -0800495 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800496
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700497 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800498 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800499}
500
Yingdi Yu2e57a582014-02-20 23:34:43 -0800501shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700502SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800503{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700504 CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName, KeyClass::PUBLIC);
505 if (publicKey == nullptr) {
506 BOOST_THROW_EXCEPTION(Error("Requested public key [" + keyName.toUri() + "] does not exist "
507 "in OSX Keychain"));
508 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800509
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700510 CFReleaser<CFDataRef> exportedKey;
511 OSStatus res = SecItemExport(publicKey.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800512 kSecFormatOpenSSL,
513 0,
Yingdi Yu99b2a002015-08-12 12:47:44 -0700514 nullptr,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700515 &exportedKey.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700516 if (res != errSecSuccess) {
517 BOOST_THROW_EXCEPTION(Error("Cannot export requested public key from OSX Keychain"));
518 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800519
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700520 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey.get()),
521 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800522 return key;
523}
524
Yingdi Yu41546342014-11-30 23:37:53 -0800525std::string
526SecTpmOsx::getScheme()
527{
528 return SCHEME;
529}
530
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800531ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700532SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800533{
534 using namespace CryptoPP;
535
Yingdi Yu99b2a002015-08-12 12:47:44 -0700536 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KeyClass::PRIVATE);
537 if (privateKey == nullptr) {
538 /// @todo Can this happen because of keychain is locked?
539 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
540 "in OSX Keychain"));
541 }
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700542
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700543 shared_ptr<PublicKey> publicKey = getPublicKeyFromTpm(keyName);
544
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700545 CFReleaser<CFDataRef> exportedKey;
546 OSStatus res = SecItemExport(privateKey.get(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800547 kSecFormatOpenSSL,
548 0,
Yingdi Yu99b2a002015-08-12 12:47:44 -0700549 nullptr,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700550 &exportedKey.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800551
Yingdi Yu99b2a002015-08-12 12:47:44 -0700552 if (res != errSecSuccess) {
553 if (res == errSecAuthFailed && !needRetry) {
554 if (unlockTpm(nullptr, 0, false))
555 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800556 else
Yingdi Yu99b2a002015-08-12 12:47:44 -0700557 return nullptr;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800558 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700559 else
560 return nullptr;
561 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800562
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800563 uint32_t version = 0;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700564 OID algorithm;
565 bool hasParameters = false;
566 OID algorithmParameter;
567 switch (publicKey->getKeyType()) {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700568 case KeyType::RSA: {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700569 algorithm = oid::RSA; // "RSA encryption"
570 hasParameters = false;
571 break;
572 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700573
574 case KeyType::EC: {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700575 // "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 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700588
589 default:
590 BOOST_THROW_EXCEPTION(Error("Unsupported key type" +
591 boost::lexical_cast<std::string>(publicKey->getKeyType())));
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700592 }
593
594 OBufferStream pkcs8Os;
595 FileSink sink(pkcs8Os);
596
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800597 SecByteBlock rawKeyBits;
598 // PrivateKeyInfo ::= SEQUENCE {
599 // version INTEGER,
600 // privateKeyAlgorithm SEQUENCE,
601 // privateKey OCTECT STRING}
602 DERSequenceEncoder privateKeyInfo(sink);
603 {
604 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
605 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
606 {
607 algorithm.encode(privateKeyAlgorithm);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700608 if (hasParameters)
609 algorithmParameter.encode(privateKeyAlgorithm);
610 else
611 DEREncodeNull(privateKeyAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800612 }
613 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700614 DEREncodeOctetString(privateKeyInfo,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700615 CFDataGetBytePtr(exportedKey.get()),
616 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800617 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700618 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800619
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700620 return pkcs8Os.buf();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800621}
622
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700623#ifdef __GNUC__
624#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
625#pragma GCC diagnostic push
626#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
627#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
628#endif // __GNUC__
629
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800630bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700631SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700632 const uint8_t* buf, size_t size,
633 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800634{
635 using namespace CryptoPP;
636
637 StringSource privateKeySource(buf, size, true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800638 SecByteBlock rawKeyBits;
639 // PrivateKeyInfo ::= SEQUENCE {
640 // INTEGER,
641 // SEQUENCE,
642 // OCTECT STRING}
643 BERSequenceDecoder privateKeyInfo(privateKeySource);
644 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700645 uint32_t versionNum;
646 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800647 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
648 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700649 OID keyTypeOID;
650 keyTypeOID.decode(sequenceDecoder);
651
652 if (keyTypeOID == oid::RSA)
653 BERDecodeNull(sequenceDecoder);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700654 else if (keyTypeOID == oid::ECDSA) {
655 OID parameterOID;
656 parameterOID.decode(sequenceDecoder);
657 }
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700658 else
659 return false; // Unsupported key type;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800660 }
661 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
662 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700663 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800664
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700665 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
666 rawKeyBits.BytePtr(),
667 rawKeyBits.size(),
668 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800669
670 SecExternalFormat externalFormat = kSecFormatOpenSSL;
671 SecExternalItemType externalType = kSecItemTypePrivateKey;
672 SecKeyImportExportParameters keyParams;
673 memset(&keyParams, 0, sizeof(keyParams));
674 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
675 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700676 CFReleaser<SecAccessRef> access;
677 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
678 keyName.toUri().c_str(),
679 kCFStringEncodingUTF8);
680 SecAccessCreate(keyLabel.get(), 0, &access.get());
681 keyParams.accessRef = access.get();
682 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800683
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700684#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700685#pragma clang diagnostic push
686#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700687#endif // __clang__
688
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700689 OSStatus res = SecKeychainItemImport(importedKey.get(),
690 0,
691 &externalFormat,
692 &externalType,
693 0,
694 &keyParams,
695 m_impl->m_keyChainRef,
696 &outItems.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700697
698#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700699#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700700#endif // __clang__
701
Yingdi Yu99b2a002015-08-12 12:47:44 -0700702 if (res != errSecSuccess) {
703 if (res == errSecAuthFailed && !needRetry) {
704 if (unlockTpm(nullptr, 0, false))
705 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800706 else
707 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800708 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700709 else
710 return false;
711 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800712
Yingdi Yu7036ce22014-06-19 18:53:37 -0700713 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700714 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800715 SecKeychainAttribute attrs[1]; // maximum number of attributes
Yingdi Yu99b2a002015-08-12 12:47:44 -0700716 SecKeychainAttributeList attrList = {0, attrs};
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800717 string keyUri = keyName.toUri();
718 {
719 attrs[attrList.count].tag = kSecKeyPrintName;
720 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700721 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800722 attrList.count++;
723 }
724
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700725 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800726 &attrList,
727 0,
Yingdi Yu99b2a002015-08-12 12:47:44 -0700728 nullptr);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700729
Yingdi Yu99b2a002015-08-12 12:47:44 -0700730 if (res != errSecSuccess) {
731 return false;
732 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700733
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800734 return true;
735}
736
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700737#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
738#pragma GCC diagnostic pop
739#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
740
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800741bool
742SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
743{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700744 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
745 buf,
746 size,
747 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800748
749 SecExternalFormat externalFormat = kSecFormatOpenSSL;
750 SecExternalItemType externalType = kSecItemTypePublicKey;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700751 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800752
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700753 OSStatus res = SecItemImport(importedKey.get(),
754 0,
755 &externalFormat,
756 &externalType,
757 0,
758 0,
759 m_impl->m_keyChainRef,
760 &outItems.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800761
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700762 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800763 return false;
764
Yingdi Yu7036ce22014-06-19 18:53:37 -0700765 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700766 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800767 SecKeychainAttribute attrs[1]; // maximum number of attributes
768 SecKeychainAttributeList attrList = { 0, attrs };
769 string keyUri = keyName.toUri();
770 {
771 attrs[attrList.count].tag = kSecKeyPrintName;
772 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700773 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800774 attrList.count++;
775 }
776
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700777 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800778 &attrList,
779 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700780 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700781
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700782 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800783 return false;
784
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800785 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800786}
787
788Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700789SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
790 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800791{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700792 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
793 data,
794 dataLength,
795 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800796
Yingdi Yu99b2a002015-08-12 12:47:44 -0700797 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KeyClass::PRIVATE);
798 if (privateKey == nullptr) {
799 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
800 "in OSX Keychain"));
801 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700802
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700803 CFReleaser<CFErrorRef> error;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700804 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700805 CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
806 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700807 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700808 BOOST_THROW_EXCEPTION(Error("Fail to create signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800809
810 // Set input
Yingdi Yu7036ce22014-06-19 18:53:37 -0700811 SecTransformSetAttribute(signer.get(),
812 kSecTransformInputAttributeName,
813 dataRef.get(),
814 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700815 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700816 BOOST_THROW_EXCEPTION(Error("Fail to configure input of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800817
818 // Enable use of padding
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700819 SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800820 kSecPaddingKey,
821 kSecPaddingPKCS1Key,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700822 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700823 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700824 BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800825
826 // Set padding type
Yingdi Yu7036ce22014-06-19 18:53:37 -0700827 SecTransformSetAttribute(signer.get(),
828 kSecDigestTypeAttribute,
829 m_impl->getDigestAlgorithm(digestAlgorithm),
830 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700831 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700832 BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800833
834 // Set padding attribute
835 long digestSize = m_impl->getDigestSize(digestAlgorithm);
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700836 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700837 SecTransformSetAttribute(signer.get(),
838 kSecDigestLengthAttribute,
839 cfDigestSize.get(),
840 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700841 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700842 BOOST_THROW_EXCEPTION(Error("Fail to configure digest size of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800843
844 // Actually sign
Yingdi Yu7036ce22014-06-19 18:53:37 -0700845 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700846 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700847 if (error != nullptr) {
848 if (!needRetry) {
849 if (unlockTpm(nullptr, 0, false))
850 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800851 else
Yingdi Yu99b2a002015-08-12 12:47:44 -0700852 BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
Yingdi Yube4150e2014-02-18 13:02:46 -0800853 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700854 else {
855 CFShow(error.get());
856 BOOST_THROW_EXCEPTION(Error("Fail to sign data"));
857 }
858 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800859
Yingdi Yu99b2a002015-08-12 12:47:44 -0700860 if (signature == nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700861 BOOST_THROW_EXCEPTION(Error("Signature is NULL!\n"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800862
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600863 return Block(tlv::SignatureValue,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700864 make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
865 CFDataGetLength(signature.get())));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800866}
867
868ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700869SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800870{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700871 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::decryptInTpm is not supported"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800872
Yingdi Yu2e57a582014-02-20 23:34:43 -0800873 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700874 // if (sym)
Yingdi Yu99b2a002015-08-12 12:47:44 -0700875 // keyClass = KeyClass::SYMMETRIC;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800876 // else
Yingdi Yu99b2a002015-08-12 12:47:44 -0700877 // keyClass = KeyClass::PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800878
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700879 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800880 // reinterpret_cast<const unsigned char*>(data),
881 // dataLength
882 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800883
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700884 // CFReleaser<SecKeyRef> decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700885 // if (decryptKey == nullptr)
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700886 // {
887 // /// @todo Can this happen because of keychain is locked?
888 // throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain");
889 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800890
Yingdi Yu2e57a582014-02-20 23:34:43 -0800891 // CFErrorRef error;
892 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
893 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800894
Yingdi Yu2e57a582014-02-20 23:34:43 -0800895 // Boolean set_res = SecTransformSetAttribute(decrypt,
896 // kSecTransformInputAttributeName,
897 // dataRef,
898 // &error);
899 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800900
Yingdi Yu2e57a582014-02-20 23:34:43 -0800901 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
902 // if (error)
903 // {
904 // CFShow(error);
905 // throw Error("Fail to decrypt data");
906 // }
907 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800908
Yingdi Yu2e57a582014-02-20 23:34:43 -0800909 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800910}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700911
Yingdi Yu2e57a582014-02-20 23:34:43 -0800912void
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700913SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800914{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700915 if (keyClass == KeyClass::PRIVATE && acl == AclType::PRIVATE) {
916 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
917 if (privateKey == nullptr) {
918 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
919 "in OSX Keychain"));
Yingdi Yu2e57a582014-02-20 23:34:43 -0800920 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700921
922 CFReleaser<SecAccessRef> accRef;
923 SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
924
925 CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
926 kSecACLAuthorizationSign);
927
928 // C-style cast is used as per Apple convention
929 SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
930
931 CFReleaser<CFArrayRef> appList;
932 CFReleaser<CFStringRef> description;
933 SecKeychainPromptSelector promptSelector;
934 SecACLCopyContents(aclRef,
935 &appList.get(),
936 &description.get(),
937 &promptSelector);
938
939 CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
940 0,
941 appList.get());
942
943 CFReleaser<SecTrustedApplicationRef> trustedApp;
944 SecTrustedApplicationCreateFromPath(appPath.c_str(),
945 &trustedApp.get());
946
947 CFArrayAppendValue(newAppList.get(), trustedApp.get());
948
949 SecACLSetContents(aclRef,
950 newAppList.get(),
951 description.get(),
952 promptSelector);
953
954 SecKeychainItemSetAccess(privateKey.get(), accRef.get());
955 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800956}
957
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800958ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700959SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800960{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700961 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::encryptInTpm is not supported"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800962
Yingdi Yu2e57a582014-02-20 23:34:43 -0800963 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700964 // if (sym)
Yingdi Yu99b2a002015-08-12 12:47:44 -0700965 // keyClass = KeyClass::SYMMETRIC;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800966 // else
Yingdi Yu99b2a002015-08-12 12:47:44 -0700967 // keyClass = KeyClass::PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700968
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700969 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800970 // reinterpret_cast<const unsigned char*>(data),
971 // dataLength
972 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700973
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700974 // CFReleaser<SecKeyRef> encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700975 // if (encryptKey == nullptr)
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700976 // {
977 // throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain");
978 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800979
Yingdi Yu2e57a582014-02-20 23:34:43 -0800980 // CFErrorRef error;
981 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
982 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800983
Yingdi Yu2e57a582014-02-20 23:34:43 -0800984 // Boolean set_res = SecTransformSetAttribute(encrypt,
985 // kSecTransformInputAttributeName,
986 // dataRef,
987 // &error);
988 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800989
Yingdi Yu2e57a582014-02-20 23:34:43 -0800990 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
991 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800992
Yingdi Yu2e57a582014-02-20 23:34:43 -0800993 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800994
Yingdi Yu2e57a582014-02-20 23:34:43 -0800995 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800996}
997
998bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700999SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001000{
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001001 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
1002
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001003 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1004 keyNameUri.c_str(),
1005 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001006
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001007 CFReleaser<CFMutableDictionaryRef> attrDict =
1008 CFDictionaryCreateMutable(0,
1009 4,
1010 &kCFTypeDictionaryKeyCallBacks,
1011 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001012
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001013 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1014 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
1015 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1016 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001017
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001018 CFReleaser<SecKeychainItemRef> itemRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001019 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001020 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001021
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001022 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001023 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -08001024 else
1025 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001026
1027}
1028
Yingdi Yu4b752752014-02-18 12:24:03 -08001029bool
1030SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
1031{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001032 return SecRandomCopyBytes(kSecRandomDefault, size, res) == 0;
Yingdi Yu4b752752014-02-18 12:24:03 -08001033}
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001034
1035////////////////////////////////
1036// OSXPrivateKeyStorage::Impl //
1037////////////////////////////////
1038
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001039CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001040SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001041{
1042 string keyNameUri = toInternalKeyName(keyName, keyClass);
1043
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001044 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1045 keyNameUri.c_str(),
1046 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001047
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001048 CFReleaser<CFMutableDictionaryRef> attrDict =
1049 CFDictionaryCreateMutable(0,
1050 5,
1051 &kCFTypeDictionaryKeyCallBacks,
1052 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001053
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001054 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1055 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1056 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
1057 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001058
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001059 CFReleaser<SecKeychainItemRef> keyItem;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001060 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001061 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001062
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001063 if (res != errSecSuccess)
1064 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001065 else
1066 return keyItem;
1067}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001068
1069string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001070SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001071{
1072 string keyUri = keyName.toUri();
1073
Yingdi Yu99b2a002015-08-12 12:47:44 -07001074 if (KeyClass::SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001075 return keyUri + "/symmetric";
1076 else
1077 return keyUri;
1078}
1079
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001080CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001081SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
1082{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001083 switch (keyType) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001084 case KeyType::RSA:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001085 return kSecAttrKeyTypeRSA;
Yingdi Yu99b2a002015-08-12 12:47:44 -07001086 case KeyType::EC:
Yingdi Yuc8f883c2014-06-20 23:25:22 -07001087 return kSecAttrKeyTypeECDSA;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001088 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001089 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001090 }
1091}
1092
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001093CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001094SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
1095{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001096 switch (keyType) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001097 case KeyType::AES:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001098 return kSecAttrKeyTypeAES;
1099 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001100 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001101 }
1102}
1103
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001104CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001105SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
1106{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001107 switch (keyClass) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001108 case KeyClass::PRIVATE:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001109 return kSecAttrKeyClassPrivate;
Yingdi Yu99b2a002015-08-12 12:47:44 -07001110 case KeyClass::PUBLIC:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001111 return kSecAttrKeyClassPublic;
Yingdi Yu99b2a002015-08-12 12:47:44 -07001112 case KeyClass::SYMMETRIC:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001113 return kSecAttrKeyClassSymmetric;
1114 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001115 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001116 }
1117}
1118
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001119CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001120SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
1121{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001122 switch (digestAlgo) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001123 case DigestAlgorithm::SHA256:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001124 return kSecDigestSHA2;
1125 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001126 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001127 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001128}
Jeff Thompson2747dc02013-10-04 19:11:34 -07001129
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001130long
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001131SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
1132{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001133 switch (digestAlgo) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001134 case DigestAlgorithm::SHA256:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001135 return 256;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001136 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001137 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001138 }
Jeff Thompson2747dc02013-10-04 19:11:34 -07001139}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001140
Yingdi Yufc40d872014-02-18 12:56:04 -08001141} // namespace ndn