blob: fc04ba019c89392b7886fd58a545678ac47017af [file] [log] [blame]
Jeff Thompson2747dc02013-10-04 19:11:34 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Yingdi Yu <yingdi@cs.ucla.edu>
5 * See COPYING for copyright and distribution information.
6 */
7
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -08008#include "common.hpp"
9
Alexander Afanasyev19508852014-01-29 01:01:51 -080010#include "sec-tpm-osx.hpp"
11
12#include "security/public-key.hpp"
13#include "util/logging.hpp"
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080014#include <cryptopp/files.h>
15#include <cryptopp/asn.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070016
Yingdi Yu2b2b4792014-02-04 16:27:07 -080017#include <pwd.h>
18#include <unistd.h>
19#include <stdlib.h>
20#include <string.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070021
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080022#include <CoreFoundation/CoreFoundation.h>
23#include <Security/Security.h>
Yingdi Yu4b752752014-02-18 12:24:03 -080024#include <Security/SecRandom.h>
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080025#include <CoreServices/CoreServices.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070026
27using namespace std;
Jeff Thompson2747dc02013-10-04 19:11:34 -070028
Yingdi Yu87581582014-01-14 14:28:39 -080029INIT_LOGGER("SecTpmOsx");
Jeff Thompson2747dc02013-10-04 19:11:34 -070030
Yingdi Yufc40d872014-02-18 12:56:04 -080031namespace ndn {
32
Yingdi Yu2b2b4792014-02-04 16:27:07 -080033class SecTpmOsx::Impl {
34public:
35 Impl()
Yingdi Yube4150e2014-02-18 13:02:46 -080036 : m_passwordSet(false)
37 , m_inTerminal(false)
Yingdi Yu2b2b4792014-02-04 16:27:07 -080038 {}
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080039
Yingdi Yu2b2b4792014-02-04 16:27:07 -080040 /**
41 * @brief Convert NDN name of a key to internal name of the key.
42 *
Yingdi Yufc40d872014-02-18 12:56:04 -080043 * @param keyName
44 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -080045 * @return the internal key name
46 */
47 std::string
48 toInternalKeyName(const Name & keyName, KeyClass keyClass);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080049
Yingdi Yu2b2b4792014-02-04 16:27:07 -080050 /**
51 * @brief Get key.
Yingdi Yufc40d872014-02-18 12:56:04 -080052 *
53 * @param keyName
54 * @param keyClass
Yingdi Yu2b2b4792014-02-04 16:27:07 -080055 * @returns pointer to the key
56 */
57 SecKeychainItemRef
58 getKey(const Name & keyName, KeyClass keyClass);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080059
Yingdi Yu2b2b4792014-02-04 16:27:07 -080060 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080061 * @brief Convert keyType to MAC OS symmetric key key type
62 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080063 * @param keyType
64 * @returns MAC OS key type
65 */
Yingdi Yu87581582014-01-14 14:28:39 -080066 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080067 getSymKeyType(KeyType keyType);
68
69 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080070 * @brief Convert keyType to MAC OS asymmetirc key type
71 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080072 * @param keyType
73 * @returns MAC OS key type
74 */
Yingdi Yu87581582014-01-14 14:28:39 -080075 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080076 getAsymKeyType(KeyType keyType);
77
78 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080079 * @brief Convert keyClass to MAC OS key class
80 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080081 * @param keyClass
82 * @returns MAC OS key class
83 */
Yingdi Yu87581582014-01-14 14:28:39 -080084 const CFTypeRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080085 getKeyClass(KeyClass keyClass);
86
87 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080088 * @brief Convert digestAlgo to MAC OS algorithm id
89 *
Yingdi Yu2b2b4792014-02-04 16:27:07 -080090 * @param digestAlgo
91 * @returns MAC OS algorithm id
92 */
Yingdi Yu87581582014-01-14 14:28:39 -080093 const CFStringRef
Yingdi Yu2b2b4792014-02-04 16:27:07 -080094 getDigestAlgorithm(DigestAlgorithm digestAlgo);
95
96 /**
Yingdi Yufc40d872014-02-18 12:56:04 -080097 * @brief Get the digest size of the corresponding algorithm
98 *
99 * @param digestAlgo
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800100 * @return digest size
101 */
102 long
103 getDigestSize(DigestAlgorithm digestAlgo);
104
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800105 ///////////////////////////////////////////////
106 // everything here is public, including data //
107 ///////////////////////////////////////////////
108public:
109 SecKeychainRef m_keyChainRef;
Yingdi Yube4150e2014-02-18 13:02:46 -0800110 bool m_passwordSet;
111 string m_password;
112 bool m_inTerminal;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800113};
114
115
116SecTpmOsx::SecTpmOsx()
117 : m_impl(new Impl)
118{
Yingdi Yube4150e2014-02-18 13:02:46 -0800119 if(m_impl->m_inTerminal)
120 SecKeychainSetUserInteractionAllowed (false);
121 else
122 SecKeychainSetUserInteractionAllowed (true);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800123
Yingdi Yube4150e2014-02-18 13:02:46 -0800124 OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800125
126 if (res == errSecNoDefaultKeychain) //If no default key chain, create one.
Yingdi Yube4150e2014-02-18 13:02:46 -0800127 throw Error("No default keychain, create one first!");
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800128}
129
130SecTpmOsx::~SecTpmOsx(){
131 //TODO: implement
132}
133
Yingdi Yube4150e2014-02-18 13:02:46 -0800134void
135SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength)
136{
137 m_impl->m_passwordSet = true;
138 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
139 m_impl->m_password.clear();
140 m_impl->m_password.append(reinterpret_cast<const char*>(password), passwordLength);
141}
142
143void
144SecTpmOsx::resetTpmPassword()
145{
146 m_impl->m_passwordSet = false;
147 memset(const_cast<char*>(m_impl->m_password.c_str()), 0, m_impl->m_password.size());
148 m_impl->m_password.clear();
149}
150
151void
152SecTpmOsx::setInTerminal(bool inTerminal)
153{
154 m_impl->m_inTerminal = inTerminal;
155 if(inTerminal)
156 SecKeychainSetUserInteractionAllowed (false);
157 else
158 SecKeychainSetUserInteractionAllowed (true);
159}
160
161bool
162SecTpmOsx::getInTerminal()
163{
164 return m_impl->m_inTerminal;
165}
166
167bool
168SecTpmOsx::locked()
169{
170 SecKeychainStatus keychainStatus;
171
172 OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus);
173 if(res != errSecSuccess)
174 return true;
175 else
176 return ((kSecUnlockStateStatus & keychainStatus) == 0);
177}
178
179void
180SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword)
181{
182 OSStatus res;
183
184 // If the default key chain is already unlocked, return immediately.
185 if(!locked())
186 return;
187
188 // If the default key chain is locked, unlock the key chain.
189 if(usePassword)
190 {
191 // Use the supplied password.
192 res = SecKeychainUnlock(m_impl->m_keyChainRef,
193 passwordLength,
194 password,
195 true);
196 }
197 else if(m_impl->m_passwordSet)
198 {
199 // If no password supplied, then use the configured password if exists.
200 SecKeychainUnlock(m_impl->m_keyChainRef,
201 m_impl->m_password.size(),
202 m_impl->m_password.c_str(),
203 true);
204 }
205 else if(m_impl->m_inTerminal)
206 {
207 // If no configured password, get password from terminal if inTerminal set.
208 bool locked = true;
209 const char* fmt = "Password to unlock the default keychain: ";
210 int count = 0;
211
212 while(locked)
213 {
214 if(count > 2)
215 break;
216
217 char* getPassword = NULL;
218 getPassword = getpass(fmt);
219 count++;
220
221 if (!getPassword)
222 continue;
223
224 res = SecKeychainUnlock(m_impl->m_keyChainRef,
225 strlen(getPassword),
226 getPassword,
227 true);
228
229 memset(getPassword, 0, strlen(getPassword));
230
231 if(res == errSecSuccess)
232 return;
233 }
234 }
235 else
236 {
237 // If inTerminal is not set, get the password from GUI.
238 SecKeychainUnlock(m_impl->m_keyChainRef, 0, 0, false);
239 }
240}
241
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800242void
Yingdi Yube4150e2014-02-18 13:02:46 -0800243SecTpmOsx::generateKeyPairInTpmInternal(const Name & keyName, KeyType keyType, int keySize, bool retry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800244{
245
246 if(doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC)){
247 _LOG_DEBUG("keyName has existed");
248 throw Error("keyName has existed");
249 }
250
251 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
252
253 SecKeyRef publicKey, privateKey;
254
255 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
256 keyNameUri.c_str(),
257 kCFStringEncodingUTF8);
258
259 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
260 3,
261 &kCFTypeDictionaryKeyCallBacks,
262 NULL);
263
264 CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getAsymKeyType(keyType));
265 CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(NULL, kCFNumberIntType, &keySize));
266 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
267
268 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict, &publicKey, &privateKey);
269
270 CFRelease(publicKey);
271 CFRelease(privateKey);
272
Yingdi Yube4150e2014-02-18 13:02:46 -0800273 if (res == errSecSuccess)
274 return;
275
276 if (res == errSecAuthFailed && !retry)
277 {
278 unlockTpm(0, 0, false);
279 generateKeyPairInTpmInternal(keyName, keyType, keySize, true);
280 }
281 else
282 {
283 _LOG_DEBUG("Fail to create a key pair: " << res);
284 throw Error("Fail to create a key pair");
285 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800286}
287
288void
Yingdi Yube4150e2014-02-18 13:02:46 -0800289SecTpmOsx::deleteKeyPairInTpmInternal(const Name &keyName, bool retry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800290{
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800291 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800292 keyName.toUri().c_str(),
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800293 kCFStringEncodingUTF8);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800294
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800295 CFMutableDictionaryRef searchDict =
296 CFDictionaryCreateMutable(NULL, 5, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800297
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800298 CFDictionaryAddValue(searchDict, kSecClass, kSecClassKey);
299 CFDictionaryAddValue(searchDict, kSecAttrLabel, keyLabel);
300 CFDictionaryAddValue(searchDict, kSecMatchLimit, kSecMatchLimitAll);
Yingdi Yube4150e2014-02-18 13:02:46 -0800301 OSStatus res = SecItemDelete(searchDict);
302
303 if (res == errSecSuccess)
304 return;
305
306 if (res == errSecAuthFailed && !retry)
307 {
308 unlockTpm(0, 0, false);
309 deleteKeyPairInTpmInternal(keyName, true);
310 }
311 else
312 {
313 _LOG_DEBUG("Fail to delete a key pair: " << res);
314 throw Error("Fail to delete a key pair");
315 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800316}
317
318void
319SecTpmOsx::generateSymmetricKeyInTpm(const Name & keyName, KeyType keyType, int keySize)
320{
321
322 if(doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
323 throw Error("keyName has existed!");
324
325 string keyNameUri = m_impl->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
326
327 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
328 0,
329 &kCFTypeDictionaryKeyCallBacks,
330 &kCFTypeDictionaryValueCallBacks);
331
332 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
333 keyNameUri.c_str(),
334 kCFStringEncodingUTF8);
335
336 CFDictionaryAddValue(attrDict, kSecAttrKeyType, m_impl->getSymKeyType(keyType));
337 CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &keySize));
338 CFDictionaryAddValue(attrDict, kSecAttrIsPermanent, kCFBooleanTrue);
339 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
340
341 CFErrorRef error = NULL;
342
343 SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
344
345 if (error)
346 throw Error("Fail to create a symmetric key");
347}
348
349ptr_lib::shared_ptr<PublicKey>
350SecTpmOsx::getPublicKeyFromTpm(const Name & keyName)
351{
352 _LOG_TRACE("OSXPrivateKeyStorage::getPublickey");
353
354 SecKeychainItemRef publicKey = m_impl->getKey(keyName, KEY_CLASS_PUBLIC);
355
356 CFDataRef exportedKey;
357
358 OSStatus res = SecItemExport(publicKey,
359 kSecFormatOpenSSL,
360 0,
361 NULL,
362 &exportedKey);
363
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800364 shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
365 CFRelease(exportedKey);
366 return key;
367}
368
369ConstBufferPtr
Yingdi Yube4150e2014-02-18 13:02:46 -0800370SecTpmOsx::exportPrivateKeyPkcs1FromTpmInternal(const Name& keyName, bool retry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800371{
372 using namespace CryptoPP;
373
374 SecKeychainItemRef privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
375 CFDataRef exportedKey;
376 OSStatus res = SecItemExport(privateKey,
377 kSecFormatOpenSSL,
378 0,
379 NULL,
380 &exportedKey);
381
382 if(res != errSecSuccess)
383 {
Yingdi Yube4150e2014-02-18 13:02:46 -0800384 if(res == errSecAuthFailed && !retry)
385 {
386 unlockTpm(0, 0, false);
387 return exportPrivateKeyPkcs1FromTpmInternal(keyName, true);
388 }
389 else
390 return shared_ptr<Buffer>();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800391 }
392
393 OBufferStream pkcs1Os;
394 FileSink sink(pkcs1Os);
395
396 uint32_t version = 0;
397 OID algorithm("1.2.840.113549.1.1.1");
398 SecByteBlock rawKeyBits;
399 // PrivateKeyInfo ::= SEQUENCE {
400 // version INTEGER,
401 // privateKeyAlgorithm SEQUENCE,
402 // privateKey OCTECT STRING}
403 DERSequenceEncoder privateKeyInfo(sink);
404 {
405 DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
406 DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
407 {
408 algorithm.encode(privateKeyAlgorithm);
409 DEREncodeNull(privateKeyAlgorithm);
410 }
411 privateKeyAlgorithm.MessageEnd();
412 DEREncodeOctetString(privateKeyInfo, CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
413 }
414 privateKeyInfo.MessageEnd();
415
416 CFRelease(exportedKey);
417 return pkcs1Os.buf();
418}
419
420bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800421SecTpmOsx::importPrivateKeyPkcs1IntoTpmInternal(const Name& keyName, const uint8_t* buf, size_t size, bool retry)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800422{
423 using namespace CryptoPP;
424
425 StringSource privateKeySource(buf, size, true);
426 uint32_t tmpNum;
427 OID tmpOID;
428 SecByteBlock rawKeyBits;
429 // PrivateKeyInfo ::= SEQUENCE {
430 // INTEGER,
431 // SEQUENCE,
432 // OCTECT STRING}
433 BERSequenceDecoder privateKeyInfo(privateKeySource);
434 {
435 BERDecodeUnsigned<uint32_t>(privateKeyInfo, tmpNum, INTEGER);
436 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
437 {
438 tmpOID.decode(sequenceDecoder);
439 BERDecodeNull(sequenceDecoder);
440 }
441 BERDecodeOctetString(privateKeyInfo, rawKeyBits);
442 }
443 privateKeyInfo.MessageEnd();
444
445 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(NULL,
446 rawKeyBits.BytePtr(),
447 rawKeyBits.size(),
448 kCFAllocatorNull);
449
450 SecExternalFormat externalFormat = kSecFormatOpenSSL;
451 SecExternalItemType externalType = kSecItemTypePrivateKey;
452 SecKeyImportExportParameters keyParams;
453 memset(&keyParams, 0, sizeof(keyParams));
454 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
455 keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
456 SecAccessRef access;
457 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
458 keyName.toUri().c_str(),
459 kCFStringEncodingUTF8);
460 SecAccessCreate(keyLabel, NULL, &access);
461 keyParams.accessRef = access;
462 CFArrayRef outItems;
463
464 OSStatus res = SecKeychainItemImport (importedKey,
465 NULL,
466 &externalFormat,
467 &externalType,
468 0,
469 &keyParams,
470 m_impl->m_keyChainRef,
471 &outItems);
472
473 if(res != errSecSuccess)
474 {
Yingdi Yube4150e2014-02-18 13:02:46 -0800475 if(res == errSecAuthFailed && !retry)
476 {
477 unlockTpm(0, 0, false);
478 return importPrivateKeyPkcs1IntoTpmInternal(keyName, buf, size, true);
479 }
480 else
481 return false;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800482 }
483
484 SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
485 SecKeychainAttribute attrs[1]; // maximum number of attributes
486 SecKeychainAttributeList attrList = { 0, attrs };
487 string keyUri = keyName.toUri();
488 {
489 attrs[attrList.count].tag = kSecKeyPrintName;
490 attrs[attrList.count].length = keyUri.size();
491 attrs[attrList.count].data = (void *)keyUri.c_str();
492 attrList.count++;
493 }
494
495 res = SecKeychainItemModifyAttributesAndData(privateKey,
496 &attrList,
497 0,
498 NULL);
499
500 if(res != errSecSuccess)
501 {
502 return false;
503 }
504
505 CFRelease(importedKey);
506 return true;
507}
508
509bool
510SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
511{
512 CFDataRef importedKey = CFDataCreateWithBytesNoCopy(NULL,
513 buf,
514 size,
515 kCFAllocatorNull);
516
517 SecExternalFormat externalFormat = kSecFormatOpenSSL;
518 SecExternalItemType externalType = kSecItemTypePublicKey;
519 CFArrayRef outItems;
520
521 OSStatus res = SecItemImport (importedKey,
522 NULL,
523 &externalFormat,
524 &externalType,
525 0,
526 NULL,
527 m_impl->m_keyChainRef,
528 &outItems);
529
530 if(res != errSecSuccess)
531 return false;
532
533 SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
534 SecKeychainAttribute attrs[1]; // maximum number of attributes
535 SecKeychainAttributeList attrList = { 0, attrs };
536 string keyUri = keyName.toUri();
537 {
538 attrs[attrList.count].tag = kSecKeyPrintName;
539 attrs[attrList.count].length = keyUri.size();
540 attrs[attrList.count].data = (void *)keyUri.c_str();
541 attrList.count++;
542 }
543
544 res = SecKeychainItemModifyAttributesAndData(publicKey,
545 &attrList,
546 0,
547 NULL);
548
549 CFRelease(importedKey);
550 return true;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800551}
552
553Block
Yingdi Yube4150e2014-02-18 13:02:46 -0800554SecTpmOsx::signInTpmInternal(const uint8_t *data, size_t dataLength, const Name& keyName, DigestAlgorithm digestAlgorithm, bool retry)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800555{
556 _LOG_TRACE("OSXPrivateKeyStorage::Sign");
557
558 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(NULL,
559 data,
560 dataLength,
561 kCFAllocatorNull
562 );
563
564 SecKeyRef privateKey = (SecKeyRef)m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
565
566 CFErrorRef error;
567 SecTransformRef signer = SecSignTransformCreate((SecKeyRef)privateKey, &error);
568 if (error) throw Error("Fail to create signer");
569
570 // Set input
571 Boolean set_res = SecTransformSetAttribute(signer,
572 kSecTransformInputAttributeName,
573 dataRef,
574 &error);
575 if (error) throw Error("Fail to configure input of signer");
576
577 // Enable use of padding
578 SecTransformSetAttribute(
579 signer,
580 kSecPaddingKey,
581 kSecPaddingPKCS1Key,
582 &error);
583 if (error) throw Error("Fail to configure digest algorithm of signer");
584
585 // Set padding type
586 set_res = SecTransformSetAttribute(signer,
587 kSecDigestTypeAttribute,
588 m_impl->getDigestAlgorithm(digestAlgorithm),
589 &error);
590 if (error) throw Error("Fail to configure digest algorithm of signer");
591
592 // Set padding attribute
593 long digestSize = m_impl->getDigestSize(digestAlgorithm);
594 set_res = SecTransformSetAttribute(signer,
595 kSecDigestLengthAttribute,
596 CFNumberCreate(NULL, kCFNumberLongType, &digestSize),
597 &error);
598 if (error) throw Error("Fail to configure digest size of signer");
599
600 // Actually sign
601 CFDataRef signature = (CFDataRef) SecTransformExecute(signer, &error);
Yingdi Yube4150e2014-02-18 13:02:46 -0800602 if (error)
603 {
604 if(!retry)
605 {
606 unlockTpm(0, 0, false);
607 return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true);
608 }
609 else
610 {
611 CFShow(error);
612 throw Error("Fail to sign data");
613 }
614 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800615
616 if (!signature) throw Error("Signature is NULL!\n");
617
618 return Block(Tlv::SignatureValue,
619 ptr_lib::make_shared<Buffer>(CFDataGetBytePtr(signature), CFDataGetLength(signature)));
620}
621
622ConstBufferPtr
Yingdi Yufc40d872014-02-18 12:56:04 -0800623SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name & keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800624{
625 _LOG_TRACE("OSXPrivateKeyStorage::Decrypt");
626
627 KeyClass keyClass;
628 if(sym)
629 keyClass = KEY_CLASS_SYMMETRIC;
630 else
631 keyClass = KEY_CLASS_PRIVATE;
632
633 CFDataRef dataRef = CFDataCreate(NULL,
634 reinterpret_cast<const unsigned char*>(data),
635 dataLength
636 );
637
638 // _LOG_DEBUG("CreateData");
639
640 SecKeyRef decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
641
642 // _LOG_DEBUG("GetKey");
643
644 CFErrorRef error;
645 SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
646 if (error) throw Error("Fail to create decrypt");
647
648 Boolean set_res = SecTransformSetAttribute(decrypt,
649 kSecTransformInputAttributeName,
650 dataRef,
651 &error);
652 if (error) throw Error("Fail to configure decrypt");
653
654 CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
655 if (error)
656 {
657 CFShow(error);
658 throw Error("Fail to decrypt data");
659 }
660 if (!output) throw Error("Output is NULL!\n");
661
662 return ptr_lib::make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
663}
664
665bool
666SecTpmOsx::setACL(const Name & keyName, KeyClass keyClass, int acl, const string & appPath)
667{
668 SecKeychainItemRef privateKey = m_impl->getKey(keyName, keyClass);
669
670 SecAccessRef accRef;
671 OSStatus acc_res = SecKeychainItemCopyAccess(privateKey, &accRef);
672
673 CFArrayRef signACL = SecAccessCopyMatchingACLList(accRef,
674 kSecACLAuthorizationSign);
675
676 SecACLRef aclRef = (SecACLRef) CFArrayGetValueAtIndex(signACL, 0);
677
678 CFArrayRef appList;
679 CFStringRef description;
680 SecKeychainPromptSelector promptSelector;
681 OSStatus acl_res = SecACLCopyContents(aclRef,
682 &appList,
683 &description,
684 &promptSelector);
685
686 CFMutableArrayRef newAppList = CFArrayCreateMutableCopy(NULL,
687 0,
688 appList);
689
690 SecTrustedApplicationRef trustedApp;
691 acl_res = SecTrustedApplicationCreateFromPath(appPath.c_str(),
692 &trustedApp);
693
694 CFArrayAppendValue(newAppList, trustedApp);
695
696
697 CFArrayRef authList = SecACLCopyAuthorizations(aclRef);
698
699 acl_res = SecACLRemove(aclRef);
700
701 SecACLRef newACL;
702 acl_res = SecACLCreateWithSimpleContents(accRef,
703 newAppList,
704 description,
705 promptSelector,
706 &newACL);
707
708 acl_res = SecACLUpdateAuthorizations(newACL, authList);
709
710 acc_res = SecKeychainItemSetAccess(privateKey, accRef);
711
712 return true;
713}
714
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800715ConstBufferPtr
Yingdi Yufc40d872014-02-18 12:56:04 -0800716SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name & keyName, bool sym)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800717{
718 _LOG_TRACE("OSXPrivateKeyStorage::Encrypt");
719
720 KeyClass keyClass;
721 if(sym)
722 keyClass = KEY_CLASS_SYMMETRIC;
723 else
724 keyClass = KEY_CLASS_PUBLIC;
725
726 CFDataRef dataRef = CFDataCreate(NULL,
727 reinterpret_cast<const unsigned char*>(data),
728 dataLength
729 );
730
731 SecKeyRef encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass);
732
733 CFErrorRef error;
734 SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
735 if (error) throw Error("Fail to create encrypt");
736
737 Boolean set_res = SecTransformSetAttribute(encrypt,
738 kSecTransformInputAttributeName,
739 dataRef,
740 &error);
741 if (error) throw Error("Fail to configure encrypt");
742
743 CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
744 if (error) throw Error("Fail to encrypt data");
745
746 if (!output) throw Error("Output is NULL!\n");
747
748 return ptr_lib::make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
749}
750
751bool
752SecTpmOsx::doesKeyExistInTpm(const Name & keyName, KeyClass keyClass)
753{
754 _LOG_TRACE("OSXPrivateKeyStorage::doesKeyExist");
755
756 string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass);
757
758 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
759 keyNameUri.c_str(),
760 kCFStringEncodingUTF8);
761
762 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
763 4,
764 &kCFTypeDictionaryKeyCallBacks,
765 NULL);
766
767 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800768 // CFDictionaryAddValue(attrDict, kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800769 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
770 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
771
772 SecKeychainItemRef itemRef;
773 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict, (CFTypeRef*)&itemRef);
774
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800775 if(res == errSecSuccess)
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800776 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800777 else
778 return false;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800779
780}
781
Yingdi Yu4b752752014-02-18 12:24:03 -0800782bool
783SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size)
784{
785 return (SecRandomCopyBytes(kSecRandomDefault, size, res) == 0);
786}
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800787
788////////////////////////////////
789// OSXPrivateKeyStorage::Impl //
790////////////////////////////////
791
792SecKeychainItemRef
793SecTpmOsx::Impl::getKey(const Name & keyName, KeyClass keyClass)
794{
795 string keyNameUri = toInternalKeyName(keyName, keyClass);
796
797 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
798 keyNameUri.c_str(),
799 kCFStringEncodingUTF8);
800
801 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
802 5,
803 &kCFTypeDictionaryKeyCallBacks,
804 NULL);
805
806 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
807 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
808 CFDictionaryAddValue(attrDict, kSecAttrKeyClass, getKeyClass(keyClass));
809 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
810
811 SecKeychainItemRef keyItem;
812
813 OSStatus res = SecItemCopyMatching((CFDictionaryRef) attrDict, (CFTypeRef*)&keyItem);
814
815 if(res != errSecSuccess){
816 _LOG_DEBUG("Fail to find the key!");
817 return NULL;
818 }
819 else
820 return keyItem;
821}
822
823string
824SecTpmOsx::Impl::toInternalKeyName(const Name & keyName, KeyClass keyClass)
825{
826 string keyUri = keyName.toUri();
827
828 if(KEY_CLASS_SYMMETRIC == keyClass)
829 return keyUri + "/symmetric";
830 else
831 return keyUri;
832}
833
834const CFTypeRef
835SecTpmOsx::Impl::getAsymKeyType(KeyType keyType)
836{
837 switch(keyType){
838 case KEY_TYPE_RSA:
839 return kSecAttrKeyTypeRSA;
840 default:
841 _LOG_DEBUG("Unrecognized key type!")
842 return NULL;
843 }
844}
845
846const CFTypeRef
847SecTpmOsx::Impl::getSymKeyType(KeyType keyType)
848{
849 switch(keyType){
850 case KEY_TYPE_AES:
851 return kSecAttrKeyTypeAES;
852 default:
853 _LOG_DEBUG("Unrecognized key type!")
854 return NULL;
855 }
856}
857
858const CFTypeRef
859SecTpmOsx::Impl::getKeyClass(KeyClass keyClass)
860{
861 switch(keyClass){
862 case KEY_CLASS_PRIVATE:
863 return kSecAttrKeyClassPrivate;
864 case KEY_CLASS_PUBLIC:
865 return kSecAttrKeyClassPublic;
866 case KEY_CLASS_SYMMETRIC:
867 return kSecAttrKeyClassSymmetric;
868 default:
869 _LOG_DEBUG("Unrecognized key class!");
870 return NULL;
871 }
872}
873
874const CFStringRef
875SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
876{
877 switch(digestAlgo){
Jeff Thompson2747dc02013-10-04 19:11:34 -0700878 // case DIGEST_MD2:
879 // return kSecDigestMD2;
880 // case DIGEST_MD5:
881 // return kSecDigestMD5;
882 // case DIGEST_SHA1:
883 // return kSecDigestSHA1;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800884 case DIGEST_ALGORITHM_SHA256:
885 return kSecDigestSHA2;
886 default:
887 _LOG_DEBUG("Unrecognized digest algorithm!");
888 return NULL;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700889 }
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800890}
Jeff Thompson2747dc02013-10-04 19:11:34 -0700891
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800892long
893SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo)
894{
895 switch(digestAlgo){
896 case DIGEST_ALGORITHM_SHA256:
897 return 256;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700898 // case DIGEST_SHA1:
899 // case DIGEST_MD2:
900 // case DIGEST_MD5:
901 // return 0;
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800902 default:
903 _LOG_DEBUG("Unrecognized digest algorithm! Unknown digest size");
904 return -1;
Jeff Thompson2747dc02013-10-04 19:11:34 -0700905 }
Jeff Thompson2747dc02013-10-04 19:11:34 -0700906}
Yingdi Yu2b2b4792014-02-04 16:27:07 -0800907
Yingdi Yufc40d872014-02-18 12:56:04 -0800908} // namespace ndn