RFC: OpenJDK JarSigner API
Weijun Wang
weijun.wang at oracle.com
Sat Aug 8 13:56:57 UTC 2015
Hi All
JDK 9 is more restricted on calling sun.* public methods but we know
there are users calling sun.security.tools.jarsigner.Main to sign jar
files. A new API is proposed for this very purpose in OpenJDK. Please
note it is defined in a jdk.* package therefore not a Java SE API. We
are also thinking of an API to cover keytool functions. Stay tuned.
The new API does not cover every option of the existing jarsigner tool,
for example, -altsign, -tsapolicyid, -tsadigestalg, -internalsf,
-sectionsonly, etc, but we hope it is enough in most use cases.
All suggestions are welcome.
Thanks
Max
package jdk.security.jarsigner;
/**
* An immutable utility class to sign a jar file.
* <p>
* A caller creates a {@code JarSigner.Builder} object, (optionally)
sets some
* parameters, and then calls the {@link JarSigner.Builder#build build}
method
* to create a {@code JarSigner} object. This {@code JarSigner} object
can then
* be used to sign a jar file.
* <p>
* Unless otherwise stated, calling a method of {@code JarSigner} or
* {@code JarSigner.Builder} with a null argument will throw
* a {@link NullPointerException}.
* <p>
* Example:
* <pre>
* JarSigner signer = new JarSigner.Builder(key, certPath)
* .digestAlg("SHA-1")
* .sigAlg("SHA1withDSA")
* .build();
* try (ZipFile in = new ZipFile(inputFile);
* FileOutputStream out = new FileOutputStream(outFile)) {
* signer.sign(in, out);
* }
* </pre>
*
* @since 1.9
*/
@jdk.Exported
public final class JarSigner {
/**
* A mutable builder class that can create an immutable {@code
JarSigner}
* from various signing-related parameters.
*
* @since 1.9
*/
@jdk.Exported
public static class Builder {
/**
* Creates a {@code JarSigner.Builder} object with
* a {@link KeyStore.PrivateKeyEntry} object.
*
* @param entry the {@link KeyStore.PrivateKeyEntry} of the signer.
*/
public Builder(KeyStore.PrivateKeyEntry entry);
/**
* Creates a {@code JarSigner.Builder} object with a private
key and
* a certification path.
*
* @param privateKey the private key of the signer.
* @param certPath the certification path of the signer.
* @throws IllegalArgumentException if {@code certPath} is
empty, or
* the {@code privateKey} algorithm does not match the
algorithm
* of the {@code PublicKey} in the end entity certificate
* (the first certificate in {@code certPath}).
*/
public Builder(PrivateKey privateKey, CertPath certPath);
/**
* Sets the digest algorithm. If no digest algorithm is specified,
* the default algorithm returned by {@link #getDefaultDigestAlg}
* will be used.
*
* @param algorithm the standard name of the algorithm. See
* the MessageDigest section in the <a href=
*
"{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
* Java Cryptography Architecture Standard Algorithm Name
* Documentation</a> for information about standard
algorithm names.
* @return the {@code JarSigner.Builder} itself.
* @throws NoSuchAlgorithmException if {@code algorithm} is not
available.
*/
public Builder digestAlg(String algorithm) throws
NoSuchAlgorithmException;
/**
* Sets the digest algorithm from the specified provider.
* If no digest algorithm is specified, the default algorithm
* returned by {@link #getDefaultDigestAlg} will be used.
*
* @param algorithm the standard name of the algorithm. See
* the MessageDigest section in the <a href=
*
"{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
* Java Cryptography Architecture Standard Algorithm Name
* Documentation</a> for information about standard
algorithm names.
* @param provider the provider.
* @return the {@code JarSigner.Builder} itself.
* @throws NoSuchAlgorithmException if {@code algorithm} is not
available
* in the specified provider.
*/
public Builder digestAlg(String algorithm, Provider provider)
throws NoSuchAlgorithmException;
/**
* Sets the signature algorithm. If no signature algorithm
* is specified, the default signature algorithm returned by
* {@link #getDefaultSigAlg} for the private key algorithm will
be used.
*
* @param algorithm the standard name of the algorithm. See
* the Signature section in the <a href=
*
"{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
* Java Cryptography Architecture Standard Algorithm Name
* Documentation</a> for information about standard
algorithm names.
* @return the {@code JarSigner.Builder} itself.
* @throws NoSuchAlgorithmException if {@code algorithm} is not
available.
* @throws IllegalArgumentException if {@code algorithm} is not
compatible
* with the algorithm of the signer's private key.
*/
public Builder sigAlg(String algorithm) throws
NoSuchAlgorithmException;
/**
* Sets the signature algorithm from the specified provider.
* If no signature algorithm is specified, the default
signature algorithm
* returned by {@link #getDefaultSigAlg} for the private key
algorithm
* will be used.
*
* @param algorithm the standard name of the algorithm. See
* the Signature section in the <a href=
*
"{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
* Java Cryptography Architecture Standard Algorithm Name
* Documentation</a> for information about standard
algorithm names.
* @param provider the provider.
* @return the {@code JarSigner.Builder} itself.
* @throws NoSuchAlgorithmException if {@code algorithm} is not
available
* in the specified provider.
* @throws IllegalArgumentException if {@code algorithm} is not
compatible
* with the algorithm of the signer's private key.
*/
public Builder sigAlg(String algorithm, Provider provider)
throws NoSuchAlgorithmException;
/**
* Sets the URI of the Time Stamping Authority (TSA).
*
* @param uri the URI.
* @return the {@code JarSigner.Builder} itself.
*/
public Builder tsa(URI uri);
/**
* Sets the signer name. The name will be used as the base name for
* the signature files. All lowercase characters will be
converted to
* uppercase for signature file names. If a signer name is not
* specified, the string "SIGNER" will be used.
*
* @param name the signer name.
* @return the {@code JarSigner.Builder} itself.
* @throws IllegalArgumentException if {@code name} is empty or
has a size
* bigger than 8, or it contains characters not from the set
* "a-zA-Z0-9_-".
*/
public Builder signerName(String name);
/**
* Gets the default digest algorithm.
*
* @implNote This implementation returns "SHA-256". The value may
* change in the future.
*
* @return the default digest algorithm.
*/
public static String getDefaultDigestAlg();
/**
* Gets the default signature algorithm for a private key
algorithm.
* For example, SHA256withRSA for RSA, and SHA256withDSA for DSA.
*
* @implNote This implementation returns "SHA256withDSA" for
the "DSA"
* key algorithm, "SHA256withRSA" for "RSA", "SHA256withECDSA"
for "EC",
* and {@code null} otherwise. The value(s) may change in the
future.
*
* @param keyAlg the key algorithm.
* @return the default signature algorithm. Returns null if a
default
* signature algorithm cannot be found. In this case, {@link
#sigAlg}
* must be called to specify a signature algorithm. Otherwise,
* the {@link #build} method will throw an {@link
IllegalArgumentException}.
* @throws IllegalArgumentException if {@code keyAlg} is empty.
*/
public static String getDefaultSigAlg(String keyAlg);
/**
* Builds a {@code JarSigner} object from the parameters set by the
* setter methods.
* <p>
* This method does not modify internal state of this {@code
Builder}
* object and can be called multiple times to generate multiple
* {@code JarSigner} objects. After a {@code JarSigner} object is
* built, calling any setter method on this {@code Builder}
will have
* no effect on it.
*
* @return the {@code JarSigner} object.
* @throws IllegalArgumentException if a signature algorithm is not
* set and cannot be derived from the private key using the
* {@link #getDefaultSigAlg} method.
*/
public JarSigner build();
}
/**
* Signs a file into an {@link OutputStream}. This method will not
close
* {@code file} or {@code os}.
*
* @param file the file to sign.
* @param os the output stream.
* @throws JarSignerException if the signing fails.
*/
public void sign(ZipFile file, OutputStream os);
/**
* Returns the digest algorithm for this {@code JarSigner}.
* @return the digest algorithm. The return value is never null.
*/
public String getDigestAlg();
/**
* Returns the signature algorithm for this {@code JarSigner}.
* @return the signature algorithm. The return value is never null.
*/
public String getSigAlg();
/**
* Returns the URI of the Time Stamping Authority (TSA).
* @return the URI of the TSA.
*/
public URI getTsa();
/**
* Returns the signer name of this {@code JarSigner}.
* @return the signer name. The return value is never null.
*/
public String getSignerName();
}
/**
* This exception is thrown when {@link JarSigner#sign} fails.
*
* @since 1.9
*/
@jdk.Exported
public class JarSignerException extends RuntimeException {
private static final long serialVersionUID = -4732217075689309530L;
/**
* Constructs a new {@code JarSignerException} with the specified
detail
* message and cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this {@code JarSignerException}'s detail message.
*
* @param message the detail message (which is saved for later
retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <tt>null</tt> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
*/
public JarSignerException(String message, Throwable cause);
}
More information about the security-dev
mailing list