security: Export/Import Identity from/into KeyChain

Change-Id: I757f51f1408cf08b9fb1b1927834889fd29c0231
diff --git a/src/security/sec-tpm-osx.cpp b/src/security/sec-tpm-osx.cpp
index 3f14f43..d85636d 100644
--- a/src/security/sec-tpm-osx.cpp
+++ b/src/security/sec-tpm-osx.cpp
@@ -11,6 +11,8 @@
 
 #include "security/public-key.hpp"
 #include "util/logging.hpp"
+#include <cryptopp/files.h>
+#include <cryptopp/asn.h>
 
 #include <pwd.h>
 #include <unistd.h>
@@ -92,9 +94,6 @@
   long 
   getDigestSize(DigestAlgorithm digestAlgo);
 
-  bool
-  getPassWord(string& password, string target);
-
   ///////////////////////////////////////////////
   // everything here is public, including data //
   ///////////////////////////////////////////////
@@ -115,7 +114,7 @@
       string keyChainName("ndnroot.keychain");
       cerr << "No Default KeyChain! Create " << keyChainName << ":" << endl;
       string password;
-      while(!m_impl->getPassWord(password, keyChainName))
+      while(!getPassWord(password, keyChainName))
         {
           cerr << "Password mismatch!" << endl;
         }
@@ -226,25 +225,17 @@
 void
 SecTpmOsx::deleteKeyPairInTpm(const Name &keyName)
 {
-  string keyNameUri = keyName.toUri();
-
   CFStringRef keyLabel = CFStringCreateWithCString(NULL, 
-                                                   keyNameUri.c_str(), 
+                                                   keyName.toUri().c_str(), 
                                                    kCFStringEncodingUTF8);
-    
-  CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL,
-                                                              5,
-                                                              &kCFTypeDictionaryKeyCallBacks,
-                                                              NULL);
 
-  CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
-  CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
-  CFDictionaryAddValue(attrDict, kSecMatchLimit, kSecMatchLimitAll);
+  CFMutableDictionaryRef searchDict = 
+    CFDictionaryCreateMutable(NULL, 5, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 
-  OSStatus res = SecItemDelete((CFDictionaryRef) attrDict);
-    
-  if(res != errSecSuccess)
-    _LOG_DEBUG("Fail to find the key!");
+  CFDictionaryAddValue(searchDict, kSecClass, kSecClassKey);
+  CFDictionaryAddValue(searchDict, kSecAttrLabel, keyLabel);
+  CFDictionaryAddValue(searchDict, kSecMatchLimit, kSecMatchLimitAll);
+  SecItemDelete(searchDict);
 }
 
 void 
@@ -293,7 +284,181 @@
                                NULL,
                                &exportedKey);
 
