forked from cawka/ndn.cxx
diff --git a/platforms/osx/keychain-osx.mm b/platforms/osx/keychain-osx.mm
new file mode 100644
index 0000000..15b9a0d
--- /dev/null
+++ b/platforms/osx/keychain-osx.mm
@@ -0,0 +1,245 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "keychain-osx.h"
+#include "ndn.cxx/error.h"
+#include "logging.h"
+
+#include <Foundation/Foundation.h>
+#include <AppKit/AppKit.h>
+#include <Security/Security.h>
+
+INIT_LOGGER ("Keychain.OSX");
+
+namespace ndn {
+
+namespace keychain {
+class OSX_Private
+{
+public:
+ static void
+ LogHumanError (OSStatus res, const std::string &errMsgStr)
+ {
+ CFStringRef errMsgPtr = SecCopyErrorMessageString (res, NULL);
+ char errMsg[1024];
+ CFStringGetCString (errMsgPtr, errMsg, 1024, kCFStringEncodingUTF8);
+ _LOG_DEBUG ("Open status: " << errMsg);
+
+ BOOST_THROW_EXCEPTION (error::Keychain ()
+ << error::msg (errMsgStr)
+ << error::msg (errMsg));
+ }
+
+ SecKeychainRef m_keychain;
+ SecKeychainRef m_origDefaultKeychain;
+ static const std::string s_keychainPath;
+};
+
+const std::string OSX_Private::s_keychainPath = "~/Library/Keychains/NDN.keychain";
+} // keychain
+
+
+
+keychain::OSX::OSX ()
+{
+ m_private = new OSX_Private ();
+ OSX_Private *self = reinterpret_cast<OSX_Private*> (m_private);
+
+ // AuthorizationRef authRef;
+ // AuthorizationItem right = { "system.keychain.modify", 0, NULL, 0 };
+ // AuthorizationRights rightSet = { 1, &right };
+
+ // /* Create authorization to access the system.keychain */
+ // OSStatus res1 = AuthorizationCreate(&rightSet, kAuthorizationEmptyEnvironment,
+ // kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, &authRef);
+ // _LOG_DEBUG ("Auth status: " << res1);
+
+ SecKeychainSetUserInteractionAllowed (true);
+
+ OSStatus res = SecKeychainCreate (OSX_Private::s_keychainPath.c_str (),
+ 0, NULL, true, NULL,
+ &self->m_keychain);
+ _LOG_DEBUG ("Create status: " << res);
+
+ if (res == errSecDuplicateKeychain)
+ {
+ res = SecKeychainOpen (OSX_Private::s_keychainPath.c_str (),
+ &self->m_keychain);
+ _LOG_DEBUG ("Open status: " << res);
+ }
+
+ if (res != errSecSuccess)
+ OSX_Private::LogHumanError (res, "Cannot open or create OSX Keychain");
+
+ // res = SecKeychainUnlock (self->m_keychain, 0, NULL, false);
+ // _LOG_DEBUG ("Unlock status: " << res);
+
+ SecKeychainCopyDefault (&self->m_origDefaultKeychain);
+ SecKeychainSetDefault (self->m_keychain);
+}
+
+keychain::OSX::~OSX ()
+{
+ OSX_Private *self = reinterpret_cast<OSX_Private*> (m_private);
+
+ SecKeychainSetDefault (self->m_origDefaultKeychain);
+
+ CFRelease (self->m_keychain);
+ CFRelease (self->m_origDefaultKeychain);
+ delete self;
+}
+
+void
+keychain::OSX::generateKeyPair (const Name &keyName)
+{
+ const void * keys[] = {
+ kSecAttrLabel,
+ kSecAttrIsPermanent,
+ kSecAttrKeyType,
+ kSecAttrKeySizeInBits,
+ kSecAttrApplicationTag
+ };
+
+ std::string uri = keyName.toUri ();
+ CFStringRef label = CFStringCreateWithCString (NULL, uri.c_str (), kCFStringEncodingUTF8);
+ CFDataRef tag = CFDataCreate (NULL, reinterpret_cast<const unsigned char *> (uri.c_str ()), uri.size ());
+
+ int keySize = 2048;
+ const void * values[] = {
+ label,
+ kCFBooleanTrue,
+ kSecAttrKeyTypeRSA,
+ CFNumberCreate (NULL, kCFNumberIntType, &keySize),
+ tag
+ };
+
+ CFDictionaryRef dict = CFDictionaryCreate (NULL,
+ keys, values,
+ sizeof(keys) / sizeof(*keys),
+ NULL, NULL);
+
+ SecKeyRef publicKey, privateKey;
+
+ OSStatus res = SecKeyGeneratePair (dict, &publicKey, &privateKey);
+ _LOG_DEBUG ("GeneratePair stats: " << res);
+
+ if (res != errSecSuccess)
+ OSX_Private::LogHumanError (res, "Cannot generate public/private key pair");
+
+ CFRelease (publicKey);
+ CFRelease (privateKey);
+}
+
+void
+keychain::OSX::deleteKeyPair (const Name &keyName)
+{
+ const void * keys[] = {
+ kSecClass,
+ kSecAttrApplicationTag
+ };
+
+ std::string uri = keyName.toUri ();
+ CFDataRef tag = CFDataCreate (NULL, reinterpret_cast<const unsigned char *> (uri.c_str ()), uri.size ());
+
+ const void * values[] = {
+ kSecClassKey,
+ tag
+ };
+
+ CFDictionaryRef dict = CFDictionaryCreate (NULL,
+ keys, values,
+ sizeof(keys) / sizeof(*keys),
+ NULL, NULL);
+
+ OSStatus res = errSecSuccess;
+ while (res == errSecSuccess)
+ {
+ res = SecItemDelete (dict);
+ _LOG_DEBUG ("SecItemDelete status: " << res);
+ }
+
+ if (res != errSecItemNotFound)
+ OSX_Private::LogHumanError (res, "Error while deleting key " + keyName.toUri ());
+}
+
+void
+keychain::OSX::deletePublicKey (const Name &keyName)
+{
+ const void * keys[] = {
+ kSecClass,
+ kSecAttrKeyClass,
+ kSecAttrApplicationTag
+ };
+
+ std::string uri = keyName.toUri ();
+ CFDataRef tag = CFDataCreate (NULL, reinterpret_cast<const unsigned char *> (uri.c_str ()), uri.size ());
+
+ const void * values[] = {
+ kSecClassKey,
+ kSecAttrKeyClassPublic,
+ tag
+ };
+
+ CFDictionaryRef dict = CFDictionaryCreate (NULL,
+ keys, values,
+ sizeof(keys) / sizeof(*keys),
+ NULL, NULL);
+
+ OSStatus res = errSecSuccess;
+ while (res == errSecSuccess)
+ {
+ res = SecItemDelete (dict);
+ _LOG_DEBUG ("SecItemDelete status: " << res);
+ }
+
+ if (res != errSecItemNotFound)
+ OSX_Private::LogHumanError (res, "Error while deleting public key " + keyName.toUri ());
+}
+
+Ptr<Blob>
+keychain::OSX::getPublicKey (const Name &publicKeyName)
+{
+ const void * keys[] = {
+ kSecClass,
+ kSecAttrKeyType,
+ kSecAttrKeyClass,
+ kSecAttrApplicationTag,
+ kSecReturnData
+ };
+
+ std::string uri = publicKeyName.toUri ();
+ CFDataRef tag = CFDataCreate (NULL, reinterpret_cast<const unsigned char *> (uri.c_str ()), uri.size ());
+
+ const void * values[] = {
+ kSecClassKey,
+ kSecAttrKeyTypeRSA,
+ kSecAttrKeyClassPublic,
+ tag,
+ [NSNumber numberWithBool:YES]
+ };
+
+ CFDictionaryRef query = CFDictionaryCreate (NULL,
+ keys, values,
+ sizeof(keys) / sizeof(*keys),
+ NULL, NULL);
+
+ NSData* publicKey;
+ OSStatus res = SecItemCopyMatching (query, (CFTypeRef *)(&publicKey));
+ if (res != errSecSuccess)
+ OSX_Private::LogHumanError (res, "Cannot find public key " + publicKeyName.toUri ());
+
+ Ptr<Blob> retval (new Blob ([publicKey bytes], [publicKey length]));
+ _LOG_DEBUG ("Key size: " << [publicKey length]);
+ return retval;
+}
+
+/// @todo Release data structures after use
+
+} // ndn