blob: adf354218491b54518ae6af0f85e252e894be99d [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
Jeff Thompsonf21e2242013-10-09 19:01:49 -07008// Only compile if ndn-cpp-config.h defines NDN_CPP_HAVE_OSX_SECURITY 1.
Jeff Thompson6e229042013-10-10 11:09:49 -07009#include <ndn-cpp/ndn-cpp-config.h>
Jeff Thompsonf21e2242013-10-09 19:01:49 -070010#if NDN_CPP_HAVE_OSX_SECURITY
Jeff Thompson2747dc02013-10-04 19:11:34 -070011
12#include <fstream>
13#include <sstream>
Jeff Thompson2747dc02013-10-04 19:11:34 -070014
15#include "../../util/logging.hpp"
Alexander Afanasyev6be1a6a2014-01-06 00:08:14 -080016
17#include <ndn-cpp/security/identity/osx-private-key-storage.hpp>
18#include <ndn-cpp/security/certificate/public-key.hpp>
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080019
20#include <CoreFoundation/CoreFoundation.h>
21#include <Security/Security.h>
22#include <CoreServices/CoreServices.h>
Jeff Thompson2747dc02013-10-04 19:11:34 -070023
24using namespace std;
Jeff Thompson2747dc02013-10-04 19:11:34 -070025
26INIT_LOGGER("ndn.OSXPrivateKeyStorage");
27
28namespace ndn
29{
Alexander Afanasyev04b22a92014-01-05 22:40:17 -080030 class OSXPrivateKeyStorage::Impl {
31 public:
32 Impl(const std::string &keychainName)
33 : keyChainName_ ("" == keychainName ? "NDN.keychain" : keychainName)
34 {
35 }
36
37 /**
38 * convert NDN name of a key to internal name of the key
39 * @param keyName the NDN name of the key
40 * @param keyClass the class of the key
41 * @return the internal key name
42 */
43 std::string
44 toInternalKeyName(const Name & keyName, KeyClass keyClass);
45
46 /**
47 * Get key
48 * @param keyName the name of the key
49 * @param keyClass the class of the key
50 * @returns pointer to the key
51 */
52 SecKeychainItemRef
53 getKey(const Name & keyName, KeyClass keyClass);
54
55 /**
56 * convert keyType to MAC OS symmetric key key type
57 * @param keyType
58 * @returns MAC OS key type
59 */
60 const CFTypeRef
61 getSymKeyType(KeyType keyType);
62
63 /**
64 * convert keyType to MAC OS asymmetirc key type
65 * @param keyType
66 * @returns MAC OS key type
67 */
68 const CFTypeRef
69 getAsymKeyType(KeyType keyType);
70
71 /**
72 * convert keyClass to MAC OS key class
73 * @param keyClass
74 * @returns MAC OS key class
75 */
76 const CFTypeRef
77 getKeyClass(KeyClass keyClass);
78
79 /**
80 * convert digestAlgo to MAC OS algorithm id
81 * @param digestAlgo
82 * @returns MAC OS algorithm id
83 */
84 const CFStringRef
85 getDigestAlgorithm(DigestAlgorithm digestAlgo);
86
87 /**
88 * get the digest size of the corresponding algorithm
89 * @param digestAlgo the digest algorithm
90 * @return digest size
91 */
92 long
93 getDigestSize(DigestAlgorithm digestAlgo);
94
95 ///////////////////////////////////////////////
96 // everything here is public, including data //
97 ///////////////////////////////////////////////
98 public:
99 const std::string keyChainName_;
100 SecKeychainRef keyChainRef_;
101 SecKeychainRef originalDefaultKeyChain_;
102 };
103
104
105
Jeff Thompson2747dc02013-10-04 19:11:34 -0700106 OSXPrivateKeyStorage::OSXPrivateKeyStorage(const string & keychainName)
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800107 : impl_(new Impl(keychainName))
Jeff Thompson2747dc02013-10-04 19:11:34 -0700108 {
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800109 OSStatus res = SecKeychainCreate(impl_->keyChainName_.c_str(), //Keychain path
Jeff Thompson2747dc02013-10-04 19:11:34 -0700110 0, //Keychain password length
111 NULL, //Keychain password
112 true, //User prompt
113 NULL, //Initial access of Keychain
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800114 &impl_->keyChainRef_); //Keychain reference
Jeff Thompson2747dc02013-10-04 19:11:34 -0700115
116 if (res == errSecDuplicateKeychain)
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800117 res = SecKeychainOpen(impl_->keyChainName_.c_str(),
118 &impl_->keyChainRef_);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700119
120 if (res != errSecSuccess){
121 _LOG_DEBUG("Fail to initialize keychain ref: " << res);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800122 throw Error("Fail to initialize keychain ref");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700123 }
124
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800125 res = SecKeychainCopyDefault(&impl_->originalDefaultKeyChain_);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700126
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800127 res = SecKeychainSetDefault(impl_->keyChainRef_);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700128 if (res != errSecSuccess){
129 _LOG_DEBUG("Fail to set default keychain: " << res);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800130 throw Error("Fail to set default keychain");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700131 }
132 }
133
134 OSXPrivateKeyStorage::~OSXPrivateKeyStorage(){
135 //TODO: implement
136 }
137
138 void
139 OSXPrivateKeyStorage::generateKeyPair(const Name & keyName, KeyType keyType, int keySize)
140 {
141
142 if(doesKeyExist(keyName, KEY_CLASS_PUBLIC)){
143 _LOG_DEBUG("keyName has existed");
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800144 throw Error("keyName has existed");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700145 }
146
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800147 string keyNameUri = impl_->toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700148
149 SecKeyRef publicKey, privateKey;
150
151 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
Jeff Thompson556cc302013-10-22 17:40:07 -0700152 keyNameUri.c_str(),
153 kCFStringEncodingUTF8);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700154
155 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
156 3,
157 &kCFTypeDictionaryKeyCallBacks,
158 NULL);
159
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800160 CFDictionaryAddValue(attrDict, kSecAttrKeyType, impl_->getAsymKeyType(keyType));
Jeff Thompson2747dc02013-10-04 19:11:34 -0700161 CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(NULL, kCFNumberIntType, &keySize));
162 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
163
164 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict, &publicKey, &privateKey);
165
166 CFRelease(publicKey);
167 CFRelease(privateKey);
168
169 if (res != errSecSuccess){
170 _LOG_DEBUG("Fail to create a key pair: " << res);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800171 throw Error("Fail to create a key pair");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700172 }
173 }
174
175 void
176 OSXPrivateKeyStorage::generateKey(const Name & keyName, KeyType keyType, int keySize)
177 {
178
179 if(doesKeyExist(keyName, KEY_CLASS_SYMMETRIC))
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800180 throw Error("keyName has existed!");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700181
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800182 string keyNameUri = impl_->toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700183
184 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
185 0,
186 &kCFTypeDictionaryKeyCallBacks,
187 &kCFTypeDictionaryValueCallBacks);
188
189 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
Jeff Thompson556cc302013-10-22 17:40:07 -0700190 keyNameUri.c_str(),
191 kCFStringEncodingUTF8);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700192
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800193 CFDictionaryAddValue(attrDict, kSecAttrKeyType, impl_->getSymKeyType(keyType));
Jeff Thompson2747dc02013-10-04 19:11:34 -0700194 CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &keySize));
195 CFDictionaryAddValue(attrDict, kSecAttrIsPermanent, kCFBooleanTrue);
196 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
197
198 CFErrorRef error = NULL;
199
200 SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
201
202 if (error)
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800203 throw Error("Fail to create a symmetric key");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700204 }
205
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800206 ptr_lib::shared_ptr<PublicKey>
207 OSXPrivateKeyStorage::getPublicKey(const Name & keyName)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700208 {
209 _LOG_TRACE("OSXPrivateKeyStorage::getPublickey");
210
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800211 SecKeychainItemRef publicKey = impl_->getKey(keyName, KEY_CLASS_PUBLIC);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700212
213 CFDataRef exportedKey;
214
215 OSStatus res = SecItemExport(publicKey,
216 kSecFormatOpenSSL,
217 0,
218 NULL,
219 &exportedKey);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700220
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800221 return ptr_lib::make_shared<PublicKey>(CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
Jeff Thompson2747dc02013-10-04 19:11:34 -0700222 }
223
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800224 Block
225 OSXPrivateKeyStorage::sign(const uint8_t *data, size_t dataLength,
226 const Name& keyName, DigestAlgorithm digestAlgorithm/* = DIGEST_ALGORITHM_SHA256*/)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700227 {
228 _LOG_TRACE("OSXPrivateKeyStorage::Sign");
229
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800230 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(NULL,
231 data,
232 dataLength,
233 kCFAllocatorNull
234 );
Jeff Thompson2747dc02013-10-04 19:11:34 -0700235
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800236 SecKeyRef privateKey = (SecKeyRef)impl_->getKey(keyName, KEY_CLASS_PRIVATE);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700237
238 CFErrorRef error;
239 SecTransformRef signer = SecSignTransformCreate((SecKeyRef)privateKey, &error);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800240 if (error) throw Error("Fail to create signer");
241
242 // Set input
Jeff Thompson2747dc02013-10-04 19:11:34 -0700243 Boolean set_res = SecTransformSetAttribute(signer,
244 kSecTransformInputAttributeName,
245 dataRef,
246 &error);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800247 if (error) throw Error("Fail to configure input of signer");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700248
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800249 // Enable use of padding
250 SecTransformSetAttribute(
251 signer,
252 kSecPaddingKey,
253 kSecPaddingPKCS1Key,
254 &error);
255 if (error) throw Error("Fail to configure digest algorithm of signer");
256
257 // Set padding type
Jeff Thompson2747dc02013-10-04 19:11:34 -0700258 set_res = SecTransformSetAttribute(signer,
259 kSecDigestTypeAttribute,
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800260 impl_->getDigestAlgorithm(digestAlgorithm),
Jeff Thompson2747dc02013-10-04 19:11:34 -0700261 &error);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800262 if (error) throw Error("Fail to configure digest algorithm of signer");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700263
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800264 // Set padding attribute
265 long digestSize = impl_->getDigestSize(digestAlgorithm);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700266 set_res = SecTransformSetAttribute(signer,
267 kSecDigestLengthAttribute,
268 CFNumberCreate(NULL, kCFNumberLongType, &digestSize),
269 &error);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800270 if (error) throw Error("Fail to configure digest size of signer");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700271
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800272 // Actually sign
Jeff Thompson2747dc02013-10-04 19:11:34 -0700273 CFDataRef signature = (CFDataRef) SecTransformExecute(signer, &error);
274 if (error) {
275 CFShow(error);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800276 throw Error("Fail to sign data");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700277 }
278
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800279 if (!signature) throw Error("Signature is NULL!\n");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700280
Alexander Afanasyevbd5ba402014-01-05 22:41:09 -0800281 return Block(Tlv::SignatureValue,
282 ptr_lib::make_shared<Buffer>(CFDataGetBytePtr(signature), CFDataGetLength(signature)));
Jeff Thompson2747dc02013-10-04 19:11:34 -0700283 }
284
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800285 void
286 OSXPrivateKeyStorage::sign(Data &data,
287 const Name& keyName, DigestAlgorithm digestAlgorithm/* = DIGEST_ALGORITHM_SHA256 */)
288 {
Alexander Afanasyevbd5ba402014-01-05 22:41:09 -0800289 const uint8_t *begin = data.wireEncode().value();
290 const uint8_t *end = &*data.getSignature().getInfo().end();
291
292 data.setSignature
293 (sign(begin, end-begin, keyName, digestAlgorithm));
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800294 }
295
296 ConstBufferPtr
297 OSXPrivateKeyStorage::decrypt(const Name & keyName, const uint8_t* data, size_t dataLength, bool sym)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700298 {
299 _LOG_TRACE("OSXPrivateKeyStorage::Decrypt");
300
301 KeyClass keyClass;
302 if(sym)
303 keyClass = KEY_CLASS_SYMMETRIC;
304 else
305 keyClass = KEY_CLASS_PRIVATE;
306
307 CFDataRef dataRef = CFDataCreate(NULL,
308 reinterpret_cast<const unsigned char*>(data),
309 dataLength
310 );
311
312 // _LOG_DEBUG("CreateData");
313
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800314 SecKeyRef decryptKey = (SecKeyRef)impl_->getKey(keyName, keyClass);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700315
316 // _LOG_DEBUG("GetKey");
317
318 CFErrorRef error;
319 SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800320 if (error) throw Error("Fail to create decrypt");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700321
322 Boolean set_res = SecTransformSetAttribute(decrypt,
323 kSecTransformInputAttributeName,
324 dataRef,
325 &error);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800326 if (error) throw Error("Fail to configure decrypt");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700327
328 CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
329 if (error)
330 {
331 CFShow(error);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800332 throw Error("Fail to decrypt data");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700333 }
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800334 if (!output) throw Error("Output is NULL!\n");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700335
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800336 return ptr_lib::make_shared<Buffer>(CFDataGetBytePtr(output), CFDataGetLength(output));
Jeff Thompson2747dc02013-10-04 19:11:34 -0700337 }
338
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800339 bool
340 OSXPrivateKeyStorage::setACL(const Name & keyName, KeyClass keyClass, int acl, const string & appPath)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700341 {
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800342 SecKeychainItemRef privateKey = impl_->getKey(keyName, keyClass);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700343
344 SecAccessRef accRef;
345 OSStatus acc_res = SecKeychainItemCopyAccess(privateKey, &accRef);
346
347 CFArrayRef signACL = SecAccessCopyMatchingACLList(accRef,
348 kSecACLAuthorizationSign);
349
350 SecACLRef aclRef = (SecACLRef) CFArrayGetValueAtIndex(signACL, 0);
351
352 CFArrayRef appList;
353 CFStringRef description;
354 SecKeychainPromptSelector promptSelector;
355 OSStatus acl_res = SecACLCopyContents(aclRef,
356 &appList,
357 &description,
358 &promptSelector);
359
360 CFMutableArrayRef newAppList = CFArrayCreateMutableCopy(NULL,
361 0,
362 appList);
363
364 SecTrustedApplicationRef trustedApp;
365 acl_res = SecTrustedApplicationCreateFromPath(appPath.c_str(),
366 &trustedApp);
367
368 CFArrayAppendValue(newAppList, trustedApp);
369
370
371 CFArrayRef authList = SecACLCopyAuthorizations(aclRef);
372
373 acl_res = SecACLRemove(aclRef);
374
375 SecACLRef newACL;
376 acl_res = SecACLCreateWithSimpleContents(accRef,
377 newAppList,
378 description,
379 promptSelector,
380 &newACL);
381
382 acl_res = SecACLUpdateAuthorizations(newACL, authList);
383
384 acc_res = SecKeychainItemSetAccess(privateKey, accRef);
385
386 return true;
387 }
388
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800389 // bool
390 // OSXPrivateKeyStorage::verifyData(const Name & keyName, const Blob & pData, const Blob & pSig, DigestAlgorithm digestAlgo)
391 // {
392 // _LOG_TRACE("OSXPrivateKeyStorage::Verify");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700393
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800394 // CFDataRef dataRef = CFDataCreate(NULL,
395 // reinterpret_cast<const unsigned char*>(pData.buf()),
396 // pData.size());
Jeff Thompson2747dc02013-10-04 19:11:34 -0700397
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800398 // CFDataRef sigRef = CFDataCreate(NULL,
399 // reinterpret_cast<const unsigned char*>(pSig.buf()),
400 // pSig.size());
Jeff Thompson2747dc02013-10-04 19:11:34 -0700401
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800402 // SecKeyRef publicKey = (SecKeyRef)impl_->getKey(keyName, KEY_CLASS_PUBLIC);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700403
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800404 // CFErrorRef error;
405 // SecTransformRef verifier = SecVerifyTransformCreate(publicKey, sigRef, &error);
406 // if (error) throw Error("Fail to create verifier");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700407
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800408 // Boolean set_res = SecTransformSetAttribute(verifier,
409 // kSecTransformInputAttributeName,
410 // dataRef,
411 // &error);
412 // if (error) throw Error("Fail to configure input of verifier");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700413
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800414 // set_res = SecTransformSetAttribute(verifier,
415 // kSecDigestTypeAttribute,
416 // impl_->getDigestAlgorithm(digestAlgo),
417 // &error);
418 // if (error) throw Error("Fail to configure digest algorithm of verifier");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700419
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800420 // long digestSize = impl_->getDigestSize(digestAlgo);
421 // set_res = SecTransformSetAttribute(verifier,
422 // kSecDigestLengthAttribute,
423 // CFNumberCreate(NULL, kCFNumberLongType, &digestSize),
424 // &error);
425 // if (error) throw Error("Fail to configure digest size of verifier");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700426
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800427 // CFBooleanRef result = (CFBooleanRef) SecTransformExecute(verifier, &error);
428 // if (error) throw Error("Fail to verify data");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700429
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800430 // if (result == kCFBooleanTrue)
431 // return true;
432 // else
433 // return false;
434 // }
Jeff Thompson2747dc02013-10-04 19:11:34 -0700435
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800436 ConstBufferPtr
437 OSXPrivateKeyStorage::encrypt(const Name & keyName, const uint8_t* data, size_t dataLength, bool sym)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700438 {
439 _LOG_TRACE("OSXPrivateKeyStorage::Encrypt");
440
441 KeyClass keyClass;
442 if(sym)
443 keyClass = KEY_CLASS_SYMMETRIC;
444 else
445 keyClass = KEY_CLASS_PUBLIC;
446
447 CFDataRef dataRef = CFDataCreate(NULL,
448 reinterpret_cast<const unsigned char*>(data),
449 dataLength
450 );
451
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800452 SecKeyRef encryptKey = (SecKeyRef)impl_->getKey(keyName, keyClass);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700453
454 CFErrorRef error;
455 SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800456 if (error) throw Error("Fail to create encrypt");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700457
458 Boolean set_res = SecTransformSetAttribute(encrypt,
459 kSecTransformInputAttributeName,
460 dataRef,
461 &error);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800462 if (error) throw Error("Fail to configure encrypt");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700463
464 CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800465 if (error) throw Error("Fail to encrypt data");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700466
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800467 if (!output) throw Error("Output is NULL!\n");
Jeff Thompson2747dc02013-10-04 19:11:34 -0700468
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800469 return ptr_lib::make_shared<Buffer> (CFDataGetBytePtr(output), CFDataGetLength(output));
Jeff Thompson2747dc02013-10-04 19:11:34 -0700470 }
471
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800472 bool
473 OSXPrivateKeyStorage::doesKeyExist(const Name & keyName, KeyClass keyClass)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700474 {
475 _LOG_TRACE("OSXPrivateKeyStorage::doesKeyExist");
476
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800477 string keyNameUri = impl_->toInternalKeyName(keyName, keyClass);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700478
479 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
Jeff Thompson556cc302013-10-22 17:40:07 -0700480 keyNameUri.c_str(),
481 kCFStringEncodingUTF8);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700482
483 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
484 3,
485 &kCFTypeDictionaryKeyCallBacks,
486 NULL);
487
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800488 CFDictionaryAddValue(attrDict, kSecAttrKeyClass, impl_->getKeyClass(keyClass));
Jeff Thompson2747dc02013-10-04 19:11:34 -0700489 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
490 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
491
492 SecKeychainItemRef itemRef;
493 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict, (CFTypeRef*)&itemRef);
494
495 if(res == errSecItemNotFound)
496 return true;
497 else
498 return false;
499
500 }
501
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800502
503 ////////////////////////////////
504 // OSXPrivateKeyStorage::Impl //
505 ////////////////////////////////
506
507 SecKeychainItemRef
508 OSXPrivateKeyStorage::Impl::getKey(const Name & keyName, KeyClass keyClass)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700509 {
510 string keyNameUri = toInternalKeyName(keyName, keyClass);
511
Jeff Thompson556cc302013-10-22 17:40:07 -0700512 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
513 keyNameUri.c_str(),
514 kCFStringEncodingUTF8);
Jeff Thompson2747dc02013-10-04 19:11:34 -0700515
516 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
517 5,
518 &kCFTypeDictionaryKeyCallBacks,
519 NULL);
520
521 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
522 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
523 CFDictionaryAddValue(attrDict, kSecAttrKeyClass, getKeyClass(keyClass));
524 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
525
526 SecKeychainItemRef keyItem;
527
528 OSStatus res = SecItemCopyMatching((CFDictionaryRef) attrDict, (CFTypeRef*)&keyItem);
529
530 if(res != errSecSuccess){
531 _LOG_DEBUG("Fail to find the key!");
532 return NULL;
533 }
534 else
535 return keyItem;
536 }
537
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800538 string OSXPrivateKeyStorage::Impl::toInternalKeyName(const Name & keyName, KeyClass keyClass)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700539 {
540 string keyUri = keyName.toUri();
541
542 if(KEY_CLASS_SYMMETRIC == keyClass)
543 return keyUri + "/symmetric";
544 else
545 return keyUri;
546 }
547
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800548 const CFTypeRef OSXPrivateKeyStorage::Impl::getAsymKeyType(KeyType keyType)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700549 {
550 switch(keyType){
551 case KEY_TYPE_RSA:
552 return kSecAttrKeyTypeRSA;
553 default:
554 _LOG_DEBUG("Unrecognized key type!")
555 return NULL;
556 }
557 }
558
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800559 const CFTypeRef OSXPrivateKeyStorage::Impl::getSymKeyType(KeyType keyType)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700560 {
561 switch(keyType){
562 case KEY_TYPE_AES:
563 return kSecAttrKeyTypeAES;
564 default:
565 _LOG_DEBUG("Unrecognized key type!")
566 return NULL;
567 }
568 }
569
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800570 const CFTypeRef OSXPrivateKeyStorage::Impl::getKeyClass(KeyClass keyClass)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700571 {
572 switch(keyClass){
573 case KEY_CLASS_PRIVATE:
574 return kSecAttrKeyClassPrivate;
575 case KEY_CLASS_PUBLIC:
576 return kSecAttrKeyClassPublic;
577 case KEY_CLASS_SYMMETRIC:
578 return kSecAttrKeyClassSymmetric;
579 default:
580 _LOG_DEBUG("Unrecognized key class!");
581 return NULL;
582 }
583 }
584
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800585 const CFStringRef OSXPrivateKeyStorage::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700586 {
587 switch(digestAlgo){
588 // case DIGEST_MD2:
589 // return kSecDigestMD2;
590 // case DIGEST_MD5:
591 // return kSecDigestMD5;
592 // case DIGEST_SHA1:
593 // return kSecDigestSHA1;
594 case DIGEST_ALGORITHM_SHA256:
595 return kSecDigestSHA2;
596 default:
597 _LOG_DEBUG("Unrecognized digest algorithm!");
598 return NULL;
599 }
600 }
601
Alexander Afanasyev04b22a92014-01-05 22:40:17 -0800602 long OSXPrivateKeyStorage::Impl::getDigestSize(DigestAlgorithm digestAlgo)
Jeff Thompson2747dc02013-10-04 19:11:34 -0700603 {
604 switch(digestAlgo){
605 case DIGEST_ALGORITHM_SHA256:
606 return 256;
607 // case DIGEST_SHA1:
608 // case DIGEST_MD2:
609 // case DIGEST_MD5:
610 // return 0;
611 default:
612 _LOG_DEBUG("Unrecognized digest algorithm! Unknown digest size");
613 return -1;
614 }
615 }
616
617}
618
Jeff Thompsonc5647812013-10-11 18:06:38 -0700619#endif // NDN_CPP_HAVE_OSX_SECURITY