Androidのキーストアから証明書をエクスポートする

業務でAndroid開発をしていて、都合上、後から鍵ペアを人に渡さなければいけない場合があります。

新しいapkのたびにキーストアファイルを作っているのなら、別にそれごと渡してしまえばいいのですが、自分用のキーストアに作ってしまった場合、キーストアごと渡すわけにはいきません。

そこでキーストアファイルから証明書をエクスポートして相手に渡すことを考えますが、apkに署名するには、証明書の他に秘密鍵が必要です。

先に結論だけ書いておきます。keytoolコマンドのimportkeystoreを使います。

> keytool -importkeystore -srckeystore .\mykeystore.jks -srcstorepass <<自分のキーストアのパスワード>> -destkeystore app1.jks -deststorepass <<新規作成するキーストアのパスワード>> -deststoretype jks -srcalias app1
<app1> の鍵パスワードを入力してください。

これでapp1.jksというキーストアファイルが新規作成され、自分のキーストアの中から特定のエイリアスの鍵ペアだけをコピーできます。

以下は説明です。

例えば自分用のキーストアの中身がこうなっていたとします。

> keytool -list -v -keystore .\mykeystore.jks -storepass <<キーストアのパスワード>>

キーストアのタイプ: JKS
キーストアのプロバイダ: SUN

キーストアには 2 エントリが含まれます。

別名: app1
作成日: 2012/03/08
エントリタイプ: PrivateKeyEntry
証明連鎖の長さ: 1
証明書[1]:
所有者: C=JP
発行者: C=JP
シリアル番号: 4f582f00
有効期間の開始日: Thu Mar 08 00:00:00 JST 2012 終了日: Wed Jul 10 00:00:00 JST 3011
証明書のフィンガープリント:
         MD5:  00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
         SHA1: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
         署名アルゴリズム名: SHA1withRSA
         バージョン: 3


*******************************************
*******************************************


別名: app2
作成日: 2012/03/08
エントリタイプ: PrivateKeyEntry
証明連鎖の長さ: 1
証明書[1]:
所有者: C=JP
発行者: C=JP
シリアル番号: 4f57f300
有効期間の開始日: Thu Mar 08 00:00:00 JST 2012 終了日: Wed Jul 10 00:00:00 JST 3011
証明書のフィンガープリント:
         MD5:  00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
         SHA1: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
         署名アルゴリズム名: SHA1withRSA
         バージョン: 3

証明書のエクスポートとインポートは以下のコマンドでできますが、秘密鍵がエクスポートできません。

> keytool -exportcert -keystore .\mykeystore.jks -storepass <<キーストアのパスワード>> -alias app1 -file .\app1.cer
証明書がファイル <.\app1.cer> に保存されました。

> keytool -import -keystore app1.jks -storepass <<新規作成するキーストアのパスワード>> -file .\app1.cer
所有者: C=JP
発行者: C=JP
シリアル番号: 4f582f00
有効期間の開始日: Thu Mar 08 00:00:00 JST 2012 終了日: Wed Jul 10 00:00:00 JST 3011
証明書のフィンガープリント:
         MD5:  00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
         SHA1: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
         署名アルゴリズム名: SHA1withRSA
         バージョン: 3
この証明書を信頼しますか? [no]:  yes
証明書がキーストアに追加されました。

この状態のキーストアはこうなっています。

> keytool -v -list -keystore .\app1.jks -storepass <<キーストアのパスワード>>

キーストアのタイプ: JKS
キーストアのプロバイダ: SUN

キーストアには 1 エントリが含まれます。

別名: app1
作成日: 2012/03/31
エントリのタイプ: trustedCertEntry

所有者: C=JP
発行者: C=JP
シリアル番号: 4f582f00
有効期間の開始日: Thu Mar 08 00:00:00 JST 2012 終了日: Wed Jul 10 00:00:00 JST 3011
証明書のフィンガープリント:
         MD5:  00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
         SHA1: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
         署名アルゴリズム名: SHA1withRSA
         バージョン: 3


*******************************************
*******************************************

