blob: 593c586bbce06e736cdaad54499f21bd0b1f40d7 [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 Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 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 Afanasyeve2dcdfd2014-02-07 15:53:28 -080024#include "common.hpp"
25
Alexander Afanasyev19508852014-01-29 01:01:51 -080026#include "sec-tpm-osx.hpp"
Yingdi Yuf56c68f2014-04-24 21:50:13 -070027#include "public-key.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070028#include "../encoding/oid.hpp"
29#include "../encoding/buffer-stream.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070030#include "cryptopp.hpp"
Jeff Thompson2747dc02013-10-04 19:11:34 -070031
Yingdi Yu2b2b4792014-02-04 16:27:07 -080032#include <pwd.h>
33#include <unistd.h>
34#include <stdlib.h>
35#include <string.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070036
Alexander Afanasyev1c6976d2014-07-13 11:40:50 -070037#include <boost/lexical_cast.hpp>
38
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080039#include <CoreFoundation/CoreFoundation.h>
40#include <Security/Security.h>
Yingdi Yu4b752752014-02-18 12:24:03 -080041#include <Security/SecRandom.h>
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080042#include <CoreServices/CoreServices.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070043
Alexander Afanasyev59d67a52014-04-03 16:09:31 -070044#include <Security/SecDigestTransform.h>
45
Yingdi Yufc40d872014-02-18 12:56:04 -080046namespace ndn {
47
Yingdi Yu7036ce22014-06-19 18:53:37 -070048using std::string;
49
Yingdi Yu41546342014-11-30 23:37:53 -080050const std::string SecTpmOsx::SCHEME("tpm-osxkeychain:");
51
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070052/**
53 * @brief Helper class to wrap CoreFoundation object pointers
54 *
55 * The class is similar in spirit to shared_ptr, but uses CoreFoundation
56 * mechanisms to retain/release object.
57 *
58 * Original implementation by Christopher Hunt and it was borrowed from
59 * http://www.cocoabuilder.com/archive/cocoa/130776-auto-cfrelease-and.html
60 */
61template<class T>
62class CFReleaser
63{
64public:
65 //////////////////////////////
66 // Construction/destruction //
67
68 CFReleaser()
69 : m_typeRef(0)
70 {
71 }
72
73 CFReleaser(const T& typeRef)
74 : m_typeRef(typeRef)
75 {
76 }
77
78 CFReleaser(const CFReleaser& inReleaser)
79 : m_typeRef(0)
80 {
81 retain(inReleaser.m_typeRef);
82 }
83
84 CFReleaser&
85 operator=(const T& typeRef)
86 {
87 if (typeRef != m_typeRef) {
88 release();
89 m_typeRef = typeRef;
90 }
91 return *this;
92 }
93
94 CFReleaser&
95 operator=(const CFReleaser& inReleaser)
96 {
97 retain(inReleaser.m_typeRef);
98 return *this;
99 }
100
101 ~CFReleaser()
102 {
103 release();
104 }
105
106 ////////////
107 // Access //
108
109 // operator const T&() const
110 // {
111 // return m_typeRef;
112 // }
113
114 // operator T&()
115 // {
116 // return m_typeRef;
117 // }
118
119 const T&
120 get() const
121 {
122 return m_typeRef;
123 }
124
125 T&
126 get()
127 {
128 return m_typeRef;
129 }
130
131 ///////////////////
132 // Miscellaneous //
133
134 void
135 retain(const T& typeRef)
136 {
137 if (typeRef != 0) {
138 CFRetain(typeRef);
139 }
140 release();
141 m_typeRef = typeRef;
142 }
143
144 void release()
145 {
146 if (m_typeRef != 0) {
147 CFRelease(m_typeRef);
148 m_typeRef = 0;
149 }
150 };
151
152private:
153 T m_typeRef;
154};
155
156
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700157class SecTpmOsx::Impl
158{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800159public:
160 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -0800161 : m_passwordSet(false)
162 , m_inTerminal(false)
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -0700163 {
164 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700165
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800166 /**
167 * @brief Convert NDN name of a key to internal name of the key.
168 *
Yingdi Yufc40d872014-02-18 12:56:04 -0800169 * @param keyName
170 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800171 * @return the internal key name
172 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700173 std::string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700174 toInternalKeyName(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700175
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800176 /**
177 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -0800178 *
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700179 * @param keyName
Yingdi Yufc40d872014-02-18 12:56:04 -0800180 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800181 * @returns pointer to the key
182 */
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700183 CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700184 getKey(const Name& keyName, KeyClass keyClass);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700185
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800186 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800187 * @brief Convert keyType to MAC OS symmetric key key type
188 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800189 * @param keyType
190 * @returns MAC OS key type
191 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300192 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800193 getSymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700194
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800195 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800196 * @brief Convert keyType to MAC OS asymmetirc key type
197 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800198 * @param keyType
199 * @returns MAC OS key type
200 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300201 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800202 getAsymKeyType(KeyType keyType);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700203
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800204 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800205 * @brief Convert keyClass to MAC OS key class
206 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800207 * @param keyClass
208 * @returns MAC OS key class
209 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300210 CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800211 getKeyClass(KeyClass keyClass);
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 Convert digestAlgo to MAC OS algorithm id
215 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800216 * @param digestAlgo
217 * @returns MAC OS algorithm id
218 */
Alexander Afanasyev24b75c82014-05-31 15:59:31 +0300219 CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800220 getDigestAlgorithm(DigestAlgorithm digestAlgo);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700221
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800222 /**
Yingdi Yufc40d872014-02-18 12:56:04 -0800223 * @brief Get the digest size of the corresponding algorithm
224 *
225 * @param digestAlgo
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800226 * @return digest size
227 */
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700228 long
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800229 getDigestSize(DigestAlgorithm digestAlgo);
230
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800231 ///////////////////////////////////////////////
232 // everything here is public, including data //
233 ///////////////////////////////////////////////
234public:
235 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800236 bool m_passwordSet;
237 string m_password;
238 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800239};
240
Yingdi Yu41546342014-11-30 23:37:53 -0800241SecTpmOsx::SecTpmOsx(const std::string& location)
242 : SecTpm(location)
243 , m_impl(new Impl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800244{
Yingdi Yu41546342014-11-30 23:37:53 -0800245 // TODO: add location support
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700246 if (m_impl->m_inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700247 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800248 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700249 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800250
Yingdi Yube4150e2014-02-18 13:02:46 -0800251 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700252
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800253 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Yingdi Yube4150e2014-02-18 13:02:46 -0800254 throw Error("No default keychain, create one first!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800255}
256
Yingdi Yu41546342014-11-30 23:37:53 -0800257SecTpmOsx::~SecTpmOsx()
258{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800259}
260
Yingdi Yube4150e2014-02-18 13:02:46 -0800261void
262SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
263{
264 m_impl->m_passwordSet = true;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700265 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800266 m_impl->m_password.clear();
267 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
268}
269
270void
271SecTpmOsx::resetTpmPassword()
272{
273 m_impl->m_passwordSet = false;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700274 std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0);
Yingdi Yube4150e2014-02-18 13:02:46 -0800275 m_impl->m_password.clear();
276}
277
278void
279SecTpmOsx::setInTerminal(bool inTerminal)
280{
281 m_impl->m_inTerminal = inTerminal;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700282 if (inTerminal)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700283 SecKeychainSetUserInteractionAllowed(false);
Yingdi Yube4150e2014-02-18 13:02:46 -0800284 else
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700285 SecKeychainSetUserInteractionAllowed(true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800286}
287
288bool
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700289SecTpmOsx::getInTerminal() const
Yingdi Yube4150e2014-02-18 13:02:46 -0800290{
291 return m_impl->m_inTerminal;
292}
293
294bool
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700295SecTpmOsx::isLocked()
Yingdi Yube4150e2014-02-18 13:02:46 -0800296{
297 SecKeychainStatus keychainStatus;
298
299 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700300 if (res != errSecSuccess)
Yingdi Yube4150e2014-02-18 13:02:46 -0800301 return true;
302 else
303 return ((kSecUnlockStateStatus & keychainStatus) == 0);
304}
305
Yingdi Yu2e57a582014-02-20 23:34:43 -0800306bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800307SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
308{
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700309 OSStatus res;
Yingdi Yube4150e2014-02-18 13:02:46 -0800310
311 // If the default key chain is already unlocked, return immediately.
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700312 if (!isLocked())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800313 return true;
Yingdi Yube4150e2014-02-18 13:02:46 -0800314
315 // If the default key chain is locked, unlock the key chain.
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700316 if (usePassword)
Yingdi Yube4150e2014-02-18 13:02:46 -0800317 {
318 // Use the supplied password.
319 res = SecKeychainUnlock(m_impl->m_keyChainRef,
320 passwordLength,
321 password,
322 true);
323 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700324 else if (m_impl->m_passwordSet)
Yingdi Yube4150e2014-02-18 13:02:46 -0800325 {
326 // If no password supplied, then use the configured password if exists.
327 SecKeychainUnlock(m_impl->m_keyChainRef,
328 m_impl->m_password.size(),
329 m_impl->m_password.c_str(),
330 true);
331 }
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 }
362 else
363 {
364 // If inTerminal is not set, get the password from GUI.
365 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
366 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800367
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700368 return !isLocked();
Yingdi Yube4150e2014-02-18 13:02:46 -0800369}
370
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700371void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700372SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName,
373 const KeyParams& params,
374 bool needRetry)
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700375{
376
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700377 if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
378 {
379 throw Error("keyName has existed");
380 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800381
382 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
383
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700384 CFReleaser<CFStringRef> keyLabel =
385 CFStringCreateWithCString(0,
386 keyNameUri.c_str(),
387 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800388
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700389 CFReleaser<CFMutableDictionaryRef> attrDict =
390 CFDictionaryCreateMutable(0,
391 3,
392 &kCFTypeDictionaryKeyCallBacks,
393 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700394
Yingdi Yu7036ce22014-06-19 18:53:37 -0700395 KeyType keyType = params.getKeyType();
396 uint32_t keySize;
397 switch (keyType)
398 {
399 case KEY_TYPE_RSA:
400 {
401 const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
402 keySize = rsaParams.getKeySize();
403 break;
404 }
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700405 case KEY_TYPE_ECDSA:
406 {
407 const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
408 keySize = ecdsaParams.getKeySize();
409 break;
410 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700411 default:
412 throw Error("Fail to create a key pair: Unsupported key type");
413 }
414
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700415 CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800416
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700417 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
418 CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
419 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800420
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700421 CFReleaser<SecKeyRef> publicKey, privateKey;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700422 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700423 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(),
424 &publicKey.get(), &privateKey.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800425
Yingdi Yube4150e2014-02-18 13:02:46 -0800426 if (res == errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800427 {
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800428 return;
429 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700430
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700431 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800432 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700433 if (unlockTpm(0, 0, false))
Yingdi Yu7036ce22014-06-19 18:53:37 -0700434 generateKeyPairInTpmInternal(keyName, params, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800435 else
436 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800437 }
438 else
439 {
Yingdi Yube4150e2014-02-18 13:02:46 -0800440 throw Error("Fail to create a key pair");
441 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800442}
443
444void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700445SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800446{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700447 CFReleaser<CFStringRef> keyLabel =
448 CFStringCreateWithCString(0,
449 keyName.toUri().c_str(),
450 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800451
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700452 CFReleaser<CFMutableDictionaryRef> searchDict =
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700453 CFDictionaryCreateMutable(0, 5,
454 &kCFTypeDictionaryKeyCallBacks,
455 &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800456
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700457 CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey);
458 CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get());
459 CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll);
460 OSStatus res = SecItemDelete(searchDict.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800461
462 if (res == errSecSuccess)
463 return;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700464
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700465 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800466 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700467 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800468 deleteKeyPairInTpmInternal(keyName, true);
Yingdi Yube4150e2014-02-18 13:02:46 -0800469 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800470}
471
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700472void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700473SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800474{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800475 throw Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700476 // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800477 // throw Error("keyName has existed!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800478
Yingdi Yu2e57a582014-02-20 23:34:43 -0800479 // string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800480
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700481 // CFReleaser<CFMutableDictionaryRef> attrDict =
482 // CFDictionaryCreateMutable(kCFAllocatorDefault,
483 // 0,
484 // &kCFTypeDictionaryKeyCallBacks,
485 // &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800486
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700487 // CFReleaser<CFStringRef> keyLabel =
488 // CFStringCreateWithCString(0,
489 // keyNameUri.c_str(),
490 // kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800491
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700492 // CFReleaser<CFNumberRef> cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize);
493
494 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType));
495 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get());
496 // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue);
497 // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800498
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700499 // CFErrorRef error = 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800500
Yingdi Yu2e57a582014-02-20 23:34:43 -0800501 // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800502
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700503 // if (error)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800504 // throw Error("Fail to create a symmetric key");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800505}
506
Yingdi Yu2e57a582014-02-20 23:34:43 -0800507shared_ptr<PublicKey>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700508SecTpmOsx::getPublicKeyFromTpm(const Name& keyName)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800509{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700510 CFReleaser<SecKeychainItemRef> publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
511 if (publicKey.get() == 0)
512 {
513 throw Error("Requested public key [" + keyName.toUri() + "] does not exist in OSX Keychain");
514 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800515
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700516 CFReleaser<CFDataRef> exportedKey;
517 OSStatus res = SecItemExport(publicKey.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800518 kSecFormatOpenSSL,
519 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700520 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700521 &exportedKey.get());
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800522 if (res != errSecSuccess)
523 {
524 throw Error("Cannot export requested public key from OSX Keychain");
525 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800526
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700527 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey.get()),
528 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800529 return key;
530}
531
Yingdi Yu41546342014-11-30 23:37:53 -0800532std::string
533SecTpmOsx::getScheme()
534{
535 return SCHEME;
536}
537
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800538ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -0700539SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800540{
541 using namespace CryptoPP;
542
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700543 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
544 if (privateKey.get() == 0)
545 {
546 /// @todo Can this happen because of keychain is locked?
547 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
548 }
549
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700550 shared_ptr<PublicKey> publicKey = getPublicKeyFromTpm(keyName);
551
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700552 CFReleaser<CFDataRef> exportedKey;
553 OSStatus res = SecItemExport(privateKey.get(),
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800554 kSecFormatOpenSSL,
555 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700556 0,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700557 &exportedKey.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800558
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700559 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800560 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700561 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800562 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700563 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700564 return exportPrivateKeyPkcs8FromTpmInternal(keyName, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800565 else
566 return shared_ptr<Buffer>();
Yingdi Yube4150e2014-02-18 13:02:46 -0800567 }
568 else
569 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800570 }
571
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800572 uint32_t version = 0;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700573 OID algorithm;
574 bool hasParameters = false;
575 OID algorithmParameter;
576 switch (publicKey->getKeyType()) {
577 case KEY_TYPE_RSA:
578 {
579 algorithm = oid::RSA; // "RSA encryption"
580 hasParameters = false;
581 break;
582 }
583 case KEY_TYPE_ECDSA:
584 {
585 // "ECDSA encryption"
586 StringSource src(publicKey->get().buf(), publicKey->get().size(), true);
587 BERSequenceDecoder subjectPublicKeyInfo(src);
588 {
589 BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo);
590 {
591 algorithm.decode(algorithmInfo);
592 algorithmParameter.decode(algorithmInfo);
593 }
594 }
595 hasParameters = true;
596 break;
597 }
598 default:
599 throw Error("Unsupported key type" +
600 boost::lexical_cast<std::string>(publicKey->getKeyType()));
601 }
602
603 OBufferStream pkcs8Os;
604 FileSink sink(pkcs8Os);
605
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800606 SecByteBlock rawKeyBits;
607 // PrivateKeyInfo ::= SEQUENCE {
608 // version INTEGER,
609 // privateKeyAlgorithm SEQUENCE,
610 // privateKey OCTECT STRING}
611 DERSequenceEncoder privateKeyInfo(sink);
612 {
613 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
614 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
615 {
616 algorithm.encode(privateKeyAlgorithm);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700617 if (hasParameters)
618 algorithmParameter.encode(privateKeyAlgorithm);
619 else
620 DEREncodeNull(privateKeyAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800621 }
622 privateKeyAlgorithm.MessageEnd();
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700623 DEREncodeOctetString(privateKeyInfo,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700624 CFDataGetBytePtr(exportedKey.get()),
625 CFDataGetLength(exportedKey.get()));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800626 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700627 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800628
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700629 return pkcs8Os.buf();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800630}
631
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700632#ifdef __GNUC__
633#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
634#pragma GCC diagnostic push
635#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
636#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
637#endif // __GNUC__
638
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800639bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700640SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700641 const uint8_t* buf, size_t size,
642 bool needRetry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800643{
644 using namespace CryptoPP;
645
646 StringSource privateKeySource(buf, size, true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800647 SecByteBlock rawKeyBits;
648 // PrivateKeyInfo ::= SEQUENCE {
649 // INTEGER,
650 // SEQUENCE,
651 // OCTECT STRING}
652 BERSequenceDecoder privateKeyInfo(privateKeySource);
653 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700654 uint32_t versionNum;
655 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800656 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
657 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700658 OID keyTypeOID;
659 keyTypeOID.decode(sequenceDecoder);
660
661 if (keyTypeOID == oid::RSA)
662 BERDecodeNull(sequenceDecoder);
663 else if (keyTypeOID == oid::ECDSA)
664 {
665 OID parameterOID;
666 parameterOID.decode(sequenceDecoder);
667 }
668 else
669 return false; // Unsupported key type;
670
671
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800672 }
673 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
674 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700675 privateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800676
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700677 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
678 rawKeyBits.BytePtr(),
679 rawKeyBits.size(),
680 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800681
682 SecExternalFormat externalFormat = kSecFormatOpenSSL;
683 SecExternalItemType externalType = kSecItemTypePrivateKey;
684 SecKeyImportExportParameters keyParams;
685 memset(&keyParams, 0, sizeof(keyParams));
686 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
687 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700688 CFReleaser<SecAccessRef> access;
689 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
690 keyName.toUri().c_str(),
691 kCFStringEncodingUTF8);
692 SecAccessCreate(keyLabel.get(), 0, &access.get());
693 keyParams.accessRef = access.get();
694 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800695
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700696#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700697#pragma clang diagnostic push
698#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700699#endif // __clang__
700
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700701 OSStatus res = SecKeychainItemImport(importedKey.get(),
702 0,
703 &externalFormat,
704 &externalType,
705 0,
706 &keyParams,
707 m_impl->m_keyChainRef,
708 &outItems.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700709
710#ifdef __clang__
Junxiao Shi482ccc52014-03-31 13:05:24 -0700711#pragma clang diagnostic pop
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700712#endif // __clang__
713
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700714 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800715 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700716 if (res == errSecAuthFailed && !needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800717 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700718 if (unlockTpm(0, 0, false))
Yingdi Yu5e96e002014-04-23 18:32:15 -0700719 return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800720 else
721 return false;
Yingdi Yube4150e2014-02-18 13:02:46 -0800722 }
723 else
724 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800725 }
726
Yingdi Yu7036ce22014-06-19 18:53:37 -0700727 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700728 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800729 SecKeychainAttribute attrs[1]; // maximum number of attributes
730 SecKeychainAttributeList attrList = { 0, attrs };
731 string keyUri = keyName.toUri();
732 {
733 attrs[attrList.count].tag = kSecKeyPrintName;
734 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700735 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800736 attrList.count++;
737 }
738
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700739 res = SecKeychainItemModifyAttributesAndData(privateKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800740 &attrList,
741 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700742 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700743
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700744 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800745 {
746 return false;
747 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700748
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800749 return true;
750}
751
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700752#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
753#pragma GCC diagnostic pop
754#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
755
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800756bool
757SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
758{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700759 CFReleaser<CFDataRef> importedKey = CFDataCreateWithBytesNoCopy(0,
760 buf,
761 size,
762 kCFAllocatorNull);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800763
764 SecExternalFormat externalFormat = kSecFormatOpenSSL;
765 SecExternalItemType externalType = kSecItemTypePublicKey;
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700766 CFReleaser<CFArrayRef> outItems;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800767
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700768 OSStatus res = SecItemImport(importedKey.get(),
769 0,
770 &externalFormat,
771 &externalType,
772 0,
773 0,
774 m_impl->m_keyChainRef,
775 &outItems.get());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800776
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700777 if (res != errSecSuccess)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800778 return false;
779
Yingdi Yu7036ce22014-06-19 18:53:37 -0700780 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700781 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800782 SecKeychainAttribute attrs[1]; // maximum number of attributes
783 SecKeychainAttributeList attrList = { 0, attrs };
784 string keyUri = keyName.toUri();
785 {
786 attrs[attrList.count].tag = kSecKeyPrintName;
787 attrs[attrList.count].length = keyUri.size();
Yingdi Yu7036ce22014-06-19 18:53:37 -0700788 attrs[attrList.count].data = const_cast<char*>(keyUri.c_str());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800789 attrList.count++;
790 }
791
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700792 res = SecKeychainItemModifyAttributesAndData(publicKey,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800793 &attrList,
794 0,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700795 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700796
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700797 if (res != errSecSuccess)
Alexander Afanasyev60c86812014-02-20 15:19:33 -0800798 return false;
799
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800800 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800801}
802
803Block
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700804SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength,
805 const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800806{
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700807 CFReleaser<CFDataRef> dataRef = CFDataCreateWithBytesNoCopy(0,
808 data,
809 dataLength,
810 kCFAllocatorNull);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800811
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700812 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
813 if (privateKey.get() == 0)
814 {
815 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
816 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700817
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700818 CFReleaser<CFErrorRef> error;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700819 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700820 CFReleaser<SecTransformRef> signer = SecSignTransformCreate((SecKeyRef)privateKey.get(),
821 &error.get());
822 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700823 throw Error("Fail to create signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800824
825 // Set input
Yingdi Yu7036ce22014-06-19 18:53:37 -0700826 SecTransformSetAttribute(signer.get(),
827 kSecTransformInputAttributeName,
828 dataRef.get(),
829 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700830 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700831 throw Error("Fail to configure input of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800832
833 // Enable use of padding
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700834 SecTransformSetAttribute(signer.get(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800835 kSecPaddingKey,
836 kSecPaddingPKCS1Key,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700837 &error.get());
838 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700839 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800840
841 // Set padding type
Yingdi Yu7036ce22014-06-19 18:53:37 -0700842 SecTransformSetAttribute(signer.get(),
843 kSecDigestTypeAttribute,
844 m_impl->getDigestAlgorithm(digestAlgorithm),
845 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700846 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700847 throw Error("Fail to configure digest algorithm of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800848
849 // Set padding attribute
850 long digestSize = m_impl->getDigestSize(digestAlgorithm);
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700851 CFReleaser<CFNumberRef> cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700852 SecTransformSetAttribute(signer.get(),
853 kSecDigestLengthAttribute,
854 cfDigestSize.get(),
855 &error.get());
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700856 if (error.get() != 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700857 throw Error("Fail to configure digest size of signer");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800858
859 // Actually sign
Yingdi Yu7036ce22014-06-19 18:53:37 -0700860 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700861 CFReleaser<CFDataRef> signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get());
862 if (error.get() != 0)
Yingdi Yube4150e2014-02-18 13:02:46 -0800863 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700864 if (!needRetry)
Yingdi Yube4150e2014-02-18 13:02:46 -0800865 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700866 if (unlockTpm(0, 0, false))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800867 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
868 else
869 throw Error("Fail to unlock the keychain");
Yingdi Yube4150e2014-02-18 13:02:46 -0800870 }
871 else
872 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700873 CFShow(error.get());
Yingdi Yube4150e2014-02-18 13:02:46 -0800874 throw Error("Fail to sign data");
875 }
876 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800877
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700878 if (signature.get() == 0)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700879 throw Error("Signature is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800880
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600881 return Block(tlv::SignatureValue,
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700882 make_shared<Buffer>(CFDataGetBytePtr(signature.get()),
883 CFDataGetLength(signature.get())));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800884}
885
886ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700887SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800888{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800889 throw Error("SecTpmOsx::decryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800890
Yingdi Yu2e57a582014-02-20 23:34:43 -0800891 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700892 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800893 // keyClass = KEY_CLASS_SYMMETRIC;
894 // else
895 // keyClass = KEY_CLASS_PRIVATE;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800896
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700897 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800898 // reinterpret_cast<const unsigned char*>(data),
899 // dataLength
900 // );
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800901
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700902 // CFReleaser<SecKeyRef> decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
903 // if (decryptKey.get() == 0)
904 // {
905 // /// @todo Can this happen because of keychain is locked?
906 // throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain");
907 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800908
Yingdi Yu2e57a582014-02-20 23:34:43 -0800909 // CFErrorRef error;
910 // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
911 // if (error) throw Error("Fail to create decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800912
Yingdi Yu2e57a582014-02-20 23:34:43 -0800913 // Boolean set_res = SecTransformSetAttribute(decrypt,
914 // kSecTransformInputAttributeName,
915 // dataRef,
916 // &error);
917 // if (error) throw Error("Fail to configure decrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800918
Yingdi Yu2e57a582014-02-20 23:34:43 -0800919 // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
920 // if (error)
921 // {
922 // CFShow(error);
923 // throw Error("Fail to decrypt data");
924 // }
925 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800926
Yingdi Yu2e57a582014-02-20 23:34:43 -0800927 // return make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800928}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700929
Yingdi Yu2e57a582014-02-20 23:34:43 -0800930void
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700931SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800932{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700933 if (keyClass == KEY_CLASS_PRIVATE && acl == ACL_TYPE_PRIVATE)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800934 {
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700935 CFReleaser<SecKeychainItemRef> privateKey = m_impl->getKey(keyName, keyClass);
936 if (privateKey.get() == 0)
937 {
938 throw Error("Private key [" + keyName.toUri() + "] does not exist in OSX Keychain");
939 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700940
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700941 CFReleaser<SecAccessRef> accRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700942 SecKeychainItemCopyAccess(privateKey.get(), &accRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700943
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700944 CFReleaser<CFArrayRef> signACL = SecAccessCopyMatchingACLList(accRef.get(),
945 kSecACLAuthorizationSign);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700946
Yingdi Yu7036ce22014-06-19 18:53:37 -0700947 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700948 SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700949
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700950 CFReleaser<CFArrayRef> appList;
951 CFReleaser<CFStringRef> description;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800952 SecKeychainPromptSelector promptSelector;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700953 SecACLCopyContents(aclRef,
954 &appList.get(),
955 &description.get(),
956 &promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700957
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700958 CFReleaser<CFMutableArrayRef> newAppList = CFArrayCreateMutableCopy(0,
959 0,
960 appList.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700961
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700962 CFReleaser<SecTrustedApplicationRef> trustedApp;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700963 SecTrustedApplicationCreateFromPath(appPath.c_str(),
964 &trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700965
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700966 CFArrayAppendValue(newAppList.get(), trustedApp.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700967
Yingdi Yu7036ce22014-06-19 18:53:37 -0700968 SecACLSetContents(aclRef,
969 newAppList.get(),
970 description.get(),
971 promptSelector);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700972
Yingdi Yu7036ce22014-06-19 18:53:37 -0700973 SecKeychainItemSetAccess(privateKey.get(), accRef.get());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800974 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800975}
976
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800977ConstBufferPtr
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700978SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800979{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800980 throw Error("SecTpmOsx::encryptInTpm is not supported");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800981
Yingdi Yu2e57a582014-02-20 23:34:43 -0800982 // KeyClass keyClass;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700983 // if (sym)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800984 // keyClass = KEY_CLASS_SYMMETRIC;
985 // else
986 // keyClass = KEY_CLASS_PUBLIC;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700987
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700988 // CFDataRef dataRef = CFDataCreate(0,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800989 // reinterpret_cast<const unsigned char*>(data),
990 // dataLength
991 // );
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700992
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700993 // CFReleaser<SecKeyRef> encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
994 // if (encryptKey.get() == 0)
995 // {
996 // throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain");
997 // }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800998
Yingdi Yu2e57a582014-02-20 23:34:43 -0800999 // CFErrorRef error;
1000 // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
1001 // if (error) throw Error("Fail to create encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001002
Yingdi Yu2e57a582014-02-20 23:34:43 -08001003 // Boolean set_res = SecTransformSetAttribute(encrypt,
1004 // kSecTransformInputAttributeName,
1005 // dataRef,
1006 // &error);
1007 // if (error) throw Error("Fail to configure encrypt");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001008
Yingdi Yu2e57a582014-02-20 23:34:43 -08001009 // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
1010 // if (error) throw Error("Fail to encrypt data");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001011
Yingdi Yu2e57a582014-02-20 23:34:43 -08001012 // if (!output) throw Error("Output is NULL!\n");
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001013
Yingdi Yu2e57a582014-02-20 23:34:43 -08001014 // return make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001015}
1016
1017bool
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001018SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001019{
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001020 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
1021
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001022 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1023 keyNameUri.c_str(),
1024 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001025
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001026 CFReleaser<CFMutableDictionaryRef> attrDict =
1027 CFDictionaryCreateMutable(0,
1028 4,
1029 &kCFTypeDictionaryKeyCallBacks,
1030 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001031
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001032 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1033 // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
1034 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1035 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001036
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001037 CFReleaser<SecKeychainItemRef> itemRef;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001038 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001039 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001040
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001041 if (res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001042 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -08001043 else
1044 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001045
1046}
1047
Yingdi Yu4b752752014-02-18 12:24:03 -08001048bool
1049SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
1050{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001051 return SecRandomCopyBytes(kSecRandomDefault, size, res) == 0;
Yingdi Yu4b752752014-02-18 12:24:03 -08001052}
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001053
1054////////////////////////////////
1055// OSXPrivateKeyStorage::Impl //
1056////////////////////////////////
1057
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001058CFReleaser<SecKeychainItemRef>
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001059SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001060{
1061 string keyNameUri = toInternalKeyName(keyName, keyClass);
1062
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001063 CFReleaser<CFStringRef> keyLabel = CFStringCreateWithCString(0,
1064 keyNameUri.c_str(),
1065 kCFStringEncodingUTF8);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001066
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001067 CFReleaser<CFMutableDictionaryRef> attrDict =
1068 CFDictionaryCreateMutable(0,
1069 5,
1070 &kCFTypeDictionaryKeyCallBacks,
1071 0);
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001072
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001073 CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey);
1074 CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get());
1075 CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass));
1076 CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001077
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001078 CFReleaser<SecKeychainItemRef> keyItem;
Yingdi Yu7036ce22014-06-19 18:53:37 -07001079 // C-style cast is used as per Apple convention
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -07001080 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001081
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001082 if (res != errSecSuccess)
1083 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001084 else
1085 return keyItem;
1086}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001087
1088string
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001089SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001090{
1091 string keyUri = keyName.toUri();
1092
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -07001093 if (KEY_CLASS_SYMMETRIC == keyClass)
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001094 return keyUri + "/symmetric";
1095 else
1096 return keyUri;
1097}
1098
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001099CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001100SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
1101{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001102 switch (keyType) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001103 case KEY_TYPE_RSA:
1104 return kSecAttrKeyTypeRSA;
Yingdi Yuc8f883c2014-06-20 23:25:22 -07001105 case KEY_TYPE_ECDSA:
1106 return kSecAttrKeyTypeECDSA;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001107 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001108 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001109 }
1110}
1111
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001112CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001113SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
1114{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001115 switch (keyType) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001116 case KEY_TYPE_AES:
1117 return kSecAttrKeyTypeAES;
1118 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001119 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001120 }
1121}
1122
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001123CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001124SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
1125{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001126 switch (keyClass) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001127 case KEY_CLASS_PRIVATE:
1128 return kSecAttrKeyClassPrivate;
1129 case KEY_CLASS_PUBLIC:
1130 return kSecAttrKeyClassPublic;
1131 case KEY_CLASS_SYMMETRIC:
1132 return kSecAttrKeyClassSymmetric;
1133 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001134 return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001135 }
1136}
1137
Alexander Afanasyev24b75c82014-05-31 15:59:31 +03001138CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001139SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
1140{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001141 switch (digestAlgo) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001142 case DIGEST_ALGORITHM_SHA256:
1143 return kSecDigestSHA2;
1144 default:
Yingdi Yu4b8c6a22014-04-15 23:00:54 -07001145 return 0;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001146 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001147}
Jeff Thompson2747dc02013-10-04 19:11:34 -07001148
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001149long
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001150SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
1151{
Yingdi Yu7036ce22014-06-19 18:53:37 -07001152 switch (digestAlgo) {
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001153 case DIGEST_ALGORITHM_SHA256:
1154 return 256;
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001155 default:
Yingdi Yu2b2b4792014-02-04 16:27:07 -08001156 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -07001157 }
Jeff Thompson2747dc02013-10-04 19:11:34 -07001158}
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -07001159
Yingdi Yufc40d872014-02-18 12:56:04 -08001160} // namespace ndn