blob: 15b9a0df7bd46f19259ccf37dd1301a1a8bd13fd [file] [log] [blame]
Jeff Thompsonfa306642013-06-17 15:06:57 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 * Alexander Afanasyev
5 *
6 * BSD license, See the LICENSE file for more information
7 *
8 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
9 */
10
11#include "keychain-osx.h"
12#include "ndn.cxx/error.h"
13#include "logging.h"
14
15#include <Foundation/Foundation.h>
16#include <AppKit/AppKit.h>
17#include <Security/Security.h>
18
19INIT_LOGGER ("Keychain.OSX");
20
21namespace ndn {
22
23namespace keychain {
24class OSX_Private
25{
26public:
27 static void
28 LogHumanError (OSStatus res, const std::string &errMsgStr)
29 {
30 CFStringRef errMsgPtr = SecCopyErrorMessageString (res, NULL);
31 char errMsg[1024];
32 CFStringGetCString (errMsgPtr, errMsg, 1024, kCFStringEncodingUTF8);
33 _LOG_DEBUG ("Open status: " << errMsg);
34
35 BOOST_THROW_EXCEPTION (error::Keychain ()
36 << error::msg (errMsgStr)
37 << error::msg (errMsg));
38 }
39
40 SecKeychainRef m_keychain;
41 SecKeychainRef m_origDefaultKeychain;
42 static const std::string s_keychainPath;
43};
44
45const std::string OSX_Private::s_keychainPath = "~/Library/Keychains/NDN.keychain";
46} // keychain
47
48
49
50keychain::OSX::OSX ()
51{
52 m_private = new OSX_Private ();
53 OSX_Private *self = reinterpret_cast<OSX_Private*> (m_private);
54
55 // AuthorizationRef authRef;
56 // AuthorizationItem right = { "system.keychain.modify", 0, NULL, 0 };
57 // AuthorizationRights rightSet = { 1, &right };
58
59 // /* Create authorization to access the system.keychain */
60 // OSStatus res1 = AuthorizationCreate(&rightSet, kAuthorizationEmptyEnvironment,
61 // kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, &authRef);
62 // _LOG_DEBUG ("Auth status: " << res1);
63
64 SecKeychainSetUserInteractionAllowed (true);
65
66 OSStatus res = SecKeychainCreate (OSX_Private::s_keychainPath.c_str (),
67 0, NULL, true, NULL,
68 &self->m_keychain);
69 _LOG_DEBUG ("Create status: " << res);
70
71 if (res == errSecDuplicateKeychain)
72 {
73 res = SecKeychainOpen (OSX_Private::s_keychainPath.c_str (),
74 &self->m_keychain);
75 _LOG_DEBUG ("Open status: " << res);
76 }
77
78 if (res != errSecSuccess)
79 OSX_Private::LogHumanError (res, "Cannot open or create OSX Keychain");
80
81 // res = SecKeychainUnlock (self->m_keychain, 0, NULL, false);
82 // _LOG_DEBUG ("Unlock status: " << res);
83
84 SecKeychainCopyDefault (&self->m_origDefaultKeychain);
85 SecKeychainSetDefault (self->m_keychain);
86}
87
88keychain::OSX::~OSX ()
89{
90 OSX_Private *self = reinterpret_cast<OSX_Private*> (m_private);
91
92 SecKeychainSetDefault (self->m_origDefaultKeychain);
93
94 CFRelease (self->m_keychain);
95 CFRelease (self->m_origDefaultKeychain);
96 delete self;
97}
98
99void
100keychain::OSX::generateKeyPair (const Name &keyName)
101{
102 const void * keys[] = {
103 kSecAttrLabel,
104 kSecAttrIsPermanent,
105 kSecAttrKeyType,
106 kSecAttrKeySizeInBits,
107 kSecAttrApplicationTag
108 };
109
110 std::string uri = keyName.toUri ();
111 CFStringRef label = CFStringCreateWithCString (NULL, uri.c_str (), kCFStringEncodingUTF8);
112 CFDataRef tag = CFDataCreate (NULL, reinterpret_cast<const unsigned char *> (uri.c_str ()), uri.size ());
113
114 int keySize = 2048;
115 const void * values[] = {
116 label,
117 kCFBooleanTrue,
118 kSecAttrKeyTypeRSA,
119 CFNumberCreate (NULL, kCFNumberIntType, &keySize),
120 tag
121 };
122
123 CFDictionaryRef dict = CFDictionaryCreate (NULL,
124 keys, values,
125 sizeof(keys) / sizeof(*keys),
126 NULL, NULL);
127
128 SecKeyRef publicKey, privateKey;
129
130 OSStatus res = SecKeyGeneratePair (dict, &publicKey, &privateKey);
131 _LOG_DEBUG ("GeneratePair stats: " << res);
132
133 if (res != errSecSuccess)
134 OSX_Private::LogHumanError (res, "Cannot generate public/private key pair");
135
136 CFRelease (publicKey);
137 CFRelease (privateKey);
138}
139
140void
141keychain::OSX::deleteKeyPair (const Name &keyName)
142{
143 const void * keys[] = {
144 kSecClass,
145 kSecAttrApplicationTag
146 };
147
148 std::string uri = keyName.toUri ();
149 CFDataRef tag = CFDataCreate (NULL, reinterpret_cast<const unsigned char *> (uri.c_str ()), uri.size ());
150
151 const void * values[] = {
152 kSecClassKey,
153 tag
154 };
155
156 CFDictionaryRef dict = CFDictionaryCreate (NULL,
157 keys, values,
158 sizeof(keys) / sizeof(*keys),
159 NULL, NULL);
160
161 OSStatus res = errSecSuccess;
162 while (res == errSecSuccess)
163 {
164 res = SecItemDelete (dict);
165 _LOG_DEBUG ("SecItemDelete status: " << res);
166 }
167
168 if (res != errSecItemNotFound)
169 OSX_Private::LogHumanError (res, "Error while deleting key " + keyName.toUri ());
170}
171
172void
173keychain::OSX::deletePublicKey (const Name &keyName)
174{
175 const void * keys[] = {
176 kSecClass,
177 kSecAttrKeyClass,
178 kSecAttrApplicationTag
179 };
180
181 std::string uri = keyName.toUri ();
182 CFDataRef tag = CFDataCreate (NULL, reinterpret_cast<const unsigned char *> (uri.c_str ()), uri.size ());
183
184 const void * values[] = {
185 kSecClassKey,
186 kSecAttrKeyClassPublic,
187 tag
188 };
189
190 CFDictionaryRef dict = CFDictionaryCreate (NULL,
191 keys, values,
192 sizeof(keys) / sizeof(*keys),
193 NULL, NULL);
194
195 OSStatus res = errSecSuccess;
196 while (res == errSecSuccess)
197 {
198 res = SecItemDelete (dict);
199 _LOG_DEBUG ("SecItemDelete status: " << res);
200 }
201
202 if (res != errSecItemNotFound)
203 OSX_Private::LogHumanError (res, "Error while deleting public key " + keyName.toUri ());
204}
205
206Ptr<Blob>
207keychain::OSX::getPublicKey (const Name &publicKeyName)
208{
209 const void * keys[] = {
210 kSecClass,
211 kSecAttrKeyType,
212 kSecAttrKeyClass,
213 kSecAttrApplicationTag,
214 kSecReturnData
215 };
216
217 std::string uri = publicKeyName.toUri ();
218 CFDataRef tag = CFDataCreate (NULL, reinterpret_cast<const unsigned char *> (uri.c_str ()), uri.size ());
219
220 const void * values[] = {
221 kSecClassKey,
222 kSecAttrKeyTypeRSA,
223 kSecAttrKeyClassPublic,
224 tag,
225 [NSNumber numberWithBool:YES]
226 };
227
228 CFDictionaryRef query = CFDictionaryCreate (NULL,
229 keys, values,
230 sizeof(keys) / sizeof(*keys),
231 NULL, NULL);
232
233 NSData* publicKey;
234 OSStatus res = SecItemCopyMatching (query, (CFTypeRef *)(&publicKey));
235 if (res != errSecSuccess)
236 OSX_Private::LogHumanError (res, "Cannot find public key " + publicKeyName.toUri ());
237
238 Ptr<Blob> retval (new Blob ([publicKey bytes], [publicKey length]));
239 _LOG_DEBUG ("Key size: " << [publicKey length]);
240 return retval;
241}
242
243/// @todo Release data structures after use
244
245} // ndn