1/* 2 * Copyright (c) 2006-2013 Apple Inc. All rights reserved. 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 <stdio.h> 25#include <stdlib.h> 26#include <unistd.h> 27#include <sys/types.h> 28#include <string.h> 29#include <TargetConditionals.h> 30#include <CoreFoundation/CFString.h> 31#include <CoreFoundation/CFNumber.h> 32#include "symbol_scope.h" 33#include "EAPLog.h" 34#include "EAPSecurity.h" 35#include "EAPKeychainUtil.h" 36#include "EAPKeychainUtilInternal.h" 37#include "myCFUtil.h" 38 39#if TARGET_OS_EMBEDDED 40 41OSStatus 42EAPSecKeychainPasswordItemRemove(SecKeychainRef keychain, 43 CFStringRef unique_id_str) 44{ 45 const void * keys[] = { 46 kSecClass, 47 kSecAttrService 48 }; 49 CFDictionaryRef query; 50 OSStatus status; 51 52 const void * values[] = { 53 kSecClassGenericPassword, 54 unique_id_str 55 }; 56 57 query = CFDictionaryCreate(NULL, keys, values, 58 sizeof(keys) / sizeof(*keys), 59 &kCFTypeDictionaryKeyCallBacks, 60 &kCFTypeDictionaryValueCallBacks); 61 status = SecItemDelete(query); 62 CFRelease(query); 63 if (status != noErr) { 64 EAPLOG_FL(LOG_NOTICE, "SecItemDelete failed: %s (%d)", 65 EAPSecurityErrorString(status), (int)status); 66 } 67 return (status); 68} 69 70OSStatus 71EAPSecKeychainPasswordItemCopy(SecKeychainRef keychain, 72 CFStringRef unique_id_str, 73 CFDataRef * ret_password) 74{ 75 const void * keys[] = { 76 kSecClass, 77 kSecAttrService, 78 kSecReturnData 79 }; 80 CFDictionaryRef query; 81 CFTypeRef results; 82 OSStatus status; 83 const void * values[] = { 84 kSecClassGenericPassword, 85 unique_id_str, 86 kCFBooleanTrue 87 }; 88 89 query = CFDictionaryCreate(NULL, keys, values, 90 sizeof(keys) / sizeof(*keys), 91 &kCFTypeDictionaryKeyCallBacks, 92 &kCFTypeDictionaryValueCallBacks); 93 status = SecItemCopyMatching(query, &results); 94 CFRelease(query); 95 if (status == noErr) { 96 *ret_password = results; 97 } 98 else { 99 *ret_password = NULL; 100 } 101 return (status); 102} 103 104OSStatus 105EAPSecKeychainPasswordItemCreateWithAccess(SecKeychainRef keychain, 106 SecAccessRef access, 107 CFStringRef unique_id_str, 108 CFDataRef label, 109 CFDataRef description, 110 CFDataRef user, 111 CFDataRef password) 112{ 113 CFMutableDictionaryRef attrs; 114 OSStatus status; 115 116 attrs = CFDictionaryCreateMutable(NULL, 0, 117 &kCFTypeDictionaryKeyCallBacks, 118 &kCFTypeDictionaryValueCallBacks); 119 CFDictionarySetValue(attrs, kSecClass, kSecClassGenericPassword); 120 CFDictionarySetValue(attrs, kSecAttrService, unique_id_str); 121 CFDictionarySetValue(attrs, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock); 122 if (label != NULL) { 123 CFDictionarySetValue(attrs, kSecAttrLabel, label); 124 } 125 if (description != NULL) { 126 CFDictionarySetValue(attrs, kSecAttrDescription, description); 127 } 128 if (user != NULL) { 129 CFDictionarySetValue(attrs, kSecAttrAccount, user); 130 } 131 CFDictionarySetValue(attrs, kSecValueData, password); 132 status = SecItemAdd(attrs, NULL); 133 CFRelease(attrs); 134 return (status); 135} 136 137OSStatus 138EAPSecKeychainPasswordItemSet(SecKeychainRef keychain, 139 CFStringRef unique_id_str, 140 CFDataRef password) 141{ 142 const void * keys[] = { 143 kSecClass, 144 kSecAttrService, 145 kSecReturnData 146 }; 147 CFTypeRef existing_password = NULL; 148 CFDictionaryRef query; 149 CFDictionaryRef pass_dict; 150 OSStatus status; 151 const void * values[] = { 152 kSecClassGenericPassword, 153 unique_id_str, 154 kCFBooleanTrue 155 }; 156 157 query = CFDictionaryCreate(NULL, keys, values, 158 sizeof(keys) / sizeof(*keys), 159 &kCFTypeDictionaryKeyCallBacks, 160 &kCFTypeDictionaryValueCallBacks); 161 status = SecItemCopyMatching(query, &existing_password); 162 CFRelease(query); 163 if (status != noErr) { 164 goto done; 165 } 166 if (existing_password != NULL 167 && CFEqual(password, existing_password)) { 168 /* nothing to do */ 169 goto done; 170 } 171 query = CFDictionaryCreate(NULL, keys, values, 172 (sizeof(keys) / sizeof(*keys)) - 1, 173 &kCFTypeDictionaryKeyCallBacks, 174 &kCFTypeDictionaryValueCallBacks); 175 pass_dict = CFDictionaryCreate(NULL, 176 (const void * *)&kSecValueData, 177 (const void * *)&password, 178 1, 179 &kCFTypeDictionaryKeyCallBacks, 180 &kCFTypeDictionaryValueCallBacks); 181 status = SecItemUpdate(query, pass_dict); 182 CFRelease(query); 183 CFRelease(pass_dict); 184 185 done: 186 my_CFRelease(&existing_password); 187 return (status); 188} 189 190#else /* TARGET_OS_EMBEDDED */ 191#include <Security/SecAccess.h> 192#include <Security/SecACL.h> 193#include <Security/SecTrustedApplication.h> 194#include <Security/SecTrustedApplicationPriv.h> 195#include <Security/AuthorizationTags.h> 196 197const CFStringRef kEAPSecKeychainPropPassword = CFSTR("Password"); 198const CFStringRef kEAPSecKeychainPropLabel = CFSTR("Label"); 199const CFStringRef kEAPSecKeychainPropDescription = CFSTR("Description"); 200const CFStringRef kEAPSecKeychainPropAccount = CFSTR("Account"); 201const CFStringRef kEAPSecKeychainPropTrustedApplications = CFSTR("TrustedApplications"); 202const CFStringRef kEAPSecKeychainPropAllowRootAccess = CFSTR("AllowRootAccess"); 203 204#include <Security/cssmtype.h> 205#include <Security/cssmapple.h> 206#include <Security/SecKeychain.h> 207#include <Security/SecKeychainItem.h> 208 209#define MY_KEYCHAIN_ATTR_MAX 6 210 211typedef struct { 212 SecKeychainAttributeInfo info; 213 UInt32 tag[MY_KEYCHAIN_ATTR_MAX]; 214 UInt32 format[MY_KEYCHAIN_ATTR_MAX]; 215} mySecKeychainAttributeInfo; 216 217typedef struct { 218 SecKeychainAttributeList list; 219 SecKeychainAttribute attr[MY_KEYCHAIN_ATTR_MAX]; 220} mySecKeychainAttributeList; 221 222typedef struct CFStringSecItemTag { 223 const CFStringRef * key; 224 UInt32 tag; 225} CFStringSecItemTag; 226 227STATIC const CFStringSecItemTag prop_tag_tbl[] = { 228 { &kEAPSecKeychainPropAccount, kSecAccountItemAttr }, 229 { &kEAPSecKeychainPropLabel, kSecLabelItemAttr }, 230 { &kEAPSecKeychainPropDescription, kSecDescriptionItemAttr }, 231}; 232STATIC const int prop_tag_tbl_size = (sizeof(prop_tag_tbl) 233 / sizeof(prop_tag_tbl[0])); 234 235STATIC void 236mySecKeychainAttributeInfoInit(mySecKeychainAttributeInfo * attr_info) 237{ 238 attr_info->info.count = 0; 239 attr_info->info.tag = attr_info->tag; 240 attr_info->info.format = attr_info->format; 241 return; 242} 243 244STATIC Boolean 245mySecKeychainAttributeInfoAdd(mySecKeychainAttributeInfo * attr_info, 246 UInt32 tag) 247{ 248 int count = attr_info->info.count; 249 250 if (count >= MY_KEYCHAIN_ATTR_MAX) { 251 EAPLOG_FL(LOG_NOTICE, "Trying to add attribute %d but list is full", 252 (int)tag); 253 return (FALSE); 254 } 255 attr_info->format[count] = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; 256 attr_info->tag[count] = tag; 257 attr_info->info.count++; 258 return (TRUE); 259} 260 261STATIC void 262mySecKeychainAttributeListInit(mySecKeychainAttributeList * attr_list) 263{ 264 attr_list->list.count = 0; 265 attr_list->list.attr = attr_list->attr; 266 return; 267} 268 269STATIC Boolean 270mySecKeychainAttributeListAdd(mySecKeychainAttributeList * attr_list, 271 UInt32 attr_tag, CFDataRef attr_data) 272{ 273 SecKeychainAttribute * attr; 274 int count = attr_list->list.count; 275 276 if (count >= MY_KEYCHAIN_ATTR_MAX) { 277 EAPLOG_FL(LOG_NOTICE, "Trying to add attribute %d but list is full", 278 (int)attr_tag); 279 return (FALSE); 280 } 281 attr = attr_list->attr + count; 282 attr->tag = attr_tag; 283 attr->length = CFDataGetLength(attr_data); 284 attr->data = (void *)CFDataGetBytePtr(attr_data); 285 attr_list->list.count++; 286 return (TRUE); 287} 288 289STATIC Boolean 290mySecKeychainAttributeListAddFromDict(mySecKeychainAttributeList * attr_list, 291 CFDictionaryRef attrs) 292{ 293 int i; 294 Boolean ret = TRUE; 295 const CFStringSecItemTag * tbl; 296 297 for (i = 0, tbl = prop_tag_tbl; i < prop_tag_tbl_size; i++, tbl++) { 298 CFDataRef val = CFDictionaryGetValue(attrs, *tbl->key); 299 300 if (val != NULL) { 301 ret = mySecKeychainAttributeListAdd(attr_list, tbl->tag, val); 302 if (ret == FALSE) { 303 EAPLOG_FL(LOG_NOTICE, "mySecKeychainAttributeListAddFromDict() " 304 "failed to add %d", (int)tbl->tag); 305 break; 306 } 307 } 308 } 309 return (ret); 310} 311 312PRIVATE_EXTERN OSStatus 313EAPSecAccessCreateWithTrustedApplications(CFArrayRef trusted_apps, 314 CFDataRef label_data, 315 SecAccessRef * ret_access) 316{ 317 CFStringRef label = NULL; 318 OSStatus status; 319 320 if (label_data != NULL) { 321 label = my_CFStringCreateWithData(label_data); 322 } 323 else { 324 label = CFSTR("--unspecified--"); 325 CFRetain(label); 326 } 327 status = SecAccessCreate(label, trusted_apps, ret_access); 328 my_CFRelease(&label); 329 return (status); 330} 331 332PRIVATE_EXTERN OSStatus 333EAPSecKeychainItemSetAccessForTrustedApplications(SecKeychainItemRef item, 334 CFArrayRef trusted_apps) 335{ 336 CFArrayRef app_list = NULL; 337 CFMutableArrayRef app_list_data = NULL; 338 SecACLRef acl; 339 CFArrayRef acl_list = NULL; 340 SecAccessRef access = NULL; 341 CFStringRef prompt_description = NULL; 342 SecKeychainPromptSelector prompt_selector; 343 OSStatus status; 344 345 status = SecKeychainItemCopyAccess(item, &access); 346 if (status != noErr) { 347 status = SecAccessCreate(CFSTR("--unspecified--"), 348 trusted_apps, &access); 349 if (status != noErr) { 350 goto done; 351 } 352 } 353 else { 354 acl_list 355 = SecAccessCopyMatchingACLList(access, kSecACLAuthorizationDecrypt); 356 if (acl_list == NULL) { 357 status = errSecAllocate; 358 goto done; 359 } 360 acl = (SecACLRef)CFArrayGetValueAtIndex(acl_list, 0); 361 status = SecACLCopyContents(acl, &app_list, &prompt_description, 362 &prompt_selector); 363 if (status == noErr && app_list != NULL) { 364 int count; 365 int i; 366 CFRange r; 367 CFMutableArrayRef new_list = NULL; 368 369 r.location = 0; 370 r.length = CFArrayGetCount(app_list); 371 app_list_data = CFArrayCreateMutable(NULL, r.length, 372 &kCFTypeArrayCallBacks); 373 for (i = 0; i < r.length; i++) { 374 SecTrustedApplicationRef app; 375 CFDataRef data = NULL; 376 377 app = (SecTrustedApplicationRef) 378 CFArrayGetValueAtIndex(app_list, i); 379 (void)SecTrustedApplicationCopyExternalRepresentation(app, 380 &data); 381 if (data != NULL) { 382 CFArrayAppendValue(app_list_data, data); 383 CFRelease(data); 384 } 385 } 386 /* in case it changed */ 387 r.length = CFArrayGetCount(app_list_data); 388 count = CFArrayGetCount(trusted_apps); 389 for (i = 0; i < count; i++) { 390 bool already_there; 391 SecTrustedApplicationRef app; 392 CFDataRef data = NULL; 393 394 app = (SecTrustedApplicationRef) 395 CFArrayGetValueAtIndex(trusted_apps, i); 396 397 (void)SecTrustedApplicationCopyExternalRepresentation(app, 398 &data); 399 if (data == NULL) { 400 continue; 401 } 402 already_there = CFArrayContainsValue(app_list_data, r, data); 403 CFRelease(data); 404 if (already_there) { 405 continue; 406 } 407 if (new_list == NULL) { 408 new_list = CFArrayCreateMutableCopy(NULL, 0, app_list); 409 } 410 CFArrayAppendValue(new_list, app); 411 } 412 if (new_list == NULL) { 413 /* no modifications required */ 414 goto done; 415 } 416 status = SecACLSetContents(acl, new_list, prompt_description, 417 prompt_selector); 418 CFRelease(new_list); 419 if (status != noErr) { 420 goto done; 421 } 422 } 423 else { 424 status = SecACLSetContents(acl, trusted_apps, 425 prompt_description, 426 prompt_selector); 427 if (status != noErr) { 428 goto done; 429 } 430 } 431 } 432 status = SecKeychainItemSetAccess(item, access); 433 434 done: 435 my_CFRelease(&access); 436 my_CFRelease(&app_list); 437 my_CFRelease(&app_list_data); 438 my_CFRelease(&prompt_description); 439 my_CFRelease(&acl_list); 440 return (status); 441} 442 443STATIC OSStatus 444KeychainPasswordItemCopy(SecKeychainRef keychain, 445 CFStringRef unique_id_str, 446 SecKeychainItemRef * ret_item) 447{ 448 SecKeychainItemRef item; 449 OSStatus status; 450 CFDataRef unique_id; 451 452 unique_id = CFStringCreateExternalRepresentation(NULL, 453 unique_id_str, 454 kCFStringEncodingUTF8, 455 0); 456 status 457 = SecKeychainFindGenericPassword(keychain, 458 CFDataGetLength(unique_id), 459 (const char *)CFDataGetBytePtr(unique_id), 460 0, 461 NULL, 462 NULL, 463 NULL, 464 &item); 465 CFRelease(unique_id); 466 *ret_item = NULL; 467 if (status != noErr) { 468#if TEST_EAPKEYCHAINUTIL 469 fprintf(stderr, "SecKeychainFindGenericPassword failed: %s (%d)\n", 470 EAPSecurityErrorString(status), (int)status); 471#endif /* TEST_EAPKEYCHAINUTIL */ 472 } 473 else { 474 *ret_item = item; 475 } 476 return (status); 477} 478 479STATIC CFStringRef 480SecKeychainAttrTypeGetCFString(SecKeychainAttrType type) 481{ 482 int i; 483 const CFStringSecItemTag * tbl; 484 485 for (i = 0, tbl = prop_tag_tbl; i < prop_tag_tbl_size; i++, tbl++) { 486 if (tbl->tag == type) { 487 return (*tbl->key); 488 } 489 } 490 return (NULL); 491} 492 493STATIC OSStatus 494KeychainItemCopyInfo(SecKeychainItemRef item, 495 CFArrayRef keys, 496 CFDictionaryRef * ret_attrs) 497{ 498 CFMutableDictionaryRef attrs = NULL; 499 int i; 500 void * password_data = NULL; 501 UInt32 password_length = 0; 502 void * * password_data_p; 503 UInt32 * password_length_p; 504 CFRange range = CFRangeMake(0, CFArrayGetCount(keys)); 505 mySecKeychainAttributeInfo req_attr_info; 506 SecKeychainAttributeInfo * req_attr_info_p; 507 SecKeychainAttributeList * ret_attr_list = NULL; 508 SecKeychainAttributeList * *ret_attr_list_p; 509 OSStatus status; 510 511 mySecKeychainAttributeInfoInit(&req_attr_info); 512 if (CFArrayContainsValue(keys, range, kEAPSecKeychainPropAccount)) { 513 mySecKeychainAttributeInfoAdd(&req_attr_info, 514 kSecAccountItemAttr); 515 } 516 if (CFArrayContainsValue(keys, range, kEAPSecKeychainPropLabel)) { 517 mySecKeychainAttributeInfoAdd(&req_attr_info, 518 kSecLabelItemAttr); 519 } 520 if (CFArrayContainsValue(keys, range, kEAPSecKeychainPropDescription)) { 521 mySecKeychainAttributeInfoAdd(&req_attr_info, 522 kSecDescriptionItemAttr); 523 } 524 if (CFArrayContainsValue(keys, range, kEAPSecKeychainPropPassword)) { 525 password_data_p = &password_data; 526 password_length_p = &password_length; 527 } 528 else { 529 password_data_p = NULL; 530 password_length_p = NULL; 531 } 532 if (req_attr_info.info.count != 0) { 533 req_attr_info_p = &req_attr_info.info; 534 ret_attr_list_p = &ret_attr_list; 535 } 536 else { 537 req_attr_info_p = NULL; 538 ret_attr_list_p = NULL; 539 } 540 status = SecKeychainItemCopyAttributesAndData(item, 541 req_attr_info_p, 542 NULL, 543 ret_attr_list_p, 544 password_length_p, 545 password_data_p); 546 if (status != noErr) { 547 goto done; 548 } 549 attrs = CFDictionaryCreateMutable(NULL, 0, 550 &kCFTypeDictionaryKeyCallBacks, 551 &kCFTypeDictionaryValueCallBacks); 552 if (password_data != NULL && password_length != 0) { 553 CFDataRef password; 554 555 password = CFDataCreate(NULL, password_data, password_length); 556 CFDictionarySetValue(attrs, kEAPSecKeychainPropPassword, password); 557 CFRelease(password); 558 } 559 if (ret_attr_list != NULL) { 560 SecKeychainAttribute * attr = ret_attr_list->attr; 561 562 for (i = 0; i < ret_attr_list->count; i++, attr++) { 563 CFStringRef key; 564 CFDataRef val; 565 566 if (attr->data == NULL || attr->length == 0) { 567 continue; 568 } 569 key = SecKeychainAttrTypeGetCFString(attr->tag); 570 if (key == NULL) { 571 /* shouldn't happen */ 572 continue; 573 } 574 val = CFDataCreate(NULL, attr->data, attr->length); 575 CFDictionarySetValue(attrs, key, val); 576 CFRelease(val); 577 } 578 } 579 SecKeychainItemFreeAttributesAndData(ret_attr_list, password_data); 580 581 done: 582 *ret_attrs = attrs; 583 return (status); 584 585} 586 587OSStatus 588EAPSecKeychainPasswordItemRemove(SecKeychainRef keychain, 589 CFStringRef unique_id_str) 590{ 591 SecKeychainItemRef item; 592 OSStatus status; 593 594 status = KeychainPasswordItemCopy(keychain, unique_id_str, &item); 595 if (status != noErr) { 596 goto done; 597 } 598 status = SecKeychainItemDelete(item); 599 CFRelease(item); 600 if (status != noErr) { 601 EAPLOG_FL(LOG_NOTICE, "SecKeychainItemDelete() failed: %s (%d)", 602 EAPSecurityErrorString(status), (int)status); 603 604 } 605 done: 606 return (status); 607} 608 609OSStatus 610EAPSecKeychainPasswordItemCopy2(SecKeychainRef keychain, 611 CFStringRef unique_id_str, 612 CFArrayRef keys, 613 CFDictionaryRef * ret_values) 614{ 615 SecKeychainItemRef item = NULL; 616 OSStatus status; 617 618 *ret_values = NULL; 619 status = KeychainPasswordItemCopy(keychain, unique_id_str, &item); 620 if (status == noErr) { 621 status = KeychainItemCopyInfo(item, keys, ret_values); 622 } 623 if (item != NULL) { 624 CFRelease(item); 625 } 626 return (status); 627} 628 629OSStatus 630EAPSecKeychainPasswordItemCopy(SecKeychainRef keychain, 631 CFStringRef unique_id_str, 632 CFDataRef * ret_password) 633{ 634 CFDataRef password; 635 CFDictionaryRef props; 636 CFArrayRef req_props; 637 OSStatus status; 638 639 *ret_password = NULL; 640 req_props = CFArrayCreate(NULL, 641 (const void * *)&kEAPSecKeychainPropPassword, 1, 642 &kCFTypeArrayCallBacks); 643 status = EAPSecKeychainPasswordItemCopy2(keychain, 644 unique_id_str, 645 req_props, 646 &props); 647 CFRelease(req_props); 648 if (status != noErr) { 649 return (status); 650 } 651 password = CFDictionaryGetValue(props, kEAPSecKeychainPropPassword); 652 if (password == NULL) { 653 status = errSecItemNotFound; 654 } 655 else { 656 *ret_password = CFRetain(password); 657 } 658 CFRelease(props); 659 return (status); 660} 661 662OSStatus 663EAPSecKeychainPasswordItemCreateWithAccess(SecKeychainRef keychain, 664 SecAccessRef access, 665 CFStringRef unique_id_str, 666 CFDataRef label, 667 CFDataRef description, 668 CFDataRef user, 669 CFDataRef password) 670{ 671 mySecKeychainAttributeList attr_list; 672 OSStatus status; 673 CFDataRef unique_id; 674 675 unique_id = CFStringCreateExternalRepresentation(NULL, 676 unique_id_str, 677 kCFStringEncodingUTF8, 678 0); 679 mySecKeychainAttributeListInit(&attr_list); 680 mySecKeychainAttributeListAdd(&attr_list, kSecServiceItemAttr, unique_id); 681 if (label != NULL) { 682 mySecKeychainAttributeListAdd(&attr_list, kSecLabelItemAttr, label); 683 } 684 if (description != NULL) { 685 mySecKeychainAttributeListAdd(&attr_list, kSecDescriptionItemAttr, 686 description); 687 } 688 if (user != NULL) { 689 mySecKeychainAttributeListAdd(&attr_list, kSecAccountItemAttr, user); 690 } 691 status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, 692 &attr_list.list, 693 CFDataGetLength(password), 694 CFDataGetBytePtr(password), 695 keychain, 696 access, 697 NULL); 698 CFRelease(unique_id); 699 return (status); 700} 701 702OSStatus 703EAPSecKeychainPasswordItemCreate(SecKeychainRef keychain, 704 CFStringRef unique_id_str, 705 CFDictionaryRef attrs) 706{ 707 CFBooleanRef allow_root; 708 SecAccessRef access = NULL; 709 mySecKeychainAttributeList attr_list; 710 CFDataRef password; 711 void * password_data; 712 UInt32 password_length; 713 OSStatus status; 714 CFArrayRef trusted_apps; 715 CFDataRef unique_id = NULL; 716 717 password = CFDictionaryGetValue(attrs, kEAPSecKeychainPropPassword); 718 if (password != NULL) { 719 /* set it */ 720 password_length = CFDataGetLength(password); 721 password_data = (void *)CFDataGetBytePtr(password); 722 } 723 else { 724 /* don't set it */ 725 password_length = 0; 726 password_data = NULL; 727 } 728 trusted_apps = CFDictionaryGetValue(attrs, 729 kEAPSecKeychainPropTrustedApplications); 730 allow_root = CFDictionaryGetValue(attrs, 731 kEAPSecKeychainPropAllowRootAccess); 732 if (trusted_apps != NULL) { 733 CFDataRef label_data; 734 735 label_data = CFDictionaryGetValue(attrs, 736 kEAPSecKeychainPropLabel); 737 status = EAPSecAccessCreateWithTrustedApplications(trusted_apps, 738 label_data, 739 &access); 740 if (status != noErr) { 741 EAPLOG_FL(LOG_NOTICE, 742 "failed to get SecAccess for Trusted Apps, %d", 743 (int)status); 744 goto done; 745 } 746 } 747 else if (allow_root != NULL && CFBooleanGetValue(allow_root)) { 748 CFErrorRef error; 749 750 access = SecAccessCreateWithOwnerAndACL(0, 0, kSecUseOnlyUID, 751 NULL, &error); 752 if (access == NULL) { 753 status = errSecAllocate; 754 if (error != NULL) { 755 EAPLOG_FL(LOG_NOTICE, 756 "SecAccessCreateWithOwnerAndACL() failed %d", 757 (int)CFErrorGetCode(error)); 758 CFRelease(error); 759 } 760 goto done; 761 } 762 } 763 mySecKeychainAttributeListInit(&attr_list); 764 unique_id = CFStringCreateExternalRepresentation(NULL, 765 unique_id_str, 766 kCFStringEncodingUTF8, 767 0); 768 mySecKeychainAttributeListAdd(&attr_list, kSecServiceItemAttr, unique_id); 769 if (mySecKeychainAttributeListAddFromDict(&attr_list, attrs) == FALSE) { 770 status = errSecBufferTooSmall; 771 } 772 else { 773 status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, 774 &attr_list.list, 775 password_length, 776 password_data, 777 keychain, 778 access, 779 NULL); 780 } 781 782 done: 783 my_CFRelease(&unique_id); 784 my_CFRelease(&access); 785 return (status); 786} 787 788OSStatus 789EAPSecKeychainPasswordItemCreateUnique(SecKeychainRef keychain, 790 CFDictionaryRef attrs, 791 CFStringRef * ret_unique_id) 792{ 793 OSStatus status; 794 CFStringRef unique_id_str; 795 796 unique_id_str = my_CFUUIDStringCreate(NULL); 797 status = EAPSecKeychainPasswordItemCreate(keychain, 798 unique_id_str, 799 attrs); 800 if (status == noErr && ret_unique_id != NULL) { 801 *ret_unique_id = unique_id_str; 802 } 803 else { 804 if (ret_unique_id != NULL) { 805 *ret_unique_id = NULL; 806 } 807 CFRelease(unique_id_str); 808 } 809 return (status); 810} 811 812OSStatus 813EAPSecKeychainPasswordItemSet(SecKeychainRef keychain, 814 CFStringRef unique_id_str, 815 CFDataRef password) 816{ 817 SecKeychainItemRef item; 818 OSStatus status; 819 820 status = KeychainPasswordItemCopy(keychain, unique_id_str, &item); 821 if (status != noErr) { 822 return (status); 823 } 824 status = SecKeychainItemModifyAttributesAndData(item, 825 NULL, 826 CFDataGetLength(password), 827 CFDataGetBytePtr(password)); 828 CFRelease(item); 829 return (status); 830} 831 832OSStatus 833EAPSecKeychainPasswordItemSet2(SecKeychainRef keychain, 834 CFStringRef unique_id_str, 835 CFDictionaryRef attrs) 836{ 837 mySecKeychainAttributeList attr_list; 838 SecKeychainItemRef item; 839 CFDataRef password; 840 void * password_data; 841 UInt32 password_length; 842 OSStatus status; 843 844 status = KeychainPasswordItemCopy(keychain, unique_id_str, &item); 845 if (status != noErr) { 846 return (status); 847 } 848 mySecKeychainAttributeListInit(&attr_list); 849 if (mySecKeychainAttributeListAddFromDict(&attr_list, attrs) == FALSE) { 850 status = errSecBufferTooSmall; 851 goto done; 852 } 853 password = CFDictionaryGetValue(attrs, kEAPSecKeychainPropPassword); 854 if (password != NULL) { 855 /* set it */ 856 password_length = CFDataGetLength(password); 857 password_data = (void *)CFDataGetBytePtr(password); 858 } 859 else { 860 /* don't set it */ 861 password_length = 0; 862 password_data = NULL; 863 } 864 status = SecKeychainItemModifyAttributesAndData(item, 865 &attr_list.list, 866 password_length, 867 password_data); 868 done: 869 CFRelease(item); 870 return (status); 871} 872 873#endif /* TARGET_OS_EMBEDDED */ 874 875OSStatus 876EAPSecKeychainPasswordItemCreateUniqueWithAccess(SecKeychainRef keychain, 877 SecAccessRef access, 878 CFDataRef label, 879 CFDataRef description, 880 CFDataRef user, 881 CFDataRef password, 882 CFStringRef * ret_unique_id) 883{ 884 OSStatus status; 885 CFStringRef unique_id_str; 886 887 unique_id_str = my_CFUUIDStringCreate(NULL); 888 status = EAPSecKeychainPasswordItemCreateWithAccess(keychain, 889 access, 890 unique_id_str, 891 label, 892 description, 893 user, 894 password); 895 if (status == noErr && ret_unique_id != NULL) { 896 *ret_unique_id = unique_id_str; 897 } 898 else { 899 if (ret_unique_id != NULL) { 900 *ret_unique_id = NULL; 901 } 902 CFRelease(unique_id_str); 903 } 904 return (status); 905} 906 907#ifdef TEST_EAPKEYCHAINUTIL 908 909#if ! TARGET_OS_EMBEDDED 910/* 911 * Create a SecAccessRef with a custom form. 912 * Both the owner and the ACL set allow free access to root, 913 * but nothing to anyone else. 914 * NOTE: This is not the easiest way to build up CSSM data structures. 915 * But it's a way that does not depend on any outside software layers 916 * (other than CSSM and Security's Sec* layer, of course). 917 */ 918static OSStatus 919SecKeychainCopySystemKeychain(SecKeychainRef * ret_keychain) 920{ 921 SecKeychainRef keychain = NULL; 922 OSStatus status; 923 924 status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, 925 &keychain); 926 if (status != noErr && keychain != NULL) { 927 CFRelease(keychain); 928 keychain = NULL; 929 } 930 *ret_keychain = keychain; 931 return (status); 932} 933 934#endif /* ! TARGET_OS_EMBEDDED */ 935 936#if TARGET_OS_EMBEDDED 937#define SYS_OPT " " 938#else /* TARGET_OS_EMBEDDED */ 939#define SYS_OPT " [system] " 940#define HAS_KEYCHAINS 941#endif /* TARGET_OS_EMBEDDED */ 942 943static void 944usage(const char * progname) 945{ 946 fprintf(stderr, "%s" SYS_OPT 947 "create <label> <description> <username> <password>\n", 948 progname); 949 fprintf(stderr, 950 "%s" SYS_OPT "set <unique_id> <username> <password>\n", 951 progname); 952 fprintf(stderr, "%s" SYS_OPT "remove <unique_id>\n", progname); 953 fprintf(stderr, "%s" SYS_OPT "get <unique_id>\n", progname); 954 exit(1); 955} 956 957typedef enum { 958 kCommandUnknown, 959 kCommandCreate, 960 kCommandRemove, 961 kCommandSet, 962 kCommandGet 963} Command; 964 965#define keapolclientPath "/System/Library/SystemConfiguration/EAPOLController.bundle/Contents/Resources/eapolclient" 966#define kAirPortApplicationGroup "AirPort" 967#define kSystemUIServerPath "/System/Library/CoreServices/SystemUIServer.app" 968 969STATIC CFArrayRef 970copy_trusted_applications(void) 971{ 972 CFMutableArrayRef array; 973 SecTrustedApplicationRef trusted_app; 974 OSStatus status; 975 976 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 977 978 /* this executable */ 979 status = SecTrustedApplicationCreateFromPath(NULL, &trusted_app); 980 if (status != noErr) { 981 fprintf(stderr, 982 "SecTrustedApplicationCreateFromPath(NULL) failed, %d\n", 983 status); 984 } 985 else { 986 CFArrayAppendValue(array, trusted_app); 987 CFRelease(trusted_app); 988 } 989 990 /* eapolclient */ 991 status = SecTrustedApplicationCreateFromPath(keapolclientPath, 992 &trusted_app); 993 if (status != noErr) { 994 fprintf(stderr, 995 "SecTrustedApplicationCreateFromPath(%s) failed, %d\n", 996 keapolclientPath, 997 status); 998 } 999 else { 1000 CFArrayAppendValue(array, trusted_app); 1001 CFRelease(trusted_app); 1002 } 1003 1004 1005 /* SystemUIServer */ 1006 status = SecTrustedApplicationCreateFromPath(kSystemUIServerPath, 1007 &trusted_app); 1008 if (status != noErr) { 1009 fprintf(stderr, 1010 "SecTrustedApplicationCreateFromPath(%s) failed, %d\n", 1011 kSystemUIServerPath, 1012 status); 1013 } 1014 else { 1015 CFArrayAppendValue(array, trusted_app); 1016 CFRelease(trusted_app); 1017 } 1018 1019 /* AirPort Application Group */ 1020 status 1021 = SecTrustedApplicationCreateApplicationGroup(kAirPortApplicationGroup, 1022 NULL, &trusted_app); 1023 if (status != noErr) { 1024 fprintf(stderr, 1025 "SecTrustedApplicationCreateApplicationGroup(" 1026 kAirPortApplicationGroup ") failed, %d\n", 1027 status); 1028 } 1029 else { 1030 CFArrayAppendValue(array, trusted_app); 1031 CFRelease(trusted_app); 1032 } 1033 if (CFArrayGetCount(array) == 0) { 1034 my_CFRelease(&array); 1035 } 1036 return (array); 1037} 1038 1039int 1040main(int argc, const char *argv[]) 1041{ 1042 Command cmd = kCommandUnknown; 1043 SecKeychainRef keychain = NULL; 1044 const char * progname = argv[0]; 1045 OSStatus status; 1046#ifdef HAS_KEYCHAINS 1047 bool use_system = FALSE; 1048#endif 1049 1050 if (argc < 2) { 1051 usage(progname); 1052 } 1053#ifdef HAS_KEYCHAINS 1054 if (strcmp(argv[1], "system") == 0) { 1055 if (argc < 3) { 1056 usage(progname); 1057 } 1058 use_system = TRUE; 1059 status = SecKeychainCopySystemKeychain(&keychain); 1060 if (status != noErr) { 1061 fprintf(stderr, "SecKeychainCopySystemKeychain failed, %s (%d)\n", 1062 EAPSecurityErrorString(status), (int)status); 1063 exit(1); 1064 } 1065 argc--; 1066 argv++; 1067 } 1068#endif /* HAS_KEYCHAINS */ 1069 1070 if (strcmp(argv[1], "create") == 0) { 1071 if (argc < 6) { 1072 usage(progname); 1073 } 1074 cmd = kCommandCreate; 1075 } 1076 else if (strcmp(argv[1], "set") == 0) { 1077 if (argc < 5) { 1078 usage(progname); 1079 } 1080 cmd = kCommandSet; 1081 } 1082 else if (strcmp(argv[1], "get") == 0) { 1083 if (argc < 3) { 1084 usage(progname); 1085 } 1086 cmd = kCommandGet; 1087 } 1088 else if (strcmp(argv[1], "remove") == 0) { 1089 if (argc < 3) { 1090 usage(progname); 1091 } 1092 cmd = kCommandRemove; 1093 } 1094 else { 1095 usage(progname); 1096 } 1097 switch (cmd) { 1098 case kCommandSet: { 1099 CFMutableDictionaryRef attrs = NULL; 1100 CFDataRef password; 1101 CFArrayRef trusted_apps; 1102 CFStringRef unique_id_str; 1103 CFDataRef username; 1104 1105 unique_id_str 1106 = CFStringCreateWithCStringNoCopy(NULL, 1107 argv[2], 1108 kCFStringEncodingUTF8, 1109 kCFAllocatorNull); 1110 username 1111 = CFDataCreateWithBytesNoCopy(NULL, 1112 (const UInt8 *)argv[3], 1113 strlen(argv[3]), 1114 kCFAllocatorNull); 1115 password 1116 = CFDataCreateWithBytesNoCopy(NULL, 1117 (const UInt8 *)argv[4], 1118 strlen(argv[4]), 1119 kCFAllocatorNull); 1120 attrs = CFDictionaryCreateMutable(NULL, 0, 1121 &kCFTypeDictionaryKeyCallBacks, 1122 &kCFTypeDictionaryValueCallBacks); 1123 CFDictionarySetValue(attrs, kEAPSecKeychainPropAccount, 1124 username); 1125 CFDictionarySetValue(attrs, kEAPSecKeychainPropPassword, 1126 password); 1127 trusted_apps = copy_trusted_applications(); 1128 CFDictionarySetValue(attrs, kEAPSecKeychainPropTrustedApplications, 1129 trusted_apps); 1130 CFRelease(trusted_apps); 1131 status = EAPSecKeychainPasswordItemSet2(keychain, 1132 unique_id_str, 1133 attrs); 1134 if (status != noErr) { 1135 fprintf(stderr, "EAPSecKeychainItemSet2 failed %s (%d)\n", 1136 EAPSecurityErrorString(status), (int)status); 1137 exit(2); 1138 } 1139 my_CFRelease(&password); 1140 break; 1141 } 1142 case kCommandCreate: { 1143 SecAccessRef access = NULL; 1144 CFMutableDictionaryRef attrs = NULL; 1145 CFDataRef data; 1146 CFArrayRef trusted_apps; 1147 CFDataRef unique_id; 1148 CFStringRef unique_id_str = NULL; 1149 1150#ifdef HAS_KEYCHAINS 1151 if (use_system) { 1152 CFErrorRef error; 1153 1154 access = SecAccessCreateWithOwnerAndACL(0, 0, kSecUseOnlyUID, 1155 NULL, &error); 1156 if (access == NULL) { 1157 if (error != NULL) { 1158 fprintf(stderr, 1159 "SecAccessCreateWithOwnerAndACL() failed %d\n", 1160 (int)CFErrorGetCode(error)); 1161 } 1162 exit(2); 1163 } 1164 } 1165 else { 1166 status = SecAccessCreate(CFSTR("keychain"), NULL, &access); 1167 if (status != noErr) { 1168 fprintf(stderr, "SecAccessCreate failed, %s (%d)\n", 1169 EAPSecurityErrorString(status), (int)status); 1170 exit(2); 1171 } 1172 } 1173#endif /* HAS_KEYCHAINS */ 1174 1175 attrs = CFDictionaryCreateMutable(NULL, 0, 1176 &kCFTypeDictionaryKeyCallBacks, 1177 &kCFTypeDictionaryValueCallBacks); 1178 1179 /* label */ 1180 data = CFDataCreateWithBytesNoCopy(NULL, 1181 (const UInt8 *)argv[2], 1182 strlen(argv[2]), 1183 kCFAllocatorNull); 1184 CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, data); 1185 CFRelease(data); 1186 1187 /* description */ 1188 data = CFDataCreateWithBytesNoCopy(NULL, 1189 (const UInt8 *)argv[3], 1190 strlen(argv[3]), 1191 kCFAllocatorNull); 1192 CFDictionarySetValue(attrs, kEAPSecKeychainPropDescription, 1193 data); 1194 CFRelease(data); 1195 1196 /* name */ 1197 data = CFDataCreateWithBytesNoCopy(NULL, 1198 (const UInt8 *)argv[4], 1199 strlen(argv[4]), 1200 kCFAllocatorNull); 1201 CFDictionarySetValue(attrs, kEAPSecKeychainPropAccount, 1202 data); 1203 CFRelease(data); 1204 1205 /* password */ 1206 data = CFDataCreateWithBytesNoCopy(NULL, 1207 (const UInt8 *)argv[5], 1208 strlen(argv[5]), 1209 kCFAllocatorNull); 1210 CFDictionarySetValue(attrs, kEAPSecKeychainPropPassword, 1211 data); 1212 CFRelease(data); 1213 1214 /* trusted apps */ 1215 trusted_apps = copy_trusted_applications(); 1216 CFDictionarySetValue(attrs, kEAPSecKeychainPropTrustedApplications, 1217 trusted_apps); 1218 CFRelease(trusted_apps); 1219 1220 if (argc > 6) { 1221 unique_id_str 1222 = CFStringCreateWithCStringNoCopy(NULL, 1223 argv[6], 1224 kCFStringEncodingUTF8, 1225 kCFAllocatorNull); 1226 status 1227 = EAPSecKeychainPasswordItemCreate(keychain, 1228 unique_id_str, 1229 attrs); 1230 if (status != noErr) { 1231 fprintf(stderr, "EAPSecKeychainItemCreate failed," 1232 " %s (%d)\n", 1233 EAPSecurityErrorString(status), (int)status); 1234 exit(1); 1235 } 1236 } 1237 else { 1238 status 1239 = EAPSecKeychainPasswordItemCreateUnique(keychain, 1240 attrs, 1241 &unique_id_str); 1242 1243 if (status != noErr) { 1244 fprintf(stderr, 1245 "EAPSecKeychainItemCreateUniqueWithAccessfailed," 1246 " %s (%d)\n", 1247 EAPSecurityErrorString(status), (int)status); 1248 exit(1); 1249 } 1250 } 1251 unique_id 1252 = CFStringCreateExternalRepresentation(NULL, 1253 unique_id_str, 1254 kCFStringEncodingUTF8, 1255 0); 1256 fwrite(CFDataGetBytePtr(unique_id), 1257 CFDataGetLength(unique_id), 1, stdout); 1258 printf("\n"); 1259 CFRelease(attrs); 1260 break; 1261 } 1262 case kCommandGet: 1263 case kCommandRemove: { 1264 CFStringRef unique_id_str; 1265 1266 unique_id_str 1267 = CFStringCreateWithCStringNoCopy(NULL, 1268 argv[2], 1269 kCFStringEncodingUTF8, 1270 kCFAllocatorNull); 1271 if (cmd == kCommandRemove) { 1272 status 1273 = EAPSecKeychainPasswordItemRemove(keychain, unique_id_str); 1274 if (status != noErr) { 1275 fprintf(stderr, 1276 "EAPSecKeychainItemRemove failed, %s (%d)\n", 1277 EAPSecurityErrorString(status), (int)status); 1278 exit(2); 1279 } 1280 } 1281 else { 1282 CFDictionaryRef attrs; 1283 const void * keys[] = { 1284 kEAPSecKeychainPropPassword, 1285 kEAPSecKeychainPropAccount, 1286 kEAPSecKeychainPropLabel, 1287 kEAPSecKeychainPropDescription 1288 }; 1289 int keys_count = sizeof(keys) / sizeof(keys[0]); 1290 CFDataRef password = NULL; 1291 CFArrayRef req_props; 1292 OSStatus status; 1293 CFDataRef username = NULL; 1294 1295 req_props = CFArrayCreate(NULL, 1296 keys, keys_count, 1297 &kCFTypeArrayCallBacks); 1298 status = EAPSecKeychainPasswordItemCopy2(keychain, 1299 unique_id_str, 1300 req_props, 1301 &attrs); 1302 CFRelease(req_props); 1303 if (status != noErr) { 1304 fprintf(stderr, 1305 "EAPSecKeychainPasswordItemCopy2 failed, %s (%d)\n", 1306 EAPSecurityErrorString(status), (int)status); 1307 exit(2); 1308 } 1309 CFShow(attrs); 1310 password = CFDictionaryGetValue(attrs, 1311 kEAPSecKeychainPropPassword); 1312 username = CFDictionaryGetValue(attrs, 1313 kEAPSecKeychainPropAccount); 1314 if (password != NULL) { 1315 printf("Password = '"); 1316 fwrite(CFDataGetBytePtr(password), 1317 CFDataGetLength(password), 1, stdout); 1318 printf("'\n"); 1319 } 1320 if (username != NULL) { 1321 printf("Name = '"); 1322 fwrite(CFDataGetBytePtr(username), 1323 CFDataGetLength(username), 1, stdout); 1324 printf("'\n"); 1325 } 1326 CFRelease(attrs); 1327 } 1328 CFRelease(unique_id_str); 1329 } 1330 default: 1331 break; 1332 } 1333 if (keychain != NULL) { 1334 CFRelease(keychain); 1335 } 1336 exit(0); 1337 return (0); 1338} 1339 1340#endif /* TEST_EAPKEYCHAINUTIL */ 1341