本記事について
Qiitaの記事と同一の内容です。
当Wikiは時々閲覧不能になることがあるため、ミラーとして置いてあることを承知下さいませ。
はじめに
MinecraftのMODはjar形式で提供されますが、このjarが読み込まれる際に署名が付いていない旨の警告がログに出力される場合があります。
本記事はその警告を出なくするため、jarファイルに署名を加える方法を解説します。
前提条件
対象となるMODの、build.gradleでのビルドが正常に完了し、本番環境で問題無く動作する状態であること。
署名に必要なツール
- Java Development Kit
- OpenSSL (証明書の作成時のみ)
証明書の作成
署名に必要な証明書は、認証局に申請して入手するかOpenSSLやWindows Serverの証明書機関で生成してもかまいません。
その場合はこの手順はスキップして、フレンドリ名の確認まで飛ばして下さい。
ここではJDKの機能で証明書を作成します。
$ keytool -genkeypair -storetype pkcs12 -keystore 証明書ファイル.p12 -alias フレンドリ名 -keyalg ec -keysize 384 -validity 3650
keytool
の引数の解説はkeytoolのオプション(英語)またはQiitaの記事をご覧下さい。
上記のコマンドを実行すると、楕円曲線暗号の384bitを鍵とした証明書を作成します。
パスワードについて
この際、証明書を使用する際のパスワードを尋ねられます。
Gradleでビルドと同時に署名を行いたいのであれば、コミットしても問題無いような文字列をパスワードにすると良いでしょう。
ただし、この場合は絶対に証明書をリポジトリにコミットしたりしてはいけません。
入力項目について
次に、いくつか入力項目が現れますので、順に追って説明します。
- 姓名
ニックネームとかツイッターアカウントの名前とかでかまいません。 - 組織単位名
個人の場合は活動のジャンルの名称でいいでしょう。
たとえば、今回作成する証明書はMODのJARファイルに署名するのでmcmodにする、といった具合です。 - 組織名
これも個人の場合は姓名と同じにするか、ウェブサイトのドメイン名などでかまいません。 - 都市名または地域名
住所を知られたくない場合は適当な地域で。 - 都道府県名または州名
4に同じく。 - 国コード
日本ならJPになります。
国コードの入力が終わると、[いいえ]:
という意味不明なプロンプトが出ますが、これにはy
だけ入力して下さい。
そうしないと最初からやり直しとなってしまいます。
2度目のパスワードについて
これはそのまま何も入力せずにEnterキーを押して次に進んだ方が混乱が無くて良いと思います。
これで証明書は作成されました。
フレンドリ名の確認と設定
jarファイルへの署名には、証明書の他にフレンドリ名の設定が行われている必要があります。
keytool
で生成した証明書であれば、-alias
で指定した名称がフレンドリ名としてファイルに記録されています。
しかし、それ以外の方法で生成した場合はフレンドリ名の設定が行われていない場合があります。
フレンドリ名の確認
$ openssl pkcs12 -in 証明書ファイル.p12 -info -nokeys
これを実行後パスワードを入力して、得られた出力の中にBag Attributes
があるはずです。
そのすぐ下にfriendlyName
の項目があれば、フレンドリ名が記録されているのでOKです。
フレンドリ名の設定
フレンドリ名が設定されていない場合は追加します。
- バックアップ
$ mv 証明書ファイル.p12 証明書ファイル.p12.bak
- PKCS12から証明書と鍵を取り出す
$ openssl pkcs12 -in 証明書ファイル.p12.bak -info -nodes -out temp.txt
- 取り出した証明書と鍵からフレンドリ名を設定しつつPKCS12を生成
$ openssl pkcs12 -export -in temp.txt -name フレンドリ名 -out 証明書ファイル.p12
注意点として、パスワードは必ず6文字以上にしなければなりません。これはjarsignerの仕様で、これを満たさないパスワードはエラーになってしまうためです。 - 後始末
$ rm temp.txt
フィンガープリントの確認
MinecraftのMODのJARファイルを署名付きで公開する場合、必要となってくるのがフィンガープリントの値です。
フィンガープリントとは、証明書をバイナリデータ(ASN-1形式)で表現したときにそのデータをハッシュ関数で処理した値のことです。
同じ証明書からは同じフィンガープリントの値が得られるので、期限が切れた等で作り直さない限りはここで調べた値を流用出来ます。
Minecraft ForgeではSHA-1ハッシュアルゴリズムでのフィンガープリントの値が要求されます。
OpenSSLを使用してフィンガープリントを取得
$ openssl pkcs12 -in 証明書ファイル.p12 -info -nokeys|openssl x509 -fingerprint -noout
実行するとパスワードを入力後、フィンガープリントの値が「:」で区切られた16進数表記で出力されます。
フィンガープリントの値をMODで記述する文字列にする
この表記から「:」を削ってつなげた後、大文字を小文字に書き直します。
これがMOD内に記述するフィンガープリントの値となります。
MODのソースコードに記述する
@Mod
アノテーションにcertificateFingerprint
を書き加え、その後にフィンガープリントの値を文字列として記述します。
@Mod(modid = "hogemod", /*…中略…*/ certificateFingerprint = "フィンガープリントの値") public class HogeMod { /*…中略…*/ }
DummyModContainerを継承したcoremodの場合
DummyModContainer
を継承する場合は@Mod
アノテーションを使用できないため、継承クラス内でgetSigningCertificate()
メソッドをオーバーライドし、クラスの証明書(Certificate
)を返します。
public class SampleCoreMod extends DummyModContainer { private Certificate certificate; public SampleCoreMod() { super(new ModMetadata()); /*---中略---*/ // ClassからCertificatesを取得 Certificate[] certificates = getClass().getProtectionDomain().getCodeSource().getCertificates(); certificate = certificates != null ? certificates[0] : null; } @Override @Nullable public Certificate getSigningCertificate() { // certificateを返す return certificate; } }
署名が一致しないときの処理
必須ではありませんが、Forgeのイベントハンドラに署名が一致しなかった場合に呼ばれるものがあります。
FMLPreInitializationEvent
やFMLInitializationEvent
と同じように、FMLFingerprintViolationEvent
の引数をもつメソッドを@Mod.EventHandler
アノテーションを使い宣言します。
@Mod.EventHandler public void badSignature(FMLFingerprintViolationEvent event) { System.err.println("署名が一致しません!オリジナルの配布ファイルではありません!"); }
JARファイルに署名する
署名処理を行いますが、これにはコマンドを実行するのとgradleで行わせるの二つの方法があります。
コマンドで署名する
$ jarsigner -sigalg SHA256withECDSA -digestalg SHA-256 -tsa http://timestamp.digicert.com -keystore 証明書ファイル.p12 署名したいjarファイル フレンドリ名
jarsigner
の引数の解説はjarsignerのオプション(英語)またはQiitaの記事をご覧下さい。
上記のコマンドを実行すると、証明書のパスワードを尋ねられた後、jar内の各ファイルについてSHA-256ハッシュを計算して、それに証明書の鍵(ECDSA)で署名を行います。
Gradleで署名する
build.gradleの最後に次のコードを追加します。
ant.signjar
に渡す各引数は前項のjarsigner
と同じです。
task signJar<<{ ant.signjar( jar:jar.archivePath, alias:"フレンドリ名", keystore:"証明書ファイル.p12", storepass:"証明書パスワード", sigalg:"SHA256withECDSA", digestalg:"SHA-256", tsaurl:"http://timestamp.digicert.com" ) } signJar.dependsOn reobfJar assemble.dependsOn signJar
このbuild.gradleを使いビルドを実行すると署名済みJARファイルが生成されます。
動作確認
生成された署名済みjarファイルをmodsフォルダーに配置して、ForgeがインストールされたMinecraftを起動します。
タイトル画面に進んだら、options.txtと同じ階層にあるlogs\debug.logを開きます。
正常に署名が認識されていれば、このような文言が現れます。
[HH:MM:SS] [main/DEBUG] [FML]: Mod signature data [HH:MM:SS] [main/DEBUG] [FML]: Valid Signatures: …中略… [HH:MM:SS] [main/DEBUG] [FML]: (フィンガープリントの値) <MOD ID> (<MOD名> <MODバージョン>) <JARファイル名> …中略…