]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_keychain/lib/SecKeychain.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecKeychain.cpp
CommitLineData
b1ab9ed8 1/*
d8f41ccd 2 * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved.
b1ab9ed8
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <Security/SecKeychain.h>
25#include <Security/SecKeychainPriv.h>
26#include <security_keychain/KCCursor.h>
27#include <security_cdsa_utilities/cssmdata.h>
d8f41ccd 28#include <security_cdsa_client/wrapkey.h>
b1ab9ed8
A
29#include <security_keychain/KCExceptions.h>
30#include <securityd_client/ssblob.h>
d8f41ccd
A
31#include <Security/SecAccess.h>
32#include <Security/SecTrustedApplicationPriv.h>
b1ab9ed8
A
33#include "SecBridge.h"
34#include "CCallbackMgr.h"
35#include <security_cdsa_utilities/Schema.h>
d8f41ccd 36#include <security_cdsa_client/mdsclient.h>
b1ab9ed8 37#include <pwd.h>
866f8763 38#include <os/activity.h>
fa7225c8
A
39#include <Security/AuthorizationTagsPriv.h>
40#include <Security/Authorization.h>
41#include "TokenLogin.h"
d64be36e
A
42#include "LegacyAPICounts.h"
43
44extern "C" {
45#include "ctkloginhelper.h"
46}
b1ab9ed8 47
d8f41ccd
A
48OSStatus
49SecKeychainMDSInstall()
50{
866f8763 51 BEGIN_SECAPI
d64be36e
A
52
53 os_activity_t activity = os_activity_create("SecKeychainMDSInstall", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
54 os_activity_scope(activity);
55 os_release(activity);
d8f41ccd
A
56
57 Security::MDSClient::Directory d;
58 d.install();
59
60 END_SECAPI
61}
62
b1ab9ed8
A
63CFTypeID
64SecKeychainGetTypeID(void)
65{
66 BEGIN_SECAPI
67
68 return gTypes().KeychainImpl.typeID;
69
70 END_SECAPI1(_kCFRuntimeNotATypeID)
71}
72
73
74OSStatus
75SecKeychainGetVersion(UInt32 *returnVers)
76{
d64be36e 77 COUNTLEGACYAPI
b1ab9ed8 78 if (!returnVers)
427c49bc 79 return errSecSuccess;
b1ab9ed8
A
80
81 *returnVers = 0x02028000;
427c49bc 82 return errSecSuccess;
b1ab9ed8
A
83}
84
85
86OSStatus
87SecKeychainOpen(const char *pathName, SecKeychainRef *keychainRef)
88{
89 BEGIN_SECAPI
b1ab9ed8 90
d64be36e 91 os_activity_t activity = os_activity_create("SecKeychainOpen", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
92 os_activity_scope(activity);
93 os_release(activity);
b1ab9ed8 94
d64be36e 95 RequiredParam(keychainRef)=globals().storageManager.make(pathName, false)->handle();
b1ab9ed8
A
96
97 END_SECAPI
98}
99
b1ab9ed8
A
100OSStatus
101SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void *password,
102 Boolean promptUser, SecAccessRef initialAccess, SecKeychainRef *keychainRef)
103{
104 BEGIN_SECAPI
d64be36e
A
105
106 os_activity_t activity = os_activity_create("SecKeychainCreate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
107 os_activity_scope(activity);
108 os_release(activity);
427c49bc
A
109
110 KCThrowParamErrIf_(!pathName);
fa7225c8 111 Keychain keychain = globals().storageManager.make(pathName, true, true);
b1ab9ed8
A
112
113 // @@@ the call to StorageManager::make above leaves keychain the the cache.
114 // If the create below fails we should probably remove it.
115 if(promptUser)
116 keychain->create();
117 else
118 {
119 KCThrowParamErrIf_(!password);
120 keychain->create(passwordLength, password);
121 }
122
123 RequiredParam(keychainRef)=keychain->handle();
124
125 END_SECAPI
126}
127
128
129OSStatus
130SecKeychainDelete(SecKeychainRef keychainOrArray)
131{
132 BEGIN_SECAPI
d64be36e
A
133
134 os_activity_t activity = os_activity_create("SecKeychainDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
135 os_activity_scope(activity);
136 os_release(activity);
b1ab9ed8
A
137
138 KCThrowIf_(!keychainOrArray, errSecInvalidKeychain);
139 StorageManager::KeychainList keychains;
140 globals().storageManager.optionalSearchList(keychainOrArray, keychains);
141
142 globals().storageManager.remove(keychains, true);
143
144 END_SECAPI
145}
146
147
148OSStatus
149SecKeychainSetSettings(SecKeychainRef keychainRef, const SecKeychainSettings *newSettings)
150{
151 BEGIN_SECAPI
d64be36e
A
152
153 os_activity_t activity = os_activity_create("SecKeychainSetSettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
154 os_activity_scope(activity);
155 os_release(activity);
b1ab9ed8
A
156
157 Keychain keychain = Keychain::optional(keychainRef);
158 if (newSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1)
159 {
160 UInt32 lockInterval=newSettings->lockInterval;
161 bool lockOnSleep=newSettings->lockOnSleep;
162 keychain->setSettings(lockInterval, lockOnSleep);
163 }
164
165 END_SECAPI
166}
167
168
169OSStatus
170SecKeychainCopySettings(SecKeychainRef keychainRef, SecKeychainSettings *outSettings)
171{
172 BEGIN_SECAPI
d64be36e
A
173
174 os_activity_t activity = os_activity_create("SecKeychainCopySettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
175 os_activity_scope(activity);
176 os_release(activity);
b1ab9ed8
A
177
178 Keychain keychain = Keychain::optional(keychainRef);
179 if (outSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1)
180 {
181 uint32 lockInterval;
182 bool lockOnSleep;
183
184 keychain->getSettings(lockInterval, lockOnSleep);
185 outSettings->lockInterval=lockInterval;
186 outSettings->lockOnSleep=lockOnSleep;
187 }
188
189 END_SECAPI
190}
191
192
193OSStatus
194SecKeychainUnlock(SecKeychainRef keychainRef, UInt32 passwordLength, const void *password, Boolean usePassword)
195{
196 BEGIN_SECAPI
d64be36e
A
197
198 os_activity_t activity = os_activity_create("SecKeychainUnlock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
199 os_activity_scope(activity);
200 os_release(activity);
b1ab9ed8
A
201
202 Keychain keychain = Keychain::optional(keychainRef);
203
204 if (usePassword)
205 keychain->unlock(CssmData(const_cast<void *>(password), passwordLength));
206 else
207 keychain->unlock();
208
209 END_SECAPI
210}
211
212
213OSStatus
214SecKeychainLock(SecKeychainRef keychainRef)
215{
216 BEGIN_SECAPI
d64be36e
A
217
218 os_activity_t activity = os_activity_create("SecKeychainLock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
219 os_activity_scope(activity);
220 os_release(activity);
b1ab9ed8
A
221
222 Keychain keychain = Keychain::optional(keychainRef);
223 keychain->lock();
224
225 END_SECAPI
226}
227
228
229OSStatus
230SecKeychainLockAll(void)
231{
232 BEGIN_SECAPI
d64be36e
A
233
234 os_activity_t activity = os_activity_create("SecKeychainLockAll", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
235 os_activity_scope(activity);
236 os_release(activity);
b1ab9ed8
A
237
238 globals().storageManager.lockAll();
239
240 END_SECAPI
241}
242
243
244OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Boolean resetSearchList)
245{
246 BEGIN_SECAPI
d64be36e
A
247
248 os_activity_t activity = os_activity_create("SecKeychainResetLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
249 os_activity_scope(activity);
250 os_release(activity);
b1ab9ed8
A
251 //
252 // Get the current user (using fallback method if necessary)
253 //
254 char* uName = getenv("USER");
255 string userName = uName ? uName : "";
256 if ( userName.length() == 0 )
257 {
258 uid_t uid = geteuid();
259 if (!uid) uid = getuid();
260 struct passwd *pw = getpwuid(uid); // fallback case...
261 if (pw)
262 userName = pw->pw_name;
263 endpwent();
264 }
265 if ( userName.length() == 0 ) // did we ultimately get one?
ecaf5866 266 {
b1ab9ed8 267 MacOSError::throwMe(errAuthorizationInternal);
ecaf5866 268 }
822b670c
A
269
270 SecurityServer::ClientSession().resetKeyStorePassphrase(password ? CssmData(const_cast<void *>(password), passwordLength) : CssmData());
ecaf5866 271 secwarning("SecKeychainResetLogin: reset AKS passphrase");
b1ab9ed8
A
272 if (password)
273 {
274 // Clear the plist and move aside (rename) the existing login.keychain
275 globals().storageManager.resetKeychain(resetSearchList);
276
277 // Create the login keychain without UI
fa7225c8 278 globals().storageManager.login((UInt32)userName.length(), userName.c_str(), passwordLength, password, true);
b1ab9ed8
A
279
280 // Set it as the default
281 Keychain keychain = globals().storageManager.loginKeychain();
282 globals().storageManager.defaultKeychain(keychain);
283 }
284 else
285 {
286 // Create the login keychain, prompting for password
287 // (implicitly calls resetKeychain, login, and defaultKeychain)
fa7225c8 288 globals().storageManager.makeLoginAuthUI(NULL, true);
b1ab9ed8 289 }
ecaf5866 290 secwarning("SecKeychainResetLogin: reset osx keychain");
b1ab9ed8
A
291
292 // Post a "list changed" event after a reset, so apps can refresh their list.
293 // Make sure we are not holding mLock when we post this event.
294 KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
295
ecaf5866 296
b1ab9ed8
A
297 END_SECAPI
298}
299
300OSStatus
301SecKeychainCopyDefault(SecKeychainRef *keychainRef)
302{
303 BEGIN_SECAPI
304
305 RequiredParam(keychainRef)=globals().storageManager.defaultKeychain()->handle();
306
307 END_SECAPI
308}
309
310
311OSStatus
312SecKeychainSetDefault(SecKeychainRef keychainRef)
313{
314 BEGIN_SECAPI
d64be36e
A
315
316 os_activity_t activity = os_activity_create("SecKeychainSetDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
317 os_activity_scope(activity);
318 os_release(activity);
b1ab9ed8
A
319
320 globals().storageManager.defaultKeychain(Keychain::optional(keychainRef));
321
322 END_SECAPI
323}
324
325OSStatus SecKeychainCopySearchList(CFArrayRef *searchList)
326{
327 BEGIN_SECAPI
d64be36e
A
328
329 os_activity_t activity = os_activity_create("SecKeychainCopySearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
330 os_activity_scope(activity);
331 os_release(activity);
b1ab9ed8
A
332
333 RequiredParam(searchList);
334 StorageManager &smr = globals().storageManager;
335 StorageManager::KeychainList keychainList;
336 smr.getSearchList(keychainList);
337 *searchList = smr.convertFromKeychainList(keychainList);
338
339 END_SECAPI
340}
341
342OSStatus SecKeychainSetSearchList(CFArrayRef searchList)
343{
344 BEGIN_SECAPI
d64be36e
A
345
346 os_activity_t activity = os_activity_create("SecKeychainSetSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
347 os_activity_scope(activity);
348 os_release(activity);
b1ab9ed8
A
349
350 RequiredParam(searchList);
351 StorageManager &smr = globals().storageManager;
352 StorageManager::KeychainList keychainList;
353 smr.convertToKeychainList(searchList, keychainList);
354 smr.setSearchList(keychainList);
355
356 END_SECAPI
357}
358
359OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRef *keychainRef)
360{
361 BEGIN_SECAPI
d64be36e
A
362
363 os_activity_t activity = os_activity_create("SecKeychainCopyDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
364 os_activity_scope(activity);
365 os_release(activity);
b1ab9ed8
A
366
367 RequiredParam(keychainRef)=globals().storageManager.defaultKeychain(domain)->handle();
368
369 END_SECAPI
370}
371
372OSStatus SecKeychainSetDomainDefault(SecPreferencesDomain domain, SecKeychainRef keychainRef)
373{
374 BEGIN_SECAPI
d64be36e
A
375
376 os_activity_t activity = os_activity_create("SecKeychainSetDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
377 os_activity_scope(activity);
378 os_release(activity);
b1ab9ed8
A
379
380 globals().storageManager.defaultKeychain(domain, Keychain::optional(keychainRef));
381
382 END_SECAPI
383}
384
385OSStatus SecKeychainCopyDomainSearchList(SecPreferencesDomain domain, CFArrayRef *searchList)
386{
387 BEGIN_SECAPI
388
389 RequiredParam(searchList);
390 StorageManager &smr = globals().storageManager;
391 StorageManager::KeychainList keychainList;
392 smr.getSearchList(domain, keychainList);
393 *searchList = smr.convertFromKeychainList(keychainList);
394
395 END_SECAPI
396}
397
398OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef searchList)
399{
400 BEGIN_SECAPI
d64be36e
A
401
402 os_activity_t activity = os_activity_create("SecKeychainSetDomainSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
403 os_activity_scope(activity);
404 os_release(activity);
b1ab9ed8
A
405
406 RequiredParam(searchList);
407 StorageManager &smr = globals().storageManager;
408 StorageManager::KeychainList keychainList;
409 smr.convertToKeychainList(searchList, keychainList);
410 smr.setSearchList(domain, keychainList);
411
412 END_SECAPI
413}
414
415OSStatus SecKeychainSetPreferenceDomain(SecPreferencesDomain domain)
416{
417 BEGIN_SECAPI
d64be36e
A
418
419 os_activity_t activity = os_activity_create("SecKeychainSetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
420 os_activity_scope(activity);
421 os_release(activity);
b1ab9ed8
A
422
423 globals().storageManager.domain(domain);
424
425 END_SECAPI
426}
427
428OSStatus SecKeychainGetPreferenceDomain(SecPreferencesDomain *domain)
429{
430 BEGIN_SECAPI
d64be36e
A
431
432 os_activity_t activity = os_activity_create("SecKeychainGetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
433 os_activity_scope(activity);
434 os_release(activity);
b1ab9ed8
A
435
436 *domain = globals().storageManager.domain();
437
438 END_SECAPI
439}
440
441
442OSStatus
443SecKeychainGetStatus(SecKeychainRef keychainRef, SecKeychainStatus *keychainStatus)
444{
445 BEGIN_SECAPI
446
447 RequiredParam(keychainStatus) = (SecKeychainStatus)Keychain::optional(keychainRef)->status();
448
449 END_SECAPI
450}
451
452
453OSStatus
454SecKeychainGetPath(SecKeychainRef keychainRef, UInt32 *ioPathLength, char *pathName)
455{
456 BEGIN_SECAPI
457
458 RequiredParam(pathName);
459 RequiredParam(ioPathLength);
460
461 const char *name = Keychain::optional(keychainRef)->name();
427c49bc 462 UInt32 nameLen = (UInt32)strlen(name);
b1ab9ed8
A
463 UInt32 callersLen = *ioPathLength;
464 *ioPathLength = nameLen;
465 if (nameLen+1 > callersLen) // if the client's buffer is too small (including null-termination), throw
466 return errSecBufferTooSmall;
467 strncpy(pathName, name, nameLen);
468 pathName[nameLen] = 0;
469 *ioPathLength = nameLen; // set the length.
470
471 END_SECAPI
472}
473
e3d460c9
A
474OSStatus
475SecKeychainGetKeychainVersion(SecKeychainRef keychainRef, UInt32* version)
476{
477 BEGIN_SECAPI
478
d64be36e 479 RequiredParam(version);
e3d460c9
A
480
481 *version = Keychain::optional(keychainRef)->database()->dbBlobVersion();
482
483 END_SECAPI
484}
485
fa7225c8
A
486OSStatus
487SecKeychainAttemptMigrationWithMasterKey(SecKeychainRef keychain, UInt32 version, const char* masterKeyFilename)
488{
489 BEGIN_SECAPI
d64be36e
A
490
491 os_activity_t activity = os_activity_create("SecKeychainAttemptMigrationWithMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
492 os_activity_scope(activity);
493 os_release(activity);
fa7225c8
A
494
495 RequiredParam(masterKeyFilename);
496 Keychain kc = Keychain::optional(keychain);
497
498 SecurityServer::SystemKeychainKey keychainKey(masterKeyFilename);
499 if(keychainKey.valid()) {
500 // We've managed to read the key; now, create credentials using it
501 string path = kc->name();
502
503 CssmClient::Key keychainMasterKey(kc->csp(), keychainKey.key(), true);
504 CssmClient::AclFactory::MasterKeyUnlockCredentials creds(keychainMasterKey, Allocator::standard(Allocator::sensitive));
505
506 // Attempt the migrate, using our master key as the ACL override
507 bool result = kc->keychainMigration(path, kc->database()->dbBlobVersion(), path, version, creds.getAccessCredentials());
508 if(!result) {
509 return errSecBadReq;
510 }
511 return (kc->database()->dbBlobVersion() == version ? errSecSuccess : errSecBadReq);
512 } else {
513 return errSecBadReq;
514 }
515
516 END_SECAPI
517}
518
b1ab9ed8
A
519
520// @@@ Deprecated
521UInt16
522SecKeychainListGetCount(void)
523{
524 BEGIN_SECAPI
525
526 return globals().storageManager.size();
527
528 END_SECAPI1(0)
529}
530
531
532// @@@ Deprecated
533OSStatus
534SecKeychainListCopyKeychainAtIndex(UInt16 index, SecKeychainRef *keychainRef)
535{
536 BEGIN_SECAPI
537
538 KeychainCore::StorageManager &smgr=KeychainCore::globals().storageManager;
539 RequiredParam(keychainRef)=smgr[index]->handle();
540
541 END_SECAPI
542}
543
544
545// @@@ Deprecated
546OSStatus
547SecKeychainListRemoveKeychain(SecKeychainRef *keychainRef)
548{
549 BEGIN_SECAPI
550
551 Required(keychainRef);
552 Keychain keychain = Keychain::optional(*keychainRef);
553 StorageManager::KeychainList keychainList;
554 keychainList.push_back(keychain);
555 globals().storageManager.remove(keychainList);
556 *keychainRef = NULL;
557
558 END_SECAPI
559}
560
561
562OSStatus
563SecKeychainAttributeInfoForItemID(SecKeychainRef keychainRef, UInt32 itemID, SecKeychainAttributeInfo **info)
564{
565 BEGIN_SECAPI
566
567 Keychain keychain = Keychain::optional(keychainRef);
568 keychain->getAttributeInfoForItemID(itemID, info);
569
570 END_SECAPI
571}
572
573
574OSStatus
575SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo *info)
576{
577 BEGIN_SECAPI
578
579 KeychainImpl::freeAttributeInfo(info);
580
581 END_SECAPI
582}
583
584
585pascal OSStatus
586SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMask eventMask, void* userContext)
587{
588 BEGIN_SECAPI
d64be36e
A
589
590 os_activity_t activity = os_activity_create("SecKeychainAddCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
591 os_activity_scope(activity);
592 os_release(activity);
b1ab9ed8
A
593
594 RequiredParam(callbackFunction);
595 CCallbackMgr::AddCallback(callbackFunction,eventMask,userContext);
596
597 END_SECAPI
598}
599
600
601OSStatus
602SecKeychainRemoveCallback(SecKeychainCallback callbackFunction)
603{
604 BEGIN_SECAPI
d64be36e
A
605
606 os_activity_t activity = os_activity_create("SecKeychainRemoveCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
607 os_activity_scope(activity);
608 os_release(activity);
b1ab9ed8
A
609
610 RequiredParam(callbackFunction);
611 CCallbackMgr::RemoveCallback(callbackFunction);
612
613 END_SECAPI
614}
615
616OSStatus
617SecKeychainAddInternetPassword(SecKeychainRef keychainRef, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef)
618{
619 BEGIN_SECAPI
d64be36e
A
620
621 os_activity_t activity = os_activity_create("SecKeychainAddInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
622 os_activity_scope(activity);
623 os_release(activity);
b1ab9ed8
A
624
625 KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL);
626 // @@@ Get real itemClass
627 Item item(kSecInternetPasswordItemClass, 'aapl', passwordLength, passwordData, false);
628
629 if (serverName && serverNameLength)
630 {
631 CssmData server(const_cast<void *>(reinterpret_cast<const void *>(serverName)), serverNameLength);
632 item->setAttribute(Schema::attributeInfo(kSecServerItemAttr), server);
633 // use server name as default label
634 item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), server);
635 }
636
637 if (accountName && accountNameLength)
638 {
639 CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength);
640 item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account);
641 }
642
643 if (securityDomain && securityDomainLength)
644 item->setAttribute(Schema::attributeInfo(kSecSecurityDomainItemAttr),
645 CssmData(const_cast<void *>(reinterpret_cast<const void *>(securityDomain)), securityDomainLength));
646
647 item->setAttribute(Schema::attributeInfo(kSecPortItemAttr), UInt32(port));
648 item->setAttribute(Schema::attributeInfo(kSecProtocolItemAttr), protocol);
649 item->setAttribute(Schema::attributeInfo(kSecAuthenticationTypeItemAttr), authenticationType);
650
651 if (path && pathLength)
652 item->setAttribute(Schema::attributeInfo(kSecPathItemAttr),
653 CssmData(const_cast<void *>(reinterpret_cast<const void *>(path)), pathLength));
654
655 Keychain keychain = nil;
656 try
657 {
658 keychain = Keychain::optional(keychainRef);
659 if ( !keychain->exists() )
660 {
661 MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time.
662 }
663 }
664 catch(...)
665 {
666 keychain = globals().storageManager.defaultKeychainUI(item);
667 }
668
669 keychain->add(item);
670
671 if (itemRef)
672 *itemRef = item->handle();
673
674 END_SECAPI
675}
676
677
678OSStatus
679SecKeychainFindInternetPassword(CFTypeRef keychainOrArray, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef)
680
681{
682 BEGIN_SECAPI
d64be36e
A
683
684 os_activity_t activity = os_activity_create("SecKeychainFindInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
685 os_activity_scope(activity);
686 os_release(activity);
b1ab9ed8
A
687
688 StorageManager::KeychainList keychains;
689 globals().storageManager.optionalSearchList(keychainOrArray, keychains);
690 KCCursor cursor(keychains, kSecInternetPasswordItemClass, NULL);
691
692 if (serverName && serverNameLength)
693 {
694 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServerItemAttr),
695 CssmData(const_cast<char *>(serverName), serverNameLength));
696 }
697
698 if (securityDomain && securityDomainLength)
699 {
700 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecSecurityDomainItemAttr),
701 CssmData (const_cast<char*>(securityDomain), securityDomainLength));
702 }
703
704 if (accountName && accountNameLength)
705 {
706 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr),
707 CssmData (const_cast<char*>(accountName), accountNameLength));
708 }
709
710 if (port)
711 {
712 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPortItemAttr),
713 UInt32(port));
714 }
715
716 if (protocol)
717 {
718 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecProtocolItemAttr),
719 protocol);
720 }
721
722 if (authenticationType)
723 {
724 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAuthenticationTypeItemAttr),
725 authenticationType);
726 }
727
728 if (path && pathLength)
729 {
730 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPathItemAttr), path);
731 }
732
733 Item item;
734 if (!cursor->next(item))
735 return errSecItemNotFound;
736
737 // Get its data (only if necessary)
738 if (passwordData || passwordLength)
739 {
740 CssmDataContainer outData;
741 item->getData(outData);
fa7225c8
A
742 if (passwordLength) {
743 *passwordLength=(UInt32)outData.length();
744 }
b1ab9ed8 745 outData.Length=0;
fa7225c8
A
746 if (passwordData) {
747 *passwordData=outData.data();
748 }
b1ab9ed8
A
749 outData.Data=NULL;
750 }
751
752 if (itemRef)
753 *itemRef=item->handle();
754
755 END_SECAPI
756}
757
758
759OSStatus
760SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef)
761{
762 BEGIN_SECAPI
d64be36e
A
763
764 os_activity_t activity = os_activity_create("SecKeychainAddGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
765 os_activity_scope(activity);
766 os_release(activity);
b1ab9ed8
A
767
768 KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL);
769 // @@@ Get real itemClass
770
771 Item item(kSecGenericPasswordItemClass, 'aapl', passwordLength, passwordData, false);
772
773 if (serviceName && serviceNameLength)
774 {
775 CssmData service(const_cast<void *>(reinterpret_cast<const void *>(serviceName)), serviceNameLength);
776 item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service);
866f8763 777 item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service);
b1ab9ed8
A
778 }
779
780 if (accountName && accountNameLength)
781 {
782 CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength);
783 item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account);
784 }
785
786 Keychain keychain = nil;
787 try
788 {
789 keychain = Keychain::optional(keychainRef);
790 if ( !keychain->exists() )
791 {
792 MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time.
793 }
794 }
795 catch(...)
796 {
797 keychain = globals().storageManager.defaultKeychainUI(item);
798 }
799
800 keychain->add(item);
801 if (itemRef)
802 *itemRef = item->handle();
803
804 END_SECAPI
805}
806
807
808OSStatus
809SecKeychainFindGenericPassword(CFTypeRef keychainOrArray, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef)
810
811{
812 BEGIN_SECAPI
d64be36e
A
813
814 os_activity_t activity = os_activity_create("SecKeychainFindGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
815 os_activity_scope(activity);
816 os_release(activity);
b1ab9ed8
A
817
818 StorageManager::KeychainList keychains;
819 globals().storageManager.optionalSearchList(keychainOrArray, keychains);
820 KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL);
821
822 if (serviceName && serviceNameLength)
823 {
824 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr),
825 CssmData(const_cast<char *>(serviceName), serviceNameLength));
826 }
827
828 if (accountName && accountNameLength)
829 {
830 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr),
831 CssmData(const_cast<char *>(accountName), accountNameLength));
832 }
833
834 Item item;
835 if (!cursor->next(item))
836 return errSecItemNotFound;
837
838 // Get its data (only if necessary)
839 if (passwordData || passwordLength)
840 {
841 CssmDataContainer outData;
842 item->getData(outData);
fa7225c8
A
843 if (passwordLength) {
844 *passwordLength=(UInt32)outData.length();
845 }
b1ab9ed8 846 outData.Length=0;
fa7225c8
A
847 if (passwordData) {
848 *passwordData=outData.data();
849 }
b1ab9ed8
A
850 outData.Data=NULL;
851 }
852
853 if (itemRef)
854 *itemRef=item->handle();
855
856 END_SECAPI
857}
858
859
860OSStatus
861SecKeychainSetUserInteractionAllowed(Boolean state)
862{
863 BEGIN_SECAPI
864
865 globals().setUserInteractionAllowed(state);
866
867 END_SECAPI
868}
869
870
871OSStatus
872SecKeychainGetUserInteractionAllowed(Boolean *state)
873{
874 BEGIN_SECAPI
875
876 Required(state)=globals().getUserInteractionAllowed();
877
878 END_SECAPI
879}
880
881
882OSStatus
883SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHandle)
884{
885 BEGIN_SECAPI
d64be36e
A
886
887 os_activity_t activity = os_activity_create("SecKeychainGetDLDBHandle", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
888 os_activity_scope(activity);
889 os_release(activity);
b1ab9ed8
A
890
891 RequiredParam(dldbHandle);
892
893 Keychain keychain = Keychain::optional(keychainRef);
894 *dldbHandle = keychain->database()->handle();
895
896 END_SECAPI
897}
898
79b9da22
A
899static ModuleNexus<Mutex> gSecReturnedKeychainCSPsMutex;
900static ModuleNexus<std::set<CssmClient::CSP>> gSecReturnedKeychainCSPs;
b1ab9ed8
A
901
902OSStatus
903SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle)
904{
905 BEGIN_SECAPI
906
907 RequiredParam(cspHandle);
908
909 Keychain keychain = Keychain::optional(keychainRef);
866f8763
A
910
911 // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP).
912 // Keep a global pointer to it to force the CSP to stay live forever.
913 CssmClient::CSP returnedKeychainCSP = keychain->csp();
914 {
79b9da22
A
915 StLock<Mutex> _(gSecReturnedKeychainCSPsMutex());
916 gSecReturnedKeychainCSPs().insert(returnedKeychainCSP);
866f8763
A
917 }
918 *cspHandle = returnedKeychainCSP->handle();
b1ab9ed8
A
919
920 END_SECAPI
921}
922
923
924OSStatus
925SecKeychainCopyAccess(SecKeychainRef keychainRef, SecAccessRef *accessRef)
926{
927 BEGIN_SECAPI
928
427c49bc 929 MacOSError::throwMe(errSecUnimplemented);//%%%for now
b1ab9ed8
A
930
931 END_SECAPI
932}
933
934
935OSStatus
936SecKeychainSetAccess(SecKeychainRef keychainRef, SecAccessRef accessRef)
937{
938 BEGIN_SECAPI
939
427c49bc 940 MacOSError::throwMe(errSecUnimplemented);//%%%for now
b1ab9ed8
A
941
942 END_SECAPI
943}
944
945
946#pragma mark ---- Private API ----
947
948
949OSStatus
950SecKeychainChangePassword(SecKeychainRef keychainRef, UInt32 oldPasswordLength, const void *oldPassword, UInt32 newPasswordLength, const void *newPassword)
951{
952 BEGIN_SECAPI
d64be36e
A
953
954 os_activity_t activity = os_activity_create("SecKeychainChangePassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
955 os_activity_scope(activity);
956 os_release(activity);
b1ab9ed8
A
957
958 Keychain keychain = Keychain::optional(keychainRef);
959 keychain->changePassphrase (oldPasswordLength, oldPassword, newPasswordLength, newPassword);
960
961 END_SECAPI
962}
963
964
965OSStatus
966SecKeychainCopyLogin(SecKeychainRef *keychainRef)
967{
968 BEGIN_SECAPI
d64be36e
A
969
970 os_activity_t activity = os_activity_create("SecKeychainCopyLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
971 os_activity_scope(activity);
972 os_release(activity);
b1ab9ed8
A
973
974 RequiredParam(keychainRef)=globals().storageManager.loginKeychain()->handle();
975
976 END_SECAPI
977}
978
979
980OSStatus
981SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, const void* password)
982{
983 BEGIN_SECAPI
d64be36e
A
984
985 os_activity_t activity = os_activity_create("SecKeychainLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
986 os_activity_scope(activity);
987 os_release(activity);
b1ab9ed8
A
988
989 try
990 {
427c49bc 991 if (password) {
fa7225c8 992 globals().storageManager.login(nameLength, name, passwordLength, password, false);
427c49bc
A
993 } else {
994 globals().storageManager.stashLogin();
995 }
b1ab9ed8
A
996 }
997 catch (CommonError &e)
998 {
b04fe171 999 secnotice("KCLogin", "SecKeychainLogin failed: %d, password was%s supplied", (int)e.osStatus(), password?"":" not");
b1ab9ed8
A
1000 if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED)
1001 {
1002 return errSecAuthFailed;
1003 }
1004 else
1005 {
1006 return e.osStatus();
1007 }
1008 }
b04fe171
A
1009
1010 catch (...) {
1011 __secapiresult=errSecInternalComponent;
1012 }
1013 secnotice("KCLogin", "SecKeychainLogin result: %d, password was%s supplied", (int)__secapiresult, password?"":" not");
1014
b1ab9ed8
A
1015 END_SECAPI
1016}
1017
427c49bc
A
1018OSStatus SecKeychainStash()
1019{
1020 BEGIN_SECAPI
d64be36e
A
1021
1022 os_activity_t activity = os_activity_create("SecKeychainStash", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1023 os_activity_scope(activity);
1024 os_release(activity);
427c49bc
A
1025
1026 try
1027 {
1028 globals().storageManager.stashKeychain();
1029 }
1030 catch (CommonError &e)
1031 {
1032 if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED)
1033 {
1034 return errSecAuthFailed;
1035 }
1036 else
1037 {
1038 return e.osStatus();
1039 }
1040 }
1041
1042 END_SECAPI
1043}
b1ab9ed8
A
1044
1045OSStatus
1046SecKeychainLogout()
1047{
1048 BEGIN_SECAPI
d64be36e
A
1049
1050 os_activity_t activity = os_activity_create("SecKeychainLogout", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1051 os_activity_scope(activity);
1052 os_release(activity);
b1ab9ed8
A
1053
1054 globals().storageManager.logout();
1055
1056 END_SECAPI
1057}
1058
1059/* (non-exported C utility routine) 'Makes' a keychain based on a full path
1060*/
1061static Keychain make(const char *name)
1062{
1063 return globals().storageManager.make(name);
1064}
1065
1066/* 'Makes' a keychain based on a full path for legacy "KC" CoreServices APIs.
1067 Note this version doesn't take an accessRef or password.
1068 The "KC" create API takes a keychainRef...
1069*/
1070OSStatus SecKeychainMakeFromFullPath(const char *fullPathName, SecKeychainRef *keychainRef)
1071{
1072 BEGIN_SECAPI
d64be36e
A
1073
1074 RequiredParam(fullPathName);
b1ab9ed8
A
1075 RequiredParam(keychainRef)=make(fullPathName)->handle();
1076 END_SECAPI
1077}
1078
1079
1080/* Determines if the keychainRef is a valid keychain.
1081*/
1082OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid)
1083{
1084 BEGIN_SECAPI
d64be36e
A
1085
1086 *isValid = false;
b1ab9ed8
A
1087 if (KeychainImpl::optional(keychainRef)->dlDbIdentifier().ssuid().guid() == gGuidAppleCSPDL)
1088 *isValid = true;
1089 END_SECAPI
1090}
1091
1092/* Removes a keychain from the keychain search list for legacy "KC" CoreServices APIs.
1093*/
1094OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef)
1095{
1096 BEGIN_SECAPI
d64be36e
A
1097
1098 os_activity_t activity = os_activity_create("SecKeychainRemoveFromSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1099 os_activity_scope(activity);
1100 os_release(activity);
b1ab9ed8
A
1101 StorageManager::KeychainList singleton;
1102 singleton.push_back(KeychainImpl::required(keychainRef));
1103 globals().storageManager.remove(singleton);
1104 END_SECAPI
1105}
1106
1107/* Create a keychain based on a keychain Ref for legacy "KC" CoreServices APIs.
1108*/
1109OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength, const char* inPassword)
1110{
1111 BEGIN_SECAPI
d64be36e
A
1112
1113 os_activity_t activity = os_activity_create("SecKeychainCreateNew", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1114 os_activity_scope(activity);
1115 os_release(activity);
b1ab9ed8
A
1116 RequiredParam(inPassword);
1117 KeychainImpl::required(keychainRef)->create(passwordLength, inPassword);
1118 END_SECAPI
1119}
1120
1121/* Modify a keychain so that it can be synchronized.
1122*/
1123OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlobArray, CFDataRef extraData)
1124{
1125 BEGIN_SECAPI
d64be36e
A
1126
1127 os_activity_t activity = os_activity_create("SecKeychainRecodeKeychain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1128 os_activity_scope(activity);
1129 os_release(activity);
b1ab9ed8
A
1130
1131 // do error checking for required parameters
1132 RequiredParam(dbBlobArray);
1133 RequiredParam(extraData);
1134
1135 const CssmData extraCssmData(const_cast<UInt8 *>(CFDataGetBytePtr(extraData)),
1136 CFDataGetLength(extraData));
1137
1138 CFIndex dbBlobArrayCount = CFArrayGetCount(dbBlobArray);
1139 size_t space = sizeof(uint8) + (dbBlobArrayCount * sizeof(SecurityServer::DbHandle));
1140 void *dataPtr = (void*)malloc(space);
1141 if ( !dataPtr )
427c49bc 1142 return errSecAllocate;
b1ab9ed8
A
1143 //
1144 // Get a DbHandle(IPCDbHandle) from securityd for each blob in the array that we'll authenticate with.
1145 //
1146 uint8* sizePtr = (uint8*)dataPtr;
1147 *sizePtr = dbBlobArrayCount;
1148 SecurityServer::DbHandle *currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1);
1149 CFIndex index;
1150 SecurityServer::ClientSession ss(Allocator::standard(), Allocator::standard());
1151 for (index=0; index < dbBlobArrayCount; index++)
1152 {
1153 CFDataRef cfBlobData = (CFDataRef)CFArrayGetValueAtIndex(dbBlobArray, index);
1154 const CssmData thisKCData(const_cast<UInt8 *>(CFDataGetBytePtr(cfBlobData)), CFDataGetLength(cfBlobData));
1155 //
1156 // Since it's to a DbHandle that's not on our disk (it came from user's iDisk),
1157 // it's OK to use the mIdentifier and access credentials of the keychain we're recoding.
1158 //
1159 Keychain kc = KeychainImpl::required(keychainRef);
1160 *currDbHandle = ss.decodeDb(kc->dlDbIdentifier(), kc->defaultCredentials(), thisKCData); /* returns a DbHandle (IPCDbHandle) */
1161
1162 currDbHandle++;
1163 }
1164 // do the work
1165 Keychain keychain = Keychain::optional(keychainRef);
1166 const CssmData data(const_cast<UInt8 *>((uint8*)dataPtr), space);
1167 Boolean recodeFailed = false;
1168
427c49bc 1169 int errCode=errSecSuccess;
b1ab9ed8
A
1170
1171 try
1172 {
1173 keychain->recode(data, extraCssmData);
1174 }
1175 catch (MacOSError e)
1176 {
1177 errCode = e.osStatus();
1178 recodeFailed = true;
1179 }
1180 catch (UnixError ue)
1181 {
1182 errCode = ue.unixError();
1183 }
1184
1185 currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1);
1186 for (index=0; index < dbBlobArrayCount; index++)
1187 {
1188 ss.releaseDb(*currDbHandle);
1189 currDbHandle++;
1190 }
1191 if ( dataPtr )
1192 free(dataPtr);
1193
1194 if ( recodeFailed )
1195 {
1196 return errCode;
1197 }
1198
1199 END_SECAPI
1200}
1201
1202OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychainSignature)
1203{
1204 BEGIN_SECAPI
d64be36e
A
1205
1206 os_activity_t activity = os_activity_create("SecKeychainCopySignature", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1207 os_activity_scope(activity);
1208 os_release(activity);
b1ab9ed8
A
1209
1210 // do error checking for required parameters
1211 RequiredParam(keychainSignature);
1212
1213 // make a keychain object "wrapper" for this keychain ref
1214 Keychain keychain = Keychain::optional(keychainRef);
1215 CssmAutoData data(keychain->database()->allocator());
1216 keychain->copyBlob(data.get());
1217
1218 // get the cssmDBBlob
1219 const SecurityServer::DbBlob *cssmDBBlob =
1220 data.get().interpretedAs<const SecurityServer::DbBlob>();
1221
1222 // convert from CDSA standards to CF standards
1223 *keychainSignature = CFDataCreate(kCFAllocatorDefault,
1224 cssmDBBlob->randomSignature.bytes,
1225 sizeof(SecurityServer::DbBlob::Signature));
1226
1227 END_SECAPI
1228}
1229
1230OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob)
1231{
1232 BEGIN_SECAPI
d64be36e
A
1233
1234 os_activity_t activity = os_activity_create("SecKeychainCopyBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1235 os_activity_scope(activity);
1236 os_release(activity);
b1ab9ed8
A
1237
1238 // do error checking for required parameters
1239 RequiredParam(dbBlob);
1240
1241 // make a keychain object "wrapper" for this keychain ref
1242 Keychain keychain = Keychain::optional(keychainRef);
1243 CssmAutoData data(keychain->database()->allocator());
1244 keychain->copyBlob(data.get());
1245
1246 // convert from CDSA standards to CF standards
1247 *dbBlob = CFDataCreate(kCFAllocatorDefault, data, data.length());
1248
1249 END_SECAPI
1250}
1251
1252// make a new keychain with pre-existing secrets
1253OSStatus SecKeychainCreateWithBlob(const char* fullPathName, CFDataRef dbBlob, SecKeychainRef *kcRef)
1254{
1255 BEGIN_SECAPI
d64be36e
A
1256
1257 os_activity_t activity = os_activity_create("SecKeychainCreateWithBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1258 os_activity_scope(activity);
1259 os_release(activity);
b1ab9ed8
A
1260
1261 KCThrowParamErrIf_(!fullPathName);
1262 KCThrowParamErrIf_(!dbBlob);
1263
1264 Keychain keychain = globals().storageManager.make(fullPathName);
1265
1266 CssmData blob(const_cast<unsigned char *>(CFDataGetBytePtr(dbBlob)), CFDataGetLength(dbBlob));
1267
1268 // @@@ the call to StorageManager::make above leaves keychain the the cache.
1269 // If the create below fails we should probably remove it.
1270 keychain->createWithBlob(blob);
1271
1272 RequiredParam(kcRef)=keychain->handle();
1273
1274 //
1275
1276 END_SECAPI
1277}
1278
1279// add a non-file based DB to the keychain list
1280OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char* dbName,
1281 const CSSM_GUID *guid, uint32 subServiceType)
1282{
1283 BEGIN_SECAPI
d64be36e
A
1284
1285 os_activity_t activity = os_activity_create("SecKeychainAddDBToKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1286 os_activity_scope(activity);
1287 os_release(activity);
b1ab9ed8
A
1288
1289 RequiredParam(dbName);
1290 StorageManager &smr = globals().storageManager;
1291 smr.addToDomainList(domain, dbName, *guid, subServiceType);
1292
1293 END_SECAPI
1294}
1295
1296// determine if a non-file based DB is in the keychain list
1297OSStatus SecKeychainDBIsInKeychainList (SecPreferencesDomain domain, const char* dbName,
1298 const CSSM_GUID *guid, uint32 subServiceType)
1299{
1300 BEGIN_SECAPI
d64be36e
A
1301
1302 RequiredParam(dbName);
b1ab9ed8
A
1303 StorageManager &smr = globals().storageManager;
1304 smr.isInDomainList(domain, dbName, *guid, subServiceType);
1305 END_SECAPI
1306}
1307
1308// remove a non-file based DB from the keychain list
1309OSStatus SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain, const char* dbName,
1310 const CSSM_GUID *guid, uint32 subServiceType)
1311{
1312 BEGIN_SECAPI
d64be36e
A
1313
1314 os_activity_t activity = os_activity_create("SecKeychainRemoveDBFromKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1315 os_activity_scope(activity);
1316 os_release(activity);
b1ab9ed8
A
1317 RequiredParam(dbName);
1318 StorageManager &smr = globals().storageManager;
1319 smr.removeFromDomainList(domain, dbName, *guid, subServiceType);
1320 END_SECAPI
1321}
1322
1323
1324// set server mode -- must be called before any other Sec* etc. call
1325void SecKeychainSetServerMode()
1326{
1327 gServerMode = true;
1328}
1329
1330
1331
1332OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean rollback)
1333{
1334 BEGIN_SECAPI
d64be36e
A
1335
1336 os_activity_t activity = os_activity_create("SecKeychainSetBatchMode", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1337 os_activity_scope(activity);
1338 os_release(activity);
b1ab9ed8
A
1339 RequiredParam(kcRef);
1340 Keychain keychain = Keychain::optional(kcRef);
1341 keychain->setBatchMode(mode, rollback);
1342 END_SECAPI
1343}
1344
1345
1346
1347OSStatus SecKeychainCleanupHandles()
1348{
1349 BEGIN_SECAPI
d64be36e
A
1350
1351 END_SECAPI // which causes the handle cache cleanup routine to run
b1ab9ed8
A
1352}
1353
427c49bc
A
1354OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries)
1355{
1356 BEGIN_SECAPI
d64be36e
A
1357
1358 os_activity_t activity = os_activity_create("SecKeychainVerifyKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1359 os_activity_scope(activity);
1360 os_release(activity);
427c49bc
A
1361 SecurityServer::ClientSession().verifyKeyStorePassphrase(retries);
1362 END_SECAPI
1363}
1364
1365OSStatus SecKeychainChangeKeyStorePassphrase()
1366{
1367 BEGIN_SECAPI
d64be36e
A
1368
1369 os_activity_t activity = os_activity_create("SecKeychainChangeKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1370 os_activity_scope(activity);
1371 os_release(activity);
427c49bc
A
1372 SecurityServer::ClientSession().changeKeyStorePassphrase();
1373 END_SECAPI
d8f41ccd
A
1374}
1375
1376static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRef *masterKey, CFStringRef password)
1377{
1378 BEGIN_SECAPI
d64be36e
A
1379
1380 os_activity_t activity = os_activity_create("SecKeychainGetMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
866f8763
A
1381 os_activity_scope(activity);
1382 os_release(activity);
d8f41ccd
A
1383
1384 // make a keychain object "wrapper" for this keychain ref
1385 Keychain keychain = Keychain::optional(userKeychainRef);
1386
1387 CssmClient::Db db = keychain->database();
1388
1389 // create the keychain, using appropriate credentials
1390 Allocator &alloc = db->allocator();
1391 AutoCredentials cred(alloc); // will leak, but we're quitting soon :-)
1392
1393 char passphrase[1024];
1394 CFStringGetCString(password, passphrase, sizeof(passphrase), kCFStringEncodingUTF8);
1395
1396 // use this passphrase
1397 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
1398 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
1399 new(alloc) ListElement(StringData(passphrase)));
fa7225c8
A
1400 db->authenticate(CSSM_DB_ACCESS_READ, &cred);
1401
1402 CSSM_DL_DB_HANDLE dlDb = db->handle();
d8f41ccd
A
1403 CssmData dlDbData = CssmData::wrap(dlDb);
1404 CssmKey refKey;
1405 KeySpec spec(CSSM_KEYUSE_ANY,
1406 CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE);
1407
1408 DeriveKey derive(keychain->csp(), CSSM_ALGID_KEYCHAIN_KEY, CSSM_ALGID_3DES_3KEY, 3 * 64);
1409 derive(&dlDbData, spec, refKey);
1410
1411 // now extract the raw keybits
1412 CssmKey rawKey;
1413 WrapKey wrap(keychain->csp(), CSSM_ALGID_NONE);
1414 wrap(refKey, rawKey);
1415
1416 *masterKey = CFDataCreate(kCFAllocatorDefault, rawKey.keyData(), rawKey.length());
1417
1418 END_SECAPI
1419}
1420
fa7225c8
A
1421static const char *kAutologinPWFilePath = "/etc/kcpassword";
1422static const uint32_t kObfuscatedPasswordSizeMultiple = 12;
1423static const uint32_t buffer_size = 512;
1424static const uint8_t kObfuscationKey[] = {0x7d, 0x89, 0x52, 0x23, 0xd2, 0xbc, 0xdd, 0xea, 0xa3, 0xb9, 0x1f};
1425
1426static void obfuscate(void *buffer, size_t bufferLength)
1427{
1428 uint8_t *pBuf = (uint8_t *) buffer;
1429 const uint8_t *pKey = kObfuscationKey, *eKey = pKey + sizeof( kObfuscationKey );
1430
1431 while (bufferLength--) {
1432 *pBuf = *pBuf ^ *pKey;
1433 ++pKey;
1434 ++pBuf;
1435 if (pKey == eKey)
1436 pKey = kObfuscationKey;
1437 }
1438}
1439
1440static bool _SASetAutologinPW(CFStringRef inAutologinPW)
1441{
1442 bool result = false;
1443 struct stat sb;
1444
1445 // Delete the kcpassword file if it exists already
1446 if (stat(kAutologinPWFilePath, &sb) == 0)
1447 unlink( kAutologinPWFilePath );
1448
1449 // NIL incoming password ==> clear auto login password (above) without setting a new one. In other words: turn auto login off.
1450 if (inAutologinPW != NULL) {
1451 char buffer[buffer_size];
1452 const char *pwAsUTF8String = CFStringGetCStringPtr(inAutologinPW, kCFStringEncodingUTF8);
1453 if (pwAsUTF8String == NULL) {
1454 if (CFStringGetCString(inAutologinPW, buffer, buffer_size, kCFStringEncodingUTF8)) pwAsUTF8String = buffer;
1455 }
1456
1457 if (pwAsUTF8String != NULL) {
1458 size_t pwLength = strlen(pwAsUTF8String) + 1;
1459 size_t obfuscatedPWLength;
1460 char *obfuscatedPWBuffer;
1461
1462 // The size of the obfuscated password should be the smallest multiple of
1463 // kObfuscatedPasswordSizeMultiple greater than or equal to pwLength.
1464 obfuscatedPWLength = (((pwLength - 1) / kObfuscatedPasswordSizeMultiple) + 1) * kObfuscatedPasswordSizeMultiple;
1465 obfuscatedPWBuffer = (char *) malloc(obfuscatedPWLength);
1466
1467 // Copy the password (including null terminator) to beginning of obfuscatedPWBuffer
1468 bcopy(pwAsUTF8String, obfuscatedPWBuffer, pwLength);
1469
1470 // Pad remainder of obfuscatedPWBuffer with random bytes
1471 {
1472 char *p;
1473 char *endOfBuffer = obfuscatedPWBuffer + obfuscatedPWLength;
1474
1475 for (p = obfuscatedPWBuffer + pwLength; p < endOfBuffer; ++p)
1476 *p = random() & 0x000000FF;
1477 }
1478
1479 obfuscate(obfuscatedPWBuffer, obfuscatedPWLength);
1480
1481 int pwFile = open(kAutologinPWFilePath, O_CREAT | O_WRONLY | O_NOFOLLOW, S_IRUSR | S_IWUSR);
1482 if (pwFile >= 0) {
1483 size_t wrote = write(pwFile, obfuscatedPWBuffer, obfuscatedPWLength);
1484 if (wrote == obfuscatedPWLength)
1485 result = true;
1486 close(pwFile);
1487 }
1488
1489 chmod(kAutologinPWFilePath, S_IRUSR | S_IWUSR);
1490 free(obfuscatedPWBuffer);
1491 }
1492 }
1493
1494 return result;
1495}
d8f41ccd
A
1496
1497OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRef systemKeychainRef, CFStringRef username, CFStringRef password) {
d64be36e 1498 COUNTLEGACYAPI
d8f41ccd
A
1499 SecTrustedApplicationRef itemPath;
1500 SecAccessRef ourAccessRef = NULL;
1501
1502 OSStatus result = errSecParam;
1503
fa7225c8
A
1504 if (userKeychainRef == NULL) {
1505 // We don't have a specific user keychain, fall back
1506 if (_SASetAutologinPW(password))
1507 result = errSecSuccess;
1508
1509 return result;
1510 }
1511
d8f41ccd
A
1512 CFDataRef masterKey = NULL;
1513 result = SecKeychainGetMasterKey(userKeychainRef, &masterKey, password);
1514 if (errSecSuccess != result) {
1515 return result;
1516 }
1517
1518 result = SecKeychainStash();
1519 if (errSecSuccess != result) {
fa7225c8 1520 if (masterKey != NULL) CFRelease(masterKey);
d8f41ccd
A
1521 return result;
1522 }
1523
1524 CFMutableArrayRef trustedApplications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
fa7225c8 1525 if (noErr == SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL, &itemPath) && itemPath)
d8f41ccd
A
1526 CFArrayAppendValue(trustedApplications, itemPath);
1527
fa7225c8 1528 if (trustedApplications && (CFArrayGetCount(trustedApplications) > 0)) {
d8f41ccd 1529 if (errSecSuccess == (result = SecAccessCreate(CFSTR("Auto-Login applications"), trustedApplications, &ourAccessRef))) {
fa7225c8 1530 SecKeychainRef internalSystemKeychainRef = NULL;
d8f41ccd 1531 if (NULL == systemKeychainRef) {
fa7225c8
A
1532 SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &internalSystemKeychainRef);
1533 } else {
1534 internalSystemKeychainRef = systemKeychainRef;
d8f41ccd
A
1535 }
1536
1537 const void *queryKeys[] = { kSecClass,
1538 kSecAttrService,
1539 kSecAttrAccount,
1540 kSecUseKeychain,
1541 };
1542 const void *queryValues[] = { kSecClassGenericPassword,
1543 CFSTR("com.apple.loginwindow.auto-login"),
1544 username,
fa7225c8 1545 internalSystemKeychainRef,
d8f41ccd
A
1546 };
1547
1548 const void *updateKeys[] = { kSecAttrAccess,
1549 kSecValueData,
1550 };
1551 const void *updateValues[] = { ourAccessRef,
1552 masterKey,
1553 };
1554
1555 CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, queryKeys, queryValues, sizeof(queryValues)/sizeof(*queryValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1556 CFDictionaryRef update = CFDictionaryCreate(kCFAllocatorDefault, updateKeys, updateValues, sizeof(updateValues)/sizeof(*updateValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1557
1558 result = SecItemUpdate(query, update);
1559
1560 if (errSecSuccess != result) {
1561 const void *addKeys[] = { kSecClass,
1562 kSecAttrService,
1563 kSecAttrAccount,
1564 kSecUseKeychain,
1565 kSecAttrAccess,
1566 kSecValueData,
1567 };
1568 const void *addValues[] = { kSecClassGenericPassword,
1569 CFSTR("com.apple.loginwindow.auto-login"),
1570 username,
fa7225c8 1571 internalSystemKeychainRef,
d8f41ccd
A
1572 ourAccessRef,
1573 masterKey,
1574 };
1575
1576 CFDictionaryRef add = CFDictionaryCreate(kCFAllocatorDefault, addKeys, addValues, sizeof(addValues)/sizeof(*addValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1577 result = SecItemAdd(add, NULL);
1578 if (NULL != add) CFRelease(add);
1579 }
1580
1581 if (NULL != query) CFRelease(query);
1582 if (NULL != update) CFRelease(update);
fa7225c8
A
1583
1584 // If the caller wanted us to locate the system keychain reference, it's okay to go ahead and free our magically created one
1585 if (systemKeychainRef == NULL) CFRelease(internalSystemKeychainRef);
d8f41ccd
A
1586 }
1587 }
1588
1589 if (NULL != masterKey) CFRelease(masterKey);
1590 if (NULL != trustedApplications) CFRelease(trustedApplications);
1591 if (NULL != ourAccessRef) CFRelease(ourAccessRef);
d8f41ccd
A
1592
1593 return result;
1594}
fa7225c8
A
1595
1596OSStatus SecKeychainGetUserPromptAttempts(uint32_t * attempts)
1597{
1598 BEGIN_SECAPI
d64be36e 1599
866f8763
A
1600 os_activity_t activity = os_activity_create("SecKeychainGetUserPromptAttempts", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
1601 os_activity_scope(activity);
1602 os_release(activity);
fa7225c8
A
1603
1604 if(attempts) {
1605 SecurityServer::ClientSession().getUserPromptAttempts(*attempts);
1606 }
1607
1608 END_SECAPI
1609}
1610
1611OSStatus SecKeychainStoreUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash, CFStringRef tokenID, CFDataRef wrapPubKeyHash,
1612 SecKeychainRef userKeychain, CFStringRef password)
1613{
d64be36e 1614 COUNTLEGACYAPI
fa7225c8
A
1615 CFRef<CFStringRef> pwd;
1616 OSStatus result;
1617
1618 if (password == NULL || CFStringGetLength(password) == 0) {
1619 AuthorizationRef authorizationRef;
1620 result = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef);
1621 if (result != errAuthorizationSuccess) {
b04fe171 1622 secnotice("SecKeychain", "failed to create authorization");
fa7225c8
A
1623 return result;
1624 }
1625
1626 AuthorizationItem myItems = {"com.apple.ctk.pair", 0, NULL, 0};
1627 AuthorizationRights myRights = {1, &myItems};
fa7225c8
A
1628
1629 char pathName[PATH_MAX];
1630 UInt32 pathLength = PATH_MAX;
1631 result = SecKeychainGetPath(userKeychain, &pathLength, pathName);
1632 if (result != errSecSuccess) {
b04fe171 1633 secnotice("SecKeychain", "failed to create authorization");
fa7225c8
A
1634 return result;
1635 }
1636
1637 Boolean checkPwd = TRUE;
b04fe171 1638 Boolean ignoreSession = TRUE;
fa7225c8
A
1639 AuthorizationItem envItems[] = {
1640 {AGENT_HINT_KEYCHAIN_PATH, pathLength, pathName, 0},
b04fe171
A
1641 {AGENT_HINT_KEYCHAIN_CHECK, sizeof(checkPwd), &checkPwd},
1642 {AGENT_HINT_IGNORE_SESSION, sizeof(ignoreSession), &ignoreSession}
fa7225c8
A
1643 };
1644
b04fe171 1645 AuthorizationEnvironment environment = {3, envItems};
fa7225c8 1646 AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
b54c578e
A
1647 result = AuthorizationCopyRights(authorizationRef, &myRights, &environment, flags, NULL);
1648 secnotice("SecKeychain", "Authorization result: %d", (int)result);
fa7225c8
A
1649
1650 if (result == errAuthorizationSuccess) {
1651 AuthorizationItemSet *items;
1652 result = AuthorizationCopyInfo(authorizationRef, kAuthorizationEnvironmentPassword, &items);
b54c578e 1653 secnotice("SecKeychain", "Items copy result: %d", (int)result);
fa7225c8 1654 if (result == errAuthorizationSuccess) {
b54c578e 1655 secnotice("SecKeychain", "Items count: %d", items->count);
fa7225c8
A
1656 if (items->count > 0) {
1657 pwd = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)items->items[0].value, kCFStringEncodingUTF8);
b54c578e
A
1658 if (pwd) {
1659 secnotice("SecKeychain", "Got kcpass");
1660 }
fa7225c8
A
1661 }
1662 AuthorizationFreeItemSet(items);
1663 }
1664 }
1665 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
1666 if (result != errAuthorizationSuccess) {
b04fe171 1667 secnotice("SecKeychain", "did not get authorization to pair the card");
fa7225c8
A
1668 return result;
1669 }
1670 } else {
1671 pwd.take(password);
1672 }
1673
1674 if (!pwd) {
b04fe171 1675 secnotice("SecKeychain", "did not get kcpass");
fa7225c8
A
1676 return errSecInternalComponent;
1677 }
1678
1679 CFRef<CFDataRef> masterKey;
1680 result = SecKeychainGetMasterKey(userKeychain, masterKey.take(), pwd);
1681 if (result != errSecSuccess) {
1682 secnotice("SecKeychain", "Failed to get master key: %d", (int) result);
1683 return result;
1684 }
1685
1686 CFRef<CFDataRef> scBlob;
1687 result = TokenLoginGetScBlob(wrapPubKeyHash, tokenID, pwd, scBlob.take());
1688 if (result != errSecSuccess) {
1689 secnotice("SecKeychain", "Failed to get stash: %d", (int) result);
1690 return result;
1691 }
1692
1693 result = TokenLoginCreateLoginData(tokenID, pubKeyHash, wrapPubKeyHash, masterKey, scBlob);
1694 if (result != errSecSuccess) {
1695 secnotice("SecKeychain", "Failed to create login data: %d", (int) result);
1696 return result;
1697 }
1698
1699 secnotice("SecKeychain", "SecKeychainStoreUnlockKeyWithPubKeyHash result %d", (int) result);
d64be36e
A
1700
1701 // create SC KEK
1702 // this might fail if KC password is different from user's password
1703 uid_t uid = geteuid();
1704 if (!uid) {
1705 uid = getuid();
1706 }
1707 struct passwd *passwd = getpwuid(uid);
1708 if (passwd) {
1709 CFRef<CFStringRef> username = CFStringCreateWithCString(kCFAllocatorDefault, passwd->pw_name, kCFStringEncodingUTF8);
1710 OSStatus kekRes = TKAddSecureToken(username, pwd, tokenID, wrapPubKeyHash);
1711 if (kekRes != noErr) {
1712 secnotice("SecKeychain", "Failed to register SC token: %d", (int) kekRes); // do not fail because KC functionality be still OK
1713 }
1714 } else {
1715 secnotice("SecKeychain", "Unable to get name for uid %d", uid);
1716 }
fa7225c8
A
1717 return result;
1718}
1719
1720OSStatus SecKeychainEraseUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash)
1721{
d64be36e 1722 COUNTLEGACYAPI
fa7225c8
A
1723 OSStatus result = TokenLoginDeleteUnlockData(pubKeyHash);
1724 if (result != errSecSuccess) {
1725 secnotice("SecKeychain", "Failed to erase stored wrapped unlock key: %d", (int) result);
1726 }
1727 return result;
1728}