blob: 33a2c7f3b894581ca7882f25aa3bc88e056fdcea [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Jeff Thompson2747dc02013-10-04 19:11:34 -07002/**
Alexander Afanasyevaf99f462015-01-19 21:43:09 -08003 * Copyright (c) 2013-2015 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Jeff Thompson2747dc02013-10-04 19:11:34 -070022 */
23
Alexander Afanasyev19508852014-01-29 01:01:51 -080024#include "sec-tpm-osx.hpp"
Yingdi Yuf56c68f2014-04-24 21:50:13 -070025#include "public-key.hpp"
Alexander Afanasyev07113802015-01-15 19:14:36 -080026
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070027#include "../encoding/oid.hpp"
28#include "../encoding/buffer-stream.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070029#include "cryptopp.hpp"
Jeff Thompson2747dc02013-10-04 19:11:34 -070030
Yingdi Yu2b2b4792014-02-04 16:27:07 -080031#include <pwd.h>
32#include <unistd.h>
33#include <stdlib.h>
34#include <string.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070035
Alexander Afanasyev1c6976d2014-07-13 11:40:50 -070036#include <boost/lexical_cast.hpp>
37
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080038#include <CoreFoundation/CoreFoundation.h>
39#include <Security/Security.h>
Yingdi Yu4b752752014-02-18 12:24:03 -080040#include <Security/SecRandom.h>
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080041#include <CoreServices/CoreServices.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070042
Alexander Afanasyev59d67a52014-04-03 16:09:31 -070043#include <Security/SecDigestTransform.h>
44
Yingdi Yufc40d872014-02-18 12:56:04 -080045namespace ndn {
46
Yingdi Yu7036ce22014-06-19 18:53:37 -070047using std::string;
48
Alexander Afanasyev07113802015-01-15 19:14:36 -080049const std::string SecTpmOsx::SCHEME("tpm-osxkeychain");
Yingdi Yu41546342014-11-30 23:37:53 -080050
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070051/**
52 * @brief Helper class to wrap CoreFoundation object pointers
53 *
54 * The class is similar in spirit to shared_ptr, but uses CoreFoundation
55 * mechanisms to retain/release object.
56 *
57 * Original implementation by Christopher Hunt and it was borrowed from
58 * http://www.cocoabuilder.com/archive/cocoa/130776-auto-cfrelease-and.html
59 */
60template<class T>
61class CFReleaser
62{
63public:
64 //////////////////////////////
65 // Construction/destruction //
66
67 CFReleaser()
68 : m_typeRef(0)
69 {
70 }
71
72 CFReleaser(const T& typeRef)
73 : m_typeRef(typeRef)
74 {
75 }
76
77 CFReleaser(const CFReleaser& inReleaser)
78 : m_typeRef(0)
79 {
80 retain(inReleaser.m_typeRef);
81 }
82
83 CFReleaser&
84 operator=(const T& typeRef)
85 {
86 if (typeRef != m_typeRef) {
87 release();
88 m_typeRef = typeRef;
89 }
90 return *this;
91 }
92
93 CFReleaser&
94 operator=(const CFReleaser& inReleaser)
95 {
96 retain(inReleaser.m_typeRef);
97 return *this;
98 }
99
100 ~CFReleaser()
101 {
102 release();
103 }
104
105 ////////////
106 // Access //
107
108 // operator const T&() const
109 // {
110 // return m_typeRef;
111 // }
112
113 // operator T&()
114 // {
115 // return m_typeRef;
116 // }
117
118 const T&
119 get() const
120 {
121 return m_typeRef;
122 }
123
124 T&
125 get()
126 {
127 return m_typeRef;
128 }
129
130 ///////////////////
131 // Miscellaneous //
132
133 void
134 retain(const T& typeRef)
135 {
136 if (typeRef != 0) {
137 CFRetain(typeRef);
138 }
139 release();
140 m_typeRef = typeRef;
141 }
142
143 void release()
144 {
145 if (m_typeRef != 0) {
146 CFRelease(m_typeRef);
147 m_typeRef = 0;
148 }
149 };
150
151private:
152 T m_typeRef;
153};
154
155
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700156class SecTpmOsx::Impl
157{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800158public:
159 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -0800160 : m_passwordSet(false)
161 , m_inTerminal(false)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700162 {
163 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700164
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800165 /**
166 * @brief Convert NDN name of a key to internal name of the key.
167 *
Yingdi Yufc40d872014-02-18 12:56:04 -0800168 * @param keyName
169 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800170 * @return the internal key name
171 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700172 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700173 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700174
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800175 /**
176 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -0800177 *
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700178 * @param keyName
Yingdi Yufc40d872014-02-18 12:56:04 -0800179 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800180 * @returns pointer to the key
181 */
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700182 CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700183 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700184
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800185 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800186 * @brief Convert keyType to MAC OS symmetric key key type
187 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800188 * @param keyType
189 * @returns MAC OS key type
190 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300191 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800192 getSymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700193
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800194 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800195 * @brief Convert keyType to MAC OS asymmetirc key type
196 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800197 * @param keyType
198 * @returns MAC OS key type
199 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300200 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800201 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700202
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800203 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800204 * @brief Convert keyClass to MAC OS key class
205 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800206 * @param keyClass
207 * @returns MAC OS key class
208 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300209 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800210 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700211
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800212 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800213 * @brief Convert digestAlgo to MAC OS algorithm id
214 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800215 * @param digestAlgo
216 * @returns MAC OS algorithm id
217 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300218 CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800219 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700220
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800221 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800222 * @brief Get the digest size of the corresponding algorithm
223 *
224 * @param digestAlgo
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800225 * @return digest size
226 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700227 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800228 getDigestSize(DigestAlgorithm digestAlgo);
229
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800230 ///////////////////////////////////////////////
231 // everything here is public, including data //
232 ///////////////////////////////////////////////
233public:
234 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800235 bool m_passwordSet;
236 string m_password;
237 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800238};
239
Yingdi Yu41546342014-11-30 23:37:53 -0800240SecTpmOsx::SecTpmOsx(const std::string& location)
241 : SecTpm(location)
242 , m_impl(new Impl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800243{
Yingdi Yu41546342014-11-30 23:37:53 -0800244 // TODO: add location support
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700245 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700246 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800247 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700248 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800249
Yingdi Yube4150e2014-02-18 13:02:46 -0800250 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700251
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800252 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700253 BOOST_THROW_EXCEPTION(Error("No default keychain, please create one first"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800254}
255
Yingdi Yu41546342014-11-30 23:37:53 -0800256SecTpmOsx::~SecTpmOsx()
257{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800258}
259
Yingdi Yube4150e2014-02-18 13:02:46 -0800260void
261SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
262{
263 m_impl->m_passwordSet = true;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700264 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800265 m_impl->m_password.clear();
266 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
267}
268
269void
270SecTpmOsx::resetTpmPassword()
271{
272 m_impl->m_passwordSet = false;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700273 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800274 m_impl->m_password.clear();
275}
276
277void
278SecTpmOsx::setInTerminal(bool inTerminal)
279{
280 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700281 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700282 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800283 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700284 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800285}
286
287bool
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700288SecTpmOsx::getInTerminal() const
Yingdi Yube4150e2014-02-18 13:02:46 -0800289{
290 return m_impl->m_inTerminal;
291}
292
293bool
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700294SecTpmOsx::isLocked()
Yingdi Yube4150e2014-02-18 13:02:46 -0800295{
296 SecKeychainStatus keychainStatus;
297
298 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700299 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800300 return true;
301 else
302 return ((kSecUnlockStateStatus & keychainStatus) == 0);
303}
304
Yingdi Yu2e57a582014-02-20 23:34:43 -0800305bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800306SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
307{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700308 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800309
310 // If the default key chain is already unlocked, return immediately.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700311 if (!isLocked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800312 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800313
314 // If the default key chain is locked, unlock the key chain.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700315 if (usePassword)
Yingdi Yube4150e2014-02-18 13:02:46 -0800316 {
317 // Use the supplied password.
318 res = SecKeychainUnlock(m_impl->m_keyChainRef,
319 passwordLength,
320 password,
321 true);
322 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700323 else if (m_impl->m_passwordSet)
Yingdi Yube4150e2014-02-18 13:02:46 -0800324 {
325 // If no password supplied, then use the configured password if exists.
326 SecKeychainUnlock(m_impl->m_keyChainRef,
327 m_impl->m_password.size(),
328 m_impl->m_password.c_str(),
329 true);
330 }
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800331#ifdef NDN_CXX_HAVE_GETPASS
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700332 else if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800333 {
334 // If no configured password, get password from terminal if inTerminal set.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700335 bool isLocked = true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800336 const char* fmt = "Password to unlock the default keychain: ";
337 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700338
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700339 while (isLocked)
Yingdi Yube4150e2014-02-18 13:02:46 -0800340 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700341 if (count > 2)
Yingdi Yube4150e2014-02-18 13:02:46 -0800342 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700343
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700344 char* getPassword = 0;
Yingdi Yube4150e2014-02-18 13:02:46 -0800345 getPassword = getpass(fmt);
346 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700347
Yingdi Yube4150e2014-02-18 13:02:46 -0800348 if (!getPassword)
349 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700350
Yingdi Yube4150e2014-02-18 13:02:46 -0800351 res = SecKeychainUnlock(m_impl->m_keyChainRef,
352 strlen(getPassword),
353 getPassword,
354 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700355
Yingdi Yube4150e2014-02-18 13:02:46 -0800356 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700357
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700358 if (res == errSecSuccess)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800359 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800360 }
361 }
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800362#endif // NDN_CXX_HAVE_GETPASS
Yingdi Yube4150e2014-02-18 13:02:46 -0800363 else
364 {
365 // If inTerminal is not set, get the password from GUI.
366 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, 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 Yu4b8c6a22014-04-15 23:00:54 -0700378 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
379 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700380 BOOST_THROW_EXCEPTION(Error("keyName already exists"));
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700381 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800382
383 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
384
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();
397 uint32_t keySize;
398 switch (keyType)
399 {
400 case KEY_TYPE_RSA:
401 {
402 const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
403 keySize = rsaParams.getKeySize();
404 break;
405 }
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700406 case KEY_TYPE_ECDSA:
407 {
408 const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
409 keySize = ecdsaParams.getKeySize();
410 break;
411 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700412 default:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700413 BOOST_THROW_EXCEPTION(Error("Fail to create a key pair: Unsupported key type"));
Yingdi Yu7036ce22014-06-19 18:53:37 -0700414 }
415
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700416 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800417
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700418 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
419 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
420 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800421
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700422 CFReleaser<SecKeyRef> publicKey, privateKey;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700423 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700424 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(),
425 &publicKey.get(), &privateKey.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800426
Yingdi Yube4150e2014-02-18 13:02:46 -0800427 if (res == errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800428 {
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800429 return;
430 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700431
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700432 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800433 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700434 if (unlockTpm(0, 0, false))
Yingdi Yu7036ce22014-06-19 18:53:37 -0700435 generateKeyPairInTpmInternal(keyName, params, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800436 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700437 BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
Yingdi Yube4150e2014-02-18 13:02:46 -0800438 }
439 else
440 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700441 BOOST_THROW_EXCEPTION(Error("Fail to create a key pair"));
Yingdi Yube4150e2014-02-18 13:02:46 -0800442 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800443}
444
445void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700446SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800447{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700448 CFReleaser<CFStringRef> keyLabel =
449 CFStringCreateWithCString(0,
450 keyName.toUri().c_str(),
451 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800452
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700453 CFReleaser<CFMutableDictionaryRef> searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700454 CFDictionaryCreateMutable(0, 5,
455 &kCFTypeDictionaryKeyCallBacks,
456 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800457
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700458 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
459 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
460 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
461 OSStatus res = SecItemDelete(searchDict.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800462
463 if (res == errSecSuccess)
464 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700465
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700466 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800467 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700468 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800469 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800470 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800471}
472
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700473void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700474SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800475{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700476 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported"));
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700477 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800478 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800479
Yingdi Yu2e57a582014-02-20 23:34:43 -0800480 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800481
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700482 // CFReleaser<CFMutableDictionaryRef> attrDict =
483 // CFDictionaryCreateMutable(kCFAllocatorDefault,
484 // 0,
485 // &kCFTypeDictionaryKeyCallBacks,
486 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800487
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700488 // CFReleaser<CFStringRef> keyLabel =
489 // CFStringCreateWithCString(0,
490 // keyNameUri.c_str(),
491 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800492
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700493 // CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
494
495 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType));
496 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
497 // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue);
498 // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800499
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700500 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800501
Yingdi Yu2e57a582014-02-20 23:34:43 -0800502 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800503
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700504 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800505 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800506}
507
Yingdi Yu2e57a582014-02-20 23:34:43 -0800508shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700509SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800510{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700511 CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
512 if (publicKey.get() == 0)
513 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700514 BOOST_THROW_EXCEPTION(Error("Requested public key [" + keyName.toUri() + "] does not exist "
515 "in OSX Keychain"));
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700516 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800517
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700518 CFReleaser<CFDataRef> exportedKey;
519 OSStatus res = SecItemExport(publicKey.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800520 kSecFormatOpenSSL,
521 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700522 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700523 &exportedKey.get());
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800524 if (res != errSecSuccess)
525 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700526 BOOST_THROW_EXCEPTION(Error("Cannot export requested public key from OSX Keychain"));
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800527 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800528
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700529 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey.get()),
530 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800531 return key;
532}
533
Yingdi Yu41546342014-11-30 23:37:53 -0800534std::string
535SecTpmOsx::getScheme()
536{
537 return SCHEME;
538}
539
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800540ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700541SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800542{
543 using namespace CryptoPP;
544
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700545 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
546 if (privateKey.get() == 0)
547 {
548 /// @todo Can this happen because of keychain is locked?
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700549 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
550 "in OSX Keychain"));
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700551 }
552
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700553 shared_ptr<PublicKey> publicKey = getPublicKeyFromTpm(keyName);
554
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700555 CFReleaser<CFDataRef> exportedKey;
556 OSStatus res = SecItemExport(privateKey.get(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800557 kSecFormatOpenSSL,
558 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700559 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700560 &exportedKey.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800561
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700562 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800563 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700564 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800565 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700566 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700567 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800568 else
569 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800570 }
571 else
572 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800573 }
574
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800575 uint32_t version = 0;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700576 OID algorithm;
577 bool hasParameters = false;
578 OID algorithmParameter;
579 switch (publicKey->getKeyType()) {
580 case KEY_TYPE_RSA:
581 {
582 algorithm = oid::RSA; // "RSA encryption"
583 hasParameters = false;
584 break;
585 }
586 case KEY_TYPE_ECDSA:
587 {
588 // "ECDSA encryption"
589 StringSource src(publicKey->get().buf(), publicKey->get().size(), true);
590 BERSequenceDecoder subjectPublicKeyInfo(src);
591 {
592 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
593 {
594 algorithm.decode(algorithmInfo);
595 algorithmParameter.decode(algorithmInfo);
596 }
597 }
598 hasParameters = true;
599 break;
600 }
601 default:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700602 BOOST_THROW_EXCEPTION(Error("Unsupported key type" +
603 boost::lexical_cast<std::string>(publicKey->getKeyType())));
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700604 }
605
606 OBufferStream pkcs8Os;
607 FileSink sink(pkcs8Os);
608
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800609 SecByteBlock rawKeyBits;
610 // PrivateKeyInfo ::= SEQUENCE {
611 // version INTEGER,
612 // privateKeyAlgorithm SEQUENCE,
613 // privateKey OCTECT STRING}
614 DERSequenceEncoder privateKeyInfo(sink);
615 {
616 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
617 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
618 {
619 algorithm.encode(privateKeyAlgorithm);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700620 if (hasParameters)
621 algorithmParameter.encode(privateKeyAlgorithm);
622 else
623 DEREncodeNull(privateKeyAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800624 }
625 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700626 DEREncodeOctetString(privateKeyInfo,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700627 CFDataGetBytePtr(exportedKey.get()),
628 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800629 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700630 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800631
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700632 return pkcs8Os.buf();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800633}
634
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700635#ifdef __GNUC__
636#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
637#pragma GCC diagnostic push
638#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
639#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
640#endif // __GNUC__
641
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800642bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700643SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700644 const uint8_t* buf, size_t size,
645 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800646{
647 using namespace CryptoPP;
648
649 StringSource privateKeySource(buf, size, true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800650 SecByteBlock rawKeyBits;
651 // PrivateKeyInfo ::= SEQUENCE {
652 // INTEGER,
653 // SEQUENCE,
654 // OCTECT STRING}
655 BERSequenceDecoder privateKeyInfo(privateKeySource);
656 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700657 uint32_t versionNum;
658 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800659 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
660 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700661 OID keyTypeOID;
662 keyTypeOID.decode(sequenceDecoder);
663
664 if (keyTypeOID == oid::RSA)
665 BERDecodeNull(sequenceDecoder);
666 else if (keyTypeOID == oid::ECDSA)
667 {
668 OID parameterOID;
669 parameterOID.decode(sequenceDecoder);
670 }
671 else
672 return false; // Unsupported key type;
673
674
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800675 }
676 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
677 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700678 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800679
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700680 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
681 rawKeyBits.BytePtr(),
682 rawKeyBits.size(),
683 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800684
685 SecExternalFormat externalFormat = kSecFormatOpenSSL;
686 SecExternalItemType externalType = kSecItemTypePrivateKey;
687 SecKeyImportExportParameters keyParams;
688 memset(&keyParams, 0, sizeof(keyParams));
689 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
690 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700691 CFReleaser<SecAccessRef> access;
692 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
693 keyName.toUri().c_str(),
694 kCFStringEncodingUTF8);
695 SecAccessCreate(keyLabel.get(), 0, &access.get());
696 keyParams.accessRef = access.get();
697 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800698
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700699#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700700#pragma clang diagnostic push
701#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700702#endif // __clang__
703
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700704 OSStatus res = SecKeychainItemImport(importedKey.get(),
705 0,
706 &externalFormat,
707 &externalType,
708 0,
709 &keyParams,
710 m_impl->m_keyChainRef,
711 &outItems.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700712
713#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700714#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700715#endif // __clang__
716
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700717 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800718 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700719 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800720 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700721 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700722 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800723 else
724 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800725 }
726 else
727 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800728 }
729
Yingdi Yu7036ce22014-06-19 18:53:37 -0700730 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700731 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800732 SecKeychainAttribute attrs[1]; // maximum number of attributes
733 SecKeychainAttributeList attrList = { 0, attrs };
734 string keyUri = keyName.toUri();
735 {
736 attrs[attrList.count].tag = kSecKeyPrintName;
737 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700738 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800739 attrList.count++;
740 }
741
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700742 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800743 &attrList,
744 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700745 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700746
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700747 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800748 {
749 return false;
750 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700751
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800752 return true;
753}
754
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700755#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
756#pragma GCC diagnostic pop
757#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
758
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800759bool
760SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
761{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700762 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
763 buf,
764 size,
765 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800766
767 SecExternalFormat externalFormat = kSecFormatOpenSSL;
768 SecExternalItemType externalType = kSecItemTypePublicKey;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700769 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800770
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700771 OSStatus res = SecItemImport(importedKey.get(),
772 0,
773 &externalFormat,
774 &externalType,
775 0,
776 0,
777 m_impl->m_keyChainRef,
778 &outItems.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800779
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700780 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800781 return false;
782
Yingdi Yu7036ce22014-06-19 18:53:37 -0700783 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700784 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800785 SecKeychainAttribute attrs[1]; // maximum number of attributes
786 SecKeychainAttributeList attrList = { 0, attrs };
787 string keyUri = keyName.toUri();
788 {
789 attrs[attrList.count].tag = kSecKeyPrintName;
790 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700791 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800792 attrList.count++;
793 }
794
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700795 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800796 &attrList,
797 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700798 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700799
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700800 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800801 return false;
802
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800803 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800804}
805
806Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700807SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
808 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800809{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700810 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
811 data,
812 dataLength,
813 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800814
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700815 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
816 if (privateKey.get() == 0)
817 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700818 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
819 "in OSX Keychain"));
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700820 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700821
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700822 CFReleaser<CFErrorRef> error;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700823 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700824 CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
825 &error.get());
826 if (error.get() != 0)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700827 BOOST_THROW_EXCEPTION(Error("Fail to create signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800828
829 // Set input
Yingdi Yu7036ce22014-06-19 18:53:37 -0700830 SecTransformSetAttribute(signer.get(),
831 kSecTransformInputAttributeName,
832 dataRef.get(),
833 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700834 if (error.get() != 0)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700835 BOOST_THROW_EXCEPTION(Error("Fail to configure input of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800836
837 // Enable use of padding
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700838 SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800839 kSecPaddingKey,
840 kSecPaddingPKCS1Key,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700841 &error.get());
842 if (error.get() != 0)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700843 BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800844
845 // Set padding type
Yingdi Yu7036ce22014-06-19 18:53:37 -0700846 SecTransformSetAttribute(signer.get(),
847 kSecDigestTypeAttribute,
848 m_impl->getDigestAlgorithm(digestAlgorithm),
849 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700850 if (error.get() != 0)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700851 BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800852
853 // Set padding attribute
854 long digestSize = m_impl->getDigestSize(digestAlgorithm);
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700855 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700856 SecTransformSetAttribute(signer.get(),
857 kSecDigestLengthAttribute,
858 cfDigestSize.get(),
859 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700860 if (error.get() != 0)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700861 BOOST_THROW_EXCEPTION(Error("Fail to configure digest size of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800862
863 // Actually sign
Yingdi Yu7036ce22014-06-19 18:53:37 -0700864 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700865 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
866 if (error.get() != 0)
Yingdi Yube4150e2014-02-18 13:02:46 -0800867 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700868 if (!needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800869 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700870 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800871 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
872 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700873 BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
Yingdi Yube4150e2014-02-18 13:02:46 -0800874 }
875 else
876 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700877 CFShow(error.get());
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700878 BOOST_THROW_EXCEPTION(Error("Fail to sign data"));
Yingdi Yube4150e2014-02-18 13:02:46 -0800879 }
880 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800881
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700882 if (signature.get() == 0)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700883 BOOST_THROW_EXCEPTION(Error("Signature is NULL!\n"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800884
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600885 return Block(tlv::SignatureValue,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700886 make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
887 CFDataGetLength(signature.get())));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800888}
889
890ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700891SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800892{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700893 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::decryptInTpm is not supported"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800894
Yingdi Yu2e57a582014-02-20 23:34:43 -0800895 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700896 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800897 // keyClass = KEY_CLASS_SYMMETRIC;
898 // else
899 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800900
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700901 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800902 // reinterpret_cast<const unsigned char*>(data),
903 // dataLength
904 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800905
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700906 // CFReleaser<SecKeyRef> decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
907 // if (decryptKey.get() == 0)
908 // {
909 // /// @todo Can this happen because of keychain is locked?
910 // throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain");
911 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800912
Yingdi Yu2e57a582014-02-20 23:34:43 -0800913 // CFErrorRef error;
914 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
915 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800916
Yingdi Yu2e57a582014-02-20 23:34:43 -0800917 // Boolean set_res = SecTransformSetAttribute(decrypt,
918 // kSecTransformInputAttributeName,
919 // dataRef,
920 // &error);
921 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800922
Yingdi Yu2e57a582014-02-20 23:34:43 -0800923 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
924 // if (error)
925 // {
926 // CFShow(error);
927 // throw Error("Fail to decrypt data");
928 // }
929 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800930
Yingdi Yu2e57a582014-02-20 23:34:43 -0800931 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800932}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700933
Yingdi Yu2e57a582014-02-20 23:34:43 -0800934void
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700935SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800936{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700937 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800938 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700939 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
940 if (privateKey.get() == 0)
941 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700942 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
943 "in OSX Keychain"));
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700944 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700945
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700946 CFReleaser<SecAccessRef> accRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700947 SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700948
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700949 CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
950 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700951
Yingdi Yu7036ce22014-06-19 18:53:37 -0700952 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700953 SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700954
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700955 CFReleaser<CFArrayRef> appList;
956 CFReleaser<CFStringRef> description;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800957 SecKeychainPromptSelector promptSelector;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700958 SecACLCopyContents(aclRef,
959 &appList.get(),
960 &description.get(),
961 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700962
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700963 CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
964 0,
965 appList.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700966
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700967 CFReleaser<SecTrustedApplicationRef> trustedApp;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700968 SecTrustedApplicationCreateFromPath(appPath.c_str(),
969 &trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700970
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700971 CFArrayAppendValue(newAppList.get(), trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700972
Yingdi Yu7036ce22014-06-19 18:53:37 -0700973 SecACLSetContents(aclRef,
974 newAppList.get(),
975 description.get(),
976 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700977
Yingdi Yu7036ce22014-06-19 18:53:37 -0700978 SecKeychainItemSetAccess(privateKey.get(), accRef.get());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800979 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800980}
981
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800982ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700983SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800984{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700985 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::encryptInTpm is not supported"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800986
Yingdi Yu2e57a582014-02-20 23:34:43 -0800987 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700988 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800989 // keyClass = KEY_CLASS_SYMMETRIC;
990 // else
991 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700992
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700993 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800994 // reinterpret_cast<const unsigned char*>(data),
995 // dataLength
996 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700997
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700998 // CFReleaser<SecKeyRef> encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
999 // if (encryptKey.get() == 0)
1000 // {
1001 // throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain");
1002 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001003
Yingdi Yu2e57a582014-02-20 23:34:43 -08001004 // CFErrorRef error;
1005 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
1006 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001007
Yingdi Yu2e57a582014-02-20 23:34:43 -08001008 // Boolean set_res = SecTransformSetAttribute(encrypt,
1009 // kSecTransformInputAttributeName,
1010 // dataRef,
1011 // &error);
1012 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001013
Yingdi Yu2e57a582014-02-20 23:34:43 -08001014 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
1015 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001016
Yingdi Yu2e57a582014-02-20 23:34:43 -08001017 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001018
Yingdi Yu2e57a582014-02-20 23:34:43 -08001019 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001020}
1021
1022bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001023SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001024{
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001025 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
1026
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001027 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1028 keyNameUri.c_str(),
1029 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001030
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001031 CFReleaser<CFMutableDictionaryRef> attrDict =
1032 CFDictionaryCreateMutable(0,
1033 4,
1034 &kCFTypeDictionaryKeyCallBacks,
1035 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001036
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001037 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1038 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
1039 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1040 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001041
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001042 CFReleaser<SecKeychainItemRef> itemRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001043 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001044 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001045
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001046 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001047 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -08001048 else
1049 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001050
1051}
1052
Yingdi Yu4b752752014-02-18 12:24:03 -08001053bool
1054SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
1055{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001056 return SecRandomCopyBytes(kSecRandomDefault, size, res) == 0;
Yingdi Yu4b752752014-02-18 12:24:03 -08001057}
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001058
1059////////////////////////////////
1060// OSXPrivateKeyStorage::Impl //
1061////////////////////////////////
1062
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001063CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001064SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001065{
1066 string keyNameUri = toInternalKeyName(keyName, keyClass);
1067
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001068 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1069 keyNameUri.c_str(),
1070 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001071
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001072 CFReleaser<CFMutableDictionaryRef> attrDict =
1073 CFDictionaryCreateMutable(0,
1074 5,
1075 &kCFTypeDictionaryKeyCallBacks,
1076 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001077
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001078 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1079 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1080 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
1081 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001082
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001083 CFReleaser<SecKeychainItemRef> keyItem;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001084 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001085 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001086
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001087 if (res != errSecSuccess)
1088 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001089 else
1090 return keyItem;
1091}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001092
1093string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001094SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001095{
1096 string keyUri = keyName.toUri();
1097
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001098 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001099 return keyUri + "/symmetric";
1100 else
1101 return keyUri;
1102}
1103
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001104CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001105SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
1106{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001107 switch (keyType) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001108 case KEY_TYPE_RSA:
1109 return kSecAttrKeyTypeRSA;
Yingdi Yuc8f883c2014-06-20 23:25:22 -07001110 case KEY_TYPE_ECDSA:
1111 return kSecAttrKeyTypeECDSA;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001112 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001113 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001114 }
1115}
1116
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001117CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001118SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
1119{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001120 switch (keyType) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001121 case KEY_TYPE_AES:
1122 return kSecAttrKeyTypeAES;
1123 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001124 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001125 }
1126}
1127
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001128CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001129SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
1130{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001131 switch (keyClass) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001132 case KEY_CLASS_PRIVATE:
1133 return kSecAttrKeyClassPrivate;
1134 case KEY_CLASS_PUBLIC:
1135 return kSecAttrKeyClassPublic;
1136 case KEY_CLASS_SYMMETRIC:
1137 return kSecAttrKeyClassSymmetric;
1138 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001139 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001140 }
1141}
1142
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001143CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001144SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
1145{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001146 switch (digestAlgo) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001147 case DIGEST_ALGORITHM_SHA256:
1148 return kSecDigestSHA2;
1149 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001150 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001151 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001152}
Jeff Thompson2747dc02013-10-04 19:11:34 -07001153
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001154long
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001155SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
1156{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001157 switch (digestAlgo) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001158 case DIGEST_ALGORITHM_SHA256:
1159 return 256;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001160 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001161 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001162 }
Jeff Thompson2747dc02013-10-04 19:11:34 -07001163}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001164
Yingdi Yufc40d872014-02-18 12:56:04 -08001165} // namespace ndn