blob: d1ea2c57efa44c8fb36491d1730aca7076272967 [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 Thompsonb7523002013-10-09 10:25:00 -07008// Only compile if ndn-cpp-config.h defines NDN_CPP_HAVE_OSX_SECKEYCHAIN 1.
9#include "../../ndn-cpp-config.h"
Jeff Thompson2747dc02013-10-04 19:11:34 -070010#if 0 // temporarily disable.
Jeff Thompsonb7523002013-10-09 10:25:00 -070011//#if NDN_CPP_HAVE_OSX_SECKEYCHAIN
Jeff Thompson2747dc02013-10-04 19:11:34 -070012
13#include <fstream>
14#include <sstream>
15#include <CoreFoundation/CoreFoundation.h>
16
17#include "../../util/logging.hpp"
18#include "osx-private-key-storage.hpp"
19#include "../security-exception.hpp"
20
21using namespace std;
22using namespace ndn::ptr_lib;
23
24INIT_LOGGER("ndn.OSXPrivateKeyStorage");
25
26namespace ndn
27{
28 OSXPrivateKeyStorage::OSXPrivateKeyStorage(const string & keychainName)
29 : keyChainName_("" == keychainName ? "NDN.keychain" : keychainName)
30 {
31 OSStatus res = SecKeychainCreate(keyChainName_.c_str(), //Keychain path
32 0, //Keychain password length
33 NULL, //Keychain password
34 true, //User prompt
35 NULL, //Initial access of Keychain
36 &keyChainRef_); //Keychain reference
37
38 if (res == errSecDuplicateKeychain)
39 res = SecKeychainOpen(keyChainName_.c_str(),
40 &keyChainRef_);
41
42 if (res != errSecSuccess){
43 _LOG_DEBUG("Fail to initialize keychain ref: " << res);
44 throw SecurityException("Fail to initialize keychain ref");
45 }
46
47 res = SecKeychainCopyDefault(&originalDefaultKeyChain_);
48
49 res = SecKeychainSetDefault(keyChainRef_);
50 if (res != errSecSuccess){
51 _LOG_DEBUG("Fail to set default keychain: " << res);
52 throw SecurityException("Fail to set default keychain");
53 }
54 }
55
56 OSXPrivateKeyStorage::~OSXPrivateKeyStorage(){
57 //TODO: implement
58 }
59
60 void
61 OSXPrivateKeyStorage::generateKeyPair(const Name & keyName, KeyType keyType, int keySize)
62 {
63
64 if(doesKeyExist(keyName, KEY_CLASS_PUBLIC)){
65 _LOG_DEBUG("keyName has existed");
66 throw SecurityException("keyName has existed");
67 }
68
69 string keyNameUri = toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
70
71 SecKeyRef publicKey, privateKey;
72
73 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
74 keyNameUri.c_str(),
75 keyNameUri.size());
76
77 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
78 3,
79 &kCFTypeDictionaryKeyCallBacks,
80 NULL);
81
82 CFDictionaryAddValue(attrDict, kSecAttrKeyType, getAsymKeyType(keyType));
83 CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(NULL, kCFNumberIntType, &keySize));
84 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
85
86 OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict, &publicKey, &privateKey);
87
88 CFRelease(publicKey);
89 CFRelease(privateKey);
90
91 if (res != errSecSuccess){
92 _LOG_DEBUG("Fail to create a key pair: " << res);
93 throw SecurityException("Fail to create a key pair");
94 }
95 }
96
97 void
98 OSXPrivateKeyStorage::generateKey(const Name & keyName, KeyType keyType, int keySize)
99 {
100
101 if(doesKeyExist(keyName, KEY_CLASS_SYMMETRIC))
102 throw SecurityException("keyName has existed!");
103
104 string keyNameUri = toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
105
106 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
107 0,
108 &kCFTypeDictionaryKeyCallBacks,
109 &kCFTypeDictionaryValueCallBacks);
110
111 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
112 keyNameUri.c_str(),
113 keyNameUri.size());
114
115 CFDictionaryAddValue(attrDict, kSecAttrKeyType, getSymKeyType(keyType));
116 CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &keySize));
117 CFDictionaryAddValue(attrDict, kSecAttrIsPermanent, kCFBooleanTrue);
118 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
119
120 CFErrorRef error = NULL;
121
122 SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
123
124 if (error)
125 throw SecurityException("Fail to create a symmetric key");
126 }
127
128 shared_ptr<PublicKey> OSXPrivateKeyStorage::getPublicKey(const Name & keyName)
129 {
130 _LOG_TRACE("OSXPrivateKeyStorage::getPublickey");
131
132 SecKeychainItemRef publicKey = getKey(keyName, KEY_CLASS_PUBLIC);
133
134 CFDataRef exportedKey;
135
136 OSStatus res = SecItemExport(publicKey,
137 kSecFormatOpenSSL,
138 0,
139 NULL,
140 &exportedKey);
141
142 Blob blob(CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
143
144 return PublicKey::fromDer(blob);
145 }
146
147 Blob OSXPrivateKeyStorage::sign(const uint8_t *data, size_t dataLength, const Name & keyName, DigestAlgorithm digestAlgo)
148 {
149 _LOG_TRACE("OSXPrivateKeyStorage::Sign");
150
151 CFDataRef dataRef = CFDataCreate(NULL,
152 reinterpret_cast<const unsigned char*>(data),
153 dataLength
154 );
155
156 SecKeyRef privateKey = (SecKeyRef)getKey(keyName, KEY_CLASS_PRIVATE);
157
158 CFErrorRef error;
159 SecTransformRef signer = SecSignTransformCreate((SecKeyRef)privateKey, &error);
160 if (error) throw SecurityException("Fail to create signer");
161
162 Boolean set_res = SecTransformSetAttribute(signer,
163 kSecTransformInputAttributeName,
164 dataRef,
165 &error);
166 if (error) throw SecurityException("Fail to configure input of signer");
167
168 set_res = SecTransformSetAttribute(signer,
169 kSecDigestTypeAttribute,
170 getDigestAlgorithm(digestAlgo),
171 &error);
172 if (error) throw SecurityException("Fail to configure digest algorithm of signer");
173
174 long digestSize = getDigestSize(digestAlgo);
175
176 set_res = SecTransformSetAttribute(signer,
177 kSecDigestLengthAttribute,
178 CFNumberCreate(NULL, kCFNumberLongType, &digestSize),
179 &error);
180 if (error) throw SecurityException("Fail to configure digest size of signer");
181
182 CFDataRef signature = (CFDataRef) SecTransformExecute(signer, &error);
183 if (error) {
184 CFShow(error);
185 throw SecurityException("Fail to sign data");
186 }
187
188 if (!signature) throw SecurityException("Signature is NULL!\n");
189
190 return Blob(CFDataGetBytePtr(signature), CFDataGetLength(signature));
191 }
192
193 Blob OSXPrivateKeyStorage::decrypt(const Name & keyName, const uint8_t* data, size_t dataLength, bool sym)
194 {
195 _LOG_TRACE("OSXPrivateKeyStorage::Decrypt");
196
197 KeyClass keyClass;
198 if(sym)
199 keyClass = KEY_CLASS_SYMMETRIC;
200 else
201 keyClass = KEY_CLASS_PRIVATE;
202
203 CFDataRef dataRef = CFDataCreate(NULL,
204 reinterpret_cast<const unsigned char*>(data),
205 dataLength
206 );
207
208 // _LOG_DEBUG("CreateData");
209
210 SecKeyRef decryptKey = (SecKeyRef)getKey(keyName, keyClass);
211
212 // _LOG_DEBUG("GetKey");
213
214 CFErrorRef error;
215 SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
216 if (error) throw SecurityException("Fail to create decrypt");
217
218 Boolean set_res = SecTransformSetAttribute(decrypt,
219 kSecTransformInputAttributeName,
220 dataRef,
221 &error);
222 if (error) throw SecurityException("Fail to configure decrypt");
223
224 CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
225 if (error)
226 {
227 CFShow(error);
228 throw SecurityException("Fail to decrypt data");
229 }
230 if (!output) throw SecurityException("Output is NULL!\n");
231
232 return Blob(CFDataGetBytePtr(output), CFDataGetLength(output));
233 }
234
235 bool OSXPrivateKeyStorage::setACL(const Name & keyName, KeyClass keyClass, int acl, const string & appPath)
236 {
237 SecKeychainItemRef privateKey = getKey(keyName, keyClass);
238
239 SecAccessRef accRef;
240 OSStatus acc_res = SecKeychainItemCopyAccess(privateKey, &accRef);
241
242 CFArrayRef signACL = SecAccessCopyMatchingACLList(accRef,
243 kSecACLAuthorizationSign);
244
245 SecACLRef aclRef = (SecACLRef) CFArrayGetValueAtIndex(signACL, 0);
246
247 CFArrayRef appList;
248 CFStringRef description;
249 SecKeychainPromptSelector promptSelector;
250 OSStatus acl_res = SecACLCopyContents(aclRef,
251 &appList,
252 &description,
253 &promptSelector);
254
255 CFMutableArrayRef newAppList = CFArrayCreateMutableCopy(NULL,
256 0,
257 appList);
258
259 SecTrustedApplicationRef trustedApp;
260 acl_res = SecTrustedApplicationCreateFromPath(appPath.c_str(),
261 &trustedApp);
262
263 CFArrayAppendValue(newAppList, trustedApp);
264
265
266 CFArrayRef authList = SecACLCopyAuthorizations(aclRef);
267
268 acl_res = SecACLRemove(aclRef);
269
270 SecACLRef newACL;
271 acl_res = SecACLCreateWithSimpleContents(accRef,
272 newAppList,
273 description,
274 promptSelector,
275 &newACL);
276
277 acl_res = SecACLUpdateAuthorizations(newACL, authList);
278
279 acc_res = SecKeychainItemSetAccess(privateKey, accRef);
280
281 return true;
282 }
283
284 bool OSXPrivateKeyStorage::verifyData(const Name & keyName, const Blob & pData, const Blob & pSig, DigestAlgorithm digestAlgo)
285 {
286 _LOG_TRACE("OSXPrivateKeyStorage::Verify");
287
288 CFDataRef dataRef = CFDataCreate(NULL,
289 reinterpret_cast<const unsigned char*>(pData.buf()),
290 pData.size());
291
292 CFDataRef sigRef = CFDataCreate(NULL,
293 reinterpret_cast<const unsigned char*>(pSig.buf()),
294 pSig.size());
295
296 SecKeyRef publicKey = (SecKeyRef)getKey(keyName, KEY_CLASS_PUBLIC);
297
298 CFErrorRef error;
299 SecTransformRef verifier = SecVerifyTransformCreate(publicKey, sigRef, &error);
300 if (error) throw SecurityException("Fail to create verifier");
301
302 Boolean set_res = SecTransformSetAttribute(verifier,
303 kSecTransformInputAttributeName,
304 dataRef,
305 &error);
306 if (error) throw SecurityException("Fail to configure input of verifier");
307
308 set_res = SecTransformSetAttribute(verifier,
309 kSecDigestTypeAttribute,
310 getDigestAlgorithm(digestAlgo),
311 &error);
312 if (error) throw SecurityException("Fail to configure digest algorithm of verifier");
313
314 long digestSize = getDigestSize(digestAlgo);
315 set_res = SecTransformSetAttribute(verifier,
316 kSecDigestLengthAttribute,
317 CFNumberCreate(NULL, kCFNumberLongType, &digestSize),
318 &error);
319 if (error) throw SecurityException("Fail to configure digest size of verifier");
320
321 CFBooleanRef result = (CFBooleanRef) SecTransformExecute(verifier, &error);
322 if (error) throw SecurityException("Fail to verify data");
323
324 if (result == kCFBooleanTrue)
325 return true;
326 else
327 return false;
328 }
329
330 Blob OSXPrivateKeyStorage::encrypt(const Name & keyName, const uint8_t* data, size_t dataLength, bool sym)
331 {
332 _LOG_TRACE("OSXPrivateKeyStorage::Encrypt");
333
334 KeyClass keyClass;
335 if(sym)
336 keyClass = KEY_CLASS_SYMMETRIC;
337 else
338 keyClass = KEY_CLASS_PUBLIC;
339
340 CFDataRef dataRef = CFDataCreate(NULL,
341 reinterpret_cast<const unsigned char*>(data),
342 dataLength
343 );
344
345 SecKeyRef encryptKey = (SecKeyRef)getKey(keyName, keyClass);
346
347 CFErrorRef error;
348 SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
349 if (error) throw SecurityException("Fail to create encrypt");
350
351 Boolean set_res = SecTransformSetAttribute(encrypt,
352 kSecTransformInputAttributeName,
353 dataRef,
354 &error);
355 if (error) throw SecurityException("Fail to configure encrypt");
356
357 CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
358 if (error) throw SecurityException("Fail to encrypt data");
359
360 if (!output) throw SecurityException("Output is NULL!\n");
361
362 return Blob(CFDataGetBytePtr(output), CFDataGetLength(output));
363 }
364
365 bool OSXPrivateKeyStorage::doesKeyExist(const Name & keyName, KeyClass keyClass)
366 {
367 _LOG_TRACE("OSXPrivateKeyStorage::doesKeyExist");
368
369 string keyNameUri = toInternalKeyName(keyName, keyClass);
370
371 CFStringRef keyLabel = CFStringCreateWithCString(NULL,
372 keyNameUri.c_str(),
373 keyNameUri.size());
374
375 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
376 3,
377 &kCFTypeDictionaryKeyCallBacks,
378 NULL);
379
380 CFDictionaryAddValue(attrDict, kSecAttrKeyClass, getKeyClass(keyClass));
381 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
382 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
383
384 SecKeychainItemRef itemRef;
385 OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict, (CFTypeRef*)&itemRef);
386
387 if(res == errSecItemNotFound)
388 return true;
389 else
390 return false;
391
392 }
393
394 SecKeychainItemRef OSXPrivateKeyStorage::getKey(const Name & keyName, KeyClass keyClass)
395 {
396 string keyNameUri = toInternalKeyName(keyName, keyClass);
397
398 CFStringRef keyLabel = CFStringCreateWithCString (NULL,
399 keyNameUri.c_str(),
400 keyNameUri.size());
401
402 CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
403 5,
404 &kCFTypeDictionaryKeyCallBacks,
405 NULL);
406
407 CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
408 CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
409 CFDictionaryAddValue(attrDict, kSecAttrKeyClass, getKeyClass(keyClass));
410 CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
411
412 SecKeychainItemRef keyItem;
413
414 OSStatus res = SecItemCopyMatching((CFDictionaryRef) attrDict, (CFTypeRef*)&keyItem);
415
416 if(res != errSecSuccess){
417 _LOG_DEBUG("Fail to find the key!");
418 return NULL;
419 }
420 else
421 return keyItem;
422 }
423
424 string OSXPrivateKeyStorage::toInternalKeyName(const Name & keyName, KeyClass keyClass)
425 {
426 string keyUri = keyName.toUri();
427
428 if(KEY_CLASS_SYMMETRIC == keyClass)
429 return keyUri + "/symmetric";
430 else
431 return keyUri;
432 }
433
434 const CFTypeRef OSXPrivateKeyStorage::getAsymKeyType(KeyType keyType)
435 {
436 switch(keyType){
437 case KEY_TYPE_RSA:
438 return kSecAttrKeyTypeRSA;
439 default:
440 _LOG_DEBUG("Unrecognized key type!")
441 return NULL;
442 }
443 }
444
445 const CFTypeRef OSXPrivateKeyStorage::getSymKeyType(KeyType keyType)
446 {
447 switch(keyType){
448 case KEY_TYPE_AES:
449 return kSecAttrKeyTypeAES;
450 default:
451 _LOG_DEBUG("Unrecognized key type!")
452 return NULL;
453 }
454 }
455
456 const CFTypeRef OSXPrivateKeyStorage::getKeyClass(KeyClass keyClass)
457 {
458 switch(keyClass){
459 case KEY_CLASS_PRIVATE:
460 return kSecAttrKeyClassPrivate;
461 case KEY_CLASS_PUBLIC:
462 return kSecAttrKeyClassPublic;
463 case KEY_CLASS_SYMMETRIC:
464 return kSecAttrKeyClassSymmetric;
465 default:
466 _LOG_DEBUG("Unrecognized key class!");
467 return NULL;
468 }
469 }
470
471 SecExternalFormat OSXPrivateKeyStorage::getFormat(KeyFormat format)
472 {
473 switch(format){
474 case KEY_FORMAT_PUBLIC_OPENSSL:
475 return kSecFormatOpenSSL;
476 default:
477 _LOG_DEBUG("Unrecognized output format!");
478 return 0;
479 }
480 }
481
482 const CFStringRef OSXPrivateKeyStorage::getDigestAlgorithm(DigestAlgorithm digestAlgo)
483 {
484 switch(digestAlgo){
485 // case DIGEST_MD2:
486 // return kSecDigestMD2;
487 // case DIGEST_MD5:
488 // return kSecDigestMD5;
489 // case DIGEST_SHA1:
490 // return kSecDigestSHA1;
491 case DIGEST_ALGORITHM_SHA256:
492 return kSecDigestSHA2;
493 default:
494 _LOG_DEBUG("Unrecognized digest algorithm!");
495 return NULL;
496 }
497 }
498
499 long OSXPrivateKeyStorage::getDigestSize(DigestAlgorithm digestAlgo)
500 {
501 switch(digestAlgo){
502 case DIGEST_ALGORITHM_SHA256:
503 return 256;
504 // case DIGEST_SHA1:
505 // case DIGEST_MD2:
506 // case DIGEST_MD5:
507 // return 0;
508 default:
509 _LOG_DEBUG("Unrecognized digest algorithm! Unknown digest size");
510 return -1;
511 }
512 }
513
514}
515
Jeff Thompsonb7523002013-10-09 10:25:00 -0700516#endif NDN_CPP_HAVE_OSX_SECKEYCHAIN