苦戦したのでメモ。
#基礎知識
Android アプリのセキュア設計セキュアコーディングガイド
「5.4. HTTPS で通信する」の項を参照。オレオレ証明書を使った使用例までは載ってますが、クライアント証明書を使った使用例は載ってません。
#下準備
認証局側で、p12 形式のクライアント証明書ファイルを発行します。
#Androidアプリ側の実装
クライアント証明書ファイル(sample.p12)は、/assets/ フォルダに配置。
通信部分の実装で、ローカルに配置したクライアント証明書を読み込むメソッドを用意して…
// クライアント証明書の登録
private void registerClientCert ( Context context ) throws Exception {
KeyManagerFactory keyManagerFactory;
final char[] PASSWORD = "".toCharArray();
InputStream inputStream;
try {
// クライアント証明書ファイルの指定(/assets/ フォルダに配置)
inputStream = context.getResources().getAssets().open( "sample.p12" );
KeyStore keyStore = KeyStore.getInstance( "PKCS12" );
keyStore.load( inputStream, PASSWORD );
keyManagerFactory = KeyManagerFactory.getInstance( "X509" );
keyManagerFactory.init( keyStore, PASSWORD );
SSLContext sslContext = SSLContext.getInstance( "TLS" );
sslContext.init( keyManagerFactory.getKeyManagers(), null, null );
HttpsURLConnection.setDefaultSSLSocketFactory( sslContext.getSocketFactory() );
} catch ( IOException e ) {
throw new Exception( e );
} catch ( KeyStoreException e ) {
throw new Exception( e );
} catch ( NoSuchAlgorithmException e ) {
throw new Exception( e );
}
}
実際の通信部分で一枚かませます。
// クライアント証明書使用設定
try {
this.registerClientCert( context );
} catch ( Exception e ) {
e.printStackTrace();
}
うまくできていれば、サーバ側で受けた php では、こんな感じで確認可能。
$_SERVER["PHP_AUTH_USER"]=> "sample"
$_SERVER["REMOTE_USER"]=> "sample"
#小ネタ
-クライアント証明書が付いてないアクセスが来たときに、apache 側で即弾くのではなく、サーバ側アプリ(php等)でより柔軟にエラー対応したい場合、apache 側のコンフィグ設定で、SSLVerifyClient : optional に指定しておくと良い。
-Android 端末自体に、クライアント証明書を仕込むこともできるが、仕込んだ瞬間から「通信が盗み見される危険性があるよ!」的な警告メッセージがユーザに出まくるようになるので、自分自身が分かってて運用するならともかく、他人に使って貰うのはとても無理っぽい。