-  return ptr_lib::make_shared<PublicKey>(CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
+  shared_ptr<PublicKey> key = make_shared<PublicKey>(CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
+  CFRelease(exportedKey);
+  return key;
+}
+
+ConstBufferPtr
+SecTpmOsx::exportPrivateKeyPkcs1FromTpm(const Name& keyName)
+{
+  using namespace CryptoPP;
+
+  SecKeychainItemRef privateKey = m_impl->getKey(keyName, KEY_CLASS_PRIVATE);
+  CFDataRef exportedKey;
+  OSStatus res = SecItemExport(privateKey,
+                               kSecFormatOpenSSL,
+                               0,
+                               NULL,
+                               &exportedKey);
+
+  if(res != errSecSuccess)
+    {
+      return shared_ptr<Buffer>();
+    }
+
+  OBufferStream pkcs1Os;
+  FileSink sink(pkcs1Os);
+
+  uint32_t version = 0;
+  OID algorithm("1.2.840.113549.1.1.1");
+  SecByteBlock rawKeyBits;
+  // PrivateKeyInfo ::= SEQUENCE {
+  //   version              INTEGER,
+  //   privateKeyAlgorithm  SEQUENCE,
+  //   privateKey           OCTECT STRING}
+  DERSequenceEncoder privateKeyInfo(sink);
+  {
+    DEREncodeUnsigned<uint32_t>(privateKeyInfo, version, INTEGER);
+    DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo);
+    {
+      algorithm.encode(privateKeyAlgorithm);
+      DEREncodeNull(privateKeyAlgorithm);
+    }
+    privateKeyAlgorithm.MessageEnd();
+    DEREncodeOctetString(privateKeyInfo, CFDataGetBytePtr(exportedKey), CFDataGetLength(exportedKey));
+  }
+  privateKeyInfo.MessageEnd(); 
+
+  CFRelease(exportedKey);
+  return pkcs1Os.buf();
+}
+
+bool
+SecTpmOsx::importPrivateKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
+{
+  using namespace CryptoPP;
+
+  StringSource privateKeySource(buf, size, true);
+  uint32_t tmpNum;
+  OID tmpOID;
+  SecByteBlock rawKeyBits;
+  // PrivateKeyInfo ::= SEQUENCE {
+  //   INTEGER,
+  //   SEQUENCE,
+  //   OCTECT STRING}
+  BERSequenceDecoder privateKeyInfo(privateKeySource);
+  {
+    BERDecodeUnsigned<uint32_t>(privateKeyInfo, tmpNum, INTEGER);
+    BERSequenceDecoder sequenceDecoder(privateKeyInfo);
+    {
+      tmpOID.decode(sequenceDecoder);
+      BERDecodeNull(sequenceDecoder);
+    }
+    BERDecodeOctetString(privateKeyInfo, rawKeyBits);
+  }
+  privateKeyInfo.MessageEnd(); 
+
+  CFDataRef importedKey = CFDataCreateWithBytesNoCopy(NULL,
+                                                      rawKeyBits.BytePtr(),
+                                                      rawKeyBits.size(),
+                                                      kCFAllocatorNull);
+
+  SecExternalFormat externalFormat = kSecFormatOpenSSL;
+  SecExternalItemType externalType = kSecItemTypePrivateKey;
+  SecKeyImportExportParameters keyParams;
+  memset(&keyParams, 0, sizeof(keyParams));
+  keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
+  keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
+  SecAccessRef access;
+  CFStringRef keyLabel = CFStringCreateWithCString(NULL, 
+                                                   keyName.toUri().c_str(), 
+                                                   kCFStringEncodingUTF8);
+  SecAccessCreate(keyLabel, NULL, &access);
+  keyParams.accessRef = access;
+  CFArrayRef outItems;
+
+  OSStatus res = SecKeychainItemImport (importedKey,
+                                        NULL,
+                                        &externalFormat,
+                                        &externalType,
+                                        0,
+                                        &keyParams,
+                                        m_impl->m_keyChainRef,
+                                        &outItems);
+  
+  if(res != errSecSuccess)
+    {
+      return false;
+    }
+
+  SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
+  SecKeychainAttribute attrs[1]; // maximum number of attributes
+  SecKeychainAttributeList attrList = { 0, attrs };
+  string keyUri = keyName.toUri();
+  {
+    attrs[attrList.count].tag = kSecKeyPrintName;
+    attrs[attrList.count].length = keyUri.size();
+    attrs[attrList.count].data = (void *)keyUri.c_str();
+    attrList.count++;
+  }
+
+  res = SecKeychainItemModifyAttributesAndData(privateKey, 
+                                               &attrList,
+                                               0,
+                                               NULL);
+  
+  if(res != errSecSuccess)
+    {
+      return false;
+    }
+ 
+  CFRelease(importedKey);
+  return true;
+}
+
+bool
+SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
+{
+  CFDataRef importedKey = CFDataCreateWithBytesNoCopy(NULL,
+                                                      buf,
+                                                      size,
+                                                      kCFAllocatorNull);
+
+  SecExternalFormat externalFormat = kSecFormatOpenSSL;
+  SecExternalItemType externalType = kSecItemTypePublicKey;
+  CFArrayRef outItems;
+
+  OSStatus res = SecItemImport (importedKey,
+                                NULL,
+                                &externalFormat,
+                                &externalType,
+                                0,
+                                NULL,
+                                m_impl->m_keyChainRef,
+                                &outItems);
+
+  if(res != errSecSuccess)
+    return false;
+
+  SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems, 0);
+  SecKeychainAttribute attrs[1]; // maximum number of attributes
+  SecKeychainAttributeList attrList = { 0, attrs };
+  string keyUri = keyName.toUri();
+  {
+    attrs[attrList.count].tag = kSecKeyPrintName;
+    attrs[attrList.count].length = keyUri.size();
+    attrs[attrList.count].data = (void *)keyUri.c_str();
+    attrList.count++;
+  }
+
+  res = SecKeychainItemModifyAttributesAndData(publicKey, 
+                                               &attrList,
+                                               0,
+                                               NULL);
+  
+  CFRelease(importedKey);
+  return true;
 }
 
 Block
@@ -549,17 +714,17 @@
                                                               NULL);
 
   CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey);
-  CFDictionaryAddValue(attrDict, kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
+  // CFDictionaryAddValue(attrDict, kSecAttrKeyClass, m_impl->getKeyClass(keyClass));
   CFDictionaryAddValue(attrDict, kSecAttrLabel, keyLabel);
   CFDictionaryAddValue(attrDict, kSecReturnRef, kCFBooleanTrue);
     
   SecKeychainItemRef itemRef;
   OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict, (CFTypeRef*)&itemRef);
     
-  if(res == errSecItemNotFound)
-    return false;
-  else
+  if(res == errSecSuccess)
     return true;
+  else
+    return false;
 
 }
 
@@ -688,40 +853,5 @@
     return -1;
   }
 }
-
-bool
-SecTpmOsx::Impl::getPassWord(string& password, string target)
-{
-  int result = false;
-
-  string prompt1 = "Password for " + target + ":";
-  string prompt2 = "Confirm password for " + target + ":";
-  char* pw0 = NULL;
-  
-  pw0 = getpass(prompt1.c_str());
-  if(!pw0) 
-    return false;
-  string password1 = pw0;
-  memset(pw0, 0, strlen(pw0));
-
-  pw0 = getpass(prompt2.c_str());
-  if(!pw0)
-    {
-      char* pw1 = const_cast<char*>(password1.c_str());
-      memset(pw1, 0, password1.size());
-      return false;
-    }
-
-  if(!password1.compare(pw0))
-    {
-      result = true;
-      password.swap(password1);
-    }
-
-  char* pw1 = const_cast<char*>(password1.c_str());
-  memset(pw1, 0, password1.size());
-  memset(pw0, 0, strlen(pw0));  
-  return result;
-}
   
 }// ndn