2012年3月14日水曜日

Android ICS のキーストアアクセスの一元化

元記事 Unifying Key Store Access in ICS

Android 4.0 (ICS) では、人々がパーソナルな Android デバイスを仕事に使えるようにするための多くの機能拡張が追加されています。ここでは、キーストア機能について取り上げます。

Android 1.6 (Donut) で VPN を利用するためにシステムキーストアが追加されました。のちに WiFi 認証のサポートにも拡張されましたが、アプリケーションがアクセスすることはできない状態でした。

これまで、セキュアなSSLウェブサーバーの認証や、クライアント証明書を介してサーバーにユーザー認証する必要がある場合、アプリにとって自身のキーストア管理は共通の課題でした。このための処理では、メールやブラウザなどのいくつかのアプリに渡って複数の証明書が共有されるようなエンタープライズ向けの環境では、管理上の問題があらわれる可能性があります。

ICS での新機能 : KeyChain

このギャップを埋めるために、ICS では KeyChain という名前の新しい API が追加されました。KeyChain はシステムキーストアへのアプリケーションアクセスを調整し、そこに保存されている証明へのアプリケーションのアクセスをユーザーが付与できるようにします。加えて、この API は X.509 証明書と PKCS#12 キーストアからの証明のインストールの初期化をアプリケーションからできるようにします。

KeyChain API はとてもシンプルです。キーストアもしくは証明書をインストールするには、install intent を取得して証明の raw bytes を適用し、システムインストールダイアログを起動する intent を使います。キーストアの場合、次の例のように PKCS#12 形式のデータを提供し、ユーザーがその PKCS#12 のパスワードを知っている必要があります。 byte[] keystore = . . (read from a PKCS#12 keystore) Intent installIntent = KeyChain.createInstallIntent(); installIntent.putExtra(KeyChain.EXTRA_PKCS12, keystore); startActivityForResult(installIntent, INSTALL_KEYSTORE_CODE);


install intent はユーザーにキーストアのパスワードを入力するよう求めるシステムダイアログを起動します。

これは、同じ CA によって発行された証明書をもつ non-public なサーバーへの認証が、全てのアプリケーションによって信頼されるようになる、組織的な CA 証明書のインストールにも使うことができます。

ICS では、Android はもはや system credential storage を守るための個別のパスワードを必要としません。代わりにスクリーンロックパスワードを使います。また、Android Device Administration API は中央管理でのポリシーの執行につかうことができます。これが意味することとして、例えば、セキュリティで保護された証明がデバイスに残っている限りスクリーンロックパスワードを削除することはできません。

Accessing System Key Store Credentials

一度システムキーストアが設定されると、KeyChain API は SSL サーバーでの認証に使うクライアント証明書をリクエストするなどの機能を提供します。アプリケーションが最初のアクセスをリクエストすると、ユーザーに利用できる証明書の一覧が表示され、アプリケーションにアクセスを付与する証明書を選択します。ユーザーが証明書へのアクセスを許可する選択をした場合、証明書用の文字列エイリアス名がアプリケーションに返ってきます。アプリケーションはその後の証明書へのアクセスでこのエイリアスを使うことでユーザーを煩わせずにすみます。

次のコードは、ユーザーが証明書エイリアスを選択してアプリケーションにアクセスを付与するためのプロンプトを表示する方法です。KeyChain はこの選択(同じアプリケーションが保存できる証明書エイリアスの選択)を覚えておき、その後の同じ証明書へのアクセスを持ちます。例えば、ICS 向けのメールアプリケーションではこの機能をサーバー設定画面で実装しています。 KeyChain.choosePrivateKeyAlias(this, new KeyChainAliasCallback() { public void alias(String alias) { // Credential alias selected. Remember the alias selection for future use. if (alias != null) saveAlias(alias); } }, new String[] {"RSA", "DSA"}, // List of acceptable key types. null for any null, // issuer, null for any "internal.example.com", // host name of server requesting the cert, null if unavailable 443, // port of server requesting the cert, -1 if unavailable null); // alias to preselect, null if unavailable


一度アプリケーションに証明書へのアクセスが付与されると、getPrivateKey() メソッドを通して秘密鍵にアクセスできるようになります。任意の PrivateKey オブジェクトに対してエンコーディングに関する仮定をするべきではない、ということは注目に値することです。例えば、いくつかの実装上の PrivateKey オブジェクトは単にハードウェアキーストア内に保存されたキーの不透明な表現であるかもしれません。

次は、キーストアから秘密鍵を取得するためのサンプルコードです。 PrivateKey privateKey = KeyChain.getPrivateKey(context, savedAlias); if (privateKey != null) { ... Signature signature = Signature.getInstance("SHA1withRSA"); signature.initSign(privateKey); ... } 秘密鍵の一般的な使い道は SSL クライアント認証です。これは HttpsURLConnection と、KeyChain API から取得した PrivateKey を返す独自の X509KeyManager を使って実装することができます。ICS 向けのオープンソースのメールアプリケーションは X509ExtendedKeyManager を使っています。より詳しくはこのソースコード(SSLUtils.java 内)を見てください。

この API はシステムキーストア証明書への一元的なアクセス方法を提供します。あなたのアプリケーションがクライアント認証を使う(エンタープライズ向けのメールクライアントやウェブブラウザの開発者)なら、次のアップデート用に KeyChain API を調べてみてください。

1 件のコメント: