I am using Lion and Xcode 4.1.
SecKeyRawSign is not documented for OSX still it can be called and successfully signed for RSA certificate but failed with EC Cert.
SecKeyRawSign method returns -50 i.e. invalid parameters for ec cert-384.
Can SecKeyRawSign be used for OSX and EC Cert? If yes what would be the padding parameter?
Thanks in advance.
SecKeyRawSign is a private function in Mac OS 10.6 and 10.7, so you shouldn't use it. Its problem with ECC certificates may just be one of the reasons it has not (yet?) been made public.
The official high-level API for data signing in 10.7 is SecSignTransformCreate in Security Transforms. It should automatically use a suitable digest algorithm; if not, you just set kSecDigestTypeAttribute and kSecDigestLengthAttribute to whatever you need. AFAIK the padding algorithm is not configurable.
On 10.6 or below, you have to use CDSA. First, you create a context with CSSM_CSP_CreateSignatureContext. The signature algorithm is CSSM_ALGID_SHA512WithECDSA (or similar); you can get the other arguments from SecKeyGetCSPHandle, SecKeyGetCSSMKey, and SecKeyGetCredentials. Once you have the signing context, you sign your data with CSSM_SignData. The digest algorithm should be CSSM_ALGID_NONE.
The padding is best explained by Thomas Pornin's answer to another question.
#Fnord
Thanks for response. I wrote following code:
CFDataRef
CreateSignature (SecKeyRef privateKeyRef, CFDataRef plaintext, CFErrorRef &error)
{
SecTransformRef signingTransform = SecSignTransformCreate(privateKeyRef, error);
if (signingTransform == NULL)
return NULL;
Boolean success = SecTransformSetAttribute(signingTransform,
kSecTransformInputAttributeName,
plaintext,
error);
if (!success) {
CFRelease(signingTransform);
return NULL;
}
CFDataRef signature = SecTransformExecute(signingTransform, error);
CFRetain(signature);
CFRelease(signingTransform);
return signature;
}
Related
I have this piece of code running on OS X 10.7:
NSLog(#"Start");
if (NSAccessibilityPriorityKey != NULL) {
NSLog(#"%p", NSAccessibilityPriorityKey);
}
NSLog(#"End");
The code crashes (SIGSEGV) after the Start marker and before it gets to the End marker. According to the headers, the NSAccessibilityPriorityKey symbol was introduced in 10.9:
APPKIT_EXTERN NSString *const NSAccessibilityPriorityKey NS_AVAILABLE_MAC(10_9);
My deployment target is set to 10.6, so I thought the code should run, just the symbol might be NULL. What am I doing wrong?
It looks like I have to use the & operator when checking for weakly linked strings:
if (&NSAccessibilityPriorityKey != NULL) { … }
See this related question.
I've run into a problem using the AudioFilePlayer audio unit with app sandboxing enabled on OS X 10.8. I have an AUGraph with only two nodes, consisting of an AudioFilePlayer unit connected to a DefaultOutput unit. The goal (right now) is to simply play a single audio file. If sandboxing is not enabled, everything works fine. If I enable sandboxing, AUGraphOpen() returns error -3000 (invalidComponentID). If I remove the file player node from the AUGraph, the error goes away, which at least implies that the audio file player is causing the problem.
Here's the code I use to set the file player node up:
OSStatus AddFileToGraph(AUGraph graph, NSURL *fileURL, AudioFileInfo *outFileInfo, AUNode *outFilePlayerNode)
{
OSStatus error = noErr;
if ((error = AudioFileOpenURL((__bridge CFURLRef)fileURL, kAudioFileReadPermission, 0, &outFileInfo->inputFile))) {
NSLog(#"Could not open audio file at %# (%ld)", fileURL, (long)error);
return error;
}
// Get the audio data format from the file
UInt32 propSize = sizeof(outFileInfo->inputFormat);
if ((error = AudioFileGetProperty(outFileInfo->inputFile, kAudioFilePropertyDataFormat, &propSize, &outFileInfo->inputFormat))) {
NSLog(#"Couldn't get format of input file %#", fileURL);
return error;
}
// Add AUAudioFilePlayer node
AudioComponentDescription fileplayercd = {0};
fileplayercd.componentType = kAudioUnitType_Generator;
fileplayercd.componentSubType = kAudioUnitSubType_AudioFilePlayer;
fileplayercd.componentManufacturer = kAudioUnitManufacturer_Apple;
fileplayercd.componentFlags = kAudioComponentFlag_SandboxSafe;
if ((error = AUGraphAddNode(graph, &fileplayercd, outFilePlayerNode))) {
NSLog(#"AUAudioFilePlayer node not found (%ld)", (long)error);
return error;
}
return error;
}
Note that fileURL in the AudioFileOpenURL() call is a URL obtained from security scoped bookmark data, and is the URL to a file that has been dragged into the application by the user.
If I set the com.apple.security.temporary-exception.audio-unit-host sandboxing entitlement, when AUGraphOpen() is called, the user is prompted to lower security settings, and assuming they accept, playback again works fine (the sandbox is disabled).
So, this points to the AudioFilePlayer unit not being sandbox-safe/compatible. Is this true? It's difficult to believe that Apple wouldn't have fixed such an important part of the CoreAudio API to be sandbox compatible. Also note that I specify the kAudioComponentFlag_SandboxSafe flag in the description passed to AUGraphAddNode, and that call does not fail. Also, I can only find one reference to AudioFilePlayer not being sandbox-safe online, in the form of this post to the CoreAudio mailing list, and it didn't receive any replies. Perhaps I'm making some other subtle mistake that happens to cause a problem with sandboxing enabled, but not when it's off (I'm new to Core Audio)?
I just went to use libcrypto on Lion and it looks like the entire api has been deprecated. The man pages haven't been updated since 10.6.6.
Does anybody know what the replacement for libcrypto is on Lion?
libcrypto is part of OpenSSL, which hasn't changed much. It's not going away, but Apple recommends that developers use their CDSA (Common Data Security Architecture) library rather than using OpenSSL directly.
In case you know what you're doing and you just want to get rid of these warnings, one way is to add
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
to the relevant headers – in my case /usr/include/openssl/crypto.h and /usr/include/openssl/md5.h.
Ok, answering my own question here.
10.7 introduced Transforms into Security.framework, which is tied closely to SecKey. Transforms let you do lots of things, including encoding (eg. base64), digests, signing/verifying, and encryption.
Here's an example of how to sign some data. All of the transforms follow the same basic pattern; if you look in the Headers for Security.framework you'll see a header for each type of transform. These are from SecTransformReadTransform.h and SecSignVerifyTransform.h. I'm omitting any error checking or cleanup code here for simplicity.
NSData *dataToBeSigned = ;// Get this from somewhere. We set sha1 attributes down below, so this should be a sha1 digest
SecKeyRef *key = ;// Get this from somewhere; keychain or SecItemImport
SecGroupTransformRef group = SecTransformCreateGroupTransform();
CFReadStreamRef readStream = NULL;
SecTransformRef readTransform = NULL;
SecTransformRef signingTransform = NULL;
// Setup our input stream as well as an input transform
readStream = CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault,
[dataToBeSigned bytes],
[dataToBeSigned length],
kCFAllocatorNull); // Pass Null allocator so it doesn't free NSData's bytes
readTransform = SecTransformCreateReadTransformWithReadStream(readStream);
// Setup a signing transform
signingTransform = SecSignTransformCreate(key, NULL);
SecTransformSetAttribute(signingTransform, kSecInputIsDigest, kCFBooleanTrue, NULL);
SecTransformSetAttribute(signingTransform, kSecDigestTypeAttribute, kSecDigestSHA1, NULL);
// Connect read and signing transform; Have read pass its data to the signer
SecTransformConnectTransforms(readTransform, kSecTransformOutputAttributeName,
self.signingTransformRef, kSecTransformInputAttributeName,
group, NULL);
// Execute the sequence of transforms (group)
// The last one in the connected sequence is the return value
NSData *signature = SecTransformExecute(group, NULL);
I want to get the OS X system version, such as: 10.5.4, 10.4.8, etc. I want to get it in my app, how do I do this? Thanks!
You can read the property list at "/System/Library/CoreServices/SystemVersion.plist and extract the "ProductVersion" key, this is how the OS X installer application does it. Here's an example:
NSString *versionString;
NSDictionary * sv = [NSDictionary dictionaryWithContentsOfFile:#"/System/Library/CoreServices/SystemVersion.plist"];
versionString = [sv objectForKey:#"ProductVersion"];
Alternatively, the command swvers -productVersion will do the same.
You can use Gestalt:
SInt32 version = 0;
Gestalt( gestaltSystemVersion, &version );
BOOL leopard = ( version >= 0x1050 );
if ( leopard )
{
//draw it this way
}
else
{
//draw it that way
}
Keep in mind if you're checking if a method is available or not, it's better to test that directly using respondsToSelector:.
NSString *osver()
{
SInt32 versionMajor=0, versionMinor=0, versionBugFix=0;
Gestalt(gestaltSystemVersionMajor, &versionMajor);
Gestalt(gestaltSystemVersionMinor, &versionMinor);
Gestalt(gestaltSystemVersionBugFix, &versionBugFix);
return [NSString stringWithFormat:#"%d.%d.%d", versionMajor, versionMinor, versionBugFix];
}
-[NSProcessInfo operatingSystemVersionString] is human readable and localized. Appropriate for displaying to user or using in bug emails and such, but not appropriate for parsing.
Again, you can use Gestalt. Look at the documentation for more information; specifically, you'll want to pass the gestaltSystemVersionMajor, gestaltSystemVersionMinor, and gestaltSystemVersionBugFix constants in the "System Version Constants" portion of the Gestalt Manager Reference documentation
After 10_10, 8_0 were presented the better & simplest way would be
[NSProcessInfo processInfo].operatingSystemVersion
which will return
NSOperatingSystemVersion struct
with all 3 numbers.
There's also a Cocoa wrapper around the Gestalt calls others have mentioned in the Google Toolbox for Mac:
http://code.google.com/p/google-toolbox-for-mac/source/browse/trunk/Foundation/GTMSystemVersion.h
use this method it will return Mac OS X version
+(SInt32) OSVersion;
{
SInt32 osxMinorVersion;
Gestalt(gestaltSystemVersionMinor, &osxMinorVersion);
return osxMinorVersion;
}
Is there an way, ideally backwards compatible to Mac OS X 10.3, to tell if "Voice Over" is activated in System Preferences?
This appears to be stored in a preferences file for Universal Access. The app identifier is "com.apple.universalaccess" and the key containing the flag for whether VoiceOver is on or off is "voiceOverOnOffKey". You should be able to retrieve this using the CFPreferences API, something looking like:
CFBooleanRef flag = CFPreferencesCopyAppValue(CFSTR("voiceOverOnOffKey"), CFSTR("com.apple.universalaccess"));
If anyone has the same question, it could be good to know, that Voice Over status is accessible via convenient interface now:
NSWorkspace.shared.isVoiceOverEnabled
Based on Petes excellent answer I’ve created this Swift 4.2 solution, which I find much easier to read. I also think it’s more handy to use a computed property in this case instead of a function.
var hasVoiceOverActivated: Bool {
let key = "voiceOverOnOffKey" as CFString
let id = "com.apple.universalaccess" as CFString
if let voiceOverActivated = CFPreferencesCopyAppValue(key, id) as? Bool {
return voiceOverActivated
}
return false
}
VoiceOver and Accessibility in general are very important topics and it is sad that the lack of Apples documentation especially for macOS makes it so hard for developers to implement it properly.
Solution in Swift 4 is as follows:
func NSIsVoiceOverRunning() -> Bool {
if let flag = CFPreferencesCopyAppValue("voiceOverOnOffKey" as CFString, "com.apple.universalaccess" as CFString) {
if let voiceOverOn = flag as? Bool {
return voiceOverOn
}
}
return false
}
Furthermore, to make a text announcement with VoiceOver on macOS, do the following:
let message = "Hello, World!"
NSAccessibilityPostNotificationWithUserInfo(NSApp.mainWindow!,
NSAccessibilityNotificationName.announcementRequested,
[NSAccessibilityNotificationUserInfoKey.announcement: message,
NSAccessibilityNotificationUserInfoKey.priority:
NSAccessibilityPriorityLevel.high.rawValue])