blob: 671a6f1839b07fff1893f6462f7de51aec1400de [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"
Alexander Afanasyev2fa59392016-07-29 17:24:23 -070025#include "v1/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"
Alexander Afanasyev2fa59392016-07-29 17:24:23 -070029#include "v1/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 {
Alexander Afanasyev2fa59392016-07-29 17:24:23 -070046namespace security {
Yingdi Yufc40d872014-02-18 12:56:04 -080047
Yingdi Yu7036ce22014-06-19 18:53:37 -070048using std::string;
49
Alexander Afanasyev07113802015-01-15 19:14:36 -080050const std::string SecTpmOsx::SCHEME("tpm-osxkeychain");
Yingdi Yu41546342014-11-30 23:37:53 -080051
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070052/**
53 * @brief Helper class to wrap CoreFoundation object pointers
54 *
55 * The class is similar in spirit to shared_ptr, but uses CoreFoundation
56 * mechanisms to retain/release object.
57 *
58 * Original implementation by Christopher Hunt and it was borrowed from
59 * http://www.cocoabuilder.com/archive/cocoa/130776-auto-cfrelease-and.html
60 */
61template<class T>
62class CFReleaser
63{
64public:
65 //////////////////////////////
66 // Construction/destruction //
67
68 CFReleaser()
Yingdi Yu99b2a002015-08-12 12:47:44 -070069 : m_typeRef(nullptr)
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070070 {
71 }
72
73 CFReleaser(const T& typeRef)
74 : m_typeRef(typeRef)
75 {
76 }
77
78 CFReleaser(const CFReleaser& inReleaser)
Yingdi Yu99b2a002015-08-12 12:47:44 -070079 : m_typeRef(nullptr)
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070080 {
81 retain(inReleaser.m_typeRef);
82 }
83
84 CFReleaser&
85 operator=(const T& typeRef)
86 {
87 if (typeRef != m_typeRef) {
88 release();
89 m_typeRef = typeRef;
90 }
91 return *this;
92 }
93
94 CFReleaser&
95 operator=(const CFReleaser& inReleaser)
96 {
97 retain(inReleaser.m_typeRef);
98 return *this;
99 }
100
101 ~CFReleaser()
102 {
103 release();
104 }
105
106 ////////////
107 // Access //
108
109 // operator const T&() const
110 // {
111 // return m_typeRef;
112 // }
113
114 // operator T&()
115 // {
116 // return m_typeRef;
117 // }
118
119 const T&
120 get() const
121 {
122 return m_typeRef;
123 }
124
125 T&
126 get()
127 {
128 return m_typeRef;
129 }
130
131 ///////////////////
132 // Miscellaneous //
133
134 void
135 retain(const T& typeRef)
136 {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700137 if (typeRef != nullptr) {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700138 CFRetain(typeRef);
139 }
140 release();
141 m_typeRef = typeRef;
142 }
143
Yingdi Yu99b2a002015-08-12 12:47:44 -0700144 void
145 release()
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700146 {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700147 if (m_typeRef != nullptr) {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700148 CFRelease(m_typeRef);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700149 m_typeRef = nullptr;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700150 }
151 };
152
Yingdi Yu99b2a002015-08-12 12:47:44 -0700153 bool
154 operator==(std::nullptr_t)
155 {
156 return get() == nullptr;
157 }
158
159 bool
160 operator!=(std::nullptr_t)
161 {
162 return get() != nullptr;
163 }
164
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700165private:
166 T m_typeRef;
167};
168
169
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700170class SecTpmOsx::Impl
171{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800172public:
173 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -0800174 : m_passwordSet(false)
175 , m_inTerminal(false)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700176 {
177 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700178
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800179 /**
180 * @brief Convert NDN name of a key to internal name of the key.
181 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800182 * @return the internal key name
183 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700184 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700185 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700186
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800187 /**
188 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -0800189 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800190 * @returns pointer to the key
191 */
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700192 CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700193 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700194
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800195 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800196 * @brief Convert keyType to MAC OS symmetric key key type
197 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800198 * @returns MAC OS key type
199 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300200 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800201 getSymKeyType(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 keyType to MAC OS asymmetirc key type
205 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800206 * @returns MAC OS key type
207 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300208 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800209 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700210
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800211 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800212 * @brief Convert keyClass to MAC OS key class
213 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800214 * @returns MAC OS key class
215 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300216 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800217 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700218
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800219 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800220 * @brief Convert digestAlgo to MAC OS algorithm id
221 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800222 * @returns MAC OS algorithm id
223 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300224 CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800225 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700226
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800227 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800228 * @brief Get the digest size of the corresponding algorithm
229 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800230 * @return digest size
231 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700232 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800233 getDigestSize(DigestAlgorithm digestAlgo);
234
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800235 ///////////////////////////////////////////////
236 // everything here is public, including data //
237 ///////////////////////////////////////////////
238public:
239 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800240 bool m_passwordSet;
241 string m_password;
242 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800243};
244
Yingdi Yu41546342014-11-30 23:37:53 -0800245SecTpmOsx::SecTpmOsx(const std::string& location)
246 : SecTpm(location)
247 , m_impl(new Impl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800248{
Yingdi Yu41546342014-11-30 23:37:53 -0800249 // TODO: add location support
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700250 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700251 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800252 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700253 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800254
Yingdi Yube4150e2014-02-18 13:02:46 -0800255 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700256
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800257 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700258 BOOST_THROW_EXCEPTION(Error("No default keychain, please create one first"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800259}
260
Yingdi Yu41546342014-11-30 23:37:53 -0800261SecTpmOsx::~SecTpmOsx()
262{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800263}
264
Yingdi Yube4150e2014-02-18 13:02:46 -0800265void
266SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
267{
268 m_impl->m_passwordSet = true;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700269 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800270 m_impl->m_password.clear();
271 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
272}
273
274void
275SecTpmOsx::resetTpmPassword()
276{
277 m_impl->m_passwordSet = false;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700278 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800279 m_impl->m_password.clear();
280}
281
282void
283SecTpmOsx::setInTerminal(bool inTerminal)
284{
285 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700286 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700287 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800288 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700289 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800290}
291
292bool
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700293SecTpmOsx::getInTerminal() const
Yingdi Yube4150e2014-02-18 13:02:46 -0800294{
295 return m_impl->m_inTerminal;
296}
297
298bool
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700299SecTpmOsx::isLocked()
Yingdi Yube4150e2014-02-18 13:02:46 -0800300{
301 SecKeychainStatus keychainStatus;
302
303 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700304 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800305 return true;
306 else
307 return ((kSecUnlockStateStatus & keychainStatus) == 0);
308}
309
Yingdi Yu2e57a582014-02-20 23:34:43 -0800310bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800311SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
312{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700313 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800314
315 // If the default key chain is already unlocked, return immediately.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700316 if (!isLocked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800317 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800318
319 // If the default key chain is locked, unlock the key chain.
Yingdi Yu99b2a002015-08-12 12:47:44 -0700320 if (usePassword) {
321 // Use the supplied password.
322 res = SecKeychainUnlock(m_impl->m_keyChainRef,
323 passwordLength,
324 password,
325 true);
326 }
327 else if (m_impl->m_passwordSet) {
328 // If no password supplied, then use the configured password if exists.
329 SecKeychainUnlock(m_impl->m_keyChainRef,
330 m_impl->m_password.size(),
331 m_impl->m_password.c_str(),
332 true);
333 }
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800334#ifdef NDN_CXX_HAVE_GETPASS
Yingdi Yu99b2a002015-08-12 12:47:44 -0700335 else if (m_impl->m_inTerminal) {
336 // If no configured password, get password from terminal if inTerminal set.
337 bool isLocked = true;
338 const char* fmt = "Password to unlock the default keychain: ";
339 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700340
Yingdi Yu99b2a002015-08-12 12:47:44 -0700341 while (isLocked) {
342 if (count > 2)
343 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700344
Yingdi Yu99b2a002015-08-12 12:47:44 -0700345 char* getPassword = nullptr;
346 getPassword = getpass(fmt);
347 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700348
Yingdi Yu99b2a002015-08-12 12:47:44 -0700349 if (!getPassword)
350 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700351
Yingdi Yu99b2a002015-08-12 12:47:44 -0700352 res = SecKeychainUnlock(m_impl->m_keyChainRef,
353 strlen(getPassword),
354 getPassword,
355 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700356
Yingdi Yu99b2a002015-08-12 12:47:44 -0700357 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700358
Yingdi Yu99b2a002015-08-12 12:47:44 -0700359 if (res == errSecSuccess)
360 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800361 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700362 }
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800363#endif // NDN_CXX_HAVE_GETPASS
Yingdi Yu99b2a002015-08-12 12:47:44 -0700364 else {
365 // If inTerminal is not set, get the password from GUI.
366 SecKeychainUnlock(m_impl->m_keyChainRef, 0, nullptr, false);
367 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800368
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700369 return !isLocked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800370}
371
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700372void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700373SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName,
374 const KeyParams& params,
375 bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700376{
377
Yingdi Yu99b2a002015-08-12 12:47:44 -0700378 if (doesKeyExistInTpm(keyName, KeyClass::PUBLIC)) {
379 BOOST_THROW_EXCEPTION(Error("keyName already exists"));
380 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800381
Yingdi Yu99b2a002015-08-12 12:47:44 -0700382 string keyNameUri = m_impl->toInternalKeyName(keyName, KeyClass::PUBLIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800383
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700384 CFReleaser<CFStringRef> keyLabel =
385 CFStringCreateWithCString(0,
386 keyNameUri.c_str(),
387 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800388
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700389 CFReleaser<CFMutableDictionaryRef> attrDict =
390 CFDictionaryCreateMutable(0,
391 3,
392 &kCFTypeDictionaryKeyCallBacks,
393 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700394
Yingdi Yu7036ce22014-06-19 18:53:37 -0700395 KeyType keyType = params.getKeyType();
Yingdi Yu99b2a002015-08-12 12:47:44 -0700396 uint32_t keySize = 0;
397 switch (keyType) {
398 case KeyType::RSA: {
399 const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
400 keySize = rsaParams.getKeySize();
401 break;
402 }
403
404 case KeyType::EC: {
405 const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
406 keySize = ecdsaParams.getKeySize();
407 break;
408 }
409
Yingdi Yu7036ce22014-06-19 18:53:37 -0700410 default:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700411 BOOST_THROW_EXCEPTION(Error("Fail to create a key pair: Unsupported key type"));
Yingdi Yu99b2a002015-08-12 12:47:44 -0700412 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700413
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 Yu99b2a002015-08-12 12:47:44 -0700425 if (res == errSecSuccess) {
426 return;
427 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700428
Yingdi Yu99b2a002015-08-12 12:47:44 -0700429 if (res == errSecAuthFailed && !needRetry) {
430 if (unlockTpm(nullptr, 0, false))
431 generateKeyPairInTpmInternal(keyName, params, true);
432 else
433 BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
434 }
435 else {
436 BOOST_THROW_EXCEPTION(Error("Fail to create a key pair"));
437 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800438}
439
440void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700441SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800442{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700443 CFReleaser<CFStringRef> keyLabel =
444 CFStringCreateWithCString(0,
445 keyName.toUri().c_str(),
446 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800447
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700448 CFReleaser<CFMutableDictionaryRef> searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700449 CFDictionaryCreateMutable(0, 5,
450 &kCFTypeDictionaryKeyCallBacks,
451 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800452
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700453 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
454 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
455 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
456 OSStatus res = SecItemDelete(searchDict.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800457
458 if (res == errSecSuccess)
459 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700460
Yingdi Yu99b2a002015-08-12 12:47:44 -0700461 if (res == errSecAuthFailed && !needRetry) {
462 if (unlockTpm(nullptr, 0, false))
463 deleteKeyPairInTpmInternal(keyName, true);
464 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800465}
466
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700467void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700468SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800469{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700470 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported"));
Yingdi Yu99b2a002015-08-12 12:47:44 -0700471 // if (doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800472 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800473
Yingdi Yu99b2a002015-08-12 12:47:44 -0700474 // string keyNameUri = m_impl->toInternalKeyName(keyName, KeyClass::SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800475
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700476 // CFReleaser<CFMutableDictionaryRef> attrDict =
477 // CFDictionaryCreateMutable(kCFAllocatorDefault,
478 // 0,
479 // &kCFTypeDictionaryKeyCallBacks,
480 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800481
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700482 // CFReleaser<CFStringRef> keyLabel =
483 // CFStringCreateWithCString(0,
484 // keyNameUri.c_str(),
485 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800486
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700487 // CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
488
489 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType));
490 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
491 // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue);
492 // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800493
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700494 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800495
Yingdi Yu2e57a582014-02-20 23:34:43 -0800496 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800497
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700498 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800499 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800500}
501
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700502shared_ptr<v1::PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700503SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800504{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700505 CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName, KeyClass::PUBLIC);
506 if (publicKey == nullptr) {
507 BOOST_THROW_EXCEPTION(Error("Requested public key [" + keyName.toUri() + "] does not exist "
508 "in OSX Keychain"));
509 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800510
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700511 CFReleaser<CFDataRef> exportedKey;
512 OSStatus res = SecItemExport(publicKey.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800513 kSecFormatOpenSSL,
514 0,
Yingdi Yu99b2a002015-08-12 12:47:44 -0700515 nullptr,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700516 &exportedKey.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700517 if (res != errSecSuccess) {
518 BOOST_THROW_EXCEPTION(Error("Cannot export requested public key from OSX Keychain"));
519 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800520
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700521 shared_ptr<v1::PublicKey> key = make_shared<v1::PublicKey>(CFDataGetBytePtr(exportedKey.get()),
522 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800523 return key;
524}
525
Yingdi Yu41546342014-11-30 23:37:53 -0800526std::string
527SecTpmOsx::getScheme()
528{
529 return SCHEME;
530}
531
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800532ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700533SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800534{
535 using namespace CryptoPP;
536
Yingdi Yu99b2a002015-08-12 12:47:44 -0700537 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KeyClass::PRIVATE);
538 if (privateKey == nullptr) {
539 /// @todo Can this happen because of keychain is locked?
540 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
541 "in OSX Keychain"));
542 }
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700543
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700544 shared_ptr<v1::PublicKey> publicKey = getPublicKeyFromTpm(keyName);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700545
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700546 CFReleaser<CFDataRef> exportedKey;
547 OSStatus res = SecItemExport(privateKey.get(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800548 kSecFormatOpenSSL,
549 0,
Yingdi Yu99b2a002015-08-12 12:47:44 -0700550 nullptr,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700551 &exportedKey.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800552
Yingdi Yu99b2a002015-08-12 12:47:44 -0700553 if (res != errSecSuccess) {
554 if (res == errSecAuthFailed && !needRetry) {
555 if (unlockTpm(nullptr, 0, false))
556 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800557 else
Yingdi Yu99b2a002015-08-12 12:47:44 -0700558 return nullptr;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800559 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700560 else
561 return nullptr;
562 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800563
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800564 uint32_t version = 0;
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700565 Oid algorithm;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700566 bool hasParameters = false;
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700567 Oid algorithmParameter;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700568 switch (publicKey->getKeyType()) {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700569 case KeyType::RSA: {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700570 algorithm = oid::RSA; // "RSA encryption"
571 hasParameters = false;
572 break;
573 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700574
575 case KeyType::EC: {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700576 // "ECDSA encryption"
577 StringSource src(publicKey->get().buf(), publicKey->get().size(), true);
578 BERSequenceDecoder subjectPublicKeyInfo(src);
579 {
580 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
581 {
582 algorithm.decode(algorithmInfo);
583 algorithmParameter.decode(algorithmInfo);
584 }
585 }
586 hasParameters = true;
587 break;
588 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700589
590 default:
591 BOOST_THROW_EXCEPTION(Error("Unsupported key type" +
592 boost::lexical_cast<std::string>(publicKey->getKeyType())));
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700593 }
594
595 OBufferStream pkcs8Os;
596 FileSink sink(pkcs8Os);
597
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800598 SecByteBlock rawKeyBits;
599 // PrivateKeyInfo ::= SEQUENCE {
600 // version INTEGER,
601 // privateKeyAlgorithm SEQUENCE,
602 // privateKey OCTECT STRING}
603 DERSequenceEncoder privateKeyInfo(sink);
604 {
605 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
606 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
607 {
608 algorithm.encode(privateKeyAlgorithm);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700609 if (hasParameters)
610 algorithmParameter.encode(privateKeyAlgorithm);
611 else
612 DEREncodeNull(privateKeyAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800613 }
614 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700615 DEREncodeOctetString(privateKeyInfo,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700616 CFDataGetBytePtr(exportedKey.get()),
617 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800618 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700619 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800620
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700621 return pkcs8Os.buf();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800622}
623
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700624#ifdef __GNUC__
625#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
626#pragma GCC diagnostic push
627#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
628#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
629#endif // __GNUC__
630
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800631bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700632SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700633 const uint8_t* buf, size_t size,
634 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800635{
636 using namespace CryptoPP;
637
638 StringSource privateKeySource(buf, size, true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800639 SecByteBlock rawKeyBits;
640 // PrivateKeyInfo ::= SEQUENCE {
641 // INTEGER,
642 // SEQUENCE,
643 // OCTECT STRING}
644 BERSequenceDecoder privateKeyInfo(privateKeySource);
645 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700646 uint32_t versionNum;
647 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800648 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
649 {
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700650 Oid keyTypeOid;
651 keyTypeOid.decode(sequenceDecoder);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700652
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700653 if (keyTypeOid == oid::RSA)
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700654 BERDecodeNull(sequenceDecoder);
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700655 else if (keyTypeOid == oid::ECDSA) {
656 Oid parameterOid;
657 parameterOid.decode(sequenceDecoder);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700658 }
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700659 else
660 return false; // Unsupported key type;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800661 }
662 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
663 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700664 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800665
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700666 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
667 rawKeyBits.BytePtr(),
668 rawKeyBits.size(),
669 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800670
671 SecExternalFormat externalFormat = kSecFormatOpenSSL;
672 SecExternalItemType externalType = kSecItemTypePrivateKey;
673 SecKeyImportExportParameters keyParams;
674 memset(&keyParams, 0, sizeof(keyParams));
675 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
676 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700677 CFReleaser<SecAccessRef> access;
678 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
679 keyName.toUri().c_str(),
680 kCFStringEncodingUTF8);
681 SecAccessCreate(keyLabel.get(), 0, &access.get());
682 keyParams.accessRef = access.get();
683 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800684
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700685#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700686#pragma clang diagnostic push
687#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700688#endif // __clang__
689
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700690 OSStatus res = SecKeychainItemImport(importedKey.get(),
691 0,
692 &externalFormat,
693 &externalType,
694 0,
695 &keyParams,
696 m_impl->m_keyChainRef,
697 &outItems.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700698
699#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700700#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700701#endif // __clang__
702
Yingdi Yu99b2a002015-08-12 12:47:44 -0700703 if (res != errSecSuccess) {
704 if (res == errSecAuthFailed && !needRetry) {
705 if (unlockTpm(nullptr, 0, false))
706 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800707 else
708 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800709 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700710 else
711 return false;
712 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800713
Yingdi Yu7036ce22014-06-19 18:53:37 -0700714 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700715 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800716 SecKeychainAttribute attrs[1]; // maximum number of attributes
Yingdi Yu99b2a002015-08-12 12:47:44 -0700717 SecKeychainAttributeList attrList = {0, attrs};
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800718 string keyUri = keyName.toUri();
719 {
720 attrs[attrList.count].tag = kSecKeyPrintName;
721 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700722 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800723 attrList.count++;
724 }
725
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700726 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800727 &attrList,
728 0,
Yingdi Yu99b2a002015-08-12 12:47:44 -0700729 nullptr);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700730
Yingdi Yu99b2a002015-08-12 12:47:44 -0700731 if (res != errSecSuccess) {
732 return false;
733 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700734
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800735 return true;
736}
737
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700738#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
739#pragma GCC diagnostic pop
740#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
741
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800742bool
743SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
744{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700745 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
746 buf,
747 size,
748 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800749
750 SecExternalFormat externalFormat = kSecFormatOpenSSL;
751 SecExternalItemType externalType = kSecItemTypePublicKey;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700752 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800753
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700754 OSStatus res = SecItemImport(importedKey.get(),
755 0,
756 &externalFormat,
757 &externalType,
758 0,
759 0,
760 m_impl->m_keyChainRef,
761 &outItems.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800762
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700763 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800764 return false;
765
Yingdi Yu7036ce22014-06-19 18:53:37 -0700766 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700767 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800768 SecKeychainAttribute attrs[1]; // maximum number of attributes
769 SecKeychainAttributeList attrList = { 0, attrs };
770 string keyUri = keyName.toUri();
771 {
772 attrs[attrList.count].tag = kSecKeyPrintName;
773 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700774 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800775 attrList.count++;
776 }
777
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700778 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800779 &attrList,
780 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700781 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700782
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700783 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800784 return false;
785
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800786 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800787}
788
789Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700790SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
791 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800792{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700793 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
794 data,
795 dataLength,
796 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800797
Yingdi Yu99b2a002015-08-12 12:47:44 -0700798 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KeyClass::PRIVATE);
799 if (privateKey == nullptr) {
800 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
801 "in OSX Keychain"));
802 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700803
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700804 CFReleaser<CFErrorRef> error;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700805 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700806 CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
807 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700808 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700809 BOOST_THROW_EXCEPTION(Error("Fail to create signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800810
811 // Set input
Yingdi Yu7036ce22014-06-19 18:53:37 -0700812 SecTransformSetAttribute(signer.get(),
813 kSecTransformInputAttributeName,
814 dataRef.get(),
815 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700816 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700817 BOOST_THROW_EXCEPTION(Error("Fail to configure input of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800818
819 // Enable use of padding
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700820 SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800821 kSecPaddingKey,
822 kSecPaddingPKCS1Key,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700823 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700824 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700825 BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800826
827 // Set padding type
Yingdi Yu7036ce22014-06-19 18:53:37 -0700828 SecTransformSetAttribute(signer.get(),
829 kSecDigestTypeAttribute,
830 m_impl->getDigestAlgorithm(digestAlgorithm),
831 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700832 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700833 BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800834
835 // Set padding attribute
836 long digestSize = m_impl->getDigestSize(digestAlgorithm);
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700837 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700838 SecTransformSetAttribute(signer.get(),
839 kSecDigestLengthAttribute,
840 cfDigestSize.get(),
841 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700842 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700843 BOOST_THROW_EXCEPTION(Error("Fail to configure digest size of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800844
845 // Actually sign
Yingdi Yu7036ce22014-06-19 18:53:37 -0700846 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700847 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700848 if (error != nullptr) {
849 if (!needRetry) {
850 if (unlockTpm(nullptr, 0, false))
851 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800852 else
Yingdi Yu99b2a002015-08-12 12:47:44 -0700853 BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
Yingdi Yube4150e2014-02-18 13:02:46 -0800854 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700855 else {
856 CFShow(error.get());
857 BOOST_THROW_EXCEPTION(Error("Fail to sign data"));
858 }
859 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800860
Yingdi Yu99b2a002015-08-12 12:47:44 -0700861 if (signature == nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700862 BOOST_THROW_EXCEPTION(Error("Signature is NULL!\n"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800863
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600864 return Block(tlv::SignatureValue,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700865 make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
866 CFDataGetLength(signature.get())));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800867}
868
869ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700870SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800871{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700872 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::decryptInTpm is not supported"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800873
Yingdi Yu2e57a582014-02-20 23:34:43 -0800874 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700875 // if (sym)
Yingdi Yu99b2a002015-08-12 12:47:44 -0700876 // keyClass = KeyClass::SYMMETRIC;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800877 // else
Yingdi Yu99b2a002015-08-12 12:47:44 -0700878 // keyClass = KeyClass::PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800879
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700880 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800881 // reinterpret_cast<const unsigned char*>(data),
882 // dataLength
883 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800884
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700885 // CFReleaser<SecKeyRef> decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700886 // if (decryptKey == nullptr)
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700887 // {
888 // /// @todo Can this happen because of keychain is locked?
889 // throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain");
890 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800891
Yingdi Yu2e57a582014-02-20 23:34:43 -0800892 // CFErrorRef error;
893 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
894 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800895
Yingdi Yu2e57a582014-02-20 23:34:43 -0800896 // Boolean set_res = SecTransformSetAttribute(decrypt,
897 // kSecTransformInputAttributeName,
898 // dataRef,
899 // &error);
900 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800901
Yingdi Yu2e57a582014-02-20 23:34:43 -0800902 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
903 // if (error)
904 // {
905 // CFShow(error);
906 // throw Error("Fail to decrypt data");
907 // }
908 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800909
Yingdi Yu2e57a582014-02-20 23:34:43 -0800910 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800911}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700912
Yingdi Yu2e57a582014-02-20 23:34:43 -0800913void
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700914SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800915{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700916 if (keyClass == KeyClass::PRIVATE && acl == AclType::PRIVATE) {
917 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
918 if (privateKey == nullptr) {
919 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
920 "in OSX Keychain"));
Yingdi Yu2e57a582014-02-20 23:34:43 -0800921 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700922
923 CFReleaser<SecAccessRef> accRef;
924 SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
925
926 CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
927 kSecACLAuthorizationSign);
928
929 // C-style cast is used as per Apple convention
930 SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
931
932 CFReleaser<CFArrayRef> appList;
933 CFReleaser<CFStringRef> description;
934 SecKeychainPromptSelector promptSelector;
935 SecACLCopyContents(aclRef,
936 &appList.get(),
937 &description.get(),
938 &promptSelector);
939
940 CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
941 0,
942 appList.get());
943
944 CFReleaser<SecTrustedApplicationRef> trustedApp;
945 SecTrustedApplicationCreateFromPath(appPath.c_str(),
946 &trustedApp.get());
947
948 CFArrayAppendValue(newAppList.get(), trustedApp.get());
949
950 SecACLSetContents(aclRef,
951 newAppList.get(),
952 description.get(),
953 promptSelector);
954
955 SecKeychainItemSetAccess(privateKey.get(), accRef.get());
956 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800957}
958
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800959ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700960SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800961{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700962 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::encryptInTpm is not supported"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800963
Yingdi Yu2e57a582014-02-20 23:34:43 -0800964 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700965 // if (sym)
Yingdi Yu99b2a002015-08-12 12:47:44 -0700966 // keyClass = KeyClass::SYMMETRIC;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800967 // else
Yingdi Yu99b2a002015-08-12 12:47:44 -0700968 // keyClass = KeyClass::PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700969
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700970 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800971 // reinterpret_cast<const unsigned char*>(data),
972 // dataLength
973 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700974
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700975 // CFReleaser<SecKeyRef> encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700976 // if (encryptKey == nullptr)
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700977 // {
978 // throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain");
979 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800980
Yingdi Yu2e57a582014-02-20 23:34:43 -0800981 // CFErrorRef error;
982 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
983 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800984
Yingdi Yu2e57a582014-02-20 23:34:43 -0800985 // Boolean set_res = SecTransformSetAttribute(encrypt,
986 // kSecTransformInputAttributeName,
987 // dataRef,
988 // &error);
989 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800990
Yingdi Yu2e57a582014-02-20 23:34:43 -0800991 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
992 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800993
Yingdi Yu2e57a582014-02-20 23:34:43 -0800994 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800995
Yingdi Yu2e57a582014-02-20 23:34:43 -0800996 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800997}
998
999bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001000SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001001{
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001002 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
1003
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001004 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1005 keyNameUri.c_str(),
1006 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001007
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001008 CFReleaser<CFMutableDictionaryRef> attrDict =
1009 CFDictionaryCreateMutable(0,
1010 4,
1011 &kCFTypeDictionaryKeyCallBacks,
1012 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001013
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001014 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1015 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
1016 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1017 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001018
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001019 CFReleaser<SecKeychainItemRef> itemRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001020 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001021 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001022
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001023 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001024 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -08001025 else
1026 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001027
1028}
1029
Yingdi Yu4b752752014-02-18 12:24:03 -08001030bool
1031SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
1032{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001033 return SecRandomCopyBytes(kSecRandomDefault, size, res) == 0;
Yingdi Yu4b752752014-02-18 12:24:03 -08001034}
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001035
1036////////////////////////////////
1037// OSXPrivateKeyStorage::Impl //
1038////////////////////////////////
1039
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001040CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001041SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001042{
1043 string keyNameUri = toInternalKeyName(keyName, keyClass);
1044
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001045 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1046 keyNameUri.c_str(),
1047 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001048
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001049 CFReleaser<CFMutableDictionaryRef> attrDict =
1050 CFDictionaryCreateMutable(0,
1051 5,
1052 &kCFTypeDictionaryKeyCallBacks,
1053 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001054
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001055 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1056 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1057 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
1058 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001059
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001060 CFReleaser<SecKeychainItemRef> keyItem;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001061 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001062 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001063
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001064 if (res != errSecSuccess)
1065 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001066 else
1067 return keyItem;
1068}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001069
1070string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001071SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001072{
1073 string keyUri = keyName.toUri();
1074
Yingdi Yu99b2a002015-08-12 12:47:44 -07001075 if (KeyClass::SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001076 return keyUri + "/symmetric";
1077 else
1078 return keyUri;
1079}
1080
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001081CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001082SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
1083{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001084 switch (keyType) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001085 case KeyType::RSA:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001086 return kSecAttrKeyTypeRSA;
Yingdi Yu99b2a002015-08-12 12:47:44 -07001087 case KeyType::EC:
Yingdi Yuc8f883c2014-06-20 23:25:22 -07001088 return kSecAttrKeyTypeECDSA;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001089 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001090 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001091 }
1092}
1093
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001094CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001095SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
1096{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001097 switch (keyType) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001098 case KeyType::AES:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001099 return kSecAttrKeyTypeAES;
1100 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001101 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001102 }
1103}
1104
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001105CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001106SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
1107{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001108 switch (keyClass) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001109 case KeyClass::PRIVATE:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001110 return kSecAttrKeyClassPrivate;
Yingdi Yu99b2a002015-08-12 12:47:44 -07001111 case KeyClass::PUBLIC:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001112 return kSecAttrKeyClassPublic;
Yingdi Yu99b2a002015-08-12 12:47:44 -07001113 case KeyClass::SYMMETRIC:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001114 return kSecAttrKeyClassSymmetric;
1115 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001116 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001117 }
1118}
1119
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001120CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001121SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
1122{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001123 switch (digestAlgo) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001124 case DigestAlgorithm::SHA256:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001125 return kSecDigestSHA2;
1126 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001127 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001128 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001129}
Jeff Thompson2747dc02013-10-04 19:11:34 -07001130
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001131long
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001132SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
1133{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001134 switch (digestAlgo) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001135 case DigestAlgorithm::SHA256:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001136 return 256;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001137 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001138 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001139 }
Jeff Thompson2747dc02013-10-04 19:11:34 -07001140}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001141
Alexander Afanasyev2fa59392016-07-29 17:24:23 -07001142} // namespace security
Yingdi Yufc40d872014-02-18 12:56:04 -08001143} // namespace ndn