署名付き JNLP ファイルを作成してみる

署名付き JNLP ファイルなるものがあるようです。

・署名付きJNLPファイル
http://docs.oracle.com/javase/jp/8/docs/technotes/guides/deploy/signed_jnlp.html

ドキュメントに書いてますが、厳密には JNLP ファイル自体に署名するわけではなく、こいつを JAR ファイルに JNLP-INF/APPLICATION.JNLP として格納してあげて、その JAR ファイルを署名するという形になるようです。

こんなことする理由は、

・たとえば、ランダム・ライブラリを追加したり、アプリケーション情報を変更したりすることによって、他人がJNLPファイルの内容を確実に変更できないようにします。
・アプリケーション内での任意のJava Virtual Machine (JVM)オプションやJavaシステム・プロパティの使用を許可します。
・他人がHTMLブラウザのアプレットでJARファイルを直接参照できないようにします。

とのことです。


ちょっとだけ試してみます。JNLP ファイル等、アプリケーションは以下のエントリーで書いたものを使用します。

・「JavaJava Web Start (JWS) を使ってみた - プログラム日記
http://a4dosanddos.hatenablog.com/entry/2014/04/10/010947

JNLP ファイルの内容だけ少し変更を加えておきます ( jnlp 要素に version 属性を追加しています )。

■ swingtest.jnlp

<?xml version="1.0" encoding="utf-8"?>
<!-- JNLP File for SwingSet2 Demo Application -->
<jnlp
  spec="6.0+"
  codebase="http://localhost/jws"
  href="swingtest.jnlp"
  version="1.0">
  <information>
    <title>swing test</title>
    <vendor>test</vendor>
  </information>
  <security>
      <all-permissions/>
  </security>
  <resources>
    <j2se version="1.6+"/>
    <jar href="test.jar"/>
  </resources>
  <application-desc main-class="test.Test"/>
</jnlp>


ドキュメント踏まえて、swingtest.jnlp からコピーで APPLICATION.JNLP を作成して JNLP-INF ディレクトリに配置、そいつを含む JAR ファイルを作成して署名します

# cp swingtest.jnlp APPLICATION.JNLP
# mkdir JNLP-INF
# mv APPLICATION.JNLP JNLP-INF/
# jar cmvf MANIFEST.MF test.jar test/*.class JNLP-INF/
マニフェストが追加されました
test/Test$1.classを追加中です(入=594)(出=406)(31%収縮されました)
test/Test.classを追加中です(入=885)(出=565)(36%収縮されました)
JNLP-INF/を追加中です(入=0)(出=0)(0%格納されました)
JNLP-INF/APPLICATION.JNLPを追加中です(入=461)(出=269)(41%収縮されました)
# jarsigner -keystore keystore -storepass password test.jar test

■ MANIFEST.MF

Manifest-Version: 1.0
Permissions: all-permissions

■ 上記コマンド実行前のディレクトリ構成

# ls -lR
.:
合計 16
-rw-r--r-- 1 root root   74 10月  7 00:30 2015 index.html
-rw-r--r-- 1 root root 1254 10月  7 00:30 2015 keystore
-rw-r--r-- 1 root root  402 10月  7 00:29 2015 swingtest.jnlp
drwxr-xr-x 2 root root 4096 10月  7 00:29 2015 test

./test:
合計 12
-rw-r--r-- 1 root root 594 10月  7 00:29 2015 Test$1.class
-rw-r--r-- 1 root root 885 10月  7 00:29 2015 Test.class
-rw-r--r-- 1 root root 721 10月  7 00:29 2015 Test.java


あとは「Java コントロールパネルの [署名者の CA] から証明書のインポート ( キーストアからは keytool -exportcert -alias test -keystore keystore -storepass password -file test.cer とかで証明書エクスポートできます )」、「例外サイトリストの追加」を行なえば、JNLP ファイル経由でアプリケーションが実行できるかと思います。


ドキュメントに記載ありますが、実行に使用される JNLP ファイルJAR ファイルの内の JNLP ファイルは同一である必要があるようです。例えば、実行される側の JNLP ファイルの jnlp 要素の version 属性とかを変更してみると、「JNLPSigningException[起動ファイルの署名の検証に失敗しました。署名済のバージョンとダウンロードされたバージョンとが一致しません。]」という例外が発生してアプリケーションが実行できません。

そのアプリケーションを実行するには、使用されるJNLPファイルと、署名付きJAR内のJNLPファイルが同一である必要があります。

JNLPSigningException[起動ファイルの署名の検証に失敗しました。署名済のバージョンとダウンロードされたバージョンとが一致しません。]
	at com.sun.javaws.jnl.LaunchDesc.checkSigning(Unknown Source)
	at com.sun.javaws.security.JNLPSignedResourcesHelper.checkSignedLaunchDescHelper(Unknown Source)
	at com.sun.javaws.security.JNLPSignedResourcesHelper.checkSignedLaunchDesc(Unknown Source)
	at com.sun.javaws.security.JNLPSignedResourcesHelper.checkSignedLaunchDesc(Unknown Source)
	at com.sun.javaws.Launcher.prepareResources(Unknown Source)
	at com.sun.javaws.Launcher.prepareAllResources(Unknown Source)
	at com.sun.javaws.Launcher.prepareToLaunch(Unknown Source)
	at com.sun.javaws.Launcher.prepareToLaunch(Unknown Source)
	at com.sun.javaws.Launcher.launch(Unknown Source)
	at com.sun.javaws.Main.launchApp(Unknown Source)
	at com.sun.javaws.Main.continueInSecureThread(Unknown Source)
	at com.sun.javaws.Main.access$000(Unknown Source)
	at com.sun.javaws.Main$1.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)


同じ内容のファイルが2つ存在するってなんとなく無駄気がしますね・・・

以上になります。

[ 環境情報 ]
CentOS 6.2
Java SE 8
Apache HTTP Server 2.2.15

Windows 7 SP1
Java SE 8 Update 45
Internet Explorer 11