エントリのタイプがtrustedCertEntryになっています。このエントリでapkを署名しようとするとjarsignerがエラーを出します。

jarsigner: 次の証明連鎖が見つかりません: app1。  app1 は、非公開鍵および対応する公開鍵証明連鎖を含む有効な KeyStore 鍵エントリを参照する必要があります。
(英語の場合)
jarsigner: Certificate chain not found for: app1.  app1 must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain.

Eclipseの場合は、何も言われず、Finishボタンが押せません。

ここで最初の結論のところで書いたimportkeystoreを使って、キーストアからキーストアへのインポートをすることで、秘密鍵を持ったまま新しいキーストアに証明書をコピーできます。コピー後のキーストアファイルはこうなります。

> keytool -list -v -keystore .\app1.jks -storepass <<キーストアのパスワード>>

キーストアのタイプ: JKS
キーストアのプロバイダ: SUN

キーストアには 1 エントリが含まれます。

別名: app1
作成日: 2012/04/01
エントリタイプ: PrivateKeyEntry
証明連鎖の長さ: 1
証明書[1]:
所有者: C=JP
発行者: C=JP
シリアル番号: 4f582f00
有効期間の開始日: Thu Mar 08 00:00:00 JST 2012 終了日: Wed Jul 10 00:00:00 JST 3011
証明書のフィンガープリント:
         MD5:  00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
         SHA1: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
         署名アルゴリズム名: SHA1withRSA
         バージョン: 3

エントリタイプがPrivateKeyEntryになっていれば、通常通りapkの署名に使えます。

あと、importkeystoreが使えるのはJDK6以降のようなので、バージョンは確認してください。


sfGuardFormSigninのメッセージをカスタマイズする

Symfony1.4でsfDoctrineGuardPluginを使っていて、ユーザ名かパスワードが違うときに、

The username and/or password is invalid.

と表示されてしまうので、これを変更したいと思います。それと、ラベルも日本語にしておきたいと思います。

sfGuardFormSigninを継承したフォームクラスをひとつ作ります。今回は/app/front/modules/sfGuardAuth/lib/form/mySigninForm.class.phpに作りました。

<?php

class mySigninForm extends sfGuardFormSignin
{
    public function configure()
    {
        parent::configure();
        
        $this->widgetSchema['username']->setLabel('ユーザID');
        $this->widgetSchema['password']->setLabel('パスワード');
        
        $this->validatorSchema['username']->setMessage('required', '入力して下さい');
        // $this->validatorSchema['username']->setMessage('invalid', 'ユーザIDかパスワードが違います'); // 効かない
        $this->validatorSchema['password']->setMessage('required', '入力して下さい');
        
        $validator = $this->getValidatorSchema()->getPostValidator();
        $validator->setMessage('invalid', 'ユーザIDかパスワードが違います');
    }
}

PostValidatorを取得してくるのが肝です。前述のメッセージはsfGuardValidatorUserで定義されているのですが、このバリデーターはBasesfGuardFormSigninでsetPostValidator(new sfGuardValidatorUser())として呼ばれているためです。

ちなみに、mySigninFormを有効にするには、/app/front/config/app.ymlに

all:
  sf_guard_plugin:
    signin_form: mySigninForm

を追加して、デフォルトのフォームクラスを変更する必要があります。


Windows 7 x64にMercurialからgitを操作できるhg-gitをインストールする

Windows 7 x64にhg-gitをeasy_installから入れようとして、ハマったことのメモです。

hg-gitについてはこちら。
Hg-Git Mercurial Plugin

コマンドプロンプトから
C:\> C:\Python27\Scripts\easy_install.exe hg-git
C:\> C:\Python27\Scripts\easy_install.exe -Z hg-git
でインストールできます。(-Zオプションを付けないと、hg_git-0.3.2-py2.7.eggに圧縮されてしまうので、あとでmercurial.iniにパスを指定できなくなる)

error: Setup script exited with error: Unable to find vcvarsall.bat

