[翻译]ICS 证书存储实现(ICS Credential Storage Implementation)

前言:

这是一篇关于Android安全的翻译,这是原文地址。接上一篇翻译。这篇文章主要讲了 key store 的存储位置,加密方式,读写权限等。随着Android源码的更新,这篇文章已经有些过时了,但它表达的思想还是非常可取的。

我会一段一段地复制原文,然后在下面给出翻译,如有图片,我会重新保存再上传,以免出现“图片无法显示的情况”。


原文:

ICS Credential Storage Implementation

November 30, 2011

译文:

ICS 证书存储实现

2011年11月30日

原文:

In the previous entry, we looked at how the new ICS KeyChain API is used and tried installing a user private key/certificate pair and a CA certificate. Now we'll will try to find out where they are actually stored and how they are protected.

译文:

在前面的部分,我们学习了新的 ICS KeyChain API 是如何被使用,并且尝试安装了一个用户私有的密钥/证书对和一个 CA 证书,现在我们要找到它们实际存储的地方,还有它们是如何被保护的。

原文:

Looking at frameworks/base/keystore/java/android/security, we notice several interesting classes that are not mentioned in the SDK documentation. The most promising is the KeyStore class, so let's have a look. Sure enough, it is marked as hidden (using the dreaded @hide comment). It does have methods for interacting with the key store (get(), put(), delete(), reset(), etc.), but where is the actual key store? As it turns out, all methods send command to a local socket aptly named 'keystore'. With a little creative grepping, we find out that there is native daemon with the same name listening on that socket. The source is in frameworks/base/cmds/keystore/keystore.cpp, so let's have a look. The file has some helpful comments, and we learn that keys are encrypted, checksummed and saved as files (one key per file). But where are the actual files? Looking at /init.rc we find the keystore daemon startup command looks like this:

译文:

查看 frameworks/base/keystore/java/android/security,我们注意到几个有意思的, SDK 文档没有提到的类。最有价值的是 KeyStore 类,所以我们看一看。果然,它被标记成 hidden (使用了可怕的 @hide 注解)(译注:@hide 注解是 Android 源码中,隐藏一个 JAVA 类或者方法时所用的注解,使用了这个注解,它就不会被编译到 Android SDK 中,所以应用开发是没法调用的。但使用 makefile 在源码环境下编译是可以访问的。)。它有和 key store (凭据存储) 交互的方法(get(), put(), delete(), reset() 等)。但真正的 key store 在哪里?事实证明,所有的方法发送命令到一个本地 socket(套接字),恰好命名为 'keystore' (译注:我看新的源码,没有使用 socket, 而是使用了 Binder, 总之是要跨进程通信)。通过一点有创造性的文本查询,我们发现有一个本地的守护进程有相同的名字,监听在那个 socket 上。代码在 frameworks/base/cmds/keystore/keystore.cpp(译注:新的代码已经没有这个文件了,因为是 Binder, 对应的类是 IKeystoreService, 在 frameworks\base\core\java\android\security 中有一个 IKeystoreService.aidl)。让我们看一下,文件有一些有帮助的注释,我们知道 key 是被加密,校验和保存为一个文件(一个 key per 文件)。但真正的文件在哪儿呢?查看 /init.rc 我们找到 keystore 守护进程的启动命令看起来是这样的(译注:我没有看 ICS 的源码):

service keystore /system/bin/keystore /data/misc/keystore
    class main
    user keystore
    group keystore
    socket keystore stream 666

原文:

Next step is, of course, peeking into /data/misc/keystore

译文:

下一步,查看 /data/misc/keystore 目录

# ls -la /data/misc/keystore
-rw------- keystore keystore       84 2011-11-30 15:26 .masterkey
-rw------- keystore keystore      980 2011-11-30 15:56 1000_CACERT_testca
-rw------- keystore keystore      820 2011-11-30 15:55 1000_USRCERT_test
-rw------- keystore keystore      932 2011-11-30 15:55 1000_USRPKEY_test

原文:

Here each file name consists of the UID of the user that created it (1000 is system), the entry type (CA certificate, user certificate or private key), and the key name (alias) connected with underscores. And, of course, there is a .masterkey. Going back to the keystore daemon source, we find out that:

译文:

这里每一个名字的构成部分有:创建它的用户的 UID (1000 是 system), 条目类型(CA 证书,用户证书或私钥),和 key 的名称(别名),用下划线连接。当然,有一个 .masterkey。回到 keystore 守护进程源码,我们找到了:

原文:

  • each key is encrypted with a 128-bit AES master key in CBC mode
  • each key blob contains an info header, the initial vector (IV) used for encryption, an MD5 hash value of the encrypted data and the encrypted data itself
  • the master key (in .masterkey) is itself encrypted with an AES key. The encryption key is derived from the password using the PBKDF2 key-derivation function with 8192 iterations (it may take a while...). The salt is randomly generated and is stored in the .masterkey file's info header.

译文:

  • 每一个 key 被用一个128位的 AES 主密钥CBC 模式加密。
  • 每一个 key 大对象包含一个头信息,一个用来加密的初始化向量initial vector (IV) ,一个被加密数据的 MD5 哈希值以及被加密数据本身。
  • 主密钥 (在 .masterkey)自己被一个 AES key 加密,加密的密钥是从密码中用 PBKDF2 密钥导出方法经过8192次迭代衍生出来的(它可能需要一些时间)。salt 是随机生成的,保存在 .masterkey 文件的头信息中。

