1/* 2 * Copyright (c) 2007 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 <Security/Security.h> 25#include <err.h> 26#include <stdio.h> 27#include <unistd.h> 28 29static CFArrayRef 30getTrustedApps(const char *trustedApp) 31 CF_RETURNS_RETAINED; 32 33static CFArrayRef 34getTrustedApps(const char *trustedApp) 35{ 36 SecTrustedApplicationRef app; 37 void *values[1]; 38 OSStatus ret; 39 40 /* 41 * Create ACL, XXX should add acl, not modify ACL. 42 */ 43 44 ret = SecTrustedApplicationCreateFromPath(trustedApp, &app); 45 if (ret) 46 errx(1, "SecTrustedApplicationCreateFromPath"); 47 48 values[0] = app; 49 50 return CFArrayCreate(NULL, (const void **)values, 51 sizeof(values)/sizeof(values[0]), NULL); 52} 53 54 55 56static SecKeychainItemRef 57findKeychainItem(SecKeychainRef keychain, const char *label) 58{ 59 SecKeychainItemRef itemRef; 60 OSStatus ret; 61 62 SecKeychainSearchRef search; 63 SecKeychainAttribute attributes[1]; 64 SecKeychainAttributeList list; 65 66 attributes[0].tag = kSecLabelItemAttr; 67 attributes[0].data = (char *)(uintptr_t)label; 68 attributes[0].length = strlen(label); 69 70 list.count = 1; 71 list.attr = attributes; 72 73 /* Should only search the System keychain ! */ 74 ret = SecKeychainSearchCreateFromAttributes(keychain, 75 CSSM_DL_DB_RECORD_PRIVATE_KEY, 76 &list, 77 &search); 78 if (ret) 79 errx(1, "failure in SecKeychainSearchCreateFromAttributes"); 80 81 ret = SecKeychainSearchCopyNext(search, &itemRef); 82 CFRelease(search); 83 if (ret == errSecItemNotFound) 84 errx(1, "didn't find private key for: %s", label); 85 else if (ret) 86 errx(1, "Failure in SecKeychainSearchCopyNext: %d for %s", 87 ret, label); 88 89 return itemRef; 90} 91 92static void 93testSign(SecKeychainItemRef itemRef) 94{ 95 const CSSM_ACCESS_CREDENTIALS *creds; 96 CSSM_CC_HANDLE sigHandle = 0; 97 CSSM_CSP_HANDLE cspHandle; 98 const CSSM_KEY *cssmKey; 99 uint8_t to[4096]; 100 CSSM_DATA sig, in; 101 CSSM_RETURN cret; 102 SecKeyRef privKeyRef = (SecKeyRef)itemRef; 103 OSStatus ret; 104 105 106 cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); 107 if(cret) abort(); 108 109 cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); 110 if(cret) abort(); 111 112 ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN, 113 kSecCredentialTypeDefault, &creds); 114 if(ret) abort(); 115 116 ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, 117 creds, cssmKey, &sigHandle); 118 if(ret) abort(); 119 120 in.Data = (uint8 *)"test signature"; 121 in.Length = strlen((char *)in.Data); 122 123 sig.Data = to; 124 sig.Length = sizeof(to); 125 126 cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig); 127 if(cret) 128 errx(1, "failed to sign"); 129 130 CSSM_DeleteContext(sigHandle); 131 132 printf("signing worked\n"); 133} 134 135static int 136checkOnACLAlreadyAndRemoveAny(SecKeychainItemRef itemRef, 137 const char *trustedAppName) 138{ 139 SecAccessRef secaccess; 140 CFArrayRef aclList; 141 OSStatus ret; 142 SecACLRef acl; 143 int modified = 0, found = 0; 144 uint32 i, j; 145 146 ret = SecKeychainItemCopyAccess(itemRef, &secaccess); 147 if (ret) 148 errx(1, "SecKeychainItemCopyAccess"); 149 150 ret = SecAccessCopyACLList (secaccess, &aclList); 151 if (ret) 152 errx(1, "SecAccessCopyACLList"); 153 154 for (i = 0; i < CFArrayGetCount(aclList) && !found; i++) { 155 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR prompt; 156 CFStringRef description; 157 CFArrayRef apps; 158 159 acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, i); 160 161 /* 162 * XXX SecACLCopySimpleContents failes on "complex" 163 * entries, what is that and should I care ? 164 */ 165 166 ret = SecACLCopySimpleContents(acl, &apps, &description, &prompt); 167 if (ret) { 168 /* warnx("SecACLCopySimpleContents: %d: %d", i, (int)ret); */ 169 continue; 170 } 171 172 CFRelease(description); 173 174 if (apps == NULL) { 175 SecACLRemove(acl); 176 modified = 1; 177 printf("removing any access\n"); 178 } else { 179 for (j = 0; j < CFArrayGetCount(apps) && !found; j++) { 180 SecTrustedApplicationRef app; 181 CFDataRef data; 182 183 app = (SecTrustedApplicationRef)CFArrayGetValueAtIndex(apps, j); 184 185 ret = SecTrustedApplicationCopyData(app, &data); 186 if (ret) 187 errx(1, "SecTrustedApplicationCopyData"); 188 189 /* http://lists.apple.com/archives/apple-cdsa/2007/Dec/msg00021.html */ 190 if (strcmp(trustedAppName, (char *)CFDataGetBytePtr(data)) == 0) 191 found = 1; 192 193 CFRelease(data); 194 } 195 CFRelease(apps); 196 } 197 } 198 199 if (modified) { 200 ret = SecKeychainItemSetAccess(itemRef, secaccess); 201 if (ret) 202 errx(1, "SecKeychainItemSetAccess: %d (any access)", ret); 203 } 204 205 CFRelease(aclList); 206 CFRelease(secaccess); 207 208 return found; 209} 210 211static void 212addTrustedApplication(SecKeychainItemRef itemRef, 213 const char *trustedAppName, 214 const char *identity) 215{ 216 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR prompt; 217 CSSM_ACL_AUTHORIZATION_TAG tags[6]; 218 CFArrayRef trustedApps; 219 SecAccessRef secaccess; 220 SecACLRef acl; 221 OSStatus ret; 222 223 /* 224 * Check if we are already on the acl list 225 */ 226 227 if (checkOnACLAlreadyAndRemoveAny(itemRef, trustedAppName)) { 228 printf("%s already in acl\n", trustedAppName); 229 return; 230 } 231 232 /* 233 * Add new acl entry for our trusted app 234 */ 235 236 ret = SecKeychainItemCopyAccess(itemRef, &secaccess); 237 if (ret) 238 errx(1, "SecKeychainItemCopyAccess"); 239 240 prompt.version = CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION; 241 prompt.flags = 0; 242 243 trustedApps = getTrustedApps(trustedAppName); 244 if (trustedApps == NULL) 245 errx(1, "getTrustedApps"); 246 247 ret = SecACLCreateFromSimpleContents(secaccess, trustedApps, 248 CFSTR("lkdc-acl"), &prompt, 249 &acl); 250 if (ret) 251 errx(1, "SecACLCreateFromSimpleContents"); 252 253 tags[0] = CSSM_ACL_AUTHORIZATION_DECRYPT; 254 tags[1] = CSSM_ACL_AUTHORIZATION_DERIVE; 255 tags[2] = CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR; 256 tags[3] = CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED; 257 tags[4] = CSSM_ACL_AUTHORIZATION_MAC; 258 tags[5] = CSSM_ACL_AUTHORIZATION_SIGN; 259 260 ret = SecACLSetAuthorizations(acl, tags, sizeof(tags) / sizeof(tags[0])); 261 if (ret) 262 errx(1, "SecACLSetAuthorizations"); 263 264 ret = SecKeychainItemSetAccess(itemRef, secaccess); 265 if (ret) 266 errx(1, "SecKeychainItemSetAccess: %d", ret); 267 268 printf("added %s to acl for %s\n", trustedAppName, identity); 269 270 CFRelease(secaccess); 271} 272 273static void 274deleteAllACL(SecKeychainItemRef itemRef) 275{ 276 SecAccessRef secaccess; 277 CFArrayRef aclList; 278 OSStatus ret; 279 CFIndex i; 280 281 ret = SecKeychainItemCopyAccess(itemRef, &secaccess); 282 if (ret) 283 errx(1, "deleteAllACL: SecKeychainItemCopyAccess: %d", ret); 284 285 ret = SecAccessCopyACLList (secaccess, &aclList); 286 if (ret) 287 errx(1, "deleteAllACL: SecAccessCopyACLList %d", ret); 288 289 for (i = 0; i < CFArrayGetCount(aclList); i++) { 290 CSSM_ACL_AUTHORIZATION_TAG tags[30]; 291 uint32 j, tagcount = sizeof(tags)/sizeof(tags[0]); 292 SecACLRef acl; 293 294 acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, i); 295 296 ret = SecACLGetAuthorizations(acl, tags, &tagcount); 297 if (ret) 298 errx(1, "deleteAllACL: SecACLGetAuthorizations: %d", ret); 299 300 for (j = 0; j < tagcount; j++) { 301 /* skip owner */ 302 if (tags[j] == CSSM_ACL_AUTHORIZATION_CHANGE_ACL) 303 break; 304 } 305 if (j < tagcount) 306 continue; 307 308 ret = SecACLRemove(acl); 309 if (ret) 310 errx(1, "deleteAllACL: SecACLRemove: %d", ret); 311 } 312 313 ret = SecKeychainItemSetAccess(itemRef, secaccess); 314 if (ret) 315 errx(1, "deleteAllACL: SecKeychainItemSetAccess: %d", ret); 316 317 CFRelease(secaccess); 318} 319 320 321static void 322listACL(SecKeychainItemRef itemRef) 323{ 324 SecAccessRef secaccess; 325 CFArrayRef aclList; 326 SecACLRef acl; 327 OSStatus ret; 328 uint32 i, j; 329 330 ret = SecKeychainItemCopyAccess(itemRef, &secaccess); 331 if (ret) 332 errx(1, "SecKeychainItemCopyAccess"); 333 334 ret = SecAccessCopyACLList (secaccess, &aclList); 335 if (ret) 336 errx(1, "SecAccessCopyACLList"); 337 338 for (i = 0; i < CFArrayGetCount(aclList); i++) { 339 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR prompt; 340 CFStringRef description; 341 CFArrayRef apps; 342 343 acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, i); 344 345 printf("acl: %lu\n", (unsigned long)i); 346 347 /* 348 * XXX SecACLCopySimpleContents failes on "complex" 349 * entries, what is that and should I care ? 350 */ 351 352 ret = SecACLCopySimpleContents(acl, &apps, &description, &prompt); 353 if (ret) { 354 /* warnx("SecACLCopySimpleContents: %d: %d", i, (int)ret); */ 355 continue; 356 } 357 358 if (description) { 359 size_t len; 360 char *str; 361 362 len = CFStringGetMaximumSizeForEncoding( 363 CFStringGetLength(description), kCFStringEncodingUTF8); 364 len += 1; 365 366 str = malloc(len); 367 if (str == NULL) 368 errx(1, "out of memory"); 369 370 CFStringGetCString(description, str, len, kCFStringEncodingUTF8); 371 printf("\tdescription: %s\n", str); 372 free(str); 373 CFRelease(description); 374 } 375 376 { 377 CSSM_ACL_AUTHORIZATION_TAG tags[30]; 378 uint32 k, tagcount = sizeof(tags)/sizeof(tags[0]); 379 380 ret = SecACLGetAuthorizations(acl, tags, &tagcount); 381 if (ret) 382 errx(1, "listAcl: SecACLGetAuthorizations: %d", ret); 383 384 printf("\ttags: "); 385 for (k = 0; k < tagcount; k++) 386 printf("%d ", tags[k]); 387 printf("\n"); 388 389 } 390 391 if (apps == NULL) { 392 printf("\tany ACL\n"); 393 } else { 394 for (j = 0; j < CFArrayGetCount(apps); j++) { 395 SecTrustedApplicationRef app; 396 CFDataRef data; 397 398 app = (SecTrustedApplicationRef)CFArrayGetValueAtIndex(apps, j); 399 400 ret = SecTrustedApplicationCopyData(app, &data); 401 if (ret) 402 errx(1, "SecTrustedApplicationCopyData"); 403 404 /* http://lists.apple.com/archives/apple-cdsa/2007/Dec/msg00021.html */ 405 printf("\tapp: %s\n", (char *)CFDataGetBytePtr(data)); 406 CFRelease(data); 407 } 408 CFRelease(apps); 409 } 410 } 411 412 CFRelease(aclList); 413 CFRelease(secaccess); 414} 415 416static void 417usage(int exit_code) 418{ 419 printf("%s -s identity -t\t\t\ttest using identitys key\n", 420 getprogname()); 421 printf("%s -s identity -a application\tadd appliction to acl\n", 422 getprogname()); 423 printf("%s -s identity -D\t\t\tdelete all ACL\n", 424 getprogname()); 425 printf("%s -s identity -l\t\t\tlist ACL\n", 426 getprogname()); 427 exit(exit_code); 428} 429 430extern int optind; 431extern char *optarg; 432 433int 434main(int argc, char **argv) 435{ 436 SecKeychainItemRef itemRef; 437 SecKeychainRef keychain = NULL; 438 int ch, test_sign = 0, delete_all = 0, do_list = 0; 439 const char *trustedAppName = NULL; 440 const char *identity = NULL; 441 442 setprogname(argv[0]); 443 444 while ((ch = getopt(argc, argv, "Da:s:tl?h")) != -1) { 445 switch(ch) { 446 case 'D': 447 delete_all = 1; 448 break; 449 case 'a': 450 trustedAppName = optarg; 451 break; 452 case 'l': 453 do_list = 1; 454 break; 455 case 's': 456 identity = optarg; 457 break; 458 case 't': 459 test_sign = 1; 460 break; 461 case '?': 462 case 'h': 463 usage(0); 464 break; 465 } 466 } 467 468 if (identity == NULL) { 469 fprintf(stderr, "no identity given\n"); 470 usage(1); 471 } 472 473 SecKeychainSetUserInteractionAllowed(FALSE); 474 475 itemRef = findKeychainItem(keychain, identity); 476 477 if (test_sign) 478 testSign(itemRef); 479 480 if (delete_all) 481 deleteAllACL(itemRef); 482 483 if (trustedAppName) 484 addTrustedApplication(itemRef, trustedAppName, identity); 485 486 if (do_list) 487 listACL(itemRef); 488 489 return 0; 490} 491