まずはvcvarsall.batが見つからないと怒られます。これはVisual C++ 2008 Express Edition with SP1をインストールすればOKです。2010は使えないようなので、2008をインストールします。
Visual Studio 2008 Express | Microsoft Visual Studio
ダウンロードリストからC++を選んでダウンロードしてください。

C:\Python27>Scripts\easy_install.exe hg-git
Searching for hg-git
Best match: hg-git 0.3.2
Processing hg_git-0.3.2-py2.7.egg
hg-git 0.3.2 is already the active version in easy-install.pth

中略

  File "C:\Python27\lib\distutils\msvc9compiler.py", line 299, in query_vcvarsall
    raise ValueError(str(list(result.keys())))
ValueError: [u'path']

で、次はValueError: [u’path’]のエラーが出たので、調べると、PythonのIssueに上がっている問題のようです。パッチが出ていますが、未だに取り込まれていない様子。

Issue 7511: msvc9compiler.py: ValueError when trying to compile with VC Express – Python tracker

ここから、vcvars4.diff(最新のdiff)をダウンロードします。

パッチを充てたいので、Windowsで動くpatchを探すと、

UnxUtils | Free software downloads at SourceForge.net

ここからダウンロードできるようです。

が、なぜかpatch.exeが管理者権限を要求するので、ちょっと怖いので結局手作業でmsvc9compiler.pyをdiffに従って編集しました。まぁ、大した量ではないので…



2012/04/18追記:

コメント欄で原因と対策を教えていただきました。Windowsがpatch.exeというファイル名を勝手にブロックするようです。patchという文字列が入っていて、実行可能形式の拡張子(exeとかscrとか)だと発動するようなので、p.exeなどにファイル名を変更すれば大丈夫です。

パッチを当てられないWindows VISTA

ちなみに、install.exeやsetup.exe、update.exeなども同じ原因で権限を要求されます。

MSDNでの公式情報はこちら。

New UAC Technologies for Windows Vista

で、再度実行すると、また新しいエラーが出ました。

Reading http://launchpad.net/dulwich
Best match: dulwich 0.8.3
Downloading http://samba.org/~jelmer/dulwich/dulwich-0.8.3.tar.gz
Processing dulwich-0.8.3.tar.gz
Running dulwich-0.8.3\setup.py -q bdist_egg --dist-dir c:\users\***\appdata\local\temp\easy_install-ghb21p\dulwich-0.8.3\egg-dist-tmp-sc0we9
error: Setup script exited with error: Visual Studio Express: need 64-bit tools from the SDK

Windows SDKの64bit版C++ Compilerをインストールしろ、ということなのですが、罠があります。最新のSDKをインストールしても解消しません。

MathWorks 日本 – How can I set up Microsoft Visual Studio 2008 Express Edition for use with MATLAB 7.7 (R2008b) on 64-bit Windows? – MATLAB & Simulink

こちらの情報によると、「Windows SDK for Windows Server 2008 and .NET Framework 3.5」か、「Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1」でないとダメのようです。

今回は「Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1」をインストールして成功しました。SDKのインストールの最後に致命的エラーとか表示されましたが、特に問題はなかったようです。

これで再度、easy_install hg_gitを実行すれば、

Installed c:\python27\lib\site-packages\dulwich-0.8.3-py2.7-win-amd64.egg

Finished processing dependencies for hg-git

となって、インストールがやっと成功しました。

最後に%userprofile%\mercurial.iniを開いて、

[extensions]

bookmarks =

hggit = C:\Python27\Lib\site-packages\hg_git-0.3.2-py2.7.egg\hggit

のようにhggitの場所を指定してやればOKです。


Conversion to Dalvik format failed with error 1

[2012-03-05 08:32:06 - Test] Dx 
trouble processing "javax/net/SocketFactory.class":

Ill-advised or mistaken usage of a core class (java.* or javax.*)
when not building a core library.

This is often due to inadvertently including a core library file
in your application's project, when using an IDE (such as
Eclipse). If you are sure you're not intentionally defining a
core class, then this is the most likely explanation of what's
going on.

