Usable Keychain Scripting

August 11th, 2006

Anybody who’s tried to use Apple’s Keychain Scripting has probably learned that its performance and functionality are both fatally flawed.

The quintessential flaw in Keychain Scripting’s performance can be observed by simply asking it to find a key by some attribute test. If it works, then it will take a long, long time. All of its “whose clause” functionality is extremely slow, but this simple case forces it to go through each item in the keychain, failing to find a key:

tell application "Keychain Scripting"
	set myKey to first key of current keychain ¬
			whose name is "zzzzz"
end tell

Just how bad is it? I knew I had seen times of at least a minute, but I decided to test with Shark just to be sure. I let it rip and to my surprise AppleScript eventually gave up with a “event timed out” error. I stopped shark and observed that Keychain Scripting had used up 2.3 minutes of CPU time (!).

I was anxious to learn how bad it could get so I put a “with timeout of 200000 seconds” around the AppleScript block and ran it again. The pipes must have been warm this time, because Keychain Access came back in a “zippy” 1.3 minutes, finally having failed to locate the item as expected.

Obviously, Keychain Scripting is freaking useless.

I decided to take a stab at writing my own, because I’ve been waiting too long for this to get fixed and I just don’t have any faith left. I figured it was a good opportunity to learn about the Security Framework, with which I have had no prior experience. I used the Keychain Access dictionary as scaffolding for everything I needed to implement, and slowly filled in the gaps, testing each attribute and command before and after implementation, learning the API as I went along. I abided by my policy of ignoring performance considerations until I got something working. Before long, I had completed set of simple Cocoa wrappers around the Security framework, which simply map through to live-fetches of the data from the underlying database.

The results? The script that takes (at best) 1.3 minutes to run in Keychain Access takes 300ms in “Usable Keychain Scripting.” Holy cow manure! That’s a 260x performance improvement, and I haven’t optimized anything. This fruit is so low-hanging it’s practically buried.

OK, you might be thinking this is just an arbitrary example of a bad edge case. How does Keychain Scripting really perform? You know … when you’re looking for something that actually exists. Here’s another arbitrary example, this time collecting the keychain items that have my name in their name:

tell application "Keychain Scripting"
	set myKey to first key of current keychain ¬
			whose name contains "daniel"
end tell

This time it’s 360ms in my Usable version, and uh oh, bad example, simply doesn’t work in Keychain Scripting.

Keychain Scripting got an error: Can’t get key 1 of current keychain whose name contains “daniel”.

Unusable. The same experience applies to most other reasonable attempts to ask it for information.

Usable Keychain Scripting is at least 260x better than Keychain Scripting in the speed of critical lookups, but there are other improvements, too. I fixed up the dictionary to not suck as much, and my code goes directly to the most modern security API, while the Apple version still goes through an outdated “KC” API. Who knows, one of these days maybe I’ll even optimize it. NOTE: the terminology is slightly different from Apple’s Keychain Scripting, but I think my terminology is clearer.

So why would you even want to script Keychain? Well, for one thing if you script Keychain instead of hardcoding passwords in your scripts, things are a lot more secure. Also, there are certain keys for which I find myself constantly going into Keychain Access and looking up the values for. Either Safari forgets how to auto-enter it, or NetNewsWire loses its wits about something. For instance, every once in a while my Daring Fireball subscriber feeds lose knowledge of their password. With the scripting mechanism working as it should, I can keep a short script attached to NNW for refetching it:

tell application "Usable Keychain Scripting" to tell current keychain
	set myPass to password of first internet password ¬
		whose protocol is HTTP and name is ¬
		"daringfireball.net (<my email address>)"
end tell
set the clipboard to myPass

Now the password is in my clipboard and I just paste it into the field as NNW requests.

Note: I have a mechanism in place for setting values of keychain items, but I am wary of making it public yet because of the risk of data loss if I did something wrong. For now just enjoy the speedy access to your existing keychain data.

