RFC: OpenJDK JarSigner API
Mandy Chung
mandy.chung at oracle.com
Sat Aug 15 06:39:54 UTC 2015
> On Aug 14, 2015, at 7:18 PM, Weijun Wang <weijun.wang at oracle.com> wrote:
>
>
>
> On 8/15/2015 5:37 AM, Mandy Chung wrote:
>> Looks good in general.
>>
>> Have you considered using “Algorithm” instead of “Alg” the abbreviation in the method names digesting, sigAlg etc
>>
>
> I reuse the jarsigner option names (-sigalg, -digestalg, -tsa), hoping people are already familiar with them.
IMO the digestAlgorithm method name isn’t too long and is clearer than the abbreviation.
>
>> 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?
>
> No. Otherwise calling build() again is useless. A user can modify a setting and create another JarSigner.
Ah.. I see. You meant no effect on the built JarSigner instance.
Mandy
>
> --Max
>
>>
>> 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