JDK-8202590 : Customizing the generation of a PKCS12 keystore
  • Type: CSR
  • Component: security-libs
  • Sub-Component: java.security
  • Priority: P3
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 12
  • Submitted: 2018-05-03
  • Updated: 2019-02-15
  • Resolved: 2018-12-10
Related Reports
CSR :  
Sub Tasks
JDK-8215440 :  
Description
Summary
-------

Define some system/Security properties to determine what parameters should be used when generating a PKCS12 keystore.

Problem
-------

1. JDK's PKCS 12 keystore implementation hardcodes PBE (password based encryption) algorithms and other parameters.

2. JDK's PKCS 12 keystore, the current default keystore type, always requires a password to access the certificate stored inside it. This is not the same as the previously default keystore type JKS, where the password is only used for integrity check. This inconsistency is breaking some existing applications where no password is given.

Solution
--------

See spec.

We would also like to take this chance to change the name of a security property from `keystore.PKCS12.keyProtectionAlgorithm` to `keystore.pkcs12.keyProtectionAlgorithm` described in `KeyStore.java`. Traditionally, lowercase characters are used in security property names. Also, there is no behavior change for this update, since the implementation is already reading names in both lowercase and uppercase (in this order).

keytool will be updated to recognize the password-less pkcs12 keystore format (i.e. both certProtectionAlgorithm and macAlgorithm being NONE), where it should not prompt for store password when creating or reading such a keystore.

Specification
-------------
(Note that the only SE-specific change is the addition of the new HmacPBE algorithm names to the Standard Algorithm Names Specification. The rest of the changes are JDK-specific.)

1) Add the following lines into `conf/security/java.security`:

    #
    # PKCS12 KeyStore properties
    #
    # The following properties, if configured, are used by the PKCS12 KeyStore
    # implementation during the creation of a new keystore. Several of the
    # properties may also be used when modifying an existing keystore. The
    # properties can be overridden by a KeyStore API that specifies its own
    # algorithms and parameters.
    #
    # If an existing PKCS12 keystore is loaded and then stored, the algorithm and
    # parameter used to generate the existing Mac will be reused. If the existing
    # keystore does not have a Mac, no Mac will be created while storing. If there
    # is at least one certificate in the existing keystore, the algorithm and
    # parameter used to encrypt the last certificate in the existing keystore will
    # be reused to encrypt all certificates while storing. If the last certificate
    # in the existing keystore is not encrypted, all certificates will be stored
    # unencrypted. If there is no certificate in the existing keystore, any newly
    # added certificate will be encrypted (or stored unencrypted if algorithm
    # value is "NONE") using the "keystore.pkcs12.certProtectionAlgorithm" and
    # "keystore.pkcs12.certPbeIterationCount" values defined here. Existing private
    # and secret key(s) are not changed. Newly set private and secret key(s) will
    # be encrypted using the "keystore.pkcs12.keyProtectionAlgorithm" and
    # "keystore.pkcs12.keyPbeIterationCount" values defined here.
    #
    # In order to apply new algorithms and parameters to all entries in an
    # existing keystore, one can create a new keystore and add entries in the
    # existing keystore into the new keystore. This can be achieved by calling the
    # "keytool -importkeystore" command.
    #
    # If a system property of the same name is also specified, it supersedes the
    # security property value defined here.
    #
    # If the property is set to an illegal value, for example,
    # an iteration count that is not a positive integer, or an unknown algorithm
    # name, an exception will be thrown when the property is used.
    # If the property is not set or empty, a default value will be used.
    #
    # Note: These properties are currently used by the JDK Reference implementation.
    # They are not guaranteed to be examined and used by other implementations.
    
    # The algorithm used to encrypt a certificate. This can be any non-Hmac PBE
    # algorithm defined in the Cipher section of the Java Security Standard
    # Algorithm Names Specification. When set to "NONE", the certificate
    # is not encrypted. The default value is "PBEWithSHA1AndRC2_40".
    #keystore.pkcs12.certProtectionAlgorithm = PBEWithSHA1AndRC2_40
    
    # The iteration count used by the PBE algorithm when encrypting a certificate.
    # This value must be a positive integer. The default value is 50000.
    #keystore.pkcs12.certPbeIterationCount = 50000
    
    # The algorithm used to encrypt a private key or secret key. This can be
    # any non-Hmac PBE algorithm defined in the Cipher section of the Java
    # Security Standard Algorithm Names Specification. The value must not be "NONE".
    # The default value is "PBEWithSHA1AndDESede".
    #keystore.pkcs12.keyProtectionAlgorithm = PBEWithSHA1AndDESede
    
    # The iteration count used by the PBE algorithm when encrypting a private key
    # or a secret key. This value must be a positive integer. The default value
    # is 50000.
    #keystore.pkcs12.keyPbeIterationCount = 50000
    
    # The algorithm used to calculate the optional MacData at the end of a PKCS12
    # file. This can be any HmacPBE algorithm defined in the Mac section of the
    # Java Security Standard Algorithm Names Specification. When set to "NONE",
    # no Mac is generated. The default value is "HmacPBESHA1".
    #keystore.pkcs12.macAlgorithm = HmacPBESHA1
    
    # The iteration count used by the MacData algorithm. This value must be a
    # positive integer. The default value is 100000.
    #keystore.pkcs12.macIterationCount = 100000

