JDK-8245274 : Signed JAR support for RSASSA-PSS and EdDSA
  • Type: CSR
  • Component: security-libs
  • Sub-Component: java.security
  • Priority: P3
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 16
  • Submitted: 2020-05-19
  • Updated: 2020-10-30
  • Resolved: 2020-10-21
Related Reports
CSR :  
Relates :  
Description
Summary
-------

Add the capability to sign JAR files with RSASSA-PSS and EdDSA signatures algorithms.

Problem
-------

We've added support for RSASSA-PSS (JDK-8146293) since JDK 11 and EdDSA (JDK-8166597) recently, and we should support them in signed JAR files as well. The usage of the 2 algorithms in Cryptographic Message Syntax (CMS, which is the format we use for signature block files inside a signed JAR file) are defined in https://tools.ietf.org/html/rfc4056 and https://www.rfc-editor.org/rfc/rfc8419.html, respectively.

Solution
--------

Support signing of a JAR file using these algorithms, which means:

1. RSASSA-RSS and EdDSA keys can be used to sign a JAR file
1. New `-sigalg` options: `RSASSA-PSS`, `EdDSA`, `Ed25519`, and `Ed448` (case-insensitive).

We will also support loading signed JAR files signed with these new algorithms.

We will support the [RFC 6211](https://tools.ietf.org/html/rfc6211#page-5) CMSAlgorithmProtection attribute on all algorithms to protect against algorithm substitution attacks (especially for the new RSASSA-PSS algorithm). This is the default style used by `openssl cms` command and BountyCastle's `JcaSignerInfoGeneratorBuilder` class. Users can turn off this feature by setting the `JarSigner.Builder` property `directsign` to `true` or adding the `-directsign` option to the jarsigner tool, which means there will be no signed attributes and the signature is calculated on the .SF file directly.

Specification
-------------

**The `JarSigner` API**

package jdk.security.jarsigner;

      public final class JarSigner {
          public static class Builder {
              /**
               * Sets an additional implementation-specific property indicated by
               * the specified key.
               ....
    +          * <li>"directsign": "true" if the signature is calculated on the
    +          * content directly, "false" if it's calculated on signed attributes
    +          * which itself is calculated from the content and stored in the
    +          * signer's SignerInfo. Default "false".
               ....
               */
              public Builder setProperty(String key, String value);

**The jarsigner tool**

The `-sigalg` options will support 4 new values: `RSASSA-PSS`, `EdDSA`, `Ed25519` and `Ed448`. The `RSASSA-PSS` algorithm can be used for both an RSA key or an RSASSA-PSS key. The `EdDSA` algorithm can only be used for an EdDSA key. The `Ed25519` algorithm can only be used for a 255-bit EdDSA key. The `Ed448` algorithm can only be used for a 448-bit EdDSA key. The option values are case-insensitive.

The block file extension for `RSASSA-PSS` is still `.RSA`. The block file extension for `EdDSA`, `Ed25519` or `Ed448` is still `.EC`.

A new `-directsign` option will be supported.

**The tooldoc**

In the [jarsigner man page][1],

1. Add info on RSASSA-PSS and EdDSA keys to the table in "Supported Algorithms".
1. Add a new column "block file extension" to this table.
1. The document was written when we only support DSA keys, and it uses the ".DSA" word everywhere. Rename it to "signature block file".
1. Always use ".RSA" in examples.

The exact diff for the jarsigner man page:

    @@ -226,18 +226,30 @@
     
     ## Supported Algorithms
     
     By default, the `jarsigner` command signs a JAR file using one of the following
    -algorithms files depending on the type and size of the private key:
    +algorithms and block file extensions depending on the type and size of
    +the private key:
     
    -keyalg   keysize   default sigalg
    --------  --------  --------------
    -DSA      any size  SHA256withDSA
    -RSA      \<= 3072  SHA256withRSA
    -         \<= 7680  SHA384withRSA
    -         \> 7680   SHA512withRSA
    -EC       \< 384    SHA256withECDSA
    -         \< 512    SHA384withECDSA
    -         = 512     SHA512withECDSA
    --------  --------  --------------
    +keyalg      keysize     default sigalg              block file extension
    +-------     --------    --------------              --------------------
    +DSA         any size    SHA256withDSA               .DSA
    +RSA         \<= 3072    SHA256withRSA               .RSA
    +            \<= 7680    SHA384withRSA
    +            \> 7680     SHA512withRSA
    +EC          \< 384      SHA256withECDSA             .EC
    +            \< 512      SHA384withECDSA
    +            = 512       SHA512withECDSA
    +RSASSA-PSS  \<= 3072    RSASSA-PSS (with SHA-256)   .RSA
    +            \<= 7680    RSASSA-PSS (with SHA-384)
    +            \> 7680     RSASSA-PSS (with SHA-512)
    +EdDSA       255         Ed25519                     .EC
    +            448         Ed448
    +-------     --------  --------------                ------
    +
    +* If an RSASSA-PSS key is encoded with parameters, then jarsigner will use the
    +same parameters in the signature. Otherwise, jarsigner will use parameters that are
    +determined by the size of the key as specified in the table above.
    +For example, an 3072-bit RSASSA-PSS key will use RSASSA-PSS as the signature
    +algorithm and SHA-256 as the hash and MGF1 algorithms.
     
     These default signature algorithms can be overridden by using the `-sigalg`
     option.
    @@ -274,10 +286,11 @@
     
     The base file names for these two files come from the value of the `-sigfile`
     option. For example, when the option is `-sigfile MKSIGN`, the files are named
    -`MKSIGN.SF` and `MKSIGN.DSA`
    +`MKSIGN.SF` and `MKSIGN.RSA`. In this document, we assume the signer always
    +uses an RSA key.
     
     If no `-sigfile` option appears on the command line, then the base file name
    -for the `.SF` and `.DSA` files is the first 8 characters of the alias name
    +for the `.SF` and the signature block files is the first 8 characters of the alias name
     specified on the command line, all converted to uppercase. If the alias name
     has fewer than 8 characters, then the full alias name is used. If the alias
     name contains any characters that aren't allowed in a signature file name, then
    @@ -318,7 +331,8 @@
     file. This file also contains, encoded inside it, the certificate or
     certificate chain from the keystore that authenticates the public key
     corresponding to the private key used for signing. The file has the extension
    -`.DSA`, `.RSA`, or `.EC`, depending on the digest algorithm used.
    +`.DSA`, `.RSA`, or `.EC`, depending on the key algorithm used. See the table
    +in [Supported Algorithms].
     
     ## Signature Time Stamp
     
    @@ -344,9 +358,9 @@
     1.  Verify the signature of the `.SF` file.
     
         The verification ensures that the signature stored in each signature block
    -    (`.DSA`) file was generated using the private key corresponding to the
    +    file was generated using the private key corresponding to the
         public key whose certificate (or certificate chain) also appears in the
    -    `.DSA` file. It also ensures that the signature is a valid signature of the
    +    signature block file. It also ensures that the signature is a valid signature of the
         corresponding signature (`.SF`) file, and thus the `.SF` file wasn't
         tampered with.
     
    @@ -403,15 +417,15 @@
     jarsigner myBundle.jar kevin
     ```
     
    -When a JAR file is signed multiple times, there are multiple `.SF` and `.DSA`
    -files in the resulting JAR file, one pair for each signature. In the previous
    +When a JAR file is signed multiple times, there are multiple `.SF` and signature 
    +block files in the resulting JAR file, one pair for each signature. In the previous
     example, the output JAR file includes files with the following names:
     
     ```
     SUSAN.SF
    -SUSAN.DSA
    +SUSAN.RSA
     KEVIN.SF
    -KEVIN.DSA
    +KEVIN.RSA
     ```
     
     ## Options for jarsigner
    @@ -529,18 +543,18 @@
         Certificate Encoding Standard](http://tools.ietf.org/html/rfc1421).
     
     `-sigfile` *file*
    -:   Specifies the base file name to be used for the generated `.SF` and `.DSA`
    +:   Specifies the base file name to be used for the generated `.SF` and signature block
         files. For example, if file is `DUKESIGN`, then the generated `.SF` and
    -    `.DSA` files are named `DUKESIGN.SF` and `DUKESIGN.DSA`, and placed in the
    +    signature block files are named `DUKESIGN.SF` and `DUKESIGN.RSA`, and placed in the
         `META-INF` directory of the signed JAR file.
     
         The characters in the file must come from the set `a-zA-Z0-9_-`. Only
         letters, numbers, underscore, and hyphen characters are allowed. All
    -    lowercase characters are converted to uppercase for the `.SF` and `.DSA`
    +    lowercase characters are converted to uppercase for the `.SF` and signature block
         file names.
     
         If no `-sigfile` option appears on the command line, then the base file
    -    name for the `.SF` and `.DSA` files is the first 8 characters of the alias
    +    name for the `.SF` and signature block files is the first 8 characters of the alias
         name specified on the command line, all converted to upper case. If the
         alias name has fewer than 8 characters, then the full alias name is used.
         If the alias name contains any characters that aren't valid in a signature
    @@ -607,7 +621,7 @@
     :   If the `-certs` option appears on the command line with the `-verify` and
         `-verbose` options, then the output includes certificate information for
         each signer of the JAR file. This information includes the name of the type
    -    of certificate (stored in the `.DSA` file) that certifies the signer's
    +    of certificate (stored in the signature block file) that certifies the signer's
         public key, and if the certificate is an X.509 certificate (an instance of
         the `java.security.cert.X509Certificate`), then the distinguished name of
         the signer.
    @@ -668,15 +682,22 @@ the following standards:
         Standard Algorithm Names.
    
     `-internalsf`
    -:   In the past, the `.DSA` (signature block) file generated when a JAR file
    +:   In the past, the signature block file generated when a JAR file
         was signed included a complete encoded copy of the `.SF` file (signature
         file) also generated. This behavior has been changed. To reduce the overall
    -    size of the output JAR file, the `.DSA` file by default doesn't contain a
    +    size of the output JAR file, the signature block file by default doesn't contain a
         copy of the `.SF` file anymore. If `-internalsf` appears on the command
         line, then the old behavior is utilized. This option is useful for testing.
         In practice, don't use the `-internalsf` option because it incurs higher
         overhead.
    
    +`-directsign`
    +:   By default, jarsigner stores the hash of the `.SF` file and possibly
    +    other information in a SignerInfo signedAttributes field, and then
    +    calculates the signature on this field. If this option is set, no
    +    SignerInfo signedAttributes field is generated and the signature is
    +    calculated on the `.SF` file directly.
    +
     `-sectionsonly`
     :   If the `-sectionsonly` option appears on the command line, then the `.SF`

     file (signature file) generated when a JAR file is signed doesn't include a
    @@ -927,8 +941,8 @@
         jane`
     
     There is no `-sigfile` specified in the previous command so the generated `.SF`
    -and `.DSA` files to be placed in the signed JAR file have default names based
    -on the alias name. They are named `JANE.SF` and `JANE.DSA`.
    +and signature block files to be placed in the signed JAR file have default names based
    +on the alias name. They are named `JANE.SF` and `JANE.RSA`.
     
     If you want to be prompted for the store password and the private key password,
     then you could shorten the previous command to the following:

In the [keytool man page][2], document the details on key pair generation for RSASSA-PSS and EdDSA keys (in retrospec).

The exact diff for the keytool man page:

    @@ -1221,9 +1221,9 @@
     -alias "mykey"
     
     -keysize
    -    2048 (when using -genkeypair and -keyalg is "RSA")
    -    2048 (when using -genkeypair and -keyalg is "DSA")
    +    2048 (when using -genkeypair and -keyalg is "RSA", "DSA", or "RSASSA-PSS")
         256 (when using -genkeypair and -keyalg is "EC")
    +    255 (when using -genkeypair and -keyalg is "EdDSA")
         56 (when using -genseckey and -keyalg is "DES")
         168 (when using -genseckey and -keyalg is "DESede")
     
    @@ -1248,16 +1248,32 @@
     algorithm (`-sigalg` option) is derived from the algorithm of the underlying
     private key to provide an appropriate level of security strength as follows:
     
    -keyalg   keysize   default sigalg
    --------  --------  --------------
    -DSA      any size  SHA256withDSA
    -RSA      \<= 3072  SHA256withRSA
    -         \<= 7680  SHA384withRSA
    -         \> 7680   SHA512withRSA
    -EC       \< 384    SHA256withECDSA
    -         \< 512    SHA384withECDSA
    -         = 512     SHA512withECDSA
    --------  --------  --------------
    +keyalg      keysize   default sigalg
    +-------     --------  --------------
    +DSA         any size  SHA256withDSA
    +RSA         \<= 3072  SHA256withRSA
    +            \<= 7680  SHA384withRSA
    +            \> 7680   SHA512withRSA
    +EC          \< 384    SHA256withECDSA
    +            \< 512    SHA384withECDSA
    +            = 512     SHA512withECDSA
    +RSASSA-PSS  \<= 3072  RSASSA-PSS (with SHA-256)
    +            \<= 7680  RSASSA-PSS (with SHA-384)
    +            \> 7680   RSASSA-PSS (with SHA-512)
    +EdDSA       255       Ed25519
    +            448       Ed448
    +Ed25519     255       Ed25519
    +Ed448       448       Ed448
    +-------     --------  --------------
    +
    +* An RSASSA-PSS signature algorithm uses a `MessageDigest`
    +algorithm as its hash and MGF1 algorithms.
    +
    +* EdDSA supports 2 key sizes: Ed25519 and Ed448. When generating an EdDSA key
    +pair using `-keyalg EdDSA`, a user can specify `-keysize 255` or `-keysize 448`
    +to generate Ed25519 or Ed448 key pairs. When no `-keysize` is specified, an
    +Ed25519 key pair is generated. A user can also directly specify `-keyalg Ed25519`
    +or `-keyalg Ed448` to generate a key pair with the expected key size.
     
     **Note:**

  [1]: https://download.java.net/java/early_access/jdk15/docs/specs/man/jarsigner.html
  [2]: https://download.java.net/java/early_access/jdk15/docs/specs/man/keytool.html




Comments
This is a bit of a late comment, but I think that the JAR specification should also be updated with information on how the signature is created using the RFC 6211 CMSAlgorithmProtection attribute. It is ok to include this in the jarsigner docs, but this format should not be specific to jarsigner and should really be specified in the Digital Signature section of the JAR specification. I think the JAR specification should explain the 2 different ways a signature could be stored in a PKCS7 SignedData, the older legacy form, and the newer form using the signedAttrs field. I see you already have a follow-on subtask opened for updating the JAR specification, so we can update it as part of that: https://bugs.openjdk.java.net/browse/JDK-8247837
27-10-2020

Moving to Approved. Please consider if a release note is warranted.
21-10-2020

Finalize the CSR again. Compared to the previously approved version: The directSign property and -directsign option are added to JarSigner API and jarsigner tool, respectively. Since the value is by default false this means a behavior change (even for existing algorithms). This is necessary for RFC 6211 and is the style used by other vendors. The compatibility risk description is updated.
16-10-2020

Sure, zoom out works~ Thanks.
13-10-2020

Typo fixed. I've tried to minimize the number of updated lines, so some will be a little longer. They do show fine on my screen. Is it possible to make the font size a little smaller? In Firefox it's View | Zoom | Zoom Out. If it really looks bad, I can rearrange the lines. Sorry.
13-10-2020

Typo: calulcated Some of the formatted spec aren't shown in completeness. Is there a way to enlarge the gray box or is this a known issue?
12-10-2020

Withdrawn and updated. New "directsign" property added: - new last paragraph in Solution - new section on JarSigner API in Specification.
10-07-2020

Moving to Approved for JDK 15.
04-06-2020

Moving to Provisional.
02-06-2020