However, you might actually be trying to define a class in a core
namespace, the source of which you may have taken, for example,
from a non-Android virtual machine project. This will most
assuredly not work. At a minimum, it jeopardizes the
compatibility of your app with future versions of the platform.
It is also often of questionable legality.

If you really intend to build a core library -- which is only
appropriate as part of creating a full virtual machine
distribution, as opposed to compiling an application -- then use
the "--core-library" option to suppress this error message.

If you go ahead and use "--core-library" but are in fact
building an application, then be forewarned that your application
will still fail to build or run, at some point. Please be
prepared for angry customers who find, for example, that your
application ceases to function once they upgrade their operating
system. You will be to blame for this problem.

If you are legitimately using some code that happens to be in a
core package, then the easiest safe alternative you have is to
repackage that code. That is, move the classes in question into
your own package namespace. This means that they will never be in
conflict with core system classes. JarJar is a tool that may help
you in this endeavor. If you find that you cannot do this, then
that is an indication that the path you are on will ultimately
lead to pain, suffering, grief, and lamentation.

[2012-03-05 08:32:06 - Test] Dx 1 error; aborting
[2012-03-05 08:32:06 - Test] Conversion to Dalvik format failed with error 1

Package Explorerからプロジェクトを右クリックして、Properties選択。

Java Build Path→Librariesを開いて、表示されているライブラリを全部Remove。

OKでウィンドウを閉じて、再度Package Explorerを右クリックして、Android ToolsからFix Project Propertiesを選択。

解決。


WindowsにISC BIND9をNSISでインストールする

WindowsでDNSサーバを立てるにあたってBINDを使ったのですが、標準のBINDInstall.exeが使いにくいのと、サイレントインストールしたかったので、NSISを使ってインストーラーを作る方向にしました。

基本的には全部展開して設置したあと、VC2005再頒布可能パッケージをインストールして、named.exeをサービス登録するだけです。

ファイアウォールの許可もしています。

プラグインを3つ使っています。
Nsisunz plug-in – NSIS Zipの展開
NSIS Simple Service Plugin – NSIS サービス登録
NSIS Simple Firewall Plugin – NSIS ファイアウォール登録
Zipを二重にするのももったいないので、あらかじめ展開しておくのが妥当かとは思います。

設定ファイルは適当に作ってください。

あと肝心のBINDはこちら。
BIND | Internet Systems Consortium

!include "MUI.nsh"
!include "Sections.nsh"

!define TEMP $R0
!define TEMP2 $R1
!define VAL1 $R2
!define VAL2 $R3

Name "BIND9 Installer"
OutFile "setup.exe"

InstallDir "C:\dns"

!define BIND9_FILENAME "BIND9.8.1-P1.zip"

Section auto_setup
  
  SetOutPath "$TEMP"
  File "${BIND9_FILENAME}"
  
  SetOutPath "$INSTDIR\bin"
  nsisunz::Unzip "$TEMP\${BIND9_FILENAME}" "$INSTDIR\bin"
  
  ; VC++ 2005 redistインストール
  ExecWait '"$INSTDIR\bin\vcredist_x86.exe" /q:a /c:"VCREDI~1.EXE /q:a /c:""msiexec /i vcredist.msi /qb!"" "' 
  
  ; BINDのインストールディレクトリをレジストリに登録
  WriteRegStr HKLM "SOFTWARE\ISC\BIND" "InstallDir" "$INSTDIR"
  
  ; etcとconfに設定ファイルを配置する
  SetOutPath "$INSTDIR\conf"
  File /r "conf\*.txt"
  
  SetOutPath "$INSTDIR\etc"
  File "named.conf"
  ExecWait '"$INSTDIR\bin\rndc-confgen" -a -b 512'
  
  ; Firewall許可
  SimpleFC::AddApplication "ISC BIND" "$INSTDIR\bin\named.exe" 0 2 "" 1
  
  ; BINDをサービスに登録
  SimpleSC::InstallService "BIND" "ISC BIND" "16" "2" "$INSTDIR\bin\named.exe" "" "NT AUTHORITY\NetworkService" ""
  
  ; BINDサービス起動
  SimpleSC::StartService "BIND" "" 30

SectionEnd

Section "Uninstall"
  
  ; サービス停止と解除
  SimpleSC::StopService "BIND" 1 30
  SimpleSC::RemoveService "BIND"
  
  ; レジストリ削除
  DeleteRegKey HKLM "SOFTWARE\ISC\BIND"
  
  ; Firewall解除
  SimpleFC::RemoveApplication "$INSTDIR\bin\named.exe"
  
  ; ファイル削除
  RMDir /r "$INSTDIR"
  
SectionEnd


Windows版MySQLの配布形態ごとの違い

Windows版のMySQL Server 5.5には、3種類の配布形態があります。

MySQL Installer

http://www-jp.mysql.com/downloads/installer/
msi形式のファイルです。
mysql-installer-5.5.21.0.msiのようなファイル名になっています。

サーバーに加えて、サンプルとドキュメント、Connectors、Workbenchなどのツールが含まれます。一番多くの人におすすめできるパッケージとの事。

The Complete Package

http://www-jp.mysql.com/downloads/mysql/
WS000006

上2つがComplete Packageです。mysql-5.5.21-win32.msiのようなファイル名になっています。組み込みサーバやベンチマークスイートなどが含まれます。

The Noinstall Archive

Complete Packageと同じURLで配布されています。上の画像では、Zip Archiveと書かれているもののうち、上2つです。mysql-5.5.21-win32.zipのようなファイル名になっています。

ファイルサイズが大きいのは、テストやベンチマークなどに加えて、デバッグ情報(pdb:プログラムデバッグデータベースファイル)が付属しているためです。

ただし、このzipファイルにはMySQLInstanceConfig.exeは含まれていません。my.iniファイルの作成とサービス登録は自力で行う必要があります。

ちなみに最後のひとつはソースコードです。バイナリは含まれていません。

それぞれのパッケージのインストール方法と、インストーラーの挙動はpdfで公開されています。
http://downloads.mysql.com/docs/mysql-windows-excerpt-5.5-en.pdf

表です。5.1のEssentialsを参考にしているので間違っているかもしれません。
出典:http://downloads.mysql.com/docs/mysql-windows-excerpt-5.1-en.pdf

 

Installer

Complete

No-install

Installer

あり

あり

なし

MySQL Server Instance Config Wizard

あり

あり

なし

Test Suite

なし

あり

なし

MySQL Server

あり

あり

あり

MySQL Client Programs

あり

あり

あり

C Headers/Libraries

あり

あり

あり

Embedded Server

なし

オプション

あり

Scripts and Examples

なし

オプション

あり

5.1まであった、Essentialsはなくなったようです。

MySQLのmsi形式のインストーラーは、別のMySQLInstaller.exeを展開して使うためにあるようなものなので、インストール先ディレクトリをmsiexecを使ったコマンドラインで指定したりできません。

NSISなどに組み込んで、インストール先を指定したい場合はzipで配布されているNo-install版を使うのが正しいようです。


URLGrabberでFatal Python error: deallocating None

URLGrabberで数千件のURLをkeep-aliveで取得しようとすると、大体同じような回数でFatal Python error: deallocating Noneが出ることがあります。

どうやら、PycURLの参照カウントの問題らしいです。

パッケージでインストールされるものは古いので、PycURLを最新のソースからインストールしなおしましょう。以下、環境はDebian squeeze+python 2.6。

python-pycurlをすでにインストールしている場合はアンインストールしておく必要があります。

# aptitude install python-pycurl
でインストールしている場合は、
# aptitude purge python-pycurl
でアンインストールしておきましょう。

pycurlは最新のものをsourceforgeのCVSからダウンロードします。

SourceForge.net Repository – [pycurl] Index of /pycurl
下の方にある、「Download GNU tarball」のリンクからtarファイルをダウンロードできます。
ダウンロードしたファイルをpycurl.tar.gzなどに名前変更して、tar xvzf pycurl.tar.gzで展開できます。

