blob: 04445c3e789cfdd0e876ab3a881e43376f5d5049 [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 Yu2b2b4792014-02-04 16:27:07 -0800168 * @return the internal key name
169 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700170 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700171 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700172
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800173 /**
174 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -0800175 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800176 * @returns pointer to the key
177 */
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700178 CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700179 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700180
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800181 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800182 * @brief Convert keyType to MAC OS symmetric key key type
183 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800184 * @returns MAC OS key type
185 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300186 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800187 getSymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700188
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800189 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800190 * @brief Convert keyType to MAC OS asymmetirc key type
191 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800192 * @returns MAC OS key type
193 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300194 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800195 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700196
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800197 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800198 * @brief Convert keyClass to MAC OS key class
199 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800200 * @returns MAC OS key class
201 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300202 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800203 getKeyClass(KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700204
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800205 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800206 * @brief Convert digestAlgo to MAC OS algorithm id
207 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800208 * @returns MAC OS algorithm id
209 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300210 CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800211 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700212
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800213 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800214 * @brief Get the digest size of the corresponding algorithm
215 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800216 * @return digest size
217 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700218 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800219 getDigestSize(DigestAlgorithm digestAlgo);
220
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800221 ///////////////////////////////////////////////
222 // everything here is public, including data //
223 ///////////////////////////////////////////////
224public:
225 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800226 bool m_passwordSet;
227 string m_password;
228 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800229};
230
Yingdi Yu41546342014-11-30 23:37:53 -0800231SecTpmOsx::SecTpmOsx(const std::string& location)
232 : SecTpm(location)
233 , m_impl(new Impl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800234{
Yingdi Yu41546342014-11-30 23:37:53 -0800235 // TODO: add location support
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700236 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700237 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800238 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700239 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800240
Yingdi Yube4150e2014-02-18 13:02:46 -0800241 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700242
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800243 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700244 BOOST_THROW_EXCEPTION(Error("No default keychain, please create one first"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800245}
246
Yingdi Yu41546342014-11-30 23:37:53 -0800247SecTpmOsx::~SecTpmOsx()
248{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800249}
250
Yingdi Yube4150e2014-02-18 13:02:46 -0800251void
252SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
253{
254 m_impl->m_passwordSet = true;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700255 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800256 m_impl->m_password.clear();
257 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
258}
259
260void
261SecTpmOsx::resetTpmPassword()
262{
263 m_impl->m_passwordSet = false;
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}
267
268void
269SecTpmOsx::setInTerminal(bool inTerminal)
270{
271 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700272 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700273 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800274 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700275 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800276}
277
278bool
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700279SecTpmOsx::getInTerminal() const
Yingdi Yube4150e2014-02-18 13:02:46 -0800280{
281 return m_impl->m_inTerminal;
282}
283
284bool
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700285SecTpmOsx::isLocked()
Yingdi Yube4150e2014-02-18 13:02:46 -0800286{
287 SecKeychainStatus keychainStatus;
288
289 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700290 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800291 return true;
292 else
293 return ((kSecUnlockStateStatus & keychainStatus) == 0);
294}
295
Yingdi Yu2e57a582014-02-20 23:34:43 -0800296bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800297SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
298{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700299 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800300
301 // If the default key chain is already unlocked, return immediately.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700302 if (!isLocked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800303 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800304
305 // If the default key chain is locked, unlock the key chain.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700306 if (usePassword)
Yingdi Yube4150e2014-02-18 13:02:46 -0800307 {
308 // Use the supplied password.
309 res = SecKeychainUnlock(m_impl->m_keyChainRef,
310 passwordLength,
311 password,
312 true);
313 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700314 else if (m_impl->m_passwordSet)
Yingdi Yube4150e2014-02-18 13:02:46 -0800315 {
316 // If no password supplied, then use the configured password if exists.
317 SecKeychainUnlock(m_impl->m_keyChainRef,
318 m_impl->m_password.size(),
319 m_impl->m_password.c_str(),
320 true);
321 }
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800322#ifdef NDN_CXX_HAVE_GETPASS
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700323 else if (m_impl->m_inTerminal)
Yingdi Yube4150e2014-02-18 13:02:46 -0800324 {
325 // If no configured password, get password from terminal if inTerminal set.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700326 bool isLocked = true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800327 const char* fmt = "Password to unlock the default keychain: ";
328 int count = 0;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700329
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700330 while (isLocked)
Yingdi Yube4150e2014-02-18 13:02:46 -0800331 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700332 if (count > 2)
Yingdi Yube4150e2014-02-18 13:02:46 -0800333 break;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700334
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700335 char* getPassword = 0;
Yingdi Yube4150e2014-02-18 13:02:46 -0800336 getPassword = getpass(fmt);
337 count++;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700338
Yingdi Yube4150e2014-02-18 13:02:46 -0800339 if (!getPassword)
340 continue;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700341
Yingdi Yube4150e2014-02-18 13:02:46 -0800342 res = SecKeychainUnlock(m_impl->m_keyChainRef,
343 strlen(getPassword),
344 getPassword,
345 true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700346
Yingdi Yube4150e2014-02-18 13:02:46 -0800347 memset(getPassword, 0, strlen(getPassword));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700348
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700349 if (res == errSecSuccess)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800350 break;
Yingdi Yube4150e2014-02-18 13:02:46 -0800351 }
352 }
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800353#endif // NDN_CXX_HAVE_GETPASS
Yingdi Yube4150e2014-02-18 13:02:46 -0800354 else
355 {
356 // If inTerminal is not set, get the password from GUI.
357 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
358 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800359
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700360 return !isLocked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800361}
362
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700363void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700364SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName,
365 const KeyParams& params,
366 bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700367{
368
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700369 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
370 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700371 BOOST_THROW_EXCEPTION(Error("keyName already exists"));
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700372 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800373
374 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
375
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700376 CFReleaser<CFStringRef> keyLabel =
377 CFStringCreateWithCString(0,
378 keyNameUri.c_str(),
379 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800380
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700381 CFReleaser<CFMutableDictionaryRef> attrDict =
382 CFDictionaryCreateMutable(0,
383 3,
384 &kCFTypeDictionaryKeyCallBacks,
385 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700386
Yingdi Yu7036ce22014-06-19 18:53:37 -0700387 KeyType keyType = params.getKeyType();
388 uint32_t keySize;
389 switch (keyType)
390 {
391 case KEY_TYPE_RSA:
392 {
393 const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
394 keySize = rsaParams.getKeySize();
395 break;
396 }
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700397 case KEY_TYPE_ECDSA:
398 {
399 const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
400 keySize = ecdsaParams.getKeySize();
401 break;
402 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700403 default:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700404 BOOST_THROW_EXCEPTION(Error("Fail to create a key pair: Unsupported key type"));
Yingdi Yu7036ce22014-06-19 18:53:37 -0700405 }
406
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700407 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800408
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700409 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
410 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
411 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800412
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700413 CFReleaser<SecKeyRef> publicKey, privateKey;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700414 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700415 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(),
416 &publicKey.get(), &privateKey.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800417
Yingdi Yube4150e2014-02-18 13:02:46 -0800418 if (res == errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800419 {
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800420 return;
421 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700422
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700423 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800424 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700425 if (unlockTpm(0, 0, false))
Yingdi Yu7036ce22014-06-19 18:53:37 -0700426 generateKeyPairInTpmInternal(keyName, params, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800427 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700428 BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
Yingdi Yube4150e2014-02-18 13:02:46 -0800429 }
430 else
431 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700432 BOOST_THROW_EXCEPTION(Error("Fail to create a key pair"));
Yingdi Yube4150e2014-02-18 13:02:46 -0800433 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800434}
435
436void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700437SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800438{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700439 CFReleaser<CFStringRef> keyLabel =
440 CFStringCreateWithCString(0,
441 keyName.toUri().c_str(),
442 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800443
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700444 CFReleaser<CFMutableDictionaryRef> searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700445 CFDictionaryCreateMutable(0, 5,
446 &kCFTypeDictionaryKeyCallBacks,
447 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800448
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700449 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
450 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
451 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
452 OSStatus res = SecItemDelete(searchDict.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800453
454 if (res == errSecSuccess)
455 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700456
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700457 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800458 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700459 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800460 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800461 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800462}
463
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700464void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700465SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800466{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700467 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported"));
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700468 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800469 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800470
Yingdi Yu2e57a582014-02-20 23:34:43 -0800471 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800472
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700473 // CFReleaser<CFMutableDictionaryRef> attrDict =
474 // CFDictionaryCreateMutable(kCFAllocatorDefault,
475 // 0,
476 // &kCFTypeDictionaryKeyCallBacks,
477 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800478
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700479 // CFReleaser<CFStringRef> keyLabel =
480 // CFStringCreateWithCString(0,
481 // keyNameUri.c_str(),
482 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800483
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700484 // CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
485
486 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType));
487 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
488 // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue);
489 // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800490
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700491 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800492
Yingdi Yu2e57a582014-02-20 23:34:43 -0800493 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800494
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700495 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800496 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800497}
498
Yingdi Yu2e57a582014-02-20 23:34:43 -0800499shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700500SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800501{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700502 CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
503 if (publicKey.get() == 0)
504 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700505 BOOST_THROW_EXCEPTION(Error("Requested public key [" + keyName.toUri() + "] does not exist "
506 "in OSX Keychain"));
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700507 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800508
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700509 CFReleaser<CFDataRef> exportedKey;
510 OSStatus res = SecItemExport(publicKey.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800511 kSecFormatOpenSSL,
512 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700513 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700514 &exportedKey.get());
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800515 if (res != errSecSuccess)
516 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700517 BOOST_THROW_EXCEPTION(Error("Cannot export requested public key from OSX Keychain"));
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800518 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800519
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700520 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey.get()),
521 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800522 return key;
523}
524
Yingdi Yu41546342014-11-30 23:37:53 -0800525std::string
526SecTpmOsx::getScheme()
527{
528 return SCHEME;
529}
530
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800531ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700532SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800533{
534 using namespace CryptoPP;
535
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700536 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
537 if (privateKey.get() == 0)
538 {
539 /// @todo Can this happen because of keychain is locked?
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700540 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
541 "in OSX Keychain"));
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700542 }
543
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700544 shared_ptr<PublicKey> publicKey = getPublicKeyFromTpm(keyName);
545
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700546 CFReleaser<CFDataRef> exportedKey;
547 OSStatus res = SecItemExport(privateKey.get(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800548 kSecFormatOpenSSL,
549 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700550 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700551 &exportedKey.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800552
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700553 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800554 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700555 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800556 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700557 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700558 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800559 else
560 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800561 }
562 else
563 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800564 }
565
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800566 uint32_t version = 0;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700567 OID algorithm;
568 bool hasParameters = false;
569 OID algorithmParameter;
570 switch (publicKey->getKeyType()) {
571 case KEY_TYPE_RSA:
572 {
573 algorithm = oid::RSA; // "RSA encryption"
574 hasParameters = false;
575 break;
576 }
577 case KEY_TYPE_ECDSA:
578 {
579 // "ECDSA encryption"
580 StringSource src(publicKey->get().buf(), publicKey->get().size(), true);
581 BERSequenceDecoder subjectPublicKeyInfo(src);
582 {
583 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
584 {
585 algorithm.decode(algorithmInfo);
586 algorithmParameter.decode(algorithmInfo);
587 }
588 }
589 hasParameters = true;
590 break;
591 }
592 default:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700593 BOOST_THROW_EXCEPTION(Error("Unsupported key type" +
594 boost::lexical_cast<std::string>(publicKey->getKeyType())));
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700595 }
596
597 OBufferStream pkcs8Os;
598 FileSink sink(pkcs8Os);
599
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800600 SecByteBlock rawKeyBits;
601 // PrivateKeyInfo ::= SEQUENCE {
602 // version INTEGER,
603 // privateKeyAlgorithm SEQUENCE,
604 // privateKey OCTECT STRING}
605 DERSequenceEncoder privateKeyInfo(sink);
606 {
607 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
608 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
609 {
610 algorithm.encode(privateKeyAlgorithm);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700611 if (hasParameters)
612 algorithmParameter.encode(privateKeyAlgorithm);
613 else
614 DEREncodeNull(privateKeyAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800615 }
616 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700617 DEREncodeOctetString(privateKeyInfo,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700618 CFDataGetBytePtr(exportedKey.get()),
619 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800620 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700621 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800622
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700623 return pkcs8Os.buf();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800624}
625
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700626#ifdef __GNUC__
627#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
628#pragma GCC diagnostic push
629#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
630#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
631#endif // __GNUC__
632
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800633bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700634SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700635 const uint8_t* buf, size_t size,
636 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800637{
638 using namespace CryptoPP;
639
640 StringSource privateKeySource(buf, size, true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800641 SecByteBlock rawKeyBits;
642 // PrivateKeyInfo ::= SEQUENCE {
643 // INTEGER,
644 // SEQUENCE,
645 // OCTECT STRING}
646 BERSequenceDecoder privateKeyInfo(privateKeySource);
647 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700648 uint32_t versionNum;
649 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800650 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
651 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700652 OID keyTypeOID;
653 keyTypeOID.decode(sequenceDecoder);
654
655 if (keyTypeOID == oid::RSA)
656 BERDecodeNull(sequenceDecoder);
657 else if (keyTypeOID == oid::ECDSA)
658 {
659 OID parameterOID;
660 parameterOID.decode(sequenceDecoder);
661 }
662 else
663 return false; // Unsupported key type;
664
665
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800666 }
667 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
668 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700669 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800670
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700671 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
672 rawKeyBits.BytePtr(),
673 rawKeyBits.size(),
674 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800675
676 SecExternalFormat externalFormat = kSecFormatOpenSSL;
677 SecExternalItemType externalType = kSecItemTypePrivateKey;
678 SecKeyImportExportParameters keyParams;
679 memset(&keyParams, 0, sizeof(keyParams));
680 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
681 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700682 CFReleaser<SecAccessRef> access;
683 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
684 keyName.toUri().c_str(),
685 kCFStringEncodingUTF8);
686 SecAccessCreate(keyLabel.get(), 0, &access.get());
687 keyParams.accessRef = access.get();
688 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800689
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700690#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700691#pragma clang diagnostic push
692#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700693#endif // __clang__
694
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700695 OSStatus res = SecKeychainItemImport(importedKey.get(),
696 0,
697 &externalFormat,
698 &externalType,
699 0,
700 &keyParams,
701 m_impl->m_keyChainRef,
702 &outItems.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700703
704#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700705#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700706#endif // __clang__
707
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700708 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800709 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700710 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800711 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700712 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700713 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800714 else
715 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800716 }
717 else
718 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800719 }
720
Yingdi Yu7036ce22014-06-19 18:53:37 -0700721 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700722 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800723 SecKeychainAttribute attrs[1]; // maximum number of attributes
724 SecKeychainAttributeList attrList = { 0, attrs };
725 string keyUri = keyName.toUri();
726 {
727 attrs[attrList.count].tag = kSecKeyPrintName;
728 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700729 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800730 attrList.count++;
731 }
732
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700733 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800734 &attrList,
735 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700736 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700737
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700738 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800739 {
740 return false;
741 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700742
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800743 return true;
744}
745
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700746#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
747#pragma GCC diagnostic pop
748#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
749
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800750bool
751SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
752{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700753 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
754 buf,
755 size,
756 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800757
758 SecExternalFormat externalFormat = kSecFormatOpenSSL;
759 SecExternalItemType externalType = kSecItemTypePublicKey;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700760 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800761
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700762 OSStatus res = SecItemImport(importedKey.get(),
763 0,
764 &externalFormat,
765 &externalType,
766 0,
767 0,
768 m_impl->m_keyChainRef,
769 &outItems.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800770
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700771 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800772 return false;
773
Yingdi Yu7036ce22014-06-19 18:53:37 -0700774 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700775 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800776 SecKeychainAttribute attrs[1]; // maximum number of attributes
777 SecKeychainAttributeList attrList = { 0, attrs };
778 string keyUri = keyName.toUri();
779 {
780 attrs[attrList.count].tag = kSecKeyPrintName;
781 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700782 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800783 attrList.count++;
784 }
785
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700786 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800787 &attrList,
788 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700789 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700790
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700791 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800792 return false;
793
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800794 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800795}
796
797Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700798SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
799 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800800{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700801 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
802 data,
803 dataLength,
804 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800805
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700806 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
807 if (privateKey.get() == 0)
808 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700809 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
810 "in OSX Keychain"));
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700811 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700812
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700813 CFReleaser<CFErrorRef> error;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700814 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700815 CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
816 &error.get());
817 if (error.get() != 0)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700818 BOOST_THROW_EXCEPTION(Error("Fail to create signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800819
820 // Set input
Yingdi Yu7036ce22014-06-19 18:53:37 -0700821 SecTransformSetAttribute(signer.get(),
822 kSecTransformInputAttributeName,
823 dataRef.get(),
824 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700825 if (error.get() != 0)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700826 BOOST_THROW_EXCEPTION(Error("Fail to configure input of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800827
828 // Enable use of padding
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700829 SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800830 kSecPaddingKey,
831 kSecPaddingPKCS1Key,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700832 &error.get());
833 if (error.get() != 0)
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 type
Yingdi Yu7036ce22014-06-19 18:53:37 -0700837 SecTransformSetAttribute(signer.get(),
838 kSecDigestTypeAttribute,
839 m_impl->getDigestAlgorithm(digestAlgorithm),
840 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700841 if (error.get() != 0)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700842 BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800843
844 // Set padding attribute
845 long digestSize = m_impl->getDigestSize(digestAlgorithm);
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700846 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700847 SecTransformSetAttribute(signer.get(),
848 kSecDigestLengthAttribute,
849 cfDigestSize.get(),
850 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700851 if (error.get() != 0)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700852 BOOST_THROW_EXCEPTION(Error("Fail to configure digest size of signer"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800853
854 // Actually sign
Yingdi Yu7036ce22014-06-19 18:53:37 -0700855 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700856 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
857 if (error.get() != 0)
Yingdi Yube4150e2014-02-18 13:02:46 -0800858 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700859 if (!needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800860 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700861 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800862 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
863 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700864 BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain"));
Yingdi Yube4150e2014-02-18 13:02:46 -0800865 }
866 else
867 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700868 CFShow(error.get());
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700869 BOOST_THROW_EXCEPTION(Error("Fail to sign data"));
Yingdi Yube4150e2014-02-18 13:02:46 -0800870 }
871 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800872
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700873 if (signature.get() == 0)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700874 BOOST_THROW_EXCEPTION(Error("Signature is NULL!\n"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800875
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600876 return Block(tlv::SignatureValue,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700877 make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
878 CFDataGetLength(signature.get())));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800879}
880
881ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700882SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800883{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700884 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::decryptInTpm is not supported"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800885
Yingdi Yu2e57a582014-02-20 23:34:43 -0800886 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700887 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800888 // keyClass = KEY_CLASS_SYMMETRIC;
889 // else
890 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800891
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700892 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800893 // reinterpret_cast<const unsigned char*>(data),
894 // dataLength
895 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800896
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700897 // CFReleaser<SecKeyRef> decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
898 // if (decryptKey.get() == 0)
899 // {
900 // /// @todo Can this happen because of keychain is locked?
901 // throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain");
902 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800903
Yingdi Yu2e57a582014-02-20 23:34:43 -0800904 // CFErrorRef error;
905 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
906 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800907
Yingdi Yu2e57a582014-02-20 23:34:43 -0800908 // Boolean set_res = SecTransformSetAttribute(decrypt,
909 // kSecTransformInputAttributeName,
910 // dataRef,
911 // &error);
912 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800913
Yingdi Yu2e57a582014-02-20 23:34:43 -0800914 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
915 // if (error)
916 // {
917 // CFShow(error);
918 // throw Error("Fail to decrypt data");
919 // }
920 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800921
Yingdi Yu2e57a582014-02-20 23:34:43 -0800922 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800923}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700924
Yingdi Yu2e57a582014-02-20 23:34:43 -0800925void
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700926SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800927{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700928 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800929 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700930 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
931 if (privateKey.get() == 0)
932 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700933 BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist "
934 "in OSX Keychain"));
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700935 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700936
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700937 CFReleaser<SecAccessRef> accRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700938 SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700939
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700940 CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
941 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700942
Yingdi Yu7036ce22014-06-19 18:53:37 -0700943 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700944 SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700945
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700946 CFReleaser<CFArrayRef> appList;
947 CFReleaser<CFStringRef> description;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800948 SecKeychainPromptSelector promptSelector;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700949 SecACLCopyContents(aclRef,
950 &appList.get(),
951 &description.get(),
952 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700953
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700954 CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
955 0,
956 appList.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700957
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700958 CFReleaser<SecTrustedApplicationRef> trustedApp;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700959 SecTrustedApplicationCreateFromPath(appPath.c_str(),
960 &trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700961
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700962 CFArrayAppendValue(newAppList.get(), trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700963
Yingdi Yu7036ce22014-06-19 18:53:37 -0700964 SecACLSetContents(aclRef,
965 newAppList.get(),
966 description.get(),
967 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700968
Yingdi Yu7036ce22014-06-19 18:53:37 -0700969 SecKeychainItemSetAccess(privateKey.get(), accRef.get());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800970 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800971}
972
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800973ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700974SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800975{
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700976 BOOST_THROW_EXCEPTION(Error("SecTpmOsx::encryptInTpm is not supported"));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800977
Yingdi Yu2e57a582014-02-20 23:34:43 -0800978 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700979 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800980 // keyClass = KEY_CLASS_SYMMETRIC;
981 // else
982 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700983
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700984 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800985 // reinterpret_cast<const unsigned char*>(data),
986 // dataLength
987 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700988
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700989 // CFReleaser<SecKeyRef> encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
990 // if (encryptKey.get() == 0)
991 // {
992 // throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain");
993 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800994
Yingdi Yu2e57a582014-02-20 23:34:43 -0800995 // CFErrorRef error;
996 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
997 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800998
Yingdi Yu2e57a582014-02-20 23:34:43 -0800999 // Boolean set_res = SecTransformSetAttribute(encrypt,
1000 // kSecTransformInputAttributeName,
1001 // dataRef,
1002 // &error);
1003 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001004
Yingdi Yu2e57a582014-02-20 23:34:43 -08001005 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
1006 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001007
Yingdi Yu2e57a582014-02-20 23:34:43 -08001008 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001009
Yingdi Yu2e57a582014-02-20 23:34:43 -08001010 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001011}
1012
1013bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001014SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001015{
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001016 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
1017
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001018 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1019 keyNameUri.c_str(),
1020 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001021
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001022 CFReleaser<CFMutableDictionaryRef> attrDict =
1023 CFDictionaryCreateMutable(0,
1024 4,
1025 &kCFTypeDictionaryKeyCallBacks,
1026 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001027
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001028 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1029 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
1030 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1031 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001032
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001033 CFReleaser<SecKeychainItemRef> itemRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001034 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001035 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001036
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001037 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001038 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -08001039 else
1040 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001041
1042}
1043
Yingdi Yu4b752752014-02-18 12:24:03 -08001044bool
1045SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
1046{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001047 return SecRandomCopyBytes(kSecRandomDefault, size, res) == 0;
Yingdi Yu4b752752014-02-18 12:24:03 -08001048}
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001049
1050////////////////////////////////
1051// OSXPrivateKeyStorage::Impl //
1052////////////////////////////////
1053
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001054CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001055SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001056{
1057 string keyNameUri = toInternalKeyName(keyName, keyClass);
1058
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001059 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1060 keyNameUri.c_str(),
1061 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001062
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001063 CFReleaser<CFMutableDictionaryRef> attrDict =
1064 CFDictionaryCreateMutable(0,
1065 5,
1066 &kCFTypeDictionaryKeyCallBacks,
1067 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001068
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001069 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1070 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1071 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
1072 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001073
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001074 CFReleaser<SecKeychainItemRef> keyItem;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001075 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001076 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001077
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001078 if (res != errSecSuccess)
1079 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001080 else
1081 return keyItem;
1082}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001083
1084string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001085SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001086{
1087 string keyUri = keyName.toUri();
1088
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001089 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001090 return keyUri + "/symmetric";
1091 else
1092 return keyUri;
1093}
1094
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001095CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001096SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
1097{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001098 switch (keyType) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001099 case KEY_TYPE_RSA:
1100 return kSecAttrKeyTypeRSA;
Yingdi Yuc8f883c2014-06-20 23:25:22 -07001101 case KEY_TYPE_ECDSA:
1102 return kSecAttrKeyTypeECDSA;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001103 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001104 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001105 }
1106}
1107
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001108CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001109SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
1110{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001111 switch (keyType) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001112 case KEY_TYPE_AES:
1113 return kSecAttrKeyTypeAES;
1114 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001115 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001116 }
1117}
1118
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001119CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001120SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
1121{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001122 switch (keyClass) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001123 case KEY_CLASS_PRIVATE:
1124 return kSecAttrKeyClassPrivate;
1125 case KEY_CLASS_PUBLIC:
1126 return kSecAttrKeyClassPublic;
1127 case KEY_CLASS_SYMMETRIC:
1128 return kSecAttrKeyClassSymmetric;
1129 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001130 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001131 }
1132}
1133
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001134CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001135SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
1136{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001137 switch (digestAlgo) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001138 case DIGEST_ALGORITHM_SHA256:
1139 return kSecDigestSHA2;
1140 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001141 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001142 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001143}
Jeff Thompson2747dc02013-10-04 19:11:34 -07001144
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001145long
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001146SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
1147{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001148 switch (digestAlgo) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001149 case DIGEST_ALGORITHM_SHA256:
1150 return 256;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001151 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001152 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001153 }
Jeff Thompson2747dc02013-10-04 19:11:34 -07001154}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001155
Yingdi Yufc40d872014-02-18 12:56:04 -08001156} // namespace ndn