On Dec 11, 2007, at 11:59 PM, Wade Tregaskis wrote:
I apologise in advance for the barrage of questions. But I have
been quiet otherwise for ages now, you have to admit... :) I'm
going to test pretty much all of this anyway, but I'm hoping if
someone has the time to pre-empt that it'll save me a bit of time &
confusion on the spikier bits..
[all this is on Tiger, btw; I haven't tested on Leopard, but will]
The ACL system on Tiger and Leopard is the same, and no new subject
types have been introduced. The only (and major!) change is that
Leopard tracks application identity with Code Signing (if they're
signed). Unsigned applications are treated pretty much the same as in
Tiger. And we've kept the API astonishingly stable, given the changes
I've been poked by a couple of people recently about ACLs. In
particular, people want to be able to pre-configure an arbitrary
keychain item to be always accessible to their app, without
requiring user input (e.g. their apps run unattended, in a shell
session, or full screen, etc; no user input is possible). The API
itself is perfectly functional (albeit a bit verbose), and that's
all good... but there's a lot of questions I can't find answers for
in the API or its documentation.
For example, here's a representative keychain item, from my keychain:
Touch-stone: secured data items are actually pairs of (key, data), and
the ACL applies to the key. So storing (or modifying) a value is
"encrypting", and retrieving a value is "decrypting".
No application is (pre)authorized to change the ACL. Any attempt to
change the ACL requires a confirmation dialog.
I've noticed that this 2nd entry is basically what's shown in
Keychain Access, and seems to control whether or not apps can use
the contents of the password. Is this combination of authorisations
significant, i.e. some kind of magic value? I guess it comes from
how the item is used at a low level, so, my point perhaps more is...
for the typical use of retrieving the password of the item, is it
sufficient to have, say, just 'Exporting clear'
(CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR) in the ACL? The documentation
for SecKeychainItemCopyContent seems to indicate you need to have
decryption access to the item, but that seems odd; wouldn't you need
decryption access to the key that decrypts the item? [I haven't
enumerated anything other than passwords & certificates yet, so I
don't know what the ACL setup on other types of items is]
For data items, encryption and decryption are the only relevant
operations. The others apply to key items; they are included for the
sake of consistency (they don't hurt). Again, you *are* looking at the
ACL of the key that encrypts the data. The Sec* layer unifies the
(key, data) pair for you.
Next question is, well... the 3rd item above is pretty self-
explanatory; any app in that ACL can modify the ACL itself without
user auth, right? It's the first one which puzzles me more; what
would 'encryption' auth on a password item (or any type, I guess)
give you? It seems to be empty for all my keychain items, so I
don't have an example to go from.
Item #2, the right to change the ACL, is given to NO application. This
means that any application making such a request will throw up a dialog.
Item #0, the right to encrypt (i.e. to store a new value), is
unrestricted. Anyone can do that.
(In the output you show, they look the same. They're not. #2 has an
empty array-of-applications. #0 has a NULL array. Check the output of
"security dump-keychain -a".)
Is there any way to get the "name"/"description" of the SecAccessRef
itself? You specify one when you create it with SecAccessCreate,
but there's no way to retrieve it in the public API. Is it just
some kind of default value for the similar attribute of the ACLs,
which is retrievable (as displayed in my output above).
The description string is stored (separately for each ACL entry) in
the PROMPT ACL subject that triggers keychain dialog prompts. Each ACL
entry has its own descriptor; by convention, they are all the same,
but you can violate that convention if you're tricky (or careless). If
you want the "most canonical" description for an item, take the one
for the change-ACL right. At the SecACL layer, you get it as the
"description" return of the SecACLCopySimpleContents API call. At the
CSSM layer, it's the third list item in the
CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT subject buried deeply inside.
(Yes, that means that there are (non-standard) ACLs that don't have
"description" strings at all, because they don't issue dialogs that
would need them. The meaning of "the" description of an item is fuzzy.)
I had to go poking through the 'data' of the
SecTrustedApplicationRef to figure out that some part of it is the
path to the app in question. I get that it's probably
implementation dependent as to what the structure of this data is,
and I'm not particularly interested in poking too much, but knowing
the path of the app seems a pretty fundamental thing. (it'd be nice
to be able to get the hash or signature or whatever it is that
cryptographically protects the entry, too). Is the format spec'd
anywhere, and is it wise to use it?
This was and is intentionally under-documented, to allow for future
First, understand that this string is a *comment*. It has no bearing
on ACL validation; it's just here for display purposes. Think of it as
whatever the ACL's creator put there as a documentation hint as to the
underlying ACL's behavior. Changing it has absolutely no effect on the
With all those caveats, you can get that string with the
SecTrustedApplicationCopyData function. Here is the whole of the
The CFData returned by SecTrustedApplicationCopyData begins with a
null-terminated UTF8 string. That string is a description of what kind
of application should be acceptable to that SecTrustedApplication
object. (Ignore any data after the null byte. Do not use the length of
the CFData. Yes, there always is a null terminating byte.) If the
string has URI-form (scheme://rest), then it is based on Code Signing
validation, and the particular scheme used indicates its meaning (e.g.
group:// for an application group). If the string is not in URI-form
(no "://"), it's a path to where an acceptable application does or did
or should reside. (Note that moving a program does not change validity.)
(The URI-scheme rule is new for Leopard. But it's good to check in
Tiger and earlier; a keychain moved from Leopard to Tiger might
contain such items.)
There is an undocumented private SPI
SecTrustedApplicationPriv.h) to check whether an application at a
given path on disk satisfies a SecTrustedApplication's requirement.
It's been around since 10.3 at least. It magically works with Code
Signing in Leopard. Did I mention it is NOT an official API? Good.
What's the payoff on all that secrecy and un-documentation? When we
introduced Code Signing in 10.5, the innards of SecTrustedApplication
were pretty much ripped out and replaced. Yet the officially
documented behavior (above) remained intact, while imprudent
assumptions ("SecTrustedApplications have a path that points to the
application on disk") were true in 10.4 and earlier but may now fail.
Lastly in the technical questions, I noticed that
SecKeychainCopyAccess returns "not implemented" on Tiger... I
haven't tried on Leopard. It rings a bell, this error, but I can't
remember why... so I just want to check: is it indeed not
implemented on Tiger, or am I misusing it somehow?
It is indeed unimplemented (through 10.5), because we don't actually
*use* ACLs on keychains (as opposed to keychain *items*) for anything.
We store them at the CSSM layer, but nobody pays any attention to
them. So currently, you'd have to use CSSM calls to handle them (but
there's no reason to).
Now, some behavioural questions... nearly done, promise.. ;) ... so,
getting back to the use case I opened with, what I'd like to know is
a) how to add an internet password with an arbitrary app (not the
caller) in the trusted accessor list. I presume you can provide any
ACLs you like in the initial SecAccessRef you can pass to
SecKeychainAddInternetPassword has no parameter for this, and I'm
presuming that the default access it uses doesn't have the calling
app in the "Changing Access" ACL, so trying to then modify the
access would prompt the user, correct? If so, I guess it's
necessary to use SecKeychainItemCreateFromContent instead, then?
Entirely correct, except that the default ACL created (if you don't
specify your own) does give access (only) to the creating application.
(Keychain Access intentionally does not use the default and doesn't
give itself access for items it creates.)
b) given an arbitrary password, if I try to add my app to its ACL
for password access, the user will be prompted to allow this
modification, won't they? And this will happen for each item... is
there any way to effectively batch these up into a single prompt of
the user (or perhaps even no user prompting; provide a password
There is not. The keychain machinery contains no mechanism for
bypassing the ACL check, and the default ACL says "ask the user before
allowing editing an ACL." You can certainly create items whose change-
ACL ACL allows more liberal modification, but there is (intentionally)
no way to bypass an ACL of an item that doesn't allow you access. (No,
not even as root.)
There is one trick: there is no ACL protection against deleting or
creating keychain items. If you can read the item without dialogs
(i.e. your application is on the decrypt ACL), you can read it, delete
it, and recreate it with a different ACL. That allows an old,
authorized application to add newer ones to the list in a crunch. On
Leopard and beyond, application groups are a better way to do that. Of
course, this won't work (well, will put up a dialog) if you're not
authorized to read the item.
Perry The Cynic email@hidden
To a blind optimist, an optimistic realist must seem like an Accursed
Do not post admin requests to the list. They will be ignored.
Apple-cdsa mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden