コード署名 ( コードサイニング ) について ( ちょっとだけ jarsigner の話 )

コード署名 ( コードサイニング ) についてちょっとしたメモです。

仕組みとしては以下の Web ページがわかりやすいです。

・情報セキュリティ入門 - デジタル署名:ITpro
http://itpro.nikkeibp.co.jp/article/COLUMN/20060704/242422/

簡単にまとめると以下の感じになるかなと思います。

1.署名付与


1-1. コードからハッシュ関数を使ってハッシュ値を得る
1-2. 1 で得たハッシュ値秘密鍵を使用して暗号化してデジタル署名を得る
1-3. コードと 3 で得たデジタル署名をセットにして配布する

2.署名検証


2-1. デジタル署名を秘密鍵と対になる公開鍵で復号する
2-2. コードからハッシュ関数を使ってハッシュ値を得る
2-3. 1 で復号化した値と 2 のハッシュ値を比較する

2-3 で値が一致すれば「確かに復号に使った公開鍵と対になっている秘密鍵の持ち主が署名しました」ということが保証されるという感じになります ( 秘密鍵が盗まれない、CA署名が同じになるような証明書が作れないという前提のもとで )。

上記からコードは暗号化されてないのでその機密性は保てません。あくまで誰がコードに署名したのか ( 秘密鍵の持ち主は誰か ) ということしかわからない感じになります。


以下はちょっと個人的に気になったところで、本題からは逸れてしまします。

一つ目は1-1 で使ったハッシュ関数証明書の署名アルゴリズムハッシュ関数に関連あるのかというところです。これは試した限り特に関連はなさそうでした ( わかってる人には、というか、仕組み考えれば当然かもしれませんが・・・ )

なので、コードからハッシュ値を得るハッシュ関数SHA-1、署名アルゴリズムが SHA256withRSA である証明書を組み合わせても普通にコード署名ができる感じです。

SHA256withRSA の証明書の作成

keytool -genkeypair -keyalg RSA -keystore keystore -storepass password -alias test

証明書の内容

keytool -v --list -keystore keystore -storepass password
 - 略 -
証明書のフィンガプリント:
         MD5:  DE:97:04:0B:54:66:FB:84:FF:24:9A:B1:84:35:D7:E2
         SHA1: BD:BC:4B:6D:54:84:D7:FC:B8:4C:F3:07:6E:FE:33:B4:40:B4:DF:10
         SHA256: B1:FF:C2:36:48:CD:29:04:97:0C:54:C2:37:0A:3B:CB:6B:C4:11:E6:B4:65:BC:67:4F:45:94:7B:15:BE:98:F9
         署名アルゴリズム名: SHA256withRSA
         バージョン: 3
 - 略 -

jarsigner でハッシュ関数 SHA-1 を指定して JAR ファイルを署名

jarsigner -keystore keystore -storepass password -digestalg SHA-1 -signedjar testSign.jar test.jar test

※ digestalg オプションで JAR のエントリからハッシュ値 ( ダイジェスト ) 得る際のハッシュ関数が指定可能です。デフォルトは SHA256 になります。

JAR の内容を表示

jar tf testSign.jar 
META-INF/MANIFEST.MF
META-INF/TEST.SF
META-INF/TEST.RSA
META-INF/
Test.class

※ 無事署名ができているようです。

・jarsigner
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jarsigner.html
・keytool
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html


二つ目は 2-2 のハッシュ関数は何使えばいいってどうやってわかるの、というところです。これは Java の場合だと TEST.SF あたりにハッシュ関数の情報が入ってそうでした。

TEST.SF ( ハッシュ関数 SHA1 )

Signature-Version: 1.0
SHA-1-Digest-Manifest-Main-Attributes: OJFmxm68yhPuEwBZXJnD8Vaaw3o=
SHA-1-Digest-Manifest: NiCjPbjNpBa2WkUj4xSreEhLbaY=
Created-By: 1.8.0_60 (Oracle Corporation)

Name: Test.class
SHA-1-Digest: STOs4C9t5LFW3vodAZquPPwksVs=

※ 例えば、ハッシュ関数 SHA256 として署名すると TEST.SF は以下のような内容になっていました。

Signature-Version: 1.0
SHA-256-Digest-Manifest-Main-Attributes: 5CMJCnGllaZgcPj5rXpXk+9g37GML
 3rQWdxhynpFfl4=
SHA-256-Digest-Manifest: RQ/P8u9Fe+PL9qlSUqncF49CkLF7QnGR9j2DTRkS1H0=
Created-By: 1.8.0_60 (Oracle Corporation)

Name: Test.class
SHA-256-Digest: tXBgT7bbE4iTsa29PFwiDW/yFbq6e5A9BrDi/dQLU/s=

Java 以外でどうなっているのかはわかりませんが、1-3 の際に使用したハッシュ関数の情報も一緒に教えてあげる感じっぽいですね。


しかし、PKI、署名あたりは構成する技術要素が多くて難しいですね。すぐにごっちゃになっちゃいます・・・まぁ、ひとつひとつお勉強していくしかないですね。

今日のところは以上になります。