多くの場合、JAR ファイルは、Java のクラスファイルやリソースの単なるアーカイブではありません。JAR ファイルは、アプリケーションおよび拡張機能の構築ブロックとして使用されます。META-INF ディレクトリが存在する場合、そのディレクトリは、セキュリティ、バージョン管理、拡張機能、サービスなど、パッケージおよび拡張機能の構成データを格納するために使用されます。
名前-値ペアのグループを「セクション」と呼びます。セクションはほかのセクションと空白行で分けられます。
バイナリデータは、どの形式であれ base64 で表されます。行の長さが 72 バイ トを超えるようなバイナリデータについては継続が必要です。バイナリデータの例はダイジェストおよび署名です。
実装によって、65535 バイトまでのヘッダ値がサポートされます。
このドキュメントの仕様には同一の文法が使われており、終端記号は固定幅のフォントで示され、終端以外の記号はイタリック書体で示されています。
; Also: 電子メールで直接送信されるファイルの分解を防止するため、
; header の先頭に「From」という 4 文字を置かないこと
上の仕様で定義されている終端以外の記号は、以降の仕様で使われています。
メインセクションには、JAR ファイル自体のセキュリティと構成情報以外に、その JAR ファイルが使われているアプリケーションまたは拡張機能のセキュリティと構成情報を指定します。また、各マニフェストエントリに適用されるメイン属性も定義します。メインセクションの属性に、「Name」と同じ名前を付けることはできません。メインセクションは、空白行で終わります。
個別セクションには、この JAR ファイルに格納されているパッケージまたはファイルのさまざまな属性を定義します。アーカイブ内のすべてのファイルをマニフェストのエントリにリストする必要はありませんが、署名するすべてのファイルはリストする必要があります。マニフェストファイル自体はリストしないでください。各セクションは、「Name」という名前の属性で始まる必要があります。この属性の値は、ファイルに対する相対パス、またはアーカイブの外部のデータを参照する絶対 URL でなければなりません。
1 つのファイルエントリに複数の個別セクションがある場合は、これらのセクションの属性はマージされます。特定の属性の値がセクションによって異なる場合は、最後のセクションの値が認識されます。
理解できない属性は無視されます。アプリケーションによって使われる実装固有の情報に、理解できない属性が含まれていることがあります。
上の仕様では、メインセクションに指定した属性はメイン属性、個別セクションに指定した属性はエントリ別属性と呼ばれています。属性によっては、メインセクションと個別セクションの両方で指定できます。 この場合、そのエントリでは、メイン属性の値はエントリ別属性の値によってオーバーライドされます。2 つのタイプの属性は、以下のように定義されます。
Name:foo/bar/
Sealed:false
エントリ別属性は、次のグループに分類されます。
拡張機能パッケージのバージョン管理およびシーリング情報を定義する。メイン属性に定義されている属性を参照。エントリ別属性として使う場合は、メイン属性はオーバーライドされる。ただし、マニフェストエントリに指定したファイルにだけ適用される
java.security
API を直接使います。JAR ファイルを jarsigner ツールで署名した場合は、META-INF
ディレクトリ内の署名に関係しないファイルを含め、すべてのファイルエントリが署名されます。署名に関係するファイルは次のとおりです。
META-INF/MANIFEST.MF
META-INF/*.SF
META-INF/*.DSA
META-INF/*.RSA
META-INF/SIG-*
META-INF
サブディレクトリ内にあっても、それらのファイルは署名に関係するファイルとは見なされません。上記のファイル名と大文字と小文字の区別が異なるファイル名は予約済みで、それらのファイルは署名されません。
JAR ファイルのサブセットを署名するには、java.security
API を使用します。署名された JAR ファイルは、ファイルのマニフェストが更新され、META-INF
ディレクトリに署名ファイルと署名ブロックファイルが追加されていますが、それ以外の内容は元の JAR ファイルと同じです。jarsigner を使用しない場合、署名プログラムは、署名ファイルと署名ブロックファイルの両方を構築する必要があります。
署名付き JAR ファイル内で署名されたすべてのファイルエントリについて、そのエントリがすでにマニフェスト内に存在していないかぎり、個別のマニフェストエントリが作成されます。各マニフェストエントリには、1 つまたは複数のダイジェスト属性とオプションの Magic 属性がリストされます。
.SF
の署名ファイルによって表されます。このファイルの大部分は、マニフェストファイルと同じです。このファイルは、署名者から提供された情報の入ったメインセクションで構成されます。ただし、この情報は特定の jar ファイルエントリに固有のものではありません。メインセクションのエントリ x-Digest-Manifest-Main-Attributes
(x
はダイジェストアルゴリズム) には、マニフェストのメイン属性のダイジェスト値が入ります。
メインセクションの後には、個々のエントリのリストが続きます。それらのエントリの名前も、マニフェストファイル内に存在する必要があります。それぞれの個別エントリには、少なくともマニフェストファイル内の対応するエントリのダイジェストが含まれている必要があります。
マニフェストファイルに登場するが署名ファイルには登場しないパスまたは URL は、計算に使用されません。
署名ファイルから検証情報を入手できる場合は、マニフェストのメイン属性も検証されます。署名ファイルに x-Digest-Manifest-Main-Attributes
エントリが存在すると、そのエントリが、マニフェストファイル内のメイン属性から計算されたダイジェストに対して比較されます。この計算に失敗すると、jar の検証が失敗します。この判断は、効率化のために記録しておくことができます。署名ファイルに x-Digest-Manifest-Main-Attributes
エントリが存在しなくても、jar 検証に影響はなく、マニフェストのメイン属性が検証されないだけです。
ファイルを検証するには、署名ファイルのダイジェスト値を、マニフェストファイルの対応するエントリから計算したダイジェスト値と比較します。次に、マニフェストファイルのダイジェストの値を、「Name:
」属性 (相対ファイルパスまたは URL) で参照されている実際のデータから計算したダイジェストと比較します。
マニフェストファイルの例:
対応する署名ファイルは次のようになります。Manifest-Version: 1.0 Created-By: 1.3 (Sun Microsystems, Inc) Name: common/class1.class MD5-Digest: (base64 representation of MD5 digest) Name: common/class2.class MD5-Digest: (base64 representation of MD5 digest) SHA-Digest: (base64 representation of SHA digest)
Signature-Version: 1.0 MD5-Digest-Manifest-Main-Attributes: (base64 representation of MD5 digest) Name: common/class1.class MD5-Digest: (base64 representation of MD5 digest) Name: common/class2.class MD5-Digest: (base64 representation of MD5 digest)
Magic 属性はオプションですが、パーサがそのエントリの署名を検証する場合は、エントリの Magic キーの値を理解する必要があります。
Magic 属性の値は、コンマで区切られたコンテキスト固有の文字列のセットです。コンマの前後の空白は無視されます。大文字と小文字も無視されます。Magic 属性の正確な意味はアプリケーションによって異なります。これらの属性は、マニフェストエントリに含まれるハッシュ値の計算方法を示し、そのため署名の正しい検証には欠くことのできないものです。このキーワードは、動的または埋め込みコンテンツ、多国語ドキュメント用の複数ハッシュなどに使用します。
以下に、マニフェストファイルでの Magic 属性の使用例を 2 つ示します。
Name:http://www.scripts.com/index#script1
SHA-Digest:(base64 representation of SHA hash)
Magic:JavaScript, Dynamic
Name:http://www.tourist.com/guide.html
SHA-Digest:(base64 representation of SHA hash)
SHA-Digest-French:(base64 representation of SHA hash)
SHA-Digest-German:(base64 representation of SHA hash)
Magic:Multilingual
最初の例では、これら Magic の値は http 問い合わせの結果がドキュメント自身ではなく、ドキュメントに埋め込まれたスクリプトであり、またそのスクリプトが動的に生成されるということを示します。この 2 つの情報は、マニフェストのダイジェスト値と比較し、有効な署名と比較するハッシュ値の計算方法を示します。
第 2 の例では、Magic 値は検索されたドキュメントの内容は特定の言語であるという合意を示し、検証のためのダイジェストの値は検索されたドキュメントを記述する言語に依存することを示します。
.SF
署名ファイルです。これらはバイナリファイルであり、人間が解釈することは意図されていません。
デジタル署名ファイルは、.SF ファイルとファイル名は同じですが、拡張子が異なります。拡張子はデジタル署名の型によって変化します。
上に示されていない署名アルゴリズム用のデジタル署名ファイルは、.RSA (PKCS7 signature, MD5 + RSA) .DSA (PKCS7 signature, DSA)
META-INF
ディレクトリに置き、「SIG-
」という接頭辞を付ける必要があります。対応する署名ファイル (.SF
ファイル) にも同じ接頭辞を付けなければなりません。
外部署名データをサポートしない形式については、ファイルは .SF
ファイルの署名されたコピーで構成されることになります。したがって、一部のデータが重複する可能性があるため、ベリファイアは 2 つのファイルを比較する必要があります。
外部データをサポートする形式は、.SF
ファイルを参照するか、暗黙的な参照によって計算を実行します。
各 .SF
ファイルは複数のデジタル署名を持つ可能性がありますが、これらの署名は同じ正当なエンティティによって生成される必要があります。
ファイル名の拡張子には、1 〜 3 文字の英数字を使うことができます。認識されない拡張子は無視されます。
属性名は大文字と小文字が区別されない。しかし、マニフェストおよび署名ファイルを生成するプログラムはこの仕様で示されているとおりに大文字と小文字を使い分ける必要がある
属性名はセクション内で繰り返してはならない
各署名エントリの順番は、署名されるダイジェストがその順番になることを除けば重要ではない
null、CR、LF をヘッダ値に含めることはできず、null、CR、LF、「:」をヘッダ名に含めることはできない。
実装では、65535 バイト (文字ではない) のヘッダ値、およびファイルごとに 65535 個のヘッダをサポートする必要がある。これによってメモリが不足するかもしれないが、これらの値にハードコーディングの制限があってはならない
既存の jar ツールの機能も拡張されています。jar ファイルのリストが検査されてから、クラスおよびリソースが属している jar ファイルについてのディレクトリ情報が生成されます。このディレクトリ情報は、ルート jar ファイルの META-INF ディレクトリの INDEX.LIST という名前の、単純なテキストファイル内に格納されます。クラスローダは、ルート jar ファイルをロードすると、INDEX.LIST ファイルを読み込みます。次に、そのファイルを使って、ファイル名とパッケージ名から jar ファイル名のリストへのマッピングを格納したハッシュテーブルを構築します。クラスまたはリソースを検索するには、クラスローダは、ハッシュテーブルを問い合わせて適切な jar ファイルを見つけてから、必要に応じてダウンロードします。
クラスローダによって、特定の jar ファイルで INDEX.LIST ファイルが検出されると、そのファイルにリストされた情報は常に信頼されます。クラスローダによって特定のクラスのマッピングが検出されたあとで、リンクをたどってもそのクラスが検出されなかった場合は、InvalidJarIndexException がスローされます。この例外が発生した場合は、アプリケーション開発者は、拡張機能に対して jar ツールを実行し直し、インデックスファイルに正しい情報を取得する必要があります。
大量の領域オーバーヘッドの発生をアプリケーションで回避し、メモリ内のハッシュテーブルを高速で構築するために、INDEX.LIST ファイルの容量はできるかぎり小さくなるように管理されます。クラスのパッケージ名が null でない場合は、マッピングはパッケージレベルで記録されます。通常は、1 つのパッケージが 1 つの jar ファイルにマッピングされます。ある特定のパッケージが 1 つ以上の jar ファイルに渡る場合は、このパッケージは jar ファイルのリストにマップされます。リソースファイルにディレクトリの接頭辞がある場合は、マッピングはディレクトリレベルで記録されます。パッケージ名が null のクラスの場合およびルートディレクトリにリソースファイルが格納されている場合にだけ、マッピングがファイルレベルで記録されます。
インデックスファイルのファイルまたはパッケージ名に、ASCII 以外の文字が使われているときは、UTF-8 エンコーディングが使われます。
サービスは、abstract クラスによって表現されます。特定のサービスのプロバイダは、サービスのクラスを継承したいくつかの具象クラスで構成されています。サービスのクラスには、プロバイダ固有のデータおよびコードが含まれます。通常、プロバイダクラスには、プロバイダ自体がすべて含まれることはありません。要求時に実際のプロバイダを作成できるコードと、プロバイダが特定の要求を満たすことができるかどうかを識別するために必要な情報で構成されるプロキシになっています。プロバイダクラスの内容は、個別のサービスに大きく依存します。1 つのクラスまたはインタフェースでプロバイダクラスを統合することはできません。このため、このようなクラスは定義されていません。プロバイダクラスには、ルックアップ中にインスタンスを生成できるように、引数をとらないコンストラクタが必要です。
public abstract CharEncoder getEncoder(String encodingName);
public abstract CharDecoder getDecoder(String encodingName);
これらのメソッドは、渡されたエンコーディングを変換できない場合、適切なオブジェクトまたは null を返します。標準の CharCodec プロバイダでは、複数のエンコーディングがサポートされています。
sun.io.StandardCodec が CharCodec サービスのプロバイダの場合は、jar ファイルに META-INF/services/java.io.spi.CharCodec ファイルが含まれます。このファイルには、次の行が含まれます。
sun.io.StandardCodec # Standard codecs for the platform
特定のエンコーディング名のエンコーダを検索するには、内部の I/O コードによって次のような処理が行われます。
CharEncoder getEncoder(String encodingName) {
Iterator ps = Service.providers(CharCodec.class);
while (ps.hasNext()) {
CharCodec cc = (CharCodec)ps.next();
CharEncoder ce = cc.getEncoder(encodingName);
if (ce != null)
return ce;
}
return null;
}
プロバイダのルックアップ機構は、常に呼び出し側のセキュリティコンテキストで実行されます。信頼できるシステムコードでは、通常、このクラスのメソッドは特権付きのセキュリティコンテキストから呼び出す必要があります。
Copyright © 2003 Sun Microsystems, Inc.All Rights Reserved. |
Java ソフトウェア |