Below are some explanations on why existing encrypted private keys retain their different algorithms but the encrypted certificates must use the same algorithm:

The `KeyStore` class is designed to be protected by a single store password and multiple key passwords. Once a keystore is loaded (after providing the store password), all certificates are in clear text, while reading each key in a key entry needs an individual key password. This means we must encrypt all certificates using the same store password. If different algorithms are used to encrypt different certificates, an attacker can decrypt the one using the weakest algorithm and then gain access to others using stronger algorithms.

In fact, storing certificates using the same algorithm is doable since they are already decrypted after loading and the `store` method has an argument for the new store password. On the other hand, one can only call `getKey(alias, password)` to get a decrypted key and the key is still stored encrypted inside a `KeyStore` object, and there is no way to re-encrypt all keys with a single algorithm when storing them.

2) Add several new Mac algorithms to the `SunJCE` provider:

    HmacPBESHA1
    HmacPBESHA224
    HmacPBESHA256
    HmacPBESHA384
    HmacPBESHA512
    HmacPBESHA512/224
    HmacPBESHA512/256

They will be added to the Mac section of the Java Security Standard Algorithm Names Specification, and the SunJCE/Mac section of the JDK Providers Documentation.

3) Make some changes to `java.security.KeyStore$PasswordProtection` in `KeyStore.java`. First, the security properties were never meant to be a part of the Java SE spec and we do not require all third-party providers to implement them. These sentences should have been put under an `@implNote` tag. Second, we have actually never implemented the `keystore.<type>.keyProtectionAlgorithm` properties for other keystore types like JKS and JCEKS. Since the settings for PKCS12 have been expanded this time and well-documented inside `java.security`, we can simply remove the sentences here.

     /**
      * Gets the name of the protection algorithm.
      * If none was set then the keystore provider will use its default
    - * protection algorithm. The name of the default protection algorithm
    - * for a given keystore type is set using the
    - * {@code 'keystore.<type>.keyProtectionAlgorithm'} security property.
    - * For example, the
    - * {@code keystore.PKCS12.keyProtectionAlgorithm} property stores the
    - * name of the default key protection algorithm used for PKCS12
    - * keystores. If the security property is not set, an
    - * implementation-specific algorithm will be used.
    + * protection algorithm.
      *
      * @return the algorithm name, or {@code null} if none was set
      *
      * @since 1.8
      */
     public String getProtectionAlgorithm()


Comments
Confirm the bottom comment box works now.
15-02-2019

Moving to Approved.
10-12-2018

It was a typo, that first line should starts with "-". I've fixed it. As Sean pointed out, the method is describing a security property so the new `@systemProperty` should not be used here. That said, since this CSR has already made the property both a security property and a system property, I think it's better to update the description here to be consistent. Otherwise it would be quite confusing. I suggest updating the text to "...used for PKCS12 keystoresIf. If a system property of the same name is also specified, it supersedes the security property value. If neither is set, an implementation-specific algorithm will be used."
08-12-2018

"keystore.PKCS12.keyProtectionAlgorithm" is a security property, not a system property. If you look at the diffs in the webrev below, 2 lines above it, it refers to it as a security property. https://cr.openjdk.java.net/~weijun/8076190/webrev.05/src/java.base/share/classes/java/security/KeyStore.java.sdiff.html So, I don't think the @systemProperty tag should be used here.
07-12-2018

Shouldn't * For example, the + * {@code keystore.PKCS12.keyProtectionAlgorithm} property stores the + * {@systemProperty keystore.pkcs12.keyProtectionAlgorithm} property stores the * name of the default key protection algorithm used for PKCS12 * keystores. be * For example, the + * {@systemProperty keystore.pkcs12.keyProtectionAlgorithm} property stores the * name of the default key protection algorithm used for PKCS12 * keystores. ?
07-12-2018

Please set the fixVersion before the request is finalized; as the parent issue is targeted at JDK 12, I assume the CSR is too. Also, please use the new {@systemPropery} tag (JDK-8213920) to document the system property. Should any part of this work be backported to earlier LTS releases? Moving to Provisional.
29-11-2018