ビルドにはcurl-configとPython.hなどが必要なので、必要なパッケージをインストールしておきます。

# aptitude install python2.6-dev libcurl4-gnutls-dev

pycurl.tar.gzを展開したら
# cd ./pycurl/
# python setup.py install
で、インストール完了です。

ちなみに、python2.6-devをインストールしていないと、
src/pycurl.c:42:20: error: Python.h
のようなエラーが大量に出ます。

とりあえずこれで、今のところ安定動作しています。


DoctrineMongoDBBundleでAbstractDoctrineExtensionのエラー

PHP Fatal error:  Class ‘Symfony\\Bridge\\Doctrine\\DependencyInjection\\AbstractDoctrineExtension’ not found in /home/path/to/Symfony/vendor/bundles/Symfony/Bundle/DoctrineMongoDBBundle/DependencyInjection/DoctrineMongoDBExtension.php on line 31

php – DoctrineMongoDBBundle getting a fatal error in Symfony2 – Stack Overflow

masterリポジトリが書き換えられていて、最新バージョンでは動かないのでdepsファイルにDoctrineMongoDBBundleのレポジトリを指定するときに、バージョン番号を指定する必要があるということでした。
DoctrineMongoDBBundleセクションにversion=v2.0.0を追加すればOKです。

[doctrine-mongodb]
    git=http://github.com/doctrine/mongodb.git

[doctrine-mongodb-odm]
    git=http://github.com/doctrine/mongodb-odm.git

[DoctrineMongoDBBundle]
    git=http://github.com/symfony/DoctrineMongoDBBundle.git
    target=/bundles/Symfony/Bundle/DoctrineMongoDBBundle
    version=v2.0.0


Windows版のPHP5.3がc0000005で強制終了する

Symfony 1.4.16をWindowsのPHP 5.3.9で実行したときに、特定の条件で強制終了する現象に悩まされていました。
主にSymfonyタスクでdoctrine:data-dumpなどを実行するときに落ちていました。

色々調べた結果、Symfonyに問題があるわけではなく、/lib/vendor/symfony/lib/config/sfDefineEnvironmentConfigHandler.class.phpがきっちり4096バイトだったということが原因でした。

つまり、PHP5.3.9では、4096バイトのファイルをrequireもしくはincludeするとc0000005(Access Violation)で強制終了します。CLIに限らず、Apache経由でも同じです。

試しに4096バイトの一切コードが書かれていないテキストファイルを作ってrequireしてみると、再現しました。

強制終了時のウィンドウと、内容は以下のとおり。

image

ちなみにモジュール名はnts(Non Thread Safe)版ならphp5.dll、ts(Thread Safe)版ならphp5ts.dllです。
どちらも確認しましたが、どちらも同じ現象です。モジュールは入っていても入っていなくても同じです。

問題の署名:
  問題イベント名:    APPCRASH
  アプリケーション名:    php.exe
  アプリケーションのバージョン:    5.3.9.0
  アプリケーションのタイムスタンプ:    4f0c5cd0
  障害モジュールの名前:    php5.dll
  障害モジュールのバージョン:    5.3.9.0
  障害モジュールのタイムスタンプ:    4f0c5dfb
  例外コード:    c0000005
  例外オフセット:    00090f5b
  OS バージョン:    6.1.7601.2.1.0.256.48
  ロケール ID:    1041
  追加情報 1:    0a9e
  追加情報 2:    0a9e372d3b4ad19135b953a78882e789
  追加情報 3:    0a9e
  追加情報 4:    0a9e372d3b4ad19135b953a78882e789

多分現象はこのバグ報告と同じだと思います。
PHP :: Bug #60758 :: require() crashes Apache

5.4.0RC5でも解決してないみたいですね。報告とほぼ同じですが、これで再現できます。

<?php
file_put_contents('test.txt', str_pad('', 4096));
include('./test.txt');

とりあえず対処法としては改行1文字でも増やしておけばいいってことですか…


2012年

nenga2012

2012年もよろしくお願いします。

久しぶりにShade使いました。

タブレットでモデリングしたいなぁ。