15 Responses to “Usable Keychain Scripting”

  1. ssp Says:

    This is great news. Now it remains to figure out what the original Keychain Scripting does to achieve its stellar performance…

    How do you handle this security wise? Giving the Usable Keychain Scripting application access to all of your keychains without asking should in principle be an insecure thing to do. But I imagine anything else would soon be annoying. For that reason having a separate application handle the fetching of passwords always seemed like a bad idea to me. Implementing it as a scripting addition would be better; I suppose (although it wouldn’t really help much if you’re using the system-wide AppleScript menu).

  2. Daniel Jalkut Says:

    I was, and remain, a little uncertain about how to handle the security thing – but the default behavior seems “about right.”

    You’ll notice that even when you ask for the password in Keychain Access, it makes you authenticate if you’ve never done it before. You can then choose to make it a permanent allowance if you see fit.

    This seems to work out pretty well because it gives the user total knowledge of what is being accessed when, and assures them that I’m not managing to sneak any data out on the side (well, I suppose I could be for the ones the user permits, but I promise I’m not!).

    Basically Usable Keychain Access is just like any of your other apps. You choose how much to let it into the trust circle, and you can choose on a per-key basis.

  3. Daniel Jalkut Says:

    Oh yeah, I meant to add – most of the attributes of keys are accessible without authentication, even if the keychain is “locked.” So it’s not until you ask for a password of an item that the authentication becomes an issue.

  4. Adam Belll Says:

    Works a treat, Daniel. Thanks for it.

  5. From Concentrate Software Says:

    [...] So when developers go out of their way to get around Applescript, well, it’s just a bit embarrassing. I noticed today that Daniel Jalkut has written a minor application to get around keychain scripting. It reminded my of an application that I put together recently. [...]

  6. Kunal Says:

    Talking about keychain security I was wondering, could you gain access to anyone’s keychain contents if you could just lay your hands on the file?

  7. Alex Says:

    I don’t know if this may be of use to anyone else, but an alternative to slow keychain scripting is doing it via the shell. Allan Odgaard wrote up a nice post about it a while back: http://macromates.com/blog/archives/2006/04/17/keychain-access-from-shell/

  8. Mike Henley Says:

    I got a slight improvement in speed by using the style of the last example with the built-in keychain access. If you know that something is a generic key, you can ask for “the first generic key where…”

  9. ssp Says:

    I’m not sure this was clear in my previous comment, but the main problem I am seeing is the concept of a proxy application for accessing the keychain. Usually the keychain will ask you about an application wanting to access your passwords. And even if you go for the ‘allow permanently’ option you will have to confirm access to those keys again after upgrading the application in question for example.

    Once you have a proxy application in between, though, this whole security feature stops to work. Not only will you not be notified that the application getting the password in the end has changed, there could even be a completely different application asking for your passwords without you having a chance to notice that.

    I am not saying that this is a practical problem today – most certainly it isn’t. But it’s mainly “security by obscurity” you are getting there. As useful as such a tool for accessing the keychain can be for private use, as dangerous it could be once it sees usage in public. I guess it all boils down to the question whether you are prepared to grant access to your passwords to an application which will just pass them on to anyone who bothers to ask.

    It could be interesting to discuss what Apple could do to improve their keychain API in that respect. While I think the traditional ‘ask for each application’ approach is a good balance of security and not annoying the user too much, the very fact that OS X is a Unixy system that lets you tie applications together through little helper applications and scripting languages makes this approach a bit weak in some cases.

  10. Daniel Jalkut Says:

    ssp: I see what you mean now. And yes, it’s a problem. It’s similar to the problem with command-line tools and network access. For instance, once you use “telnet” or “ssh” or “curl” to connect to a particular site and grant network permissions via Little Snitch or whatever, the tool is suddenly blessed for whoever might call it.

  11. Keychain scripting letting the Twitters down « A Dog’s Breakfast, part II Says:

    [...] Red Sweater Blog says : [...]

  12. Kem Tekinay Says:

    I just found this. Outstanding! It also solves the problem of applets saved as bundles constantly asking for permission to access the keychain. Thanks for this.

  13. Red Sweater Blog – Usable Keychain Scripting For Lion Says:

    [...] the other hand, I wrote an alternative years ago, called Usable Keychain Scripting. Its main advantage over Apple’s implementation is that it is (or at least, was) enormously [...]

  14. Red Sweater Blog – Safari Keychain Woes Says:

    [...] it’s NULL! What is going on, here? I decided to dust off my Usable Keychain Scripting tool, which makes it easy to use AppleScript to search and inspect the keychain. Is the inability [...]

  15. Usable Keychain Scripting For Lion | Bookmarks Says:

    [...] Snow Leopard in order to keep using it.On the other hand, I wrote an alternative years ago, called Usable Keychain Scripting. Its main advantage over Appleā€™s implementation is that it is (or at least, was) enormously [...]

Comments are closed.

Follow the Conversation

Stay up-to-date by subscribing to the Comments RSS Feed for this entry.