STATIC SecTrustedApplicationRef create_trusted_app_from_bundle_resource(CFStringRef bundle_path, CFStringRef resource_path) { CFBundleRef bundle; CFURLRef bundle_url; CFURLRef eapolclient_url = NULL; char path[MAXPATHLEN]; Boolean success = FALSE; SecTrustedApplicationRef trusted_app = NULL; bundle_url = CFURLCreateWithFileSystemPath(NULL, bundle_path, kCFURLPOSIXPathStyle, FALSE); if (bundle_url == NULL) { goto done; } bundle = CFBundleCreate(NULL, bundle_url); CFRelease(bundle_url); if (bundle == NULL) { goto done; } eapolclient_url = CFBundleCopyResourceURL(bundle, CFSTR(keapolclientPath), NULL, NULL); CFRelease(bundle); if (eapolclient_url == NULL) { goto done; } success = CFURLGetFileSystemRepresentation(eapolclient_url, TRUE, (UInt8 *)path, sizeof(path)); CFRelease(eapolclient_url); if (success) { OSStatus status; status = SecTrustedApplicationCreateFromPath(path, &trusted_app); if (status != noErr) { fprintf(stderr, "SecTrustedApplicationCreateFromPath(%s) failed, %d\n", path, (int)status); } } done: return (trusted_app); }
/* app path string to SecTrustedApplicationRef */ SecTrustedApplicationRef appPathToAppRef( const char *appPath) { SecTrustedApplicationRef appRef = NULL; OSStatus ortn; if(appPath == NULL) { return NULL; } ortn = SecTrustedApplicationCreateFromPath(appPath, &appRef); if(ortn) { cssmPerror("SecTrustedApplicationCreateFromPath", ortn); return NULL; } return appRef; }
int keychain_import(int argc, char * const *argv) { int ch, result = 0; char *inFile = NULL; char *kcName = NULL; SecKeychainRef kcRef = NULL; SecExternalFormat externFormat = kSecFormatUnknown; SecExternalItemType itemType = kSecItemTypeUnknown; Boolean wrapped = FALSE; Boolean nonExtractable = FALSE; const char *passphrase = NULL; unsigned char *inFileData = NULL; unsigned inFileLen = 0; CFDataRef inData = NULL; unsigned numExtendedAttributes = 0; char **attrNames = NULL; char **attrValues = NULL; Boolean access_specified = FALSE; Boolean always_allow = FALSE; SecAccessRef access = NULL; CFMutableArrayRef trusted_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if(argc < 2) { result = 2; /* @@@ Return 2 triggers usage message. */ goto cleanup; } inFile = argv[1]; if((argc == 2) && (inFile[0] == '-')) { result = 2; goto cleanup; } optind = 2; while ((ch = getopt(argc, argv, "k:t:f:P:wxa:hAT:")) != -1) { switch (ch) { case 'k': kcName = optarg; break; case 't': if(!strcmp("pub", optarg)) { itemType = kSecItemTypePublicKey; } else if(!strcmp("priv", optarg)) { itemType = kSecItemTypePrivateKey; } else if(!strcmp("session", optarg)) { itemType = kSecItemTypeSessionKey; } else if(!strcmp("cert", optarg)) { itemType = kSecItemTypeCertificate; } else if(!strcmp("agg", optarg)) { itemType = kSecItemTypeAggregate; } else { result = 2; /* @@@ Return 2 triggers usage message. */ goto cleanup; } break; case 'f': if(!strcmp("openssl", optarg)) { externFormat = kSecFormatOpenSSL; } else if(!strcmp("openssh1", optarg)) { externFormat = kSecFormatSSH; } else if(!strcmp("openssh2", optarg)) { externFormat = kSecFormatSSHv2; } else if(!strcmp("bsafe", optarg)) { externFormat = kSecFormatBSAFE; } else if(!strcmp("raw", optarg)) { externFormat = kSecFormatRawKey; } else if(!strcmp("pkcs7", optarg)) { externFormat = kSecFormatPKCS7; } else if(!strcmp("pkcs8", optarg)) { externFormat = kSecFormatWrappedPKCS8; } else if(!strcmp("pkcs12", optarg)) { externFormat = kSecFormatPKCS12; } else if(!strcmp("netscape", optarg)) { externFormat = kSecFormatNetscapeCertSequence; } else if(!strcmp("x509", optarg)) { externFormat = kSecFormatX509Cert; } else if(!strcmp("pemseq", optarg)) { externFormat = kSecFormatPEMSequence; } else { result = 2; /* @@@ Return 2 triggers usage message. */ goto cleanup; } break; case 'w': wrapped = TRUE; break; case 'x': nonExtractable = TRUE; break; case 'P': passphrase = optarg; break; case 'a': /* this takes an additional argument */ if(optind > (argc - 1)) { result = 2; /* @@@ Return 2 triggers usage message. */ goto cleanup; } attrNames = (char **)realloc(attrNames, numExtendedAttributes * sizeof(char *)); attrValues = (char **)realloc(attrValues, numExtendedAttributes * sizeof(char *)); attrNames[numExtendedAttributes] = optarg; attrValues[numExtendedAttributes] = argv[optind]; numExtendedAttributes++; optind++; break; case 'A': always_allow = TRUE; access_specified = TRUE; break; case 'T': if (optarg[0]) { SecTrustedApplicationRef app = NULL; OSStatus status = noErr; /* check whether the argument specifies an application group */ const char *groupPrefix = "group://"; size_t prefixLen = strlen(groupPrefix); if (strlen(optarg) > prefixLen && !memcmp(optarg, groupPrefix, prefixLen)) { const char *groupName = &optarg[prefixLen]; if ((status = SecTrustedApplicationCreateApplicationGroup(groupName, NULL, &app)) != noErr) { sec_error("SecTrustedApplicationCreateApplicationGroup %s: %s", optarg, sec_errstr(status)); } } else { if ((status = SecTrustedApplicationCreateFromPath(optarg, &app)) != noErr) { sec_error("SecTrustedApplicationCreateFromPath %s: %s", optarg, sec_errstr(status)); } } if (status) { result = 1; goto cleanup; } CFArrayAppendValue(trusted_list, app); CFRelease(app); } access_specified = TRUE; break; case '?': default: result = 2; /* @@@ Return 2 triggers usage message. */ goto cleanup; } } if(wrapped) { switch(externFormat) { case kSecFormatOpenSSL: case kSecFormatUnknown: // i.e., use default externFormat = kSecFormatWrappedOpenSSL; break; case kSecFormatSSH: externFormat = kSecFormatWrappedSSH; break; case kSecFormatSSHv2: /* there is no wrappedSSHv2 */ externFormat = kSecFormatWrappedOpenSSL; break; case kSecFormatWrappedPKCS8: /* proceed */ break; default: fprintf(stderr, "Don't know how to wrap in specified format/type\n"); result = 2; /* @@@ Return 2 triggers usage message. */ goto cleanup; } } if(kcName) { kcRef = keychain_open(kcName); if(kcRef == NULL) { return 1; } } if(readFile(inFile, &inFileData, &inFileLen)) { sec_error("Error reading infile %s: %s", inFile, strerror(errno)); result = 1; goto cleanup; } inData = CFDataCreate(NULL, inFileData, inFileLen); if(inData == NULL) { result = 1; goto cleanup; } free(inFileData); if(access_specified) { char *accessName = NULL; CFStringRef fileStr = CFStringCreateWithCString(NULL, inFile, kCFStringEncodingUTF8); if (fileStr) { CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, fileStr, kCFURLPOSIXPathStyle, FALSE); if (fileURL) { CFStringRef nameStr = CFURLCopyLastPathComponent(fileURL); if (nameStr) { CFIndex nameLen = CFStringGetLength(nameStr); CFIndex bufLen = 1 + CFStringGetMaximumSizeForEncoding(nameLen, kCFStringEncodingUTF8); accessName = (char *)malloc(bufLen); if (!CFStringGetCString(nameStr, accessName, bufLen-1, kCFStringEncodingUTF8)) accessName[0]=0; nameLen = strlen(accessName); char *p = &accessName[nameLen]; // initially points to terminating null while (--nameLen > 0) { if (*p == '.') { // strip extension, if any *p = '\0'; break; } p--; } safe_CFRelease(&nameStr); } safe_CFRelease(&fileURL); } safe_CFRelease(&fileStr); } result = create_access(accessName, always_allow, trusted_list, &access); if (accessName) { free(accessName); } if (result != 0) { goto cleanup; } } result = do_keychain_import(kcRef, inData, externFormat, itemType, access, nonExtractable, passphrase, inFile, attrNames, attrValues, numExtendedAttributes); cleanup: safe_CFRelease(&trusted_list); safe_CFRelease(&access); safe_CFRelease(&kcRef); safe_CFRelease(&inData); return result; }
STATIC CFArrayRef copy_trusted_applications(bool eapolclient_only) { CFMutableArrayRef array; SecTrustedApplicationRef trusted_app; OSStatus status; array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); /* eapolclient */ trusted_app = create_trusted_app_from_bundle_resource(CFSTR(kEAPOLControllerPath), CFSTR(keapolclientPath)); if (trusted_app != NULL) { CFArrayAppendValue(array, trusted_app); CFRelease(trusted_app); } /* AirPort Application Group */ status = SecTrustedApplicationCreateApplicationGroup(kAirPortApplicationGroup, NULL, &trusted_app); if (status != noErr) { fprintf(stderr, "SecTrustedApplicationCreateApplicationGroup(" kAirPortApplicationGroup ") failed, %d\n", (int)status); } else { CFArrayAppendValue(array, trusted_app); CFRelease(trusted_app); } if (eapolclient_only) { goto done; } /* this executable */ status = SecTrustedApplicationCreateFromPath(NULL, &trusted_app); if (status != noErr) { fprintf(stderr, "SecTrustedApplicationCreateFromPath(NULL) failed, %d\n", (int)status); } else { CFArrayAppendValue(array, trusted_app); CFRelease(trusted_app); } /* SystemUIServer */ status = SecTrustedApplicationCreateFromPath(kSystemUIServerPath, &trusted_app); if (status != noErr) { fprintf(stderr, "SecTrustedApplicationCreateFromPath(%s) failed, %d\n", kSystemUIServerPath, (int)status); } else { CFArrayAppendValue(array, trusted_app); CFRelease(trusted_app); } done: if (CFArrayGetCount(array) == 0) { my_CFRelease(&array); } return (array); }
OSStatus SecAccessCreateWithTrustedApplications(CFStringRef trustedApplicationsPListPath, CFStringRef accessLabel, Boolean allowAny, SecAccessRef* returnedAccess) { OSStatus err = errSecSuccess; SecAccessRef accessToReturn=nil; CFMutableArrayRef trustedApplications=nil; if (!allowAny) // use default access ("confirm access") { // make an exception list of applications you want to trust, // which are allowed to access the item without requiring user confirmation SecTrustedApplicationRef myself=NULL, someOther=NULL; CFArrayRef trustedAppListFromBundle=NULL; trustedApplications=CFArrayCreateMutable(kCFAllocatorDefault,0,&kCFTypeArrayCallBacks); err = SecTrustedApplicationCreateFromPath(NULL, &myself); if (!err) CFArrayAppendValue(trustedApplications,myself); CFURLRef url = CFURLCreateWithFileSystemPath(NULL, trustedApplicationsPListPath, kCFURLPOSIXPathStyle, 0); CFStringRef leafStr = NULL; leafStr = CFURLCopyLastPathComponent(url); CFURLRef bndlPathURL = NULL; bndlPathURL = CFURLCreateCopyDeletingLastPathComponent(NULL, url); CFStringRef bndlPath = NULL; bndlPath = CFURLCopyFileSystemPath(bndlPathURL, kCFURLPOSIXPathStyle); trustedAppListFromBundle=copyTrustedAppListFromBundle(bndlPath, leafStr); if ( leafStr ) CFRelease(leafStr); if ( bndlPath ) CFRelease(bndlPath); if ( url ) CFRelease(url); if ( bndlPathURL ) CFRelease(bndlPathURL); if (trustedAppListFromBundle) { CFIndex ix,top; char buffer[MAXPATHLEN]; top = CFArrayGetCount(trustedAppListFromBundle); for (ix=0;ix<top;ix++) { CFStringRef filename = (CFStringRef)CFArrayGetValueAtIndex(trustedAppListFromBundle,ix); CFIndex stringLength = CFStringGetLength(filename); CFIndex usedBufLen; if (stringLength != CFStringGetBytes(filename,CFRangeMake(0,stringLength),kCFStringEncodingUTF8,0, false,(UInt8 *)&buffer,MAXPATHLEN, &usedBufLen)) break; buffer[usedBufLen] = 0; // // Support specification of trusted applications by either // a full pathname or a code requirement string. // if (buffer[0]=='/') { err = SecTrustedApplicationCreateFromPath(buffer,&someOther); } else { char *buf = NULL; CFStringRef reqStr = filename; CFArrayRef descArray = CFStringCreateArrayBySeparatingStrings(NULL, reqStr, CFSTR("\"")); if (descArray && (CFArrayGetCount(descArray) > 1)) { CFStringRef descStr = (CFStringRef) CFArrayGetValueAtIndex(descArray, 1); if (descStr) buf = CFStringToCString(descStr); } SecRequirementRef reqRef = NULL; err = SecRequirementCreateWithString(reqStr, kSecCSDefaultFlags, &reqRef); if (!err) err = SecTrustedApplicationCreateFromRequirement((const char *)buf, reqRef, &someOther); if (buf) free(buf); CFReleaseSafe(reqRef); CFReleaseSafe(descArray); } if (!err) CFArrayAppendValue(trustedApplications,someOther); if (someOther) CFReleaseNull(someOther); } CFRelease(trustedAppListFromBundle); } } err = SecAccessCreate((CFStringRef)accessLabel, (CFArrayRef)trustedApplications, &accessToReturn); if (!err) { if (allowAny) // change access to be wide-open for decryption ("always allow access") { // get the access control list for decryption operations CFArrayRef aclList=nil; err = SecAccessCopySelectedACLList(accessToReturn, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList); if (!err) { // get the first entry in the access control list SecACLRef aclRef=(SecACLRef)CFArrayGetValueAtIndex(aclList, 0); CFArrayRef appList=nil; CFStringRef promptDescription=nil; CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector; err = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector); // modify the default ACL to not require the passphrase, and have a nil application list promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE; err = SecACLSetSimpleContents(aclRef, NULL, promptDescription, &promptSelector); if (appList) CFRelease(appList); if (promptDescription) CFRelease(promptDescription); } } } *returnedAccess = accessToReturn; return err; }