blob: f3c3029916adabadc79a2b6209a25fd20bd73df7 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Jeff Thompson2747dc02013-10-04 19:11:34 -07002/**
Alexander Afanasyev4c9a3d52017-01-03 17:45:19 -08003 * Copyright (c) 2013-2017 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 Afanasyev4c9a3d52017-01-03 17:45:19 -080025#include "public-key.hpp"
Alexander Afanasyev07113802015-01-15 19:14:36 -080026
Alexander Afanasyev4c9a3d52017-01-03 17:45:19 -080027#include "../../encoding/oid.hpp"
28#include "../../encoding/buffer-stream.hpp"
29#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 {
Alexander Afanasyev2fa59392016-07-29 17:24:23 -070046namespace security {
Alexander Afanasyev4c9a3d52017-01-03 17:45:19 -080047namespace v1 {
Yingdi Yufc40d872014-02-18 12:56:04 -080048
Yingdi Yu7036ce22014-06-19 18:53:37 -070049using std::string;
50
Alexander Afanasyev07113802015-01-15 19:14:36 -080051const std::string SecTpmOsx::SCHEME("tpm-osxkeychain");
Yingdi Yu41546342014-11-30 23:37:53 -080052
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070053/**
54 * @brief Helper class to wrap CoreFoundation object pointers
55 *
56 * The class is similar in spirit to shared_ptr, but uses CoreFoundation
57 * mechanisms to retain/release object.
58 *
59 * Original implementation by Christopher Hunt and it was borrowed from
60 * http://www.cocoabuilder.com/archive/cocoa/130776-auto-cfrelease-and.html
61 */
62template<class T>
63class CFReleaser
64{
65public:
66 //////////////////////////////
67 // Construction/destruction //
68
69 CFReleaser()
Yingdi Yu99b2a002015-08-12 12:47:44 -070070 : m_typeRef(nullptr)
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070071 {
72 }
73
74 CFReleaser(const T& typeRef)
75 : m_typeRef(typeRef)
76 {
77 }
78
79 CFReleaser(const CFReleaser& inReleaser)
Yingdi Yu99b2a002015-08-12 12:47:44 -070080 : m_typeRef(nullptr)
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070081 {
82 retain(inReleaser.m_typeRef);
83 }
84
85 CFReleaser&
86 operator=(const T& typeRef)
87 {
88 if (typeRef != m_typeRef) {
89 release();
90 m_typeRef = typeRef;
91 }
92 return *this;
93 }
94
95 CFReleaser&
96 operator=(const CFReleaser& inReleaser)
97 {
98 retain(inReleaser.m_typeRef);
99 return *this;
100 }
101
102 ~CFReleaser()
103 {
104 release();
105 }
106
107 ////////////
108 // Access //
109
110 // operator const T&() const
111 // {
112 // return m_typeRef;
113 // }
114
115 // operator T&()
116 // {
117 // return m_typeRef;
118 // }
119
120 const T&
121 get() const
122 {
123 return m_typeRef;
124 }
125
126 T&
127 get()
128 {
129 return m_typeRef;
130 }
131
132 ///////////////////
133 // Miscellaneous //
134
135 void
136 retain(const T& typeRef)
137 {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700138 if (typeRef != nullptr) {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700139 CFRetain(typeRef);
140 }
141 release();
142 m_typeRef = typeRef;
143 }
144
Yingdi Yu99b2a002015-08-12 12:47:44 -0700145 void
146 release()
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700147 {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700148 if (m_typeRef != nullptr) {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700149 CFRelease(m_typeRef);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700150 m_typeRef = nullptr;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700151 }
152 };
153
Yingdi Yu99b2a002015-08-12 12:47:44 -0700154 bool
155 operator==(std::nullptr_t)
156 {
157 return get() == nullptr;
158 }
159
160 bool
161 operator!=(std::nullptr_t)
162 {
163 return get() != nullptr;
164 }
165
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700166private:
167 T m_typeRef;
168};
169
170
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700171class SecTpmOsx::Impl
172{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800173public:
174 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -0800175 : m_passwordSet(false)
176 , m_inTerminal(false)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700177 {
178 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700179
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800180 /**
181 * @brief Convert NDN name of a key to internal name of the key.
182 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800183 * @return the internal key name
184 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700185 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700186 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700187
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800188 /**
189 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -0800190 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800191 * @returns pointer to the key
192 */
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700193 CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700194 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700195
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800196 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800197 * @brief Convert keyType to MAC OS symmetric key key type
198 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800199 * @returns MAC OS key type
200 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300201 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800202 getSymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700203
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800204 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800205 * @brief Convert keyType to MAC OS asymmetirc key type
206 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800207 * @returns MAC OS key type
208 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300209 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800210 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700211
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800212 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800213 * @brief Convert keyClass to MAC OS key class
214 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800215 * @returns MAC OS key class
216 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300217 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800218 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700219
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800220 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800221 * @brief Convert digestAlgo to MAC OS algorithm id
222 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800223 * @returns MAC OS algorithm id
224 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300225 CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800226 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700227
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800228 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800229 * @brief Get the digest size of the corresponding algorithm
230 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800231 * @return digest size
232 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700233 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800234 getDigestSize(DigestAlgorithm digestAlgo);
235
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800236 ///////////////////////////////////////////////
237 // everything here is public, including data //
238 ///////////////////////////////////////////////
239public:
240 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800241 bool m_passwordSet;
242 string m_password;
243 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800244};
245
Yingdi Yu41546342014-11-30 23:37:53 -0800246SecTpmOsx::SecTpmOsx(const std::string& location)
247 : SecTpm(location)
248 , m_impl(new Impl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800249{
Yingdi Yu41546342014-11-30 23:37:53 -0800250 // TODO: add location support
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700251 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700252 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800253 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700254 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800255
Yingdi Yube4150e2014-02-18 13:02:46 -0800256 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700257
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800258 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700259 BOOST_THROW_EXCEPTION(Error("No default keychain, please create one first"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800260}
261
Yingdi Yu41546342014-11-30 23:37:53 -0800262SecTpmOsx::~SecTpmOsx()
263{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800264}
265
Yingdi Yube4150e2014-02-18 13:02:46 -0800266void
267SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
268{
269 m_impl->m_passwordSet = true;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700270 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800271 m_impl->m_password.clear();
272 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
273}
274
275void
276SecTpmOsx::resetTpmPassword()
277{
278 m_impl->m_passwordSet = false;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700279 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800280 m_impl->m_password.clear();
281}
282
283void
284SecTpmOsx::setInTerminal(bool inTerminal)
285{
286 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700287 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700288 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800289 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700290 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800291}
292
293bool
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700294SecTpmOsx::getInTerminal() const
Yingdi Yube4150e2014-02-18 13:02:46 -0800295{
296 return m_impl->m_inTerminal;
297}
298
299bool
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700300SecTpmOsx::isLocked()
Yingdi Yube4150e2014-02-18 13:02:46 -0800301{
302 SecKeychainStatus keychainStatus;
303
304 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700305 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800306 return true;
307 else
308 return ((kSecUnlockStateStatus & keychainStatus) == 0);
309}
310
Yingdi Yu2e57a582014-02-20 23:34:43 -0800311bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800312SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
313{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700314 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800315
316 // If the default key chain is already unlocked, return immediately.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700317 if (!isLocked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800318 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800319
320 // If the default key chain is locked, unlock the key chain.
Yingdi Yu99b2a002015-08-12 12:47:44 -0700321 if (usePassword) {
322 // Use the supplied password.
323 res = SecKeychainUnlock(m_impl->m_keyChainRef,
324 passwordLength,
325 password,
326 true);
327 }
328 else if (m_impl->m_passwordSet) {
329 // If no password supplied, then use the configured password if exists.
330 SecKeychainUnlock(m_impl->m_keyChainRef,
331 m_impl->m_password.size(),
332 m_impl->m_password.c_str(),
333 true);
334 }
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800335#ifdef NDN_CXX_HAVE_GETPASS
Yingdi Yu99b2a002015-08-12 12:47:44 -0700336 else if (m_impl->m_inTerminal) {
337 // If no configured password, get password from terminal if inTerminal set.
338 bool isLocked = true;
339 const char* fmt = "Password to unlock the default keychain: ";
340 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700341
Yingdi Yu99b2a002015-08-12 12:47:44 -0700342 while (isLocked) {
343 if (count > 2)
344 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700345
Yingdi Yu99b2a002015-08-12 12:47:44 -0700346 char* getPassword = nullptr;
347 getPassword = getpass(fmt);
348 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700349
Yingdi Yu99b2a002015-08-12 12:47:44 -0700350 if (!getPassword)
351 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700352
Yingdi Yu99b2a002015-08-12 12:47:44 -0700353 res = SecKeychainUnlock(m_impl->m_keyChainRef,
354 strlen(getPassword),
355 getPassword,
356 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700357
Yingdi Yu99b2a002015-08-12 12:47:44 -0700358 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700359
Yingdi Yu99b2a002015-08-12 12:47:44 -0700360 if (res == errSecSuccess)
361 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800362 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700363 }
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800364#endif // NDN_CXX_HAVE_GETPASS
Yingdi Yu99b2a002015-08-12 12:47:44 -0700365 else {
366 // If inTerminal is not set, get the password from GUI.
367 SecKeychainUnlock(m_impl->m_keyChainRef, 0, nullptr, false);
368 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800369
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700370 return !isLocked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800371}
372
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700373void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700374SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName,
375 const KeyParams& params,
376 bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700377{
378
Yingdi Yu99b2a002015-08-12 12:47:44 -0700379 if (doesKeyExistInTpm(keyName, KeyClass::PUBLIC)) {
380 BOOST_THROW_EXCEPTION(Error("keyName already exists"));
381 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800382
Yingdi Yu99b2a002015-08-12 12:47:44 -0700383 string keyNameUri = m_impl->toInternalKeyName(keyName, KeyClass::PUBLIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800384
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700385 CFReleaser<CFStringRef> keyLabel =
386 CFStringCreateWithCString(0,
387 keyNameUri.c_str(),
388 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800389
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700390 CFReleaser<CFMutableDictionaryRef> attrDict =
391 CFDictionaryCreateMutable(0,
392 3,
393 &kCFTypeDictionaryKeyCallBacks,
394 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700395
Yingdi Yu7036ce22014-06-19 18:53:37 -0700396 KeyType keyType = params.getKeyType();
Yingdi Yu99b2a002015-08-12 12:47:44 -0700397 uint32_t keySize = 0;
398 switch (keyType) {
399 case KeyType::RSA: {
400 const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
401 keySize = rsaParams.getKeySize();
402 break;
403 }
404
405 case KeyType::EC: {
406 const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
407 keySize = ecdsaParams.getKeySize();
408 break;
409 }
410
Yingdi Yu7036ce22014-06-19 18:53:37 -0700411 default:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700412 BOOST_THROW_EXCEPTION(Error("Fail to create a key pair: Unsupported key type"));
Yingdi Yu99b2a002015-08-12 12:47:44 -0700413 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700414
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700415 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800416
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700417 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
418 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
419 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800420
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700421 CFReleaser<SecKeyRef> publicKey, privateKey;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700422 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700423 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(),
424 &publicKey.get(), &privateKey.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800425
Yingdi Yu99b2a002015-08-12 12:47:44 -0700426 if (res == errSecSuccess) {
427 return;
428 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700429
Yingdi Yu99b2a002015-08-12 12:47:44 -0700430 if (res == errSecAuthFailed && !needRetry) {
431 if (unlockTpm(nullptr, 0, false))
432 generateKeyPairInTpmInternal(keyName, params, true);
433 else
434 BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
435 }
436 else {
437 BOOST_THROW_EXCEPTION(Error("Fail to create a key pair"));
438 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800439}
440
441void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700442SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800443{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700444 CFReleaser<CFStringRef> keyLabel =
445 CFStringCreateWithCString(0,
446 keyName.toUri().c_str(),
447 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800448
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700449 CFReleaser<CFMutableDictionaryRef> searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700450 CFDictionaryCreateMutable(0, 5,
451 &kCFTypeDictionaryKeyCallBacks,
452 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800453
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700454 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
455 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
456 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
457 OSStatus res = SecItemDelete(searchDict.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800458
459 if (res == errSecSuccess)
460 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700461
Yingdi Yu99b2a002015-08-12 12:47:44 -0700462 if (res == errSecAuthFailed && !needRetry) {
463 if (unlockTpm(nullptr, 0, false))
464 deleteKeyPairInTpmInternal(keyName, true);
465 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800466}
467
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700468void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700469SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800470{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700471 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported"));
Yingdi Yu99b2a002015-08-12 12:47:44 -0700472 // if (doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800473 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800474
Yingdi Yu99b2a002015-08-12 12:47:44 -0700475 // string keyNameUri = m_impl->toInternalKeyName(keyName, KeyClass::SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800476
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700477 // CFReleaser<CFMutableDictionaryRef> attrDict =
478 // CFDictionaryCreateMutable(kCFAllocatorDefault,
479 // 0,
480 // &kCFTypeDictionaryKeyCallBacks,
481 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800482
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700483 // CFReleaser<CFStringRef> keyLabel =
484 // CFStringCreateWithCString(0,
485 // keyNameUri.c_str(),
486 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800487
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700488 // CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
489
490 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType));
491 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
492 // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue);
493 // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800494
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700495 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800496
Yingdi Yu2e57a582014-02-20 23:34:43 -0800497 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800498
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700499 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800500 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800501}
502
Alexander Afanasyev4c9a3d52017-01-03 17:45:19 -0800503shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700504SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800505{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700506 CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName, KeyClass::PUBLIC);
507 if (publicKey == nullptr) {
508 BOOST_THROW_EXCEPTION(Error("Requested public key [" + keyName.toUri() + "] does not exist "
509 "in OSX Keychain"));
510 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800511
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700512 CFReleaser<CFDataRef> exportedKey;
513 OSStatus res = SecItemExport(publicKey.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800514 kSecFormatOpenSSL,
515 0,
Yingdi Yu99b2a002015-08-12 12:47:44 -0700516 nullptr,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700517 &exportedKey.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700518 if (res != errSecSuccess) {
519 BOOST_THROW_EXCEPTION(Error("Cannot export requested public key from OSX Keychain"));
520 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800521
Alexander Afanasyev4c9a3d52017-01-03 17:45:19 -0800522 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey.get()),
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700523 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800524 return key;
525}
526
Yingdi Yu41546342014-11-30 23:37:53 -0800527std::string
528SecTpmOsx::getScheme()
529{
530 return SCHEME;
531}
532
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800533ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700534SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800535{
536 using namespace CryptoPP;
537
Yingdi Yu99b2a002015-08-12 12:47:44 -0700538 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KeyClass::PRIVATE);
539 if (privateKey == nullptr) {
540 /// @todo Can this happen because of keychain is locked?
541 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
542 "in OSX Keychain"));
543 }
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700544
Alexander Afanasyev4c9a3d52017-01-03 17:45:19 -0800545 shared_ptr<PublicKey> publicKey = getPublicKeyFromTpm(keyName);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700546
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700547 CFReleaser<CFDataRef> exportedKey;
548 OSStatus res = SecItemExport(privateKey.get(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800549 kSecFormatOpenSSL,
550 0,
Yingdi Yu99b2a002015-08-12 12:47:44 -0700551 nullptr,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700552 &exportedKey.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800553
Yingdi Yu99b2a002015-08-12 12:47:44 -0700554 if (res != errSecSuccess) {
555 if (res == errSecAuthFailed && !needRetry) {
556 if (unlockTpm(nullptr, 0, false))
557 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800558 else
Yingdi Yu99b2a002015-08-12 12:47:44 -0700559 return nullptr;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800560 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700561 else
562 return nullptr;
563 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800564
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800565 uint32_t version = 0;
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700566 Oid algorithm;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700567 bool hasParameters = false;
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700568 Oid algorithmParameter;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700569 switch (publicKey->getKeyType()) {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700570 case KeyType::RSA: {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700571 algorithm = oid::RSA; // "RSA encryption"
572 hasParameters = false;
573 break;
574 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700575
576 case KeyType::EC: {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700577 // "ECDSA encryption"
578 StringSource src(publicKey->get().buf(), publicKey->get().size(), true);
579 BERSequenceDecoder subjectPublicKeyInfo(src);
580 {
581 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
582 {
583 algorithm.decode(algorithmInfo);
584 algorithmParameter.decode(algorithmInfo);
585 }
586 }
587 hasParameters = true;
588 break;
589 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700590
591 default:
592 BOOST_THROW_EXCEPTION(Error("Unsupported key type" +
593 boost::lexical_cast<std::string>(publicKey->getKeyType())));
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700594 }
595
596 OBufferStream pkcs8Os;
597 FileSink sink(pkcs8Os);
598
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800599 SecByteBlock rawKeyBits;
600 // PrivateKeyInfo ::= SEQUENCE {
601 // version INTEGER,
602 // privateKeyAlgorithm SEQUENCE,
603 // privateKey OCTECT STRING}
604 DERSequenceEncoder privateKeyInfo(sink);
605 {
606 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
607 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
608 {
609 algorithm.encode(privateKeyAlgorithm);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700610 if (hasParameters)
611 algorithmParameter.encode(privateKeyAlgorithm);
612 else
613 DEREncodeNull(privateKeyAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800614 }
615 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700616 DEREncodeOctetString(privateKeyInfo,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700617 CFDataGetBytePtr(exportedKey.get()),
618 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800619 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700620 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800621
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700622 return pkcs8Os.buf();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800623}
624
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700625#ifdef __GNUC__
626#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
627#pragma GCC diagnostic push
628#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
629#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
630#endif // __GNUC__
631
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800632bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700633SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700634 const uint8_t* buf, size_t size,
635 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800636{
637 using namespace CryptoPP;
638
639 StringSource privateKeySource(buf, size, true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800640 SecByteBlock rawKeyBits;
641 // PrivateKeyInfo ::= SEQUENCE {
642 // INTEGER,
643 // SEQUENCE,
644 // OCTECT STRING}
645 BERSequenceDecoder privateKeyInfo(privateKeySource);
646 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700647 uint32_t versionNum;
648 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800649 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
650 {
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700651 Oid keyTypeOid;
652 keyTypeOid.decode(sequenceDecoder);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700653
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700654 if (keyTypeOid == oid::RSA)
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700655 BERDecodeNull(sequenceDecoder);
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700656 else if (keyTypeOid == oid::ECDSA) {
657 Oid parameterOid;
658 parameterOid.decode(sequenceDecoder);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700659 }
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700660 else
661 return false; // Unsupported key type;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800662 }
663 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
664 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700665 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800666
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700667 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
668 rawKeyBits.BytePtr(),
669 rawKeyBits.size(),
670 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800671
672 SecExternalFormat externalFormat = kSecFormatOpenSSL;
673 SecExternalItemType externalType = kSecItemTypePrivateKey;
674 SecKeyImportExportParameters keyParams;
675 memset(&keyParams, 0, sizeof(keyParams));
676 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
677 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700678 CFReleaser<SecAccessRef> access;
679 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
680 keyName.toUri().c_str(),
681 kCFStringEncodingUTF8);
682 SecAccessCreate(keyLabel.get(), 0, &access.get());
683 keyParams.accessRef = access.get();
684 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800685
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700686#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700687#pragma clang diagnostic push
688#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700689#endif // __clang__
690
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700691 OSStatus res = SecKeychainItemImport(importedKey.get(),
692 0,
693 &externalFormat,
694 &externalType,
695 0,
696 &keyParams,
697 m_impl->m_keyChainRef,
698 &outItems.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700699
700#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700701#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700702#endif // __clang__
703
Yingdi Yu99b2a002015-08-12 12:47:44 -0700704 if (res != errSecSuccess) {
705 if (res == errSecAuthFailed && !needRetry) {
706 if (unlockTpm(nullptr, 0, false))
707 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800708 else
709 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800710 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700711 else
712 return false;
713 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800714
Yingdi Yu7036ce22014-06-19 18:53:37 -0700715 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700716 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800717 SecKeychainAttribute attrs[1]; // maximum number of attributes
Yingdi Yu99b2a002015-08-12 12:47:44 -0700718 SecKeychainAttributeList attrList = {0, attrs};
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800719 string keyUri = keyName.toUri();
720 {
721 attrs[attrList.count].tag = kSecKeyPrintName;
722 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700723 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800724 attrList.count++;
725 }
726
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700727 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800728 &attrList,
729 0,
Yingdi Yu99b2a002015-08-12 12:47:44 -0700730 nullptr);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700731
Yingdi Yu99b2a002015-08-12 12:47:44 -0700732 if (res != errSecSuccess) {
733 return false;
734 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700735
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800736 return true;
737}
738
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700739#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
740#pragma GCC diagnostic pop
741#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
742
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800743bool
744SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
745{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700746 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
747 buf,
748 size,
749 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800750
751 SecExternalFormat externalFormat = kSecFormatOpenSSL;
752 SecExternalItemType externalType = kSecItemTypePublicKey;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700753 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800754
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700755 OSStatus res = SecItemImport(importedKey.get(),
756 0,
757 &externalFormat,
758 &externalType,
759 0,
760 0,
761 m_impl->m_keyChainRef,
762 &outItems.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800763
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700764 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800765 return false;
766
Yingdi Yu7036ce22014-06-19 18:53:37 -0700767 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700768 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800769 SecKeychainAttribute attrs[1]; // maximum number of attributes
770 SecKeychainAttributeList attrList = { 0, attrs };
771 string keyUri = keyName.toUri();
772 {
773 attrs[attrList.count].tag = kSecKeyPrintName;
774 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700775 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800776 attrList.count++;
777 }
778
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700779 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800780 &attrList,
781 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700782 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700783
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700784 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800785 return false;
786
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800787 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800788}
789
790Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700791SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
792 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800793{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700794 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
795 data,
796 dataLength,
797 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800798
Yingdi Yu99b2a002015-08-12 12:47:44 -0700799 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KeyClass::PRIVATE);
800 if (privateKey == nullptr) {
801 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
802 "in OSX Keychain"));
803 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700804
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700805 CFReleaser<CFErrorRef> error;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700806 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700807 CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
808 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700809 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700810 BOOST_THROW_EXCEPTION(Error("Fail to create signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800811
812 // Set input
Yingdi Yu7036ce22014-06-19 18:53:37 -0700813 SecTransformSetAttribute(signer.get(),
814 kSecTransformInputAttributeName,
815 dataRef.get(),
816 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700817 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700818 BOOST_THROW_EXCEPTION(Error("Fail to configure input of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800819
820 // Enable use of padding
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700821 SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800822 kSecPaddingKey,
823 kSecPaddingPKCS1Key,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700824 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700825 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700826 BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800827
828 // Set padding type
Yingdi Yu7036ce22014-06-19 18:53:37 -0700829 SecTransformSetAttribute(signer.get(),
830 kSecDigestTypeAttribute,
831 m_impl->getDigestAlgorithm(digestAlgorithm),
832 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700833 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700834 BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800835
836 // Set padding attribute
837 long digestSize = m_impl->getDigestSize(digestAlgorithm);
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700838 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700839 SecTransformSetAttribute(signer.get(),
840 kSecDigestLengthAttribute,
841 cfDigestSize.get(),
842 &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700843 if (error != nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700844 BOOST_THROW_EXCEPTION(Error("Fail to configure digest size of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800845
846 // Actually sign
Yingdi Yu7036ce22014-06-19 18:53:37 -0700847 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700848 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
Yingdi Yu99b2a002015-08-12 12:47:44 -0700849 if (error != nullptr) {
850 if (!needRetry) {
851 if (unlockTpm(nullptr, 0, false))
852 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800853 else
Yingdi Yu99b2a002015-08-12 12:47:44 -0700854 BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
Yingdi Yube4150e2014-02-18 13:02:46 -0800855 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700856 else {
857 CFShow(error.get());
858 BOOST_THROW_EXCEPTION(Error("Fail to sign data"));
859 }
860 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800861
Yingdi Yu99b2a002015-08-12 12:47:44 -0700862 if (signature == nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700863 BOOST_THROW_EXCEPTION(Error("Signature is NULL!\n"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800864
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600865 return Block(tlv::SignatureValue,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700866 make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
867 CFDataGetLength(signature.get())));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800868}
869
870ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700871SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800872{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700873 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::decryptInTpm is not supported"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800874
Yingdi Yu2e57a582014-02-20 23:34:43 -0800875 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700876 // if (sym)
Yingdi Yu99b2a002015-08-12 12:47:44 -0700877 // keyClass = KeyClass::SYMMETRIC;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800878 // else
Yingdi Yu99b2a002015-08-12 12:47:44 -0700879 // keyClass = KeyClass::PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800880
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700881 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800882 // reinterpret_cast<const unsigned char*>(data),
883 // dataLength
884 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800885
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700886 // CFReleaser<SecKeyRef> decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700887 // if (decryptKey == nullptr)
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700888 // {
889 // /// @todo Can this happen because of keychain is locked?
890 // throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain");
891 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800892
Yingdi Yu2e57a582014-02-20 23:34:43 -0800893 // CFErrorRef error;
894 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
895 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800896
Yingdi Yu2e57a582014-02-20 23:34:43 -0800897 // Boolean set_res = SecTransformSetAttribute(decrypt,
898 // kSecTransformInputAttributeName,
899 // dataRef,
900 // &error);
901 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800902
Yingdi Yu2e57a582014-02-20 23:34:43 -0800903 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
904 // if (error)
905 // {
906 // CFShow(error);
907 // throw Error("Fail to decrypt data");
908 // }
909 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800910
Yingdi Yu2e57a582014-02-20 23:34:43 -0800911 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800912}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700913
Yingdi Yu2e57a582014-02-20 23:34:43 -0800914void
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700915SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800916{
Yingdi Yu99b2a002015-08-12 12:47:44 -0700917 if (keyClass == KeyClass::PRIVATE && acl == AclType::PRIVATE) {
918 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
919 if (privateKey == nullptr) {
920 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
921 "in OSX Keychain"));
Yingdi Yu2e57a582014-02-20 23:34:43 -0800922 }
Yingdi Yu99b2a002015-08-12 12:47:44 -0700923
924 CFReleaser<SecAccessRef> accRef;
925 SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
926
927 CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
928 kSecACLAuthorizationSign);
929
930 // C-style cast is used as per Apple convention
931 SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
932
933 CFReleaser<CFArrayRef> appList;
934 CFReleaser<CFStringRef> description;
935 SecKeychainPromptSelector promptSelector;
936 SecACLCopyContents(aclRef,
937 &appList.get(),
938 &description.get(),
939 &promptSelector);
940
941 CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
942 0,
943 appList.get());
944
945 CFReleaser<SecTrustedApplicationRef> trustedApp;
946 SecTrustedApplicationCreateFromPath(appPath.c_str(),
947 &trustedApp.get());
948
949 CFArrayAppendValue(newAppList.get(), trustedApp.get());
950
951 SecACLSetContents(aclRef,
952 newAppList.get(),
953 description.get(),
954 promptSelector);
955
956 SecKeychainItemSetAccess(privateKey.get(), accRef.get());
957 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800958}
959
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800960ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700961SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800962{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700963 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::encryptInTpm is not supported"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800964
Yingdi Yu2e57a582014-02-20 23:34:43 -0800965 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700966 // if (sym)
Yingdi Yu99b2a002015-08-12 12:47:44 -0700967 // keyClass = KeyClass::SYMMETRIC;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800968 // else
Yingdi Yu99b2a002015-08-12 12:47:44 -0700969 // keyClass = KeyClass::PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700970
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700971 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800972 // reinterpret_cast<const unsigned char*>(data),
973 // dataLength
974 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700975
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700976 // CFReleaser<SecKeyRef> encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
Yingdi Yu99b2a002015-08-12 12:47:44 -0700977 // if (encryptKey == nullptr)
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700978 // {
979 // throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain");
980 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800981
Yingdi Yu2e57a582014-02-20 23:34:43 -0800982 // CFErrorRef error;
983 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
984 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800985
Yingdi Yu2e57a582014-02-20 23:34:43 -0800986 // Boolean set_res = SecTransformSetAttribute(encrypt,
987 // kSecTransformInputAttributeName,
988 // dataRef,
989 // &error);
990 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800991
Yingdi Yu2e57a582014-02-20 23:34:43 -0800992 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
993 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800994
Yingdi Yu2e57a582014-02-20 23:34:43 -0800995 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800996
Yingdi Yu2e57a582014-02-20 23:34:43 -0800997 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800998}
999
1000bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001001SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001002{
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001003 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
1004
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001005 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1006 keyNameUri.c_str(),
1007 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001008
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001009 CFReleaser<CFMutableDictionaryRef> attrDict =
1010 CFDictionaryCreateMutable(0,
1011 4,
1012 &kCFTypeDictionaryKeyCallBacks,
1013 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001014
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001015 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1016 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
1017 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1018 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001019
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001020 CFReleaser<SecKeychainItemRef> itemRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001021 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001022 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001023
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001024 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001025 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -08001026 else
1027 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001028
1029}
1030
Yingdi Yu4b752752014-02-18 12:24:03 -08001031bool
1032SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
1033{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001034 return SecRandomCopyBytes(kSecRandomDefault, size, res) == 0;
Yingdi Yu4b752752014-02-18 12:24:03 -08001035}
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001036
1037////////////////////////////////
1038// OSXPrivateKeyStorage::Impl //
1039////////////////////////////////
1040
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001041CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001042SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001043{
1044 string keyNameUri = toInternalKeyName(keyName, keyClass);
1045
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001046 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1047 keyNameUri.c_str(),
1048 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001049
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001050 CFReleaser<CFMutableDictionaryRef> attrDict =
1051 CFDictionaryCreateMutable(0,
1052 5,
1053 &kCFTypeDictionaryKeyCallBacks,
1054 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001055
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001056 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1057 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1058 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
1059 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001060
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001061 CFReleaser<SecKeychainItemRef> keyItem;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001062 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001063 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001064
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001065 if (res != errSecSuccess)
1066 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001067 else
1068 return keyItem;
1069}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001070
1071string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001072SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001073{
1074 string keyUri = keyName.toUri();
1075
Yingdi Yu99b2a002015-08-12 12:47:44 -07001076 if (KeyClass::SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001077 return keyUri + "/symmetric";
1078 else
1079 return keyUri;
1080}
1081
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001082CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001083SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
1084{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001085 switch (keyType) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001086 case KeyType::RSA:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001087 return kSecAttrKeyTypeRSA;
Yingdi Yu99b2a002015-08-12 12:47:44 -07001088 case KeyType::EC:
Yingdi Yuc8f883c2014-06-20 23:25:22 -07001089 return kSecAttrKeyTypeECDSA;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001090 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001091 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001092 }
1093}
1094
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001095CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001096SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
1097{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001098 switch (keyType) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001099 case KeyType::AES:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001100 return kSecAttrKeyTypeAES;
1101 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001102 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001103 }
1104}
1105
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001106CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001107SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
1108{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001109 switch (keyClass) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001110 case KeyClass::PRIVATE:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001111 return kSecAttrKeyClassPrivate;
Yingdi Yu99b2a002015-08-12 12:47:44 -07001112 case KeyClass::PUBLIC:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001113 return kSecAttrKeyClassPublic;
Yingdi Yu99b2a002015-08-12 12:47:44 -07001114 case KeyClass::SYMMETRIC:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001115 return kSecAttrKeyClassSymmetric;
1116 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001117 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001118 }
1119}
1120
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001121CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001122SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
1123{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001124 switch (digestAlgo) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001125 case DigestAlgorithm::SHA256:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001126 return kSecDigestSHA2;
1127 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001128 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001129 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001130}
Jeff Thompson2747dc02013-10-04 19:11:34 -07001131
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001132long
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001133SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
1134{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001135 switch (digestAlgo) {
Yingdi Yu99b2a002015-08-12 12:47:44 -07001136 case DigestAlgorithm::SHA256:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001137 return 256;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001138 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001139 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001140 }
Jeff Thompson2747dc02013-10-04 19:11:34 -07001141}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001142
Alexander Afanasyev4c9a3d52017-01-03 17:45:19 -08001143} // namespace v1
Alexander Afanasyev2fa59392016-07-29 17:24:23 -07001144} // namespace security
Yingdi Yufc40d872014-02-18 12:56:04 -08001145} // namespace ndn