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