How to create certificate choosing window like one in Safari? - macos

I was looking for a way to create a window like that one in my program, but I haven't found any implementation of that. All I can do for now is get all certificates from keychain, but I can't get a cert in pem or der format. It is needed to supply certificate to a particular site.
- (void)logMessageForStatus:(OSStatus)status
functionName:(NSString *)functionName
{
CFStringRef errorMessage;
errorMessage = SecCopyErrorMessageString(status, NULL);
NSLog(#"error after %#: %#", functionName, (__bridge NSString *)errorMessage);
CFRelease(errorMessage);
}
- (void)listCertificates
{
OSStatus status;
SecKeychainSearchRef search = NULL;
// The first argument being NULL indicates the user's current keychain list
status = SecKeychainSearchCreateFromAttributes(NULL,
kSecCertificateItemClass, NULL, &search);
if (status != errSecSuccess) {
[self logMessageForStatus:status
functionName:#"SecKeychainSearchCreateFromAttributes()"];
return;
}
SecKeychainItemRef searchItem = NULL;
while (SecKeychainSearchCopyNext(search, &searchItem) != errSecItemNotFound) {
SecKeychainAttributeList attrList;
CSSM_DATA certData;
attrList.count = 0;
attrList.attr = NULL;
status = SecKeychainItemCopyContent(searchItem, NULL, &attrList,
(UInt32 *)(&certData.Length),
(void **)(&certData.Data));
if (status != errSecSuccess) {
[self logMessageForStatus:status
functionName:#"SecKeychainItemCopyContent()"];
CFRelease(searchItem);
continue;
}
// At this point you should have a valid CSSM_DATA structure
// representing the certificate
SecCertificateRef certificate;
status = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_BER, &certificate);
if (status != errSecSuccess) {
[self logMessageForStatus:status
functionName:#"SecCertificateCreateFromData()"];
SecKeychainItemFreeContent(&attrList, certData.Data);
CFRelease(searchItem);
continue;
}
// Do whatever you want to do with the certificate
// For instance, print its common name (if there's one)
CFStringRef commonName = NULL;
CFErrorRef err = NULL;
///CFArrayRef arr = NULL;
SecCertificateCopyCommonName(certificate, &commonName);
certs = SecCertificateCopyValues(certificate, NULL, &err);
//NSLog(#"common name = %#", (__bridge NSString *)commonName);
//NSLog(#"data = %#", (__bridge NSArray *)arr);
//certs = arr;
if (commonName) CFRelease(commonName);
//if (arr) CFRelease(arr);
SecKeychainItemFreeContent(&attrList, certData.Data);
CFRelease(searchItem);
}
CFRelease(search);
}
example
Is there any standard api to call such window? Or maybe there is some library? And how can I get der data from SecCertificateRef.
Thank you in advance!

Related

Possible to programatically installed 'Untrusted Certificate' or 'P12' file in Keychain Access with 'Always Trust '?

I am new to the Keychain Access from mac.
I just have to installed Untrused Certificate or P12 file in keychain access programatically in Mac as 'Trust Always'.
I am using below code :
-(void)addCertificate
{
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:
#"/Users/Desktop/Certificates.p12"];
CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
CFStringRef password = (CFStringRef)#"";
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys,
values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
SecCertificateRef rootCert =
SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)
inPKCS12Data);
OSStatus securityError = SecPKCS12Import(inPKCS12Data,
optionsDictionary, &items);
if (securityError == 0) {
NSLog(#" *** Certificate install Success ***");
} else {
NSLog(#" *** Certificate install Failure ***");
}
OSStatus err = noErr;
CFTypeRef result;
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kSecClassCertificate, kSecClass,
rootCert, kSecValueRef,
nil];
err = SecItemAdd((__bridge CFDictionaryRef)dict, &result);
if(err!=noErr) NSLog(#"error while importing");
if (err==errSecDuplicateItem) NSLog(#"Cert already installed");
NSLog(#":%i",(int)err);
assert(err==noErr||err==errSecDuplicateItem);
// accept no errors other than duplicate
err = noErr;
SecTrustRef trust;
err = SecTrustCreateWithCertificates(rootCert,
SecPolicyCreateBasicX509() ,&trust);
assert(err==noErr);
err = noErr;
CFMutableArrayRef newAnchorArray =
CFArrayCreateMutable(kCFAllocatorDefault,0,&kCFTypeArrayCallBacks);
CFArrayAppendValue(newAnchorArray,rootCert);
err = SecTrustSetAnchorCertificates(trust, newAnchorArray);
assert(err==noErr);
SecTrustResultType trustResult;
err=SecTrustEvaluate(trust,&trustResult);
assert(err==noErr);
rootCert=nil; // Done with the policy object
}
By using this code we are adding certificate only
Please help me to out from this...

How to deserialize the IPXDefaultLibraryURLBookmark of the Photos plist

So, I've been trying to deserialize the IPXDefaultLibraryURLBookmark of the com.apple.Photos defaults (defaults read com.apple.Photos IPXDefaultLibraryURLBookmark) but no luck. Ideally I'd like a programmatic way in c++ to deserialize that value to retrieve the last known location of the photo
bookd0xUsersmateuscbPicturesPhotos Library.photoslibrary 0#˜ì5$r$Éò|åú¨A∫˙æJ file:///Macintosh HDÇ1tA∫‘}•$6465C0A4-1771-3C89-9055-147CEDFBBF2EÅÔ/∆72cd528f2dcfb4b3434986cf3caa02cc946333b8;00000000;00000000;0000000000000020;com.apple.app-sandbox.read-write;00000001;01000004;0000000002980783;/users/mateuscb/pictures/photos library.photoslibrary¥˛ˇˇˇdº‰#‘ î  H ( 8 t0 †–Ä®
I know its not a bplist, since the first format specifier denotes bookd.
But I have no clue what that is. I'm somewhat new to OSX development, so this may be something very basic I'm missing.
I want to retrieve the: /users/mateuscb/pictures/photos library.photoslibrary portion so I can find the defaults photoslibrary.
Unless there is another way to retrieve the default photoslibrary path?
I figured out how to retrieve the path to the .photoslibrary. I used CFURLCreateByResolvingBookmarkData to get a CFURLRef from the plist then used CFURLGetFileSystemRepresentation to get the full path as a string.
Help from this sample to retrieve sandbox preferences: https://gist.github.com/glebd/4759724
Here is my full solution:
int main(int argc, const char * argv[]) {
bool success = FALSE;
UInt8 photosUrlString[PATH_MAX];
struct passwd *pwd = getpwuid(getuid());
if (pwd == NULL){
Log("Unable to retrieve current user");
return 0;
}
const char *home = pwd->pw_dir;
if (home == NULL){
Log("Unable to retrieve current user directory");
return 0;
}
CFMutableStringRef preferencesPath = CFStringCreateMutable(NULL, 0);
if (preferencesPath) {
CFStringAppend(preferencesPath, CFStringCreateWithCStringNoCopy(NULL, home, kCFStringEncodingUTF8, NULL));
CFStringAppend(preferencesPath, CFSTR("/Library/Containers/com.apple.Photos/Data/Library/Preferences/com.apple.Photos"));
} else {
Log("Unable to create CFString of user directory");
return 0;
}
CFPropertyListRef photosUrlPrefs = CFPreferencesCopyValue(CFSTR("IPXDefaultLibraryURLBookmark"), preferencesPath, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
CFRelease(preferencesPath);
if (photosUrlPrefs) {
CFTypeID prefsType = CFGetTypeID(photosUrlPrefs);
if (CFDataGetTypeID() == prefsType) {
CFDataRef photosUrlData = (CFDataRef) photosUrlPrefs;
CFErrorRef urlResolveError = nil;
CFURLRef photosUrl = CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault, photosUrlData, NULL, NULL, NULL, NULL, &urlResolveError);
if (photosUrl == NULL) {
if(urlResolveError != NULL) {
CFStringRef resolveErrorString = CFErrorCopyDescription(urlResolveError);
if (resolveErrorString != NULL) {
char resolveErrorCString[PATH_MAX];
if (CFStringGetCString((CFStringRef) resolveErrorString, resolveErrorCString, sizeof(resolveErrorCString), kCFStringEncodingUTF8)) {
Log("Error resolving URL: %s", resolveErrorCString);
}
CFRelease(resolveErrorString);
}
} else {
Log("Error resolving URL, no resolveError");
}
} else {
success = CFURLGetFileSystemRepresentation(photosUrl, false, photosUrlString, sizeof(photosUrlString));
CFRelease(photosUrl);
}
} else {
Log("Url plist value is not CFData");
}
if (photosUrlPrefs != NULL) {
CFRelease(photosUrlPrefs);
}
}
if(success) {
Log("path: %s", photosUrlString);
}
return 0;
}

get disk number(s) before getting bsdName

I have just encountered one problem, I can get the bsdName with below code lines but if there are two partitions in a USB flash disk, then I can only get the last bsdName, can someone tell me how do I get all the bsdName from the USB drive? actually I would like to get the volume name of each partition... thanks in advance
CFStringRef bsdName = ( CFStringRef ) IORegistryEntrySearchCFProperty ( usbDevice,
kIOServicePlane,
CFSTR ( kIOBSDNameKey ),
kCFAllocatorDefault,
kIORegistryIterateRecursively );
NSLog(#"bsdName=%#",bsdName);
volumeName = deviceNameWithMountPath((NSString*)bsdName);
//find_hid_device(usbDevice);
NSLog(#"volume Name=%#",volumeName);
NSString *mediaType = FindWholeMedia(usbDevice);
NSLog(#"media type = %#",mediaType);
//CFRelease(bsdName);
// Done with this USB device; release the reference added by IOIteratorNext
kr = IOObjectRelease(usbDevice);
}
}
NSString *deviceNameWithMountPath(NSString *mountPath)
{
DASessionRef session = NULL;
DADiskRef disk = NULL;
CFDictionaryRef dd = NULL;
CFTypeRef val = nil;
session = DASessionCreate(kCFAllocatorDefault);
if (!session) {
NSLog(#"Can't create DiskArb session");
return nil;
}
// DASessionScheduleWithRunLoop(session,
// CFRunLoopGetCurrent(),
// kCFRunLoopDefaultMode);
//
// DARegisterDiskAppearedCallback(session, NULL, DiskAppeared, NULL);
disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, [mountPath UTF8String]);
if (!disk) {
NSLog(#"DADiskCreateFromBSDName(%s) failed", [mountPath UTF8String]);
return nil;
}
dd = DADiskCopyDescription(disk);
if (!dd) {
NSLog(#"DADiskCopyDescription(%s) failed", [mountPath UTF8String]);
return nil;
}
CFDictionaryGetValueIfPresent(dd, (kDADiskDescriptionVolumeNameKey), &val);
DiskAppeared(disk, NULL);
CFRelease(disk);
CFRelease(session);
return (NSString *)val;
}

How can a Cocoa application add itself as a global login item?

I tried
LSSharedFileListRef globalLoginItems = LSSharedFileListCreate(NULL, kLSSharedFileListGlobalLoginItems, NULL);
if (globalLoginItems) {
LSSharedFileListItemRef ourLoginItem = LSSharedFileListInsertItemURL(globalLoginItems,
kLSSharedFileListItemLast,
NULL, NULL,
(CFURLRef)[[NSBundle mainBundle] bundleURL],
NULL, NULL);
if (ourLoginItem) {
CFRelease(ourLoginItem);
} else {
NSLog(#"Could not insert ourselves as a global login item");
}
CFRelease(globalLoginItems);
} else {
NSLog(#"Could not get the global login items");
}
LSSharedFileListInsertItemURL() just returned NULL when I built and ran the application. Is there something else that I need to do? Some kind of authorization?
NOTE: The use-case here is for global login items, that is using kLSSharedFileListGlobalLoginItems and not kLSSharedFileListSessionLoginItems.
I got this working. All I had to do was add these lines before I insert the app into the login items:
AuthorizationRef auth = NULL;
AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &auth);
LSSharedFileListSetAuthorization(globalLoginItems, auth);
The docs for LSSharedFileListSetAuthorization say that we have to get the right system.global-login-items for this, but it worked nevertheless!
But this will fail if the user is not an administrator. For it to work then too, you'll have to do this:
AuthorizationItem right[1] = {{"system.global-login-items.", 0, NULL, 0}};
AuthorizationRights setOfRights = {1, right};
AuthorizationRef auth = NULL;
AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &auth);
AuthorizationCopyRights(auth, &setOfRights, kAuthorizationEmptyEnvironment,
(kAuthorizationFlagDefaults
| kAuthorizationFlagInteractionAllowed
| kAuthorizationFlagExtendRights), NULL);
It's also advisable to refer to the docs for details.
This works for me:
NSString * appPath = [[NSBundle mainBundle] bundlePath];
// This will retrieve the path for the application
CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:appPath];
// Create a reference to the shared file list.
// We are adding it to the current user only.
// If we want to add it all users, use
// kLSSharedFileListGlobalLoginItems instead of
//kLSSharedFileListSessionLoginItems
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
if (loginItems) {
//Insert an item to the list.
LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(loginItems,kLSSharedFileListItemLast, NULL, NULL,url, NULL, NULL);
if (item){
CFRelease(item);
}
}
CFRelease(loginItems);
NSString * appPath = [[NSBundle mainBundle] bundlePath];
// This will retrieve the path for the application
CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:appPath];
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListGlobalLoginItems, NULL);
if (loginItems) {
//Insert an item to the list.
LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(loginItems,kLSSharedFileListItemLast, NULL, NULL,url, NULL, NULL);
if (item){
CFRelease(item);
}
}
CFRelease(loginItems);
Doesn't work this code? I replaced kLSSharedFileListSessionLoginItems with kLSSharedFileListGlobalLoginItems

Sqlite3 : "Database is locked" error

In my cocoa application I am maintaining a SQLite db within resources folder and trying to do some select, delete operations in it but after some time it starts giving me 'Database is locked' error.
The methods which I am using for select delete operations are as follows:
// method to retrieve data
if (sqlite3_open([databasePath UTF8String], &database) != SQLITE_OK)
{
sqlite3_close(database);
NSAssert(0, #"Failed to open database");
}
NSLog(#"mailBodyFor:%d andFlag:%d andFlag:%#",UId,x,Ffolder);
NSMutableArray *recordsToReturn = [[NSMutableArray alloc] initWithCapacity:2];
NSString *tempMsg;
const char *sqlStatementNew;
NSLog(#"before switch");
switch (x) {
case 9:
// tempMsg=[NSString stringWithFormat:#"SELECT * FROM users_messages"];
tempMsg=[NSString stringWithFormat:#"SELECT message,AttachFileOriName as oriFileName,AttachmentFileName as fileName FROM users_messages WHERE id = (select message_id from users_messages_status where id= '%d')",UId];
NSLog(#"mail body query - %#",tempMsg);
break;
default:
break;
}
sqlStatementNew = [tempMsg cStringUsingEncoding:NSUTF8StringEncoding];
sqlite3_stmt *compiledStatementNew;
NSLog(#"before if statement");
if(sqlite3_prepare_v2(database, sqlStatementNew, -1, &compiledStatementNew, NULL) == SQLITE_OK) {
NSLog(#"the sql is finalized");
while(sqlite3_step(compiledStatementNew) == SQLITE_ROW) {
NSMutableDictionary *recordDict = [[NSMutableDictionary alloc] initWithCapacity:3];
NSString *message;
if((char *)sqlite3_column_text(compiledStatementNew, 0)){
message = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatementNew, 0)];
}
else{
message = #"";
}
NSLog(#"message - %#",message);
NSString *oriFileName;
if((char *)sqlite3_column_text(compiledStatementNew, 1)){
oriFileName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatementNew, 1)];
}
else{
oriFileName = #"";
}
NSLog(#"oriFileName - %#",oriFileName);
NSString *fileName;
if((char *)sqlite3_column_text(compiledStatementNew, 2)){
fileName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatementNew, 2)];
}
else{
fileName = #"";
}
NSLog(#"fileName - %#",fileName);
[recordDict setObject:message forKey:#"message"];
[recordDict setObject:oriFileName forKey:#"oriFileName"];
[recordDict setObject:fileName forKey:#"fileName"];
[recordsToReturn addObject:recordDict];
[recordDict release];
}
sqlite3_finalize(compiledStatementNew);
sqlite3_close(database);
NSLog(#"user messages return -%#",recordsToReturn);
return recordsToReturn;
}
else{
NSLog(#"Error while creating retrieving mailBodyFor in messaging '%s'", sqlite3_errmsg(database));
sqlite3_close(database);
}
// method to delete data
if (sqlite3_open([databasePath UTF8String], &database) != SQLITE_OK)
{
sqlite3_close(database);
NSAssert(0, #"Failed to open database");
}
NSString *deleteQuery = [[NSString alloc] initWithFormat:#"delete from users_messages_status where id IN(%#)",ids];
NSLog(#"users_messages_status msg deleteQuery - %#",deleteQuery);
sqlite3_stmt *deleteStmnt;
const char *sql = [deleteQuery cStringUsingEncoding:NSUTF8StringEncoding];
if(sqlite3_prepare_v2(database, sql, -1, &deleteStmnt, NULL) != SQLITE_OK){
NSLog(#"Error while creating delete statement. '%s'", sqlite3_errmsg(database));
}
else{
NSLog(#"successful deletion from users_messages");
}
if(SQLITE_DONE != sqlite3_step(deleteStmnt)){
NSLog(#"Error while deleting. '%s'", sqlite3_errmsg(database));
}
sqlite3_close(database);
Things are going wrong in this sequence
Data is retrieved
'Database is locked' error arises on performing delete operation.
When I retry to perform 1st step.. it now gives same error.
Can anyone suggest me:
If I am doing anything wrong or missing some check?
Is there any way to unlock it when it gives locked error?
Thanks,
Miraaj
It is really uncommon that open/close the database every time you access.
If it is your intended scenario, it would be much better to use a normal file.
Open the database at startup and close at exit. This could solve all your problems.

Resources