Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Welcome to Session
709: Protecting Secrets
with the Keychain. If you
have ever used a keychain
or if you think you should,
this is your session; iOS, OS X,
we're quite agnostic here
Let's get started. What will you
learn here?
Well, I'll tell you what
keychains are I'll tell you how
to use them. There is
iOS specific information
and there is OS X specific
information I'll mark them very
specifically so you know when
to go off and check your tweets
And pointers to more stuff
because there's always
more stuff. All right
So why do we have a keychain?
We've actually had one
for a very long time. There was
a keychain API and keychains
in Mac OS 9; so long time
There's a lot of small secrets
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that your programs
need to handle --
passwords, account
numbers maybe, PINs --
you want to store them securely,
but you don't want to do
that cryptographic thing
because it sounds dangerous
and it's hard. And you really
want to be as particular
as you can about who gets
those little secrets,
not just in terms of which
user, but also which programs
because we all know that not
all programs are is meticulous
with the user's secrets as yours
And you want some assurance
that if the user loses
their laptop or their iPhone
and somebody walks away with it,
those secrets actually
stay secrets. That's called
"off-line attack" in
security lingo. The control
over these secrets
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in the keychain universe is
always the users. This is kind
of important point
to get out of the way
up front. These are the user's
secrets. These are not your
secrets A keychain doesn't give
you a way of hiding something
from the user of the system
It's just a way for you
to protect the user's secrets
better and more easily. And,
of course, we all know,
less code is better
So keychain APIs try to be a
high level API. Fewer calls,
fewer parameters for the most
part. It may not always seem
that way, but believe me,
the low-level solutions look
a lot worse than this. Okay
So what is a keychain?
It's a database I
mean, in its heart,
it's a database. It's got rows
which in keychain lingo
are called "items";
and the items have values,
that's where you
put the secrets;
and they have attributes which
is things that you find them by
or that you stick on the side
We call those "metadata."
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And keychains are optimized
for storing small secrets
and finding them quickly
That's what they do
for a living. You know,
the prototypical example is a
user's password to a website
or some web service or
something else; little secrets,
little individual secrets that
you use one at a time. Now,
there is nothing in
the APIs that keeps you
from storing 150,000 secrets in
a keychain, and there's nothing
in the APIs that keeps you
from storing a 50 megabytes
large secret in the keychain
But don't do that because that's
not what the APIs are written
for. You can do it, but it will
hurt. It will definitely hurt
your program, and it may
hurt the system depending
on the circumstances
So remember,
this is for small secrets
Don't sweat it, you know;
couple hundred bytes is fine,
kilobytes probably fine
Thousands of secrets is fine
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
as long as you're not trying
to iterate through all of them
and pick them up one at a time
in your program while the
user waits. So that's kind
of the environment they we're
here for. You can stretch this,
just don't overstretch it
Yeah, and this is the point
where somebody always raises
their finger and says,
"I just write it to a file," you
know "I'll encrypt it myself,"
or "Why do I bother anyway?
I'll use ROT-13," you
know "Nobody's going
to find the data. Why should
I call these weird APIs
with their weird
security things?"
Well, the keychain APIs give
you canned access control
Essentially, a predefined way
of determining what programs,
and to a certain extent,
what users get at the secret,
and they give you a way of
controlling how your program
and other programs can share
access to these secrets
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If you write your secrets
to a file, then anybody
who gets a hold of the
file has the secret I mean,
they may not know where to look
but eventually they'll
figure it out,
and that's not good. Plain
files, there is many,
many ways of scanning
for files in the system
And I don't just mean on OS X
There's ways of finding files
in iOS by. Jailbreak or
other ways. And besides,
when you start manipulating
this data yourself --
you copy it around, you write it
to a file, you fetch it back -
every time you make a
copy, there's another place
where the secret sits, and once
you lose control of a secret,
once it goes to places where
you didn't realize it was going,
there's no way of
getting it back
because you just wrote
it there. Keychain is
about doing the cryptography
right without you having
to think about it. And believe me
This is hard. It really is very
hard. And it's not typically
what you want to spend your time
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on. So that's why you want
to bother using the
keychain. The less code,
the better. So let's start
with the minimum kind
of code you can get away with
if your needs are simple --
you want to store a password,
you want to store a PIN. You
can create a keychain item,
which is an entry in this
database that is the keychain,
with a single API call it's
called SecItemAdd. It's a core
foundation level API, so
you pass it a CFDictionary
but we're all rather happier
with writing Objective-C code
so I wrote you the sample
code in Objective-C. Basically,
what you do is, you make up a
dictionary, you stick in all
of the attributes that
you want the item to have,
you stick in the
value, you say go,
and it goes. It returns an
OS status, and you always,
always check the OS status
of course. You would never even
think of ignoring an error code
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And that's it. If the call
returns no error, zero,
then it worked. You now
have a keychain item,
and you don't have to
worry about protecting it
because that's what
the API's for. Okay
So how do you get it back?
Oh, one note. Just like any
good database, it has a notion
of uniquely identifying items
In the case of these kinds
of items, that's the
service attribute
and the account attribute
And if you're trying
to create another item with the
same service and account values,
it will not work because
these are unique. So one
of the errors you can get
back from SecItemAdd is,
this item already
exists so I'm not going
to make you another one. So
keep that in mind Uniquing. Okay
So this is how you get it
back SecItemCopyMatching,
which is literally what this
does. Let me give you a bag
of attributes and I'll
match that against items
in the keychain and I'll give
you back the matching value
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So this is the same
dictionary that you passed in,
with the same attributes,
service attribute an account
attribute. You typically pass
in "return data", that is,
give me the value. You can also
get back references to items
that let you manipulate the
items themselves. And, again,
you check the error code,
it gives you back the value
These values, by the way,
are datas. They're not strings. Of
course, you know, secrets come
in many different shapes and
forms so keep that one in mind
And that's basically the
tools you have to work
with. You can create an item
You can get the value back,
you know. Sometimes
it's convenient
to do the other two things
that you typically do
with databases. You can change
an existing item. That's done
with SecItemUpdate This one
actually takes two dictionaries
because it's sort of a
combination of a lookup
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and a creation; so it takes
one dictionary that you use
to find the item you want to
update, and another dictionary
with all of the stuff you want
to change. It's really
quite straightforward
And we have a call for
deleting, which, again,
you pass a dictionary saying
which item you want to delete
and off it goes and deletes it
Always check your error codes
And there you have it: Keychain
APIs. That's all you need to know
When you want to change an
item, a lot of people fall
into that one, really
change the item,
use SecItemUpdate. It's sometimes
tempting to go, "Yeah, well,
I'll just delete the old item
I'll make a new one. Who's going
to notice?"
Programs will notice because
there are attributes to items
that you may not actually
know about. There are --
there may be attributes
to items that don't exist
yet because we'll invent
them in the next version
of the operating system
If you delete an item,
you're throwing everything about
it away. You forget about it,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and then you make a new one
and it gets default values
for stuff you don't specify,
and this may not actually
be the same values
that the old item had; so
don't do that. If you need
to change an existing keychain
item, use SecItemUpdate
because that way, you
keep the stuff. And --
well, if you're in a situation
where you have a
particular place in your UI
where the user gives you
the secret for safekeeping,
then you call SecItemAdd
right there. And then
if you have another
place in your code
where you know now you need it,
you call SecItemCopyMatching,
and these calls are
all you need. But a lot
of times that's not really
what you want to do A lot
of times you start
to write your program
and it goes something
like, oh, I need to connect
to that website. Oh, wait
He says I need a password,
so let's go ask the
user about the password,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
pop up a dialog or, you
know, something like that,
and the user types
in the password,
you send it to the
website, and that's great
until it happens again and
you ask the user again. So, no,
wait I heard this is keychain,
so let's use that keychain
to remember the thing that the
user gave me I call this the
"memory work flow" because it's
really not a store and retrieve
from the user's perspective
The user just want
to remember something
he's already told you once
And this happens often enough
that I wrote up a little bit
of pseudo code just to get you
started with it. What you do
in a situation where, oh,
suddenly I need a password,
is the first thing you do is
you look it up in the keychain
in case it's already
there. And if that worked,
if the keychain retrieval
succeeds, you just take this
and you use it and you don't
bother the user. That's,
after all, the whole point
of this. If you don't find it
in the keychain, then go
off and ask the user --
this may be the first
time or, you know,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
something may have
happened to the keychain --
and the user gives you the
password and you try it out,
and if it works, then you
stick it in the keychain
with SecItemAdd so that the
next time when you're running
through the same code flow,
you're hitting the copy matching
at the top and you don't
ask the user again. This is
about as straightforward
as it can go. The password
you retrieved or the password
that the user gave you may not
actually work. The user may have
mistyped it or it may
have been changed;
so you do need code for,
well, that didn't work
And give a little bit of
thought to what you do
when it didn't work. Try it first
before you store in the keychain
If it didn't work --
the keychain item you've
retrieved didn't work
and you ask the user
for a new one,
try that one before you go off
and replace it in the keychain
But it's basically your workflow
I didn't put a loop in here
If you want to keep asking
the user three times,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
as many of you want, you
know, just add the code,
the obvious code, but that's
basically the idea. This is how
to just remember stuff for the
user. The only thing the user
notices is that you don't
keep asking the same question,
which is kind of the Apple
thing. Couple things to think
about when you build
this workflow: As I said,
don't store a password until
you have some assurance
that it works; It's kind
of silly to store something
that turns out not to be the
right secret. If you can at all,
when you try out this password,
this secret, this PIN, whatever,
try to distinguish between
this is the wrong password
and this didn't work. There
are programs out there --
and I am trying really
hard not to mention them --
whose response to
network problems is, oh,
that password didn't
work I'll delete it
from the keychain
There. Aren't you happy?
No. Try to distinguish between
a environmental problems,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
which basically means you don't
know if the password worked
because you never got there,
and a perfectly good connection
to a service that tells you no,
no, no, that's not good I don't
like your password. If the answer
is "I don't like your password,"
then go ask the user
for a new one,
replace it in the
keychain. That's good
If the problem you're having is,
I'm having connectivity problems
or the service down, or if
you're not so totally sure,
when in doubt, leave the
old item in the keychain
because if you're not sure that
it's wrong, it's probably better
to keep it. Always keep in mind
that in most environments,
particularly with websites,
there's always another way
of changing the password that
doesn't involve your application
So just because everything
worked fine the last time
doesn't mean it's
going to work today
And ask yourself a little bit
how hard it is for the user
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to get the stuff back. We
security people like to say
that when doubt, erase
the secret and start over
and that's a very good security
rule. And if this is a password
that the user probably remembers
and you're just doing
some convenience for him,
then that's good. When it
doubt, throw it out --
ask the user. But if that happens
to be a password that they have
to get out of their safe and
read it off of a piece of paper
because it's some highly
valuable recovery password,
then maybe you want to
err on the side of keep it
in the keychain unless you're
totally sure that it's wrong
And in all of these
keychain workflows,
have a way to continue working
if everything falls apart
If the keychain APIs just give
you these mysterious error codes
that you've never seen before,
don't just splat on the user
and say, you can't
have your website,
you can't have your
service. Always fall back
when everything else fails on
ask the user for the secret
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and then feed it out to the
service. That's your last
defense; if you build your
workflow, that's always
where you want to end up
if everything else fails.
I told you that a keychain item
has a value and attributes,
or metadata. Now,
this is important
because it's really the
value we are protecting
with our high-grade
cryptographic munitions. The
attributes are what we use to
find stuff with, and that means
that they can't be that
secret, because, after all,
you can look them up in
the keychain to find items
So anything that you want
to store for the user
that the user thinks is a
secret, that the user wants
to keep a secret, needs to
go into the item value not
into attributes. Now,
obviously, if it's a password,
it goes in the value. If it's
a PIN, it goes in the value
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If it's their name,
it's probably not a secret
It's a good thing to use
as an attribute. But sometimes
this is a little bit not
so clear. Security people tend to
think of account numbers as not
as secret Social
Security numbers;
let's take a Social Security
number. We all know it's not a
secret, and it's pretty easy
to find somebody's
Social Security number
But there are banks and there
are lots of companies who think
that knowing somebody's Social
Security number actually makes a
difference and proves something;
so there is a lot of users
out there who think that
their Social Security number,
if you happen to store
it, should be a secret
So you probably want to make
it a secret and not use it
as an attribute. Same thing
with credit card numbers:
Credit card numbers are not
really very good secrets,
but strangely enough, a
lot of banks seem to think
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that they should be
So think a little bit
about how you are identifying
your keychain items,
because in the end,
in order to find them,
you need to give them attributes
that make them easy to find;
otherwise, you know, you'll end
up with your keychain
being a write once store
and you can't ever get it
back out. So if you can come
up with something that you and
the user agree is pretty obvious
and a public identification
of the user
and what the user's
trying to do,
then use that. If you have a hard
time coming up with something
that you don't think some user
will think is a disclosure
of dangerous proportions,
your fall back is to make
up something. If you can't
think up anything else,
generate a UUID, use that as
a key. Of course, then you need
to store that, but
since it's an identifier
that you're only using to
identify the keychain item,
you can just store that
in a key value attribute
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in your cloud storage, or in
your file if you're so inclined
So that's your way out of
the "I don't have anything
to tag my keychain items with."
In the end, you can
make something
up. This is not really keychain
specific but it's something
that we always tell you. The
whole point of having secrets is
that you don't leak
them; so retrieve them
from the keychain right when
you need them, use them,
and then throw them away. Do not
keep your secrets in a variable
in memory; do not write your
secrets to a file because it was
so annoying to get them out of
the keychain in the first place;
and do not send them to your
buddy, the helpful XPC service
for the helpful daemon
to hold them
for you. The whole keychain
workflow is based on,
just get it, use it, throw it
out. Let the keychain hold it
for any time when you don't
actively use the secret
And that's basically all
you need to know in order
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to use keychains as
a high-level service
on Apple products. Everything
I've told you so far is true
on iOS and OS X. Everything I've
told you so far works on both
That is good. That's a
really good argument
for using just what
I told you so far
because it works. You don't have
to worry about it. But, well,
okay. Maybe you want to know a
little bit more. So let's talk
about iOS first. The SecItem APIs
that I told you about are going
to serve you well on iOS
because they're the only API
that is there, so cool. If you
store a keychain item on iOS,
it is secured, cryptographically
secured, by the user. And by
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that we mean, by the PIN or
password that the user enters
to unlock the device. That's how
the off-line protection thing
works: If somebody steals
your phone and walks away
with it and, you know, does a
big storage dump of the phone,
if they don't know your passcode
and your phone wasn't jailbroken
to begin with when you lost
it, there is no shortcut other
than brute force attack to
actually get your secrets
out of the keychain. You can also
connect keychain items on iOS
to the particular hardware
platform to the instance
of device, which means that it's
also cryptographically linked
to a secret that is embedded --
baked into your particular phone
That's a cool feature, because,
well, it means you can
make secrets that belong
to this particular phone and
non other, and the user. On iOS,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
by default, if you just use
the calls that I showed you,
a keychain item is totally bound
to the application that made it;
so if you write a app and you
call SecItemAdd, no other app
in the universe can
see that item. On iOS,
this is done totally
by visibility. You basically just
don't see keychain items made
by other applications. On the
other hand, if you can see it
and the user has, you
know, unlocked their phone,
then you can actually get them
So this is the fundamental
access control that we're having
on iOS. And that's cool
unless, of course,
you want to make a family of
three apps the share a secret --
it's been known to happen --
so we have a way of doing that
And the way you do it is you add
an entitlement. It's called the
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Keychain-Access-Groups
Entitlement,
and it's basically just a name
that the different apps agree on
and that is used as
a rendezvous point
If you are storing
a keychain item
under a particular
keychain access group name,
then all the applications
that have this entitlement
with that value have access
to the item. This is how
you share. Obviously,
this is an entitlement so
you can set it up in Xcode
when you build your app. And it
wouldn't be much of security
if you could share
it with everybody,
so there are some
restrictions that guarantee
that somebody else will
not come along and say,
"I'll share that with you."
The basic restriction is that
the keychain access group names,
in order to be acceptable
to the store, needs to start
with your team ID. So all of
these names are teamID, dot,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and then make up something
What this practically means,
of course, is you get to share
whatever you want with yourself,
with your own apps, between
your apps. You just don't get
to share them with somebody
else's app. Not by accident
and also not on purpose. You
just can't. Whereby can't,
I mean that you can
build the app like that
but the store take it. And if you
are sending out ad hoc copies
of your app to your friends,
you would need a
provisioning profile,
and the provisioning
profiles will not allow you
to have this entitlement. So
basically, you can't. You get
to share with yourself
between your own apps
and that's all the
sharing you get
In Xcode there's
this little section
in the general configuration
of your app called
keychain. Basically,
that's what you add it. The
bundle ID of your app acts
as essentially a
keychain access group;
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
so by default you're only
sharing yourself. What you do is
you add another value
there and you start sharing
with other apps that
have the same value there
If you're ever wondering
about whether your app actually
has an entitlement like that,
there is the good old
codesign command. Of course,
you have to run it on OS X. Just
ask it to display entitlements
and you'll get back the plist
that contains your keychain
access groups entitlement. You've
probably heard of data
protection I certainly hope
you've heard of data
protection. That's iOS's way
of classifying data as to when
it becomes available. And one
of the attributes
you can specify
when you create item is its
data protection class. So, yes,
each item can have a different
data protection class. The
default, if you don't say
anything, is this line,
so you don't have to specify
but you can. What that means is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that keychain items
can be retrieved
when the phone is unlocked,
which is kind of what you want
If the phone is locked,
well, your code's not running
and then the user loses the
phone and user's very happy
that the keychain item is
not accessible. Of course,
if there happens to be a
way of running your app
in the background, as I've
heard maybe there might be,
and you want your app to have
access to a keychain item,
even though the phone's locked
because the user locked it
and walked away, then you
need to weaken the protection
of the item and specify
after first unlock. What
this basically means is
that the item is
still not accessible
if the phone got
rebooted or powered off,
but after the user
unlocked it at least once,
even if he locks it after that,
the item is still available
So if you do need
to access an item
from a background activity while
the user is not using the phone,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
this is what you need to
specify when you make the item
But don't do that unless
that's a situation you're
in because it means that your
item is protected less well. It
means that if the user loses his
phone and the thief walks away
and manages to bypass the
lock screen, they might get
at the item. If you
are in a situation
where you have background
activity that you need to do
because it's part
of your feature set
because it's really cool
that your code is doing stuff
while the user isn't around,
and you're uncomfortable with
taking the primary password
of the user, the primary secret,
the one that you're safekeeping
for him, and sticking it into
and after first unlock protected
item. There's a trick you can use
sometimes, and that is to do
what we call "derive secrets."
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If you have control over the
service because, let's say,
you're making it, you're
actually running that service
on the Web, you can
authenticate to it with a secret
that is cryptographically
derived from the real password
of the user. The advantage
is that then you can store
that derived password in the
less protected keychain item
and if it gets out
for some reason,
your service can be attacked
with the user's derived
password,
but the user's password is
still secure. That matters
because users are
so terribly bad
at reusing passwords
That's extra work,
and it's a little bit beyond
the scope of just talking
about keychains, but I thought
I'd mention it because, well,
it matters. What happens
when you backup your phone?
Pretty much what you'd expect
Your keychains get backed
up along with the phone as long
as your backups are encrypted --
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and all of your backups
are encrypted, right?
You can restore them back onto
the phone and you will get all
of the items back that
were in the keychain
when the backup was made;
so this is totally
seamless it just works. Items
that were marked as belonging to
a particular piece of hardware,
to a particular device, can
be restored to that device,
and that will work fine. If you
are migrating to another device,
then, by the nature of their
security, they won't come along
So if you are -- if the user
is migrating to another device
and they're restoring a backup,
they will essentially get
a keychain that has all
of the device specific keychain
items missing. Be prepared
for these items to disappear in
what seems to be a random moment
in time because the user just
bought a new iPhone something
All right. This all
looks perfectly,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
so there will be no need
to debug anything
That's a good thing
because here's the bad news:
There is on iOS no tool
for introspecting the keychain
data. There is no command line
tool, because where would you
run it; and there is no utility
that has access to all of
the keychain items of all
of the applications on your
phone. That's actually a security
feature. Remember that the
access control on iOS is based
on you can only see keychain
items made by your app
So if Apple wrote a utility
for inspecting your keychain,
it would only see the
keychain items that it wrote,
which is kind of pointless
So this being the bad news,
the tip is, you need to put
your debugging code inside
of your app because only
code that's running inside
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of your app actually can
see the keychain items
that you're having trouble
with. You all know how
to put debug code in your
program, and you know,
you know what kind of debug
code you're comfortable
with One thing: If you
actually ship your debug code
in some neat, tricky little --
if you triple tap over there
while holding the phone
sideways, and then a
new debug menu pops up
and you can actually figure
out why the keychains aren't
working, tell App Review
because otherwise they
might get the idea
that you have a secret
feature in your phone
that you don't want
people to know about
and that would be
sad Debugging tip:
When you are passing
these dictionaries
to the keychain APIs,
particularly for Add,
understand that these entries
in those dictionaries fall
into two classes. There are the
values that become attributes
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and item values. They're data
They are stuff that goes
into the item. And then there are
other keys that are control keys
that say what you want to
happen. Like the storage class
as an example. If you
reuse those dictionaries
between the ItemAdd call
and the CopyMatching call
and the Update call be really
careful because all of the keys
in your dictionary may not
all be useful and valuable
on all the API calls. It may
actually be safer to make
up these dictionaries
from scratch for each call
And if you run into any problems
where the APIs are yelling
at you and telling you
that you are just having a
"parameter error"@, something
that just doesn't
make any sense other
than I don't know what
you're talking about,
that often means one of
the keys that you passed
in doesn't make a sense here
so. And that's it for iOS. Hey,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that's great. Welcome back
OS X crowd. The keychain
on OS X has been
around for much longer,
and we have a lot more API and
a lot more complexity simply
because it's been around that
much longer. So let me tell you
about it. The SecItem APIs
that I've told you about work
on OS X, and they are what you
-- what we want to use. Honestly,
seriously, if you can at all,
please use the SecItem APIs
to work with your keychains
because that's what all the
new work goes. If there's a bug
in them, we'll fix it much --
with much more alacrity than
in the older APIs. So try
that first. There
are some things --
and I'll tell you about them --
that you cannot do with
the SecItem APIs on OS X
and then you'll have
to fall back
on the older APIs we
call SecKeychain APIs
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
because they are all folded
around the SecKeychain calls
in the API suite. These are not
deprecated. They are supported
API. They are just not where
we're putting the new cool stuff
On OS X a keychain is a file
in the file system. Seriously,
if you look in your home
directory in Library Keychains,
there's a file in there, it's
called login.keychain. That's
where your secrets sit. It's just
a file. So just deal with that
That means that standard
file access controls apply
to keychains. Your
login.keychain is owned by you,
it's not generally readable
or writable by other users
And if you mess with
permissions,
you can actually mess up access
to your keychain OS X keychains
are cryptographically protected
by the user's login
password. Just like on iOS,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
they are protected by the
users PIN or, you know,
the password they entered to
unlock the phone; on OS X,
they're protected by the
password the user uses to log
in. Makes perfect sense. Now,
while on iOS the default is
that there's no sharing and
you have to do a special thing
to start sharing
between applications,
on OS X keychains
-- keychain items
of one user are all visible
to all applications run
by that user. Remember,
OS X multiuser files,
Posix permissions, all of
that stuff. So OS X sort
of has the reverse
logic: Instead of starting
with you can't even see
any items that aren't yours
and then you'll have
to do special things
to make them visible,
OS X's approach is you
can see all the items made
by all the applications for
that user, and then we put
on controls that determine
which applications
actually are allowed
to retrieve the item
The way this is done is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with access control lists. Every
Keychain item on OS X has an ACL
And the ACL says what
applications are allowed
to retrieve the value. You set
the ACL when you create the item
If you don't specify
anything in particular,
you'll get pretty much exactly
the behavior you'd expect,
which is that the creating
application is the only one
that is allowed to retrieve the
item. So the default behavior
on iOS and OS X is very similar
but the machinery is very
different. There are calls
for changing the ACL
of an existing item I do
not recommend you use them
because they are
pretty complicated
and the system will throw
up a dialog to confirm
that you actually
wanted to change the ACL,
which is usually not a
very good user experience
So the 98 percent takeaway
rule is: Create the ACLs right
when you create the item
and then forget about them
So what is in these ACLs
An access control list
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on a keychain item
is essentially a list
of applications that are allowed
to access the item. As I said,
by default, it's the creating
application, but you can,
when you make the item, make a
list and say, me and that app
over there and that third
app over there; and on OS X,
that doesn't have to be your
own. You can, if you want,
create an item and say, "and
Safari has access to this item."
I'm not sure why
you would want to
but you can System does. The
APs are SecAccess, SecACL,
and SecTrustedApplication,
if you are unfortunate enough
to have to do this, go
read the documentation,
which is public documentation
on the keychain, and it's,
you know, pretty good actually
Here is one other distinction
that is important
between iOS and OS X:
On iOS if you don't have access
to an item, you don't see it,
you can't do anything with it,
end of story. There's just no
discussion. On OS X if you're
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in an application that
doesn't have access to an item
because it's not on the access
control list and you try anyway,
the system will try to put up a
dialog. Now, you've probably seen
that one. We lovingly call it
the "rogue application alert"
because it's the system saying,
hey, this program wants access
to the item and I don't think
it should, but do you want
to allow it anyway. So on OS X,
the user actually
has the ability
to override your access control
list by saying, yes, I want it
and it's my secret and
he can have it. So keep
that in mind. There is a
separate keychain file
on OS X that's called the
system keychain. It's in /Library
because it belongs to the system
And the system keychain belongs
to the system as a whole. It's
a multiuser operating system,
remember. If you write
a system daemon
and you use the keychain APIs,
that's where your secrets go
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But the system keychain
is actually accessible
to every program in the system
So if you're in a situation
where you need to create a
keychain item that is shared
between users, you
want that secret to go
into the system keychain,
because the system keychain
can be read by every user
on the system. That's a
capability that, well,
OS X has. Of course, the
system keychain does belong
to the system as a whole,
so asking a user, hey,
do you want this
program to have access
to that system secret
wouldn't be very fair
if the user isn't perhaps
even an administrator;
so if that happens to a
secret in the system keychain,
we're not just asking,
is this okay
to do this. We're
actually asking, hey,
prove that you're
an administrator
So the keychain dialog
for overriding ACL control
for the system keychain is an
admin check. Let's talk a little
bit more about these prompts
There's a particular error code,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
one of the OSStatus values that
can come out of a keychain call,
it's called "user
interaction not allowed."
And a lot of people get
very confused by it; like,
what user interaction?
I did want any user interaction
I just want the item. What this
means is, I needed to put up a
dialog to get you what you want
and I couldn't. Well, why would
the system put up a dialog?
We've already had one situation
If the application isn't
on the ACL approved
list, if it's an intruder
and an interloper that
is trying to get an item
that the ACL says it shouldn't
have, system tries to put
up a dialog. The other
situation is for keychains
that are not actually at the
moment unlocked. Remember,
I told you that the
cryptographic protection
of a keychain is based on
the user's login password?
When you log in through the
standard OS X login screen,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
the password you type in
that allows you to log
into the system is also used
to unlock the user's keychain
The passwords are in sync
As a matter of fact, when
you change your pass --
your login password, it actually
changes the cryptographically
secured password on the login
keychain at the same time
So it's always unlocked, right?
So why would the system
ever need to ask for it?
Because there are
preferences for paranoid people
where you can actually say
that you want your keychain
to lock automatically after
inactivity. And some people turn
that on. Yeah, I do
At which point
if you then asking the
keychain API for an item
and the keychain is locked at
this point, the system will put
up a dialog and say, Could you
please enter that password again
because you're paranoid?
Which is fine as long
as this dialog can come
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
up. If your program is not
running in a graphic context,
meaning, if it doesn't
have the ability to put
up standard CocoaDialogs,
the system knows that --
the keychain system knows
that, and in any situation
where it's trying to put up
a dialog on your behalf --
from the user's behalf and it
can't, instead the call fails
and that's the error
code you're getting --
user interaction not allowed I
was trying to talk to the user
and ask him if it's
okay but I couldn't
So what this really means, what
this error code really means
to you, is you are in a
nongraphical environment
for some reason. You
are in the cron job,
you are in the system daemon,
you SSHed into the system SSHing
does not get you graphical
access even if you are
logged in as the same user
at the same time on the same
Mac. They are totally separate
security sessions. So keep
this in mind because that's
like probably 50 to
80 percent of all
of the problems people have
So what do you do if you're
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in a nongraphical context?
You want to use the keychain
anyway. There are API calls
and the SecKeychain APIs that
allow you to unlock the keychain
Of course, you'll have to say,
"and the password is this"
because you can't put up
a dialog. There are APIs
for retrieving items and
all of this good stuff;
so if you happen to have
the user's login password
or whatever secret protects
the keychain, you can just pass
that to API. But if you have a
command that normally works fine
from terminal but now you want
to use it from an SSH session,
the easiest way is to use
the security command. That's a
command line command, it's the
Swiss Army keychain command
And it has an option for "I want
to unlock this keychain
now. Here's the password."
So most of the time if the
problem is unlocking keychains,
just running security unlock
before you run your program will
get you out of your
hole. If the problem is
that your application isn't
on the access control list
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of the item, well, that's your
mistake. You should have created
the item with the right ACL to
begin with. And I should mention
that when we're talking about
application identity here,
these are codesigning identities
And I am glad everybody
here is signing their code
because the keychain stuff
system doesn't work very well
if your programs
unsigned anymore. Well,
let's talk a little
bit about backup
and migration. There
isn't have much
to stay I told you keychains are
files. If you backup your files
and restore them,
everything will be fine
And if you're migrating accounts
using Migration Assistant,
it will migrate your keychains
Everything's fine. Hardly a
problem actually. If you happen
to be writing system daemons,
I've already alluded to
that, system daemons are not
in graphic sessions. They
can't put up security dialogs
So you are in that particular
hole. The system keychain is your
default keychain. If you
are in a system daemon,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you can store secrets in
the keychain, but it will go
into the system keychain. The
system keychain is writable
by root only; so in order to
write to the system keychain,
in order to create or modify
keychain items, you need to run
as root. Retrieving is fine
no matter what UID you are
So as a daemon, your keychain
is the system keychain
And you have no access
without a lot of back flipping
to the user's keychain because
if you're a system daemon,
you don't have a user
For all you know,
there might be four users logged
into the system right now,
or none at all; so if you're
searching for keychain items
in a system daemon, anything
that the user created
the normal way inside
of that normal login keychain,
you just can't see. So the not
so bad news on OS X is that
there is a tool that allows
to you to work with keychain
files. It's called the
"security command."
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It's in usr/bin, and because the
default sharing rule on OS X is,
if you can see it,
you can fondle it,
you just can't get the value
out without passing the ACL test
The security command can show
you all of the items
in the user's keychain,
or for that matter, all of the
items in the system keychain,
and it will, if you pass it,
the right convoluted options
will actually tell you what
access control lists it has and
what its attributes are. In fact,
you can use the keychain --
the security command to
essentially preflight APIs
from the command line if you're
so inclined. If you're wondering
if a particular combination
of attributes will work
to find an item, there
is a security subcommand
that just searches
the keychain for items
with particular attributes
So it's pretty handy. There's
security dump keychain
with dumps out the entire
keychain for your introspection
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Of course, it was still not
give you the actual values
of the secrets unless you have
access to them. So they're --
just to clarify: The security
command has no special magic
features. It's just
a normal API client
for the keychain APIs
It will not do anything
that the normal keychain
APIs cannot do. But on OS X,
that's actually a heck of a lot
All right. Welcome back IOS crowd
We're now talking about
both systems again
And this is the section
where I talk about stuff
that just didn't make
it anywhere earlier
in the presentation I've
talked about secrets so far --
accounts, passwords, and
PINS, you know, all that stuff
that you generally retrieve from
a keychain in order to use it
as the text or data value
that it is for something,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
authenticating, passing
it off to a service,
whatever. The keychain actually
can store a lot of other things,
too I told you it's a
database, and it really is,
and in particular, it has
database schemas. And one
of the things that you can store
in the keychain is certificates
and cryptographic keys. This
presentation focuses on how
to simply work with passwords,
but I should at least mention,
if you're doing things like
client-side SSL authentication,
what will happen is that your
cryptographic identity, the key
and the certificate
that you're presenting
to the web server will end
up stored in a keychain,
and the CF network
APIs will essentially,
if everything works well,
automatically fetch them
out of there and use them. Keys
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and keychains are actually
handled by reference,
which is a really
cool feature. It means
that unlike certain other
legacy APIs, you don't ever have
to have the keys in your
address space. And so
if you get compromised all, is
not lost. That's good. So keep
in mind there is an API suite
called SecKey for dealing
with cryptographic keys, and
those are typically stored
in keychains, works on iOS
and OS X. There is a
SecCertificate API for dealing
with certificates; mostly for
finding them, but there's also
and API for creating them
And there is SecIdentity
which is a little bit odd
because it's literally a pair
of private key and a certificate
SecIdentity objects aren't
actually anything physical. They
are a pair of a certificate
and a private key that
were found in your keychain
so that belong together. The
system knows how they fit
together. This is what you use
for cryptographic
authentication. What --
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
yeah. Okay. All right
Well, one last thing:
iCloud keychain. It's been
announced so I can tell you
about it. Once upon a time there
was a way to synchronize secrets
in keychains and that
feature disappeared awhile ago
because times change. So now
we have something better. The
SecItem APIs are our simple
APIs, the "straightforward,
just do this if you
can get away with it,
don't get any more complicated
if you can avoid it" APIs. You
can add one more key to them --
this one. And it starts sharing
your items between OS X devices
and iOS devices for that user
That's all you have to do.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We try to make things
simple. So this works on iOS,
it works on OS X; of course,
iOS 7, OS X 10.9. You need to add
that attribute to all
of your API calls,
not just the creation call. And
as it says on the label usually,
"some restrictions apply";
in particular the lower-level
APIs I told you about on OS X,
the SecKeychain APIs, they don't
play nice with iCloud keychain
So if you are planning on using
iCloud keychain, you really,
really need to stick
to the high-level APIs. Just call
SecItem, add that attribute,
and keep it simple. It does work
with the application sharing
feature. So to sum it all up:
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Use the keychain APIs to
store your secrets. It's better
for you. It's better for
the user. It's better
for the environment. Don't do
your own secret storage. It's
going to end up badly,
if not now, then later,
because this is hard and you're
doing enough hard coding already
Keep your APIs as simple as
possible, and that's not just
because complicated
breeds more bugs,
but also because complicated
is a really bad thing
when you're doing security. The
more complicated you make your
secret storage setup,
the more likely it is
that some combination
of circumstances
that you didn't even think about
it, is going to lead to a hole
in your security strategy
If you can at all,
stick with this SecItem APIs
Stick with the memory workflows
if that's what you're
doing Try not
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to manipulate ACLs unless
you absolutely have to,
and if you do, stick with the
sample code for that on OS X,
and you'll be living
happily ever
after. All right Paul
Danbold, the gentleman here,
is usually lonely and bored,
and he loves to get e-mails;
the more the better
He's the evangelist,
and he has gotten very
good at telling you
who should be talking to you. The
keychain APIs are public APIs
They're documented
on the developer website. There
is plenty of documentation to go
around. Start with this URL if
you haven't ever looked at it,
and there will be
cross-references leading you
elsewhere. If you are
wondering about storing keys
and certificates in keychains,
there is a technical Q&A, 1745,
that focuses on that and
should serve to get you started
with how to set this all up. If
you're just wondering how all
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of that cryptographic
protection thing works
and why you should trust
us, there's a white paper
that describes how it works
under the hood. You don't need
to read that in order to use the
keychain, but if you're curious
And if you have any questions
start asking each other
in the developer forums,
and then we'll take it
from there. And that's it.