RFC: OpenJDK JarSigner API

Mandy Chung mandy.chung at oracle.com
Fri Aug 14 21:37:16 UTC 2015


Looks good in general.   

Have you considered using “Algorithm” instead of  “Alg” the abbreviation in the method names digesting, sigAlg etc

The Builder::build method:
   After a {@code JarSigner} object is built, calling any setter method on this {@code Builder} will have no effect on it.

Will the setter methods throw IllegalStateException if the build method has already been called?

Mandy

> On Aug 8, 2015, at 6:56 AM, Weijun Wang <weijun.wang at oracle.com> wrote:
> 
> 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