原文:

What this means in practice is that the Android key store is pretty secure for a software solution: even if you had access to a rooted device and managed to extract the key blobs, you would still need the keystore password to derive the master key. Trying out different password to decrypt the master key would require at least 8192 iterations to derive a key, which is prohibitively expensive. In addition, the derivation function is seeded with a 128-bit random number, so pre-calculated password tables cannot be used.

译文:

这意味着在实践中 Android 凭据存储在软件方案上是非常安全的,即使你访问一个 root 过的设备,并且成功提取凭据文件,你仍然需要 keystore 的密码来导出主密钥。尝试用不同的密码来解密主密钥需要至少 8192 次迭代来衍生一个凭据,这是过度昂贵的。此外,衍生方法用了一个128位数字的随机种子,所以预设的密码表是不能用的。

原文:

Key blobs are owned by the keystore user, so on a regular (not rooted) device, you need to go through the daemon to access the keys. As it turns out, there is a helpful command line utility that talks to the daemon and lets us manipulate the key store: keystore_cli. It has commands for initializing the key store, listing, getting and deleting keys, etc. Experimenting with it shows that the keystore daemon is additionally checking the calling process's UID to grant or deny access to each command:

译文:

keystore 用户拥有凭据文件,因此在一个正常(没有 root)的设备上,你需要通过守护进程访问私钥。事实表明,有一个很有用的命令行工具,它和守护进程对话并让我们操作 key store:keystore_cli。它有初始化(initializing)、列出(listing)、获取(getting)、删除(deleting )等命令。实验显示:keystore 守护进程额外地检查了调用者的进程UID,来对每一个命名授权或者拒绝。

# keystore_cli unlock
keystore_cli unlock
6 Permission denied
# keystore_cli get CACERT_testca
keystore_cli get CACERT_testca
1 No error
-----BEGIN CERTIFICATE-----
MIICiTCCAfKgAwI...

# su system
su system
$ keystore_cli insert foo bar
keystore_cli insert foo bar
1 No error
$ keystore_cli saw ""
keystore_cli saw ""
1 No error
foo
USRPKEY_test
USRCERT_test
CACERT_testca
$ keystore_cli get foo
keystore_cli get foo
1 No error
bar
$ exit

# su app_44
su app_44
$ keystore_cli saw ""
keystore_cli saw ""
1 No error
$ keystore_cli insert baz boo
keystore_cli insert baz boo
1 No error
$ keystore_cli get baz
keystore_cli get baz
1 No error
boo

原文:

This basically translates to:

  • root cannot lock/unlock the key store, but can access system keys
  • the system user can do pretty much anything (initialize or reset the key store, etc.)
  • regular users can insert, delete and access keys, but can only see their own keys

译文:

这可以简单理解成:

  • root 不能加锁/解锁 key store,但可以访问系统 key
  • system 用户可以做不少其它事情(初始化或重置 key store)
  • 普通用户能插入、删除和访问 key,但只能看到他们自己的

原文:

The android.security.KeyStore class we found while browsing the framework's source is almost a one-to-one port of the keystore_cli command's functionality to Java. By using it Java apps can get direct access to the keystore daemon, but as we said, that class is not part of the public API. There are a couple of reasons for this:

译文:

我们浏览 framework 源码发现的 android.security.KeyStore 类,几乎是 keystore_cli 命令功能到 Java 的一对一的端口。通过使用它,Java 应用能直接访问 keystore 守护进程,但面我们前说过,这个类不是公开 API 的一部分,有下面的一些原因:

原文:

  • even if they had access to it, normal apps wouldn't have the needed permissions to initialize or unlock the key store
  • it's interface exposes the current implementation: keys are returned as raw blobs which wouldn't be possible if the key store and related cryptographic operations were implemented in hardware (such as in a TPM).

译文:

  • 即使它们能够访问,普通 app 也是没有所需权限初始化或解锁 key store 的。
  • 它的接口暴露了当前的实现,key 是以原始文件返回的,这是不可能的,如果 key store 和关联的密码操作是在硬件实现的(例如在一个 受信任的平台模块(Trusted Platform Module))

原文:

As mentioned in the previous article, most of the described credential storage functionality has been available in Android since at least Donut (1.5), but the key store was only accessible to system applications such as Settings, and the WiFi and VPN clients. What ICS adds are a few layers on top of this that make it possible to offer user applications access to the system key store and assert fine-grained control over what keys each app is allowed to use. In the next part of the series we will look at the implementation of the new credential storage functionality added in ICS.

译文:

正如前一篇文章提到的,大多数所描述的证书存储功能已经在 Android Donut(1.5) 以后可用了,但 key store 只对系统应用例如设置、WIFI、VPN客户端等可用。ICS在这上部增加了一些层,使得用户应用访问系统 key store 成为可能,并在允许一个应用使用什么 key 上维护了细粒度控制。在这系列的下一部分,我们将要学习 ICS 添加的新证书存储的实现。

你可能感兴趣的:([翻译]ICS 证书存储实现(ICS Credential Storage Implementation))