JAR File Specification |
In many cases, JAR files are not just simple archives of java classes files and/or resources. They are used as building blocks for applications and extensions. The META-INF directory, if it exists, is used to store package and extension configuration data, including security, versioning, extension and services.
Groups of name-value pairs are known as a "section". Sections are separated from other sections by empty lines.
Binary data of any form is represented as base64. Continuations are required for binary data which causes line length to exceed 72 bytes. Examples of binary data are digests and signatures.
Implementations shall support header values of up to 65535 bytes.
All the specifications in this document use the same grammar in which terminal symbols are shown in fixed width font and non-terminal symbols are shown in italic type face.
; Also: To prevent mangling of files sent via straight
e-mail, no
; header will start with the four letters "From".
Non-terminal symbols defined in the above specification will be referenced in the following specifications.
The main section contains security and configuration information about the JAR file itself, as well as the application or extension that this JAR file is a part of. It also defines main attributes that apply to every individual manifest entry. No attribute in this section can have its name equal to "Name". This section is terminated by an empty line.
The individual sections define various attributes for packages or files contained in this JAR file. Not all files in the JAR file need to be listed in the manifest as entries, but all files which are to be signed must be listed. The manifest file itself must not be listed. Each section must start with an attribute with the name as "Name", and the value must be a relative path to the file, or an absolute URL referencing data outside the archive.
If there are multiple individual sections for the same file entry, the attributes in these sections are merged. If a certain attribute have different values in different sections, the last one is recognized.
Attributes which are not understood are ignored. Such attributes may include implementation specific information used by applications.
In the above specification, attributes that can appear in the
main section are referred to as main attributes, whereas
attributes that can appear in individual sections are referred to
as per-entry attributes. Certain attributes can appear both in
the main section and the individual sections, in which case the
per-entry attribute value overrides the main attribute value for
the specified entry. The two types of attributes are defined as
follows.
Name: foo/bar/
Sealed: false
The per-entry attributes fall into the following groups:
These are the same set of attributes defined above as main
attributes that defines the extension package versioning and
sealing information. When used as per-entry attributes, these
attributes overwrites the main attributes but only apply to
the individual file specified by the manifest entry.
java.security
API. Every file
entry, including non-signature related files in the
META-INF
directory, will be signed if the JAR file
is signed by the jarsigner tool. The signature related files are:
META-INF/MANIFEST.MF
META-INF/*.SF
META-INF/*.DSA
META-INF/*.RSA
META-INF/SIG-*
META-INF
subdirectories, they are not considered signature-related.
Case-insensitive versions of these filenames are reserved and
will also not be signed.
Subsets of a JAR file can be signed by using the
java.security
API. A signed JAR file is exactly the
same as the original JAR file, except that its manifest is
updated and two additional files are added to the
META-INF
directory: a signature file and a signature
block file. When jarsigner is not used, the signing program has
to construct both the signature file and the signature block
file.
For every file entry signed in the signed JAR file, an individual manifest entry is created for it as long as it does not already exist in the manifest. Each manifest entry lists one or more digest attribute and an optional Magic attribute.
.SF
. The major part of the file is similar to the
manifest file. It consists of a main section which includes
information supplied by the signer but not specific to any
particular jar file entry. The main section entry,
x-Digest-Manifest-Main-Attributes
(where
x
is a digest algorithm), contains the digest value
for the main attributes of the manifest.
The main section is followed by a list of individual entries whose names must also be present in the manifest file. Each individual entry must contain at least the digest of its corresponding entry in the manifest file.
Paths or URLs appearing in the manifest file but not in the signature file are not used in the calculation.
The manifest main attributes are also verified when
verification information is available in the signature file. If
an x-Digest-Manifest-Main-Attributes
entry exists in
the signature file, it is compared against a digest calculated
against the main attributes in the manifest file. If this
calculation fails, then jar validation fails. This decision can
be remembered, for efficiency. If an
x-Digest-Manifest-Main-Attributes
entry does not
exist in the signature file, its nonexistence does not affect jar
validation and the manifest main attributes are not verified.
To validate a file, a digest value in the signature file is
compared against a digest calculated against the corresponding
entry in the manifest file. Then, a digest value in the manifest
file is compared against a digest calculated against the actual
data referenced in the "Name:
" attribute, which
specifies either a relative file path or URL.
Example manifest file:
The corresponding signature file would be: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)
The Magic attribute is optional but it is required that a parser understand the value of an entry's Magic key if it is verifying that entry's signature.
The value or values of the Magic attribute are a set of comma-separated context-specific strings. The spaces before and after the commas are ignored. Case is ignored. The exact meaning of the magic attributes is application specific. These values indicate how to compute the hash value contained in the manifest entry, and are therefore crucial to the proper verification of the signature. The keywords may be used for dynamic or embedded content, multiple hashes for multilingual documents, etc.
Here are two examples of the potential use of Magic attribute in the manifest file:
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
In the first example, these Magic values may indicate that the result of an http query is the script embedded in the document, as opposed to the document itself, and also that the script is generated dynamically. These two pieces of information indicate how to compute the hash value against which to compare the manifest's digest value, thus comparing a valid signature.
In the second example, the Magic value indicates that the document retrieved may have been content-negotiated for a specific language, and that the digest to verify against is dependent on which language the document retrieved is written in.
.SF
signature file. These are binary files not intended to be
interpreted by humans.
Digital signature files have the same filenames as the .SF files but different extensions. The extension varies depending on the type of digital signature.
Digital signature files for signature algorithms not listed above must reside in the.RSA (PKCS7 signature, MD5 + RSA) .DSA (PKCS7 signature, DSA)
META-INF
directory
and have the prefix "SIG-
". The corresonding
signature file (.SF
file) must also have the same
prefix.
For those formats that do not support external signed data,
the file shall consist of a signed copy of the .SF
file. Thus some data may be duplicated and a verifier should
compare the two files.
Formats that support external data either reference the
.SF
file, or perform calculations on it with
implicit reference.
Each .SF
file may have multiple digital
signatures, but those signatures should be generated by the same
legal entity.
File name extensions may be 1 to 3 alphanum characters. Unrecognized extensions are ignored.
Attribute names are case insensitive. Programs which generate manifest and signature files should use the cases shown in this specification however.
Attribute names cannot be repeated within a section.
The order of individual signature entries is not significant, except that the digests that get signed are in that order.
NUL, CR, and LF can't be embedded in header values, and NUL, CR, LF and ":" can't be embedded in header names.
Implementations should support 65535-byte (not character) header values, and 65535 headers per file. They might run out of memory, but there should not be hard-coded limits below these values.
The existing jar tool is enhanced to be able to examine a list of jar files and generate directory information as to which classes and resources reside in which jar file. This directory information is stored in a simple text file named INDEX.LIST in the META-INF directory of the root jar file. When the classloader loads the root jar file, it reads the INDEX.LIST file and uses it to construct a hash table of mappings from file and package names to lists of jar file names. In order to find a class or a resource, the class loader queries the hashtable to find the proper jar file and then downloads it if necessary.
Once the class loader finds a INDEX.LIST file in a particular jar file, it always trusts the information listed in it. If a mapping is found for a particular class, but the class loader fails to find it by following the link, an InvalidJarIndexException is thrown. When this occurs, the application developer should rerun the jar tool on the extension to get the right information into the index file.
To prevent adding too much space overhead to the application and to speed up the construction of the in-memory hash table, the INDEX.LIST file is kept as small as possible. For classes with non-null package names, mappings are recorded at the package level. Normally one package name is mapped to one jar file, but if a particular package spans more than one jar file, then the mapped value of this package will be a list of jar files. For resource files with non-empty directory prefixes, mappings are also recorded at the directory level. Only for classes with null package name, and resource files which reside in the root directory, will the mapping be recorded at the individual file level.
The UTF-8 encoding is used to support non ASCII characters in
file or package names in the index file.
A service is represented by an abstract class. A provider of a
given service contains one or more concrete classes that extend
this service class with data and code specific to the provider.
This provider class will typically not be the entire provider
itself but rather a proxy that contains enough information to
decide whether the provider is able to satisfy a particular
request together with code that can create the actual provider on
demand. The details of provider classes tend to be highly
service-specific; no single class or interface could possibly
unify them, so no such class has been defined. The only
requirement enforced here is that provider classes must have a
zero-argument constructor so that they may be instantiated during
lookup.
public abstract CharEncoder
getEncoder(String encodingName);
public abstract CharDecoder getDecoder(String
encodingName);
Each method returns an appropriate object or null if it cannot translate the given encoding. Typical CharCodec providers will support more than one encoding.
If sun.io.StandardCodec is a provider of the CharCodec service then its jar file would contain the file META-INF/services/java.io.spi.CharCodec. This file would contain the single line:
sun.io.StandardCodec # Standard codecs for the platform
To locate an encoder for a given encoding name, the internal I/O code would do something like this:
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;
}
The provider-lookup mechanism always executes in the security context of the caller. Trusted system code should typically invoke the methods in this class from within a privileged security context.
Copyright © 2003 Sun Microsystems, Inc. All Rights Reserved. |
Java Software |