security: Added initial port of OSXPrivateKeyStorage
diff --git a/ndn-cpp/security/identity/osx-private-key-storage.cpp b/ndn-cpp/security/identity/osx-private-key-storage.cpp
new file mode 100644
index 0000000..2840e64
--- /dev/null
+++ b/ndn-cpp/security/identity/osx-private-key-storage.cpp
@@ -0,0 +1,517 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+// Only compile if config.h defines HAVE_OSX_SECKEYCHAIN 1.
+#include "../../c/common.h"
+#if 0 // temporarily disable.
+//#if HAVE_OSX_SECKEYCHAIN
+
+
+#include <fstream>
+#include <sstream>
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "../../util/logging.hpp"
+#include "osx-private-key-storage.hpp"
+#include "../security-exception.hpp"
+
+using namespace std;
+using namespace ndn::ptr_lib;
+
+INIT_LOGGER("ndn.OSXPrivateKeyStorage");
+
+namespace ndn
+{
+  OSXPrivateKeyStorage::OSXPrivateKeyStorage(const string & keychainName)
+    : keyChainName_("" == keychainName ?  "NDN.keychain" : keychainName)
+  {
+    OSStatus res = SecKeychainCreate(keyChainName_.c_str(), //Keychain path
+                                      0,                       //Keychain password length
+                                      NULL,                    //Keychain password
+                                      true,                    //User prompt
+                                      NULL,                    //Initial access of Keychain
+                                      &keyChainRef_);         //Keychain reference
+
+    if (res == errSecDuplicateKeychain)
+      res = SecKeychainOpen(keyChainName_.c_str(),
+                             &keyChainRef_);
+
+    if (res != errSecSuccess){
+      _LOG_DEBUG("Fail to initialize keychain ref: " << res);
+      throw SecurityException("Fail to initialize keychain ref");
+    }
+
+    res = SecKeychainCopyDefault(&originalDefaultKeyChain_);
+
+    res = SecKeychainSetDefault(keyChainRef_);
+    if (res != errSecSuccess){
+      _LOG_DEBUG("Fail to set default keychain: " << res);
+      throw SecurityException("Fail to set default keychain");
+    }
+  }
+
+  OSXPrivateKeyStorage::~OSXPrivateKeyStorage(){
+    //TODO: implement
+  }
+
+  void 
+  OSXPrivateKeyStorage::generateKeyPair(const Name & keyName, KeyType keyType, int keySize)
+  { 
+    
+    if(doesKeyExist(keyName, KEY_CLASS_PUBLIC)){
+      _LOG_DEBUG("keyName has existed");
+      throw SecurityException("keyName has existed");
+    }
+
+    string keyNameUri = toInternalKeyName(keyName, KEY_CLASS_PUBLIC);
+
+    SecKeyRef publicKey, privateKey;
+
+    CFStringRef keyLabel = CFStringCreateWithCString(NULL, 
+                                                      keyNameUri.c_str(), 
+                                                      keyNameUri.size());
+    
+    CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
+                                                             3,
+                                                             &kCFTypeDictionaryKeyCallBacks,
+                                                             NULL);
+
+    CFDictionaryAddValue(attrDict, kSecAttrKeyType, getAsymKeyType(keyType));
+    CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(NULL, kCFNumberIntType, &keySize));
+    CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
+
+    OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict, &publicKey, &privateKey);
+
+    CFRelease(publicKey);
+    CFRelease(privateKey);
+
+    if (res != errSecSuccess){
+      _LOG_DEBUG("Fail to create a key pair: " << res);
+      throw SecurityException("Fail to create a key pair");
+    }
+  }
+
+  void 
+  OSXPrivateKeyStorage::generateKey(const Name & keyName, KeyType keyType, int keySize)
+  {
+
+    if(doesKeyExist(keyName, KEY_CLASS_SYMMETRIC))
+        throw SecurityException("keyName has existed!");
+
+    string keyNameUri =  toInternalKeyName(keyName, KEY_CLASS_SYMMETRIC);
+
+    CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
+                                                                0,
+                                                                &kCFTypeDictionaryKeyCallBacks,
+                                                                &kCFTypeDictionaryValueCallBacks);
+
+    CFStringRef keyLabel = CFStringCreateWithCString(NULL, 
+                                                      keyNameUri.c_str(), 
+                                                      keyNameUri.size());
+
+    CFDictionaryAddValue(attrDict, kSecAttrKeyType, getSymKeyType(keyType));
+    CFDictionaryAddValue(attrDict, kSecAttrKeySizeInBits, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &keySize));
+    CFDictionaryAddValue(attrDict, kSecAttrIsPermanent, kCFBooleanTrue);
+    CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
+
+    CFErrorRef error = NULL;
+
+    SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error);
+
+    if (error) 
+        throw SecurityException("Fail to create a symmetric key");
+  }
+
+  shared_ptr<PublicKey> OSXPrivateKeyStorage::getPublicKey(const Name & keyName)
+  {
+    _LOG_TRACE("OSXPrivateKeyStorage::getPublickey");
+
+    SecKeychainItemRef publicKey = getKey(keyName, KEY_CLASS_PUBLIC);
+
+    CFDataRef exportedKey;
+
+    OSStatus res = SecItemExport(publicKey,
+                                  kSecFormatOpenSSL,
+                                  0,
+                                  NULL,
+                                  &exportedKey);
+    
+    Blob blob(CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
+
+    return PublicKey::fromDer(blob);
+  }
+
+  Blob OSXPrivateKeyStorage::sign(const uint8_t *data, size_t dataLength, const Name & keyName, DigestAlgorithm digestAlgo)
+  {
+    _LOG_TRACE("OSXPrivateKeyStorage::Sign");
+    
+    CFDataRef dataRef = CFDataCreate(NULL,
+                                      reinterpret_cast<const unsigned char*>(data),
+                                      dataLength
+                                      );
+
+    SecKeyRef privateKey = (SecKeyRef)getKey(keyName, KEY_CLASS_PRIVATE);
+    
+    CFErrorRef error;
+    SecTransformRef signer = SecSignTransformCreate((SecKeyRef)privateKey, &error);
+    if (error) throw SecurityException("Fail to create signer");
+    
+    Boolean set_res = SecTransformSetAttribute(signer,
+                                               kSecTransformInputAttributeName,
+                                               dataRef,
+                                               &error);
+    if (error) throw SecurityException("Fail to configure input of signer");
+
+    set_res = SecTransformSetAttribute(signer,
+                                       kSecDigestTypeAttribute,
+                                       getDigestAlgorithm(digestAlgo),
+                                       &error);
+    if (error) throw SecurityException("Fail to configure digest algorithm of signer");
+
+    long digestSize = getDigestSize(digestAlgo);
+
+    set_res = SecTransformSetAttribute(signer,
+                                       kSecDigestLengthAttribute,
+                                       CFNumberCreate(NULL, kCFNumberLongType, &digestSize),
+                                       &error);
+    if (error) throw SecurityException("Fail to configure digest size of signer");
+
+    CFDataRef signature = (CFDataRef) SecTransformExecute(signer, &error);
+    if (error) {
+      CFShow(error);
+      throw SecurityException("Fail to sign data");
+    }
+
+    if (!signature) throw SecurityException("Signature is NULL!\n");
+
+    return Blob(CFDataGetBytePtr(signature), CFDataGetLength(signature));
+  }
+
+  Blob OSXPrivateKeyStorage::decrypt(const Name & keyName, const uint8_t* data, size_t dataLength, bool sym)
+  {
+    _LOG_TRACE("OSXPrivateKeyStorage::Decrypt");
+
+    KeyClass keyClass;
+    if(sym)
+        keyClass = KEY_CLASS_SYMMETRIC;
+    else
+        keyClass = KEY_CLASS_PRIVATE;
+
+    CFDataRef dataRef = CFDataCreate(NULL,
+                                      reinterpret_cast<const unsigned char*>(data),
+                                      dataLength
+                                      );
+
+    // _LOG_DEBUG("CreateData");
+    
+    SecKeyRef decryptKey = (SecKeyRef)getKey(keyName, keyClass);
+
+    // _LOG_DEBUG("GetKey");
+
+    CFErrorRef error;
+    SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error);
+    if (error) throw SecurityException("Fail to create decrypt");
+
+    Boolean set_res = SecTransformSetAttribute(decrypt,
+                                               kSecTransformInputAttributeName,
+                                               dataRef,
+                                               &error);
+    if (error) throw SecurityException("Fail to configure decrypt");
+
+    CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error);
+    if (error)
+      {
+        CFShow(error);
+        throw SecurityException("Fail to decrypt data");
+      }
+    if (!output) throw SecurityException("Output is NULL!\n");
+
+    return Blob(CFDataGetBytePtr(output), CFDataGetLength(output));
+  }
+  
+  bool OSXPrivateKeyStorage::setACL(const Name & keyName, KeyClass keyClass, int acl, const string & appPath)
+  {
+    SecKeychainItemRef privateKey = getKey(keyName, keyClass);
+    
+    SecAccessRef accRef;
+    OSStatus acc_res = SecKeychainItemCopyAccess(privateKey, &accRef);
+
+    CFArrayRef signACL = SecAccessCopyMatchingACLList(accRef,
+                                                       kSecACLAuthorizationSign);
+
+    SecACLRef aclRef = (SecACLRef) CFArrayGetValueAtIndex(signACL, 0);
+
+    CFArrayRef appList;
+    CFStringRef description;
+    SecKeychainPromptSelector promptSelector;
+    OSStatus acl_res = SecACLCopyContents(aclRef,
+                                           &appList,
+                                           &description,
+                                           &promptSelector);
+
+    CFMutableArrayRef newAppList = CFArrayCreateMutableCopy(NULL,
+                                                            0,
+                                                            appList);
+
+    SecTrustedApplicationRef trustedApp;
+    acl_res = SecTrustedApplicationCreateFromPath(appPath.c_str(),
+                                                   &trustedApp);
+    
+    CFArrayAppendValue(newAppList, trustedApp);
+
+
+    CFArrayRef authList = SecACLCopyAuthorizations(aclRef);
+    
+    acl_res = SecACLRemove(aclRef);
+
+    SecACLRef newACL;
+    acl_res = SecACLCreateWithSimpleContents(accRef,
+                                              newAppList,
+                                              description,
+                                              promptSelector,
+                                              &newACL);
+
+    acl_res = SecACLUpdateAuthorizations(newACL, authList);
+
+    acc_res = SecKeychainItemSetAccess(privateKey, accRef);
+
+    return true;
+  }
+
+  bool OSXPrivateKeyStorage::verifyData(const Name & keyName, const Blob & pData, const Blob & pSig, DigestAlgorithm digestAlgo)
+  {
+    _LOG_TRACE("OSXPrivateKeyStorage::Verify");
+    
+    CFDataRef dataRef = CFDataCreate(NULL,
+                                      reinterpret_cast<const unsigned char*>(pData.buf()),
+                                      pData.size());
+
+    CFDataRef sigRef = CFDataCreate(NULL,
+                                     reinterpret_cast<const unsigned char*>(pSig.buf()),
+                                     pSig.size());
+
+    SecKeyRef publicKey = (SecKeyRef)getKey(keyName, KEY_CLASS_PUBLIC);
+    
+    CFErrorRef error;
+    SecTransformRef verifier = SecVerifyTransformCreate(publicKey, sigRef, &error);
+    if (error) throw SecurityException("Fail to create verifier");
+    
+    Boolean set_res = SecTransformSetAttribute(verifier,
+                                               kSecTransformInputAttributeName,
+                                               dataRef,
+                                               &error);
+    if (error) throw SecurityException("Fail to configure input of verifier");
+
+    set_res = SecTransformSetAttribute(verifier,
+                                       kSecDigestTypeAttribute,
+                                       getDigestAlgorithm(digestAlgo),
+                                       &error);
+    if (error) throw SecurityException("Fail to configure digest algorithm of verifier");
+
+    long digestSize = getDigestSize(digestAlgo);
+    set_res = SecTransformSetAttribute(verifier,
+                                       kSecDigestLengthAttribute,
+                                       CFNumberCreate(NULL, kCFNumberLongType, &digestSize),
+                                       &error);
+    if (error) throw SecurityException("Fail to configure digest size of verifier");
+
+    CFBooleanRef result = (CFBooleanRef) SecTransformExecute(verifier, &error);
+    if (error) throw SecurityException("Fail to verify data");
+
+    if (result == kCFBooleanTrue)
+      return true;
+    else
+      return false;
+  }
+
+  Blob OSXPrivateKeyStorage::encrypt(const Name & keyName, const uint8_t* data, size_t dataLength, bool sym)
+  {
+    _LOG_TRACE("OSXPrivateKeyStorage::Encrypt");
+
+    KeyClass keyClass;
+    if(sym)
+        keyClass = KEY_CLASS_SYMMETRIC;
+    else
+        keyClass = KEY_CLASS_PUBLIC;
+    
+    CFDataRef dataRef = CFDataCreate(NULL,
+                                      reinterpret_cast<const unsigned char*>(data),
+                                      dataLength
+                                      );
+    
+    SecKeyRef encryptKey = (SecKeyRef)getKey(keyName, keyClass);
+
+    CFErrorRef error;
+    SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error);
+    if (error) throw SecurityException("Fail to create encrypt");
+
+    Boolean set_res = SecTransformSetAttribute(encrypt,
+                                               kSecTransformInputAttributeName,
+                                               dataRef,
+                                               &error);
+    if (error) throw SecurityException("Fail to configure encrypt");
+
+    CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error);
+    if (error) throw SecurityException("Fail to encrypt data");
+
+    if (!output) throw SecurityException("Output is NULL!\n");
+
+    return Blob(CFDataGetBytePtr(output), CFDataGetLength(output));
+  }
+
+  bool OSXPrivateKeyStorage::doesKeyExist(const Name & keyName, KeyClass keyClass)
+  {
+    _LOG_TRACE("OSXPrivateKeyStorage::doesKeyExist");
+
+    string keyNameUri = toInternalKeyName(keyName, keyClass);
+
+    CFStringRef keyLabel = CFStringCreateWithCString(NULL, 
+                                                      keyNameUri.c_str(), 
+                                                      keyNameUri.size());
+    
+    CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
+                                                                3,
+                                                                &kCFTypeDictionaryKeyCallBacks,
+                                                                NULL);
+
+    CFDictionaryAddValue(attrDict, kSecAttrKeyClass, getKeyClass(keyClass));
+    CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
+    CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
+    
+    SecKeychainItemRef itemRef;
+    OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict, (CFTypeRef*)&itemRef);
+    
+    if(res == errSecItemNotFound)
+      return true;
+    else
+      return false;
+
+  }
+
+  SecKeychainItemRef OSXPrivateKeyStorage::getKey(const Name & keyName, KeyClass keyClass)
+  {
+    string keyNameUri = toInternalKeyName(keyName, keyClass);
+
+    CFStringRef keyLabel = CFStringCreateWithCString (NULL, 
+                                                      keyNameUri.c_str(), 
+                                                      keyNameUri.size());
+    
+    CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
+                                                             5,
+                                                             &kCFTypeDictionaryKeyCallBacks,
+                                                             NULL);
+
+    CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
+    CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
+    CFDictionaryAddValue(attrDict, kSecAttrKeyClass, getKeyClass(keyClass));
+    CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
+    
+    SecKeychainItemRef keyItem;
+
+    OSStatus res = SecItemCopyMatching((CFDictionaryRef) attrDict, (CFTypeRef*)&keyItem);
+    
+    if(res != errSecSuccess){
+      _LOG_DEBUG("Fail to find the key!");
+      return NULL;
+    }
+    else
+      return keyItem;
+  }
+  
+  string OSXPrivateKeyStorage::toInternalKeyName(const Name & keyName, KeyClass keyClass)
+  {
+    string keyUri = keyName.toUri();
+
+    if(KEY_CLASS_SYMMETRIC == keyClass)
+      return keyUri + "/symmetric";
+    else
+      return keyUri;
+  }
+
+  const CFTypeRef OSXPrivateKeyStorage::getAsymKeyType(KeyType keyType)
+  {
+    switch(keyType){
+    case KEY_TYPE_RSA:
+      return kSecAttrKeyTypeRSA;
+    default:
+      _LOG_DEBUG("Unrecognized key type!")
+      return NULL;
+    }
+  }
+
+  const CFTypeRef OSXPrivateKeyStorage::getSymKeyType(KeyType keyType)
+  {
+    switch(keyType){
+    case KEY_TYPE_AES:
+      return kSecAttrKeyTypeAES;
+    default:
+      _LOG_DEBUG("Unrecognized key type!")
+      return NULL;
+    }
+  }
+
+  const CFTypeRef OSXPrivateKeyStorage::getKeyClass(KeyClass keyClass)
+  {
+    switch(keyClass){
+    case KEY_CLASS_PRIVATE:
+      return kSecAttrKeyClassPrivate;
+    case KEY_CLASS_PUBLIC:
+      return kSecAttrKeyClassPublic;
+    case KEY_CLASS_SYMMETRIC:
+      return kSecAttrKeyClassSymmetric;
+    default:
+      _LOG_DEBUG("Unrecognized key class!");
+      return NULL;
+    }
+  }
+
+  SecExternalFormat OSXPrivateKeyStorage::getFormat(KeyFormat format)
+  {
+    switch(format){
+    case KEY_FORMAT_PUBLIC_OPENSSL:
+      return kSecFormatOpenSSL;
+    default:
+      _LOG_DEBUG("Unrecognized output format!");
+      return 0;
+    }
+  }
+
+  const CFStringRef OSXPrivateKeyStorage::getDigestAlgorithm(DigestAlgorithm digestAlgo)
+  {
+    switch(digestAlgo){
+    // case DIGEST_MD2:
+    //   return kSecDigestMD2;
+    // case DIGEST_MD5:
+    //   return kSecDigestMD5;
+    // case DIGEST_SHA1:
+    //   return kSecDigestSHA1;
+    case DIGEST_ALGORITHM_SHA256:
+      return kSecDigestSHA2;
+    default:
+      _LOG_DEBUG("Unrecognized digest algorithm!");
+      return NULL;
+    }
+  }
+
+  long OSXPrivateKeyStorage::getDigestSize(DigestAlgorithm digestAlgo)
+  {
+    switch(digestAlgo){
+    case DIGEST_ALGORITHM_SHA256:
+      return 256;
+    // case DIGEST_SHA1:
+    // case DIGEST_MD2:
+    // case DIGEST_MD5:
+    //   return 0;
+    default:
+      _LOG_DEBUG("Unrecognized digest algorithm! Unknown digest size");
+      return -1;
+    }
+  }
+  
+}
+
+#endif HAVE_OSX_SECKEYCHAIN