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