On Fri, 3 Feb 2023 01:41:41 GMT, Martin Balao <mba...@openjdk.org> wrote:
> We would like to propose an implementation for the [JDK-8301553: Support > Password-Based Cryptography in > SunPKCS11](https://bugs.openjdk.org/browse/JDK-8301553) enhancement > requirement. > > In addition to pursuing the requirement goals and guidelines of > [JDK-8301553](https://bugs.openjdk.org/browse/JDK-8301553), we want to share > the following implementation notes (grouped per altered file): > > * > ```src/java.base/share/classes/com/sun/crypto/provider/HmacPKCS12PBECore.java``` > (modified) > * This file contains the ```SunJCE``` implementation for the [PKCS #12 > General Method for Password > Integrity](https://datatracker.ietf.org/doc/html/rfc7292#appendix-B) > algorithms. It has been modified with the intent of consolidating all > parameter checks in a common file > (```src/java.base/share/classes/sun/security/util/PBEUtil.java```), that can > be used both by ```SunJCE``` and ```SunPKCS11```. This change does not only > serve the purpose of avoiding duplicated code but also ensuring alignment and > compatibility between different implementations of the same algorithms. No > changes have been made to parameter checks themselves. > * The new ```PBEUtil::getPBAKeySpec``` method introduced for parameters > checking takes both a ```Key``` and a ```AlgorithmParameterSpec``` instance > (same as the ```HmacPKCS12PBECore::engineInit``` method), and returns a > ```PBEKeySpec``` instance which consolidates all the data later required to > proceed with the computation (password, salt and iteration count). > > * ```src/java.base/share/classes/com/sun/crypto/provider/PBES2Core.java``` > (modified) > * This file contains the ```SunJCE``` implementation for the [PKCS #5 > Password-Based Encryption > Scheme](https://datatracker.ietf.org/doc/html/rfc8018#section-6.2) > algorithms, which use PBKD2 algorithms underneath for key derivation. In the > same spirit than for the ```HmacPKCS12PBECore``` case, we decided to > consolidate common code for parameters validation and default values in a > single file > (```src/java.base/share/classes/sun/security/util/PBEUtil.java```), that can > serve both ```SunJCE``` and ```SunPKCS11``` and ensure compatibility. > However, instead of a single static method at the implementation level (see > ```PBEUtil::getPBAKeySpec```), we create an instance of an auxiliary class > and invoke an instance method (```PBEUtil.PBES2Params::getPBEKeySpec```). The > reason is to persist parameters data that has to be consistent between calls > to ```PBES2Core::engineInit``` (in its multiple overloads) and > ```PBES2Core::engineGetParameters```, given a single ```PBES2Core``` > instance. In particular, a call to any of these methods can potentially modify the state in an observable way by means of generating a random IV and a salt. Previous to the proposed patch, this data was persisted in the ```PBES2Core::ivSpec``` and ```PBES2Core::salt``` instance fields. For compatibility purposes, we decided to preserve ```SunJCE```'s current behavior. > > * ```src/java.base/share/classes/sun/security/util/PBEUtil.java``` (new > file) > * This utility file contains the PBE parameters checking routines and > default values that are used by both ```SunJCE``` and ```SunPKCS11```. These > routines are invoked from ```HmacPKCS12PBECore``` (```SunJCE```), > ```PBES2Core``` (```SunJCE```), ```P11PBECipher``` (```SunPKCS11```) and > ```P11Mac``` (```SunPKCS11```). As previously noted, the goals are to avoid > duplicate code and to improve compatibility between different security > providers that implement PBE algorithms. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java``` > (modified) > * An utility function to determine if the token is NSS is now called. > This function is in a common utility class (```P11Util```) and invoked from > ```P11Key``` and ```P11SecretKeyFactory``` too. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java``` > (modified) > * A new type of P11 key is introduced: ```P11PBEKey```. This new type > represents a secret key that exists inside the token. Thus, this type > inherits from ```P11SecretKey```. At the same time, this type holds data used > for key derivation. Thus, this type implements the > ```javax.crypto.interfaces.PBEKey``` interface. In addition to the conceptual > modeling, there are practical advantages of identifying a key by this new > ```P11PBEKey``` type and holding the data used for derivation: 1) if the key > is used in another token (different than the one where it was originally > derived), a new derivation must take place; 2) if the key is passed to a > non-```SunPKCS11``` security provider, its key translation method might use > derivation data to derive again; and, 3) it's possible to return the > ```PBEKeySpec``` for the key (see for example > ```P11SecretKeyFactory::engineGetKeySpec```). > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java``` > (modified) > * We decided to integrate PBE algorithms to the existing ```P11Mac``` > service because the changes required have a low impact on the existing code. > When the ```P11Mac``` instance is created, we use the algorithm to get PBE > key information (if available). Only PBE algorithms have this type of > information. In the ```P11Mac::engineInit``` method, we now need to handle > the PBE service case. In such case, if the key is a ```P11Key```, we check > parameters and that the key implements ```javax.crypto.interfaces.PBEKey``` > by calling ```PBEUtil::checkKeyParams```. In other words, the key has to be a > ```P11PBEKey``` and the parameters used for its derivation must match the > ones passed in the invocation to ```P11Mac::engineInit```. If the key is not > a ```P11Key```, a PBE derivation is needed. As for the ```SunJCE``` case, we > go through parameters processing in ```PBEUtil::getPBAKeySpec```. > * There are two cases in which we need to call > ```P11SecretKeyFactory::convertKey```. One is when the service is not PBE, as > we did before the proposed change. In the PBE case, we must call this > function because it might be possible that, if the key token is not the same > than the service's token, a new key derivation is required. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PBECipher.java``` > (new file) > * Contrary to the ```P11Mac``` case, we decided to separate PBE > ```Cipher``` from non-PBE ```Cipher``` in a different class. There is some > additional complexity or gap between the two that we prefer to keep simple. A > PBE ```Cipher``` uses a non-PBE ```Cipher``` service underneath and forwards > most of its operations, but adds wrapping code to potentially derive keys > during initialization (see ```P11PBECipher::engineInit```). The code > associated to key derivation and parameters consistency checking is analogous > to the one described for ```P11Mac```. > * ```P11PBECipher``` has a ```P11PBECipher::engineGetParameters``` method > which calls ```PBEUtil.PBES2Params::getAlgorithmParameters``` and can > potentially initialize an IV and a salt with a random value, as explained in > the comments for ```PBES2Core```. > * A ```P11PBECipher``` service accepts PBE keys only. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java``` > (modified) > * The first significant change to this class that we want to discuss is > the introduction of the ```KeyInfo``` class and the refactoring of the > previous ```keyTypes``` map. Previous to the proposed change, the key > information that we needed to retain for key creation at the PKCS #⁠11 > level was simple: key algorithm -> PKCS #⁠11 native key type. With > PBE, we must consider not only the algorithm name and key type but also > (depending on the case) the mechanism that has to be used for derivation, the > underlying derivation function and the key length. As an example, to derive a > key for the PBEWithHmacSHA512AndAES_256 algorithm, we need to know that this > algorithm maps to a PKCS #⁠11 derivation mechanism value of > ```CKM_PKCS5_PBKD2```, a derivation function value of > ```CKP_PKCS5_PBKD2_HMAC_SHA512```, a derived key type of ```CKK_AES``` —so it > can be used in an AES Cipher service— and a key length of 256 bits. A new > hierarchy of classes to represent these diffe rent entries on the mapping structure has been introduced (see ```KeyInfo```, ```PBEKeyInfo```, ```AESPBEKeyInfo```, ```PBKDF2KeyInfo``` and ```P12MacPBEKeyInfo```). The methods to add or find entries in the new map have been adjusted. The previous pseudo key types strategy (```HMAC```, ```SSLMAC```), that allows any key type to be used in a HMAC service, has not been modified. > * The second significant change to this class was in the > ```P11SecretKeyFactory::convertKey``` method. When checking if a key can be > used in a service —notice here that the service can be any of > ```SecretKeyFactory```, ```Cipher``` or ```Mac```—, the following rules apply: > * If the key algorithm matches the service algorithm, the use is allowed > * If the key algorithm does not match the service algorithm and the > service is not one of the pseudo types, further checks are needed. The > ```KeyInfo``` structure for the key and service algorithms are obtained from > the map and the ```KeyInfo::checkUse``` method is invoked. The following > principles apply to make a decision: 1) PBE services require a > ```javax.crypto.interfaces.PBEKey``` of the same algorithm —we cannot use an > AES key, for example, in a PBEWithHmacSHA512AndAES_256 ```Cipher``` service—, > 2) PBKD2 keys can be used on any service —there is no information about the > key purpose to make a decision— and 3) keys can be used in a service if their > underlying type match —as an example, a PBEWithHmacSHA512AndAES_256 PBE key > has an underlying type of ```CKK_AES``` and can be used in an AES > ```Cipher``` service—. > * The third significant change to this class was the addition of the > ```P11SecretKeyFactory::derivePBEKey``` function. This function does > different checks and creates the PKCS #⁠11 structures to make a native > call to ```C_GenerateKey``` to derive the key. They key returned, in case of > success, is of ```P11PBEKey``` type. It is worth mentioning that this > function is the only path to invoke a native key derivation. It's used not > only by the PBE ```P11SecretKeyFactory``` service but also by PBE > ```Cipher``` and PBE ```Mac``` services when they need to derive a key. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Util.java``` > (modified) > * Added some utility functions. One of them is > ```P11Util::encodePassword``` which serves the purpose of encoding a password > in a way that can go through native library truncation (OpenJDK) and reach > the PKCS #⁠11 API in the expected encoding. Password encoding must be > UTF-8 for PKCS #⁠5 v2.1 derivation and BMPString (UTF-16 big endian) > for PKCS #⁠12 v1.1 General Method for Password Integrity derivation. > By avoiding a modification to the existing native > ```jCharArrayToCKUTF8CharArray``` function (```p11_util.c```), we reduce the > risk of breaking existing code. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java``` > (modified) > * The new PBE algorithms are registered for ```SunPKCS11``` services. > It's worth noting that there is an additional (and optional) > ```requiredMechs``` array to specify a list of native mechanisms that must be > available in the token for the service to be enabled. To explain the need for > this structure, we will focus on the HmacPBESHA1 ```Mac``` service example. > On the one hand, we require the ```CKM_SHA_1_HMAC``` mechanism to be > available in the token because this is, ultimately, a SHA-1 HMAC operation. > However, the ```CKM_PBA_SHA1_WITH_SHA1_HMAC``` mechanism must be available as > well for the preceding PBE key derivation. In the PBKDF2 case, we leverage on > this structure to require a mechanism associated to the derivation function. > The assumption is that, for example, if the ```CKM_PKCS5_PBKD2``` and > ```CKM_SHA_1_HMAC``` mechanisms are available, a PBKDF2 derivation using HMAC > SHA-1 underneath will be available. In this case, the derivation function is > represented by the ```CKP_ PKCS5_PBKD2_HMAC_SHA1``` constant. > * As mentioned in > [JDK-8301553](https://bugs.openjdk.org/browse/JDK-8301553), for some > algorithms there isn't a PKCS #⁠11 constant and we use the NSS > vendor-specific one. This code can be easily be updated in the future if a > constant is introduced to the standard. We don't know if that will ever > happen as the newer PKCS #⁠5 derivation for Mac (PBMAC1) might be > considered in the future as a PKCS #⁠12 integrity scheme replacement. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_ECDH1_DERIVE_PARAMS.java``` > (modified) > * Minor comment fix. This mistake was probably the result of using the > ```CK_PKCS5_PBKD2_PARAMS``` file as a template and forgetting to update the > comment. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java``` > (modified) > * New constructors for the ```CK_PBE_PARAMS```, > ```CK_PKCS5_PBKD2_PARAMS``` and ```CK_PKCS5_PBKD2_PARAMS2``` structures that > can be used along with a ```CK_MECHANISM```. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java``` > (modified) > * Some minor adjustments to comments and a constructor to make this class > usable with the PKCS #⁠12 General Method for Password Integrity > derivation. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS.java``` > (modified) > * Same than for ```CK_PBE_PARAMS```. It is worth noting that this > structure is the one used in PKCS #⁠11 revisions previous to v2.40 > Errata 01. Given that NSS has decided to keep using it —even when it's not > compliant with the latest revisions of the v2.40 and v3.0 standards—, we make > an exception for it. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS2.java``` > (new file) > * The new structure for passing PBE parameters to the PKCS #⁠11 > token in the PKCS #⁠5 v2.1 derivation scheme. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_X9_42_DH1_DERIVE_PARAMS.java``` > (modified) > * Same comment than for ```CK_ECDH1_DERIVE_PARAMS```. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java``` > (modified) > * More visibility of major and minor versions of the PKCS #⁠11 > standard implemented by a token is needed to decide between the > ```CK_PKCS5_PBKD2_PARAMS``` and ```CK_PKCS5_PBKD2_PARAMS2``` structures. > > * > ```src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11Constants.java``` > (modified) > * New constants added. > > * ```src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c``` > (modified) > * Adjustments made to work with the structures to pass parameters to the > token for PBE derivation. It's worth noting that native PBKD2 parameter > structures have a tag before the data so we can execute the correct logic to > free up resources, once the operation is completed. This is how we > differentiate a ```CK_PKCS5_PBKD2_PARAMS``` from a > ```CK_PKCS5_PBKD2_PARAMS2``` one. > > * ```src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c``` > (modified) > * Adjustments to work with the new PBE parameter structures. > * A bug affecting non-null Java arrays whose length is 0 and need to be > converted to native PKCS #⁠11 arrays has been fixed. For these arrays, > it was possible that some platforms return ```NULL``` as a result of calling > memory allocation functions when the size was 0 and an ```OutOfMemory``` > exception was incorrectly thrown. > > * ```src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h``` > (modified) > * Native constants and structures added. > > Test files > > * ```test/jdk/sun/security/pkcs11/Cipher/PBECipher.java``` (new file) > * Tests the PBE ```Cipher``` service in ```SunPKCS11```, cross-comparing > results against ```SunJCE``` (if available) and static data. > * The PBE ```Cipher``` service is tested with different types of keys: > derived from data in a ```PBEParameterSpec```, derived with a ```SunPKCS11``` > ```SecretKeyFactory``` service, derived from data in > ```AlgorithmParameters``` and derived from data contained in a > ```javax.crypto.interfaces.PBEKey``` instance. > > * ```test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java``` (new file) > * Tests that, for several PBE algorithms, PKCS #⁠12 key stores > (with Privacy and Integrity) written using ```SunPKCS11``` underneath can be > read using ```SunJCE``` underneath. > > * ```test/jdk/sun/security/pkcs11/Mac/MacSameTest.java``` (modified) > * This test was not expecting PBE services to be available in the > ```SunPKCS11``` security provider, and needs to invoke a new function > (```PKCS11Test::generateKey```) to generate a random key (password). > > * ```test/jdk/sun/security/pkcs11/Mac/PBAMac.java``` (new file) > * Similar to ```PBECipher``` but these are the possible types of keys: > derived from data in a ```PBEParameterSpec```, derived with a ```SunPKCS11``` > ```SecretKeyFactory``` service and derived from data contained in a > ```javax.crypto.interfaces.PBEKey``` instance. > > * ```test/jdk/sun/security/pkcs11/Mac/ReinitMac.java``` (modified) > * Same issue fixed than for ```MacSameTest```. > > * ```test/jdk/sun/security/pkcs11/PKCS11Test.java``` (modified) > * Functions to generate random keys or passwords for PBE and non-PBE > algorithms. > > * ```test/jdk/sun/security/pkcs11/SecretKeyFactory/TestPBKD.java``` (new > file) > * In addition to testing derived keys for different algorithms against > ```SunJCE``` and static assertion data, this test asserts: 1) different types > of valid and invalid key conversions, and 2) invalid or inconsistent > parameters passed for key derivation. Keys are derived with data contained in > a ```PBEKeySpec``` or in a ```javax.crypto.interfaces.PBEKey``` instance. > * Both an empty and a unicode password, containing a non-ASCII character, > are used during this test. > > Testing > > * No regressions have been observed in the ```jdk/sun/security/pkcs11``` > category (```SunPKCS11```). > > * No regressions have been observed in the > ```jdk/com/sun/crypto/provider``` category (```SunJCE```). > > * No regressions have been observed in the JDK Tier-1 category. > > * Anecdotally, a partial version of the proposed patch containing > ```Cipher``` and ```Mac``` changes is shipped in Red Hat Enterprise Linux > builds of OpenJDK 17 since November 2022, without any known issues at this > moment. > > This contribution is co-authored between @franferrax and @martinuy. We are > both under the cover of the OCA agreement per our employer (Red Hat). We look > forward to sharing this new feature for the benefit of the broad OpenJDK > community and users. src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c line 423: > 421: case CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN: > 422: case CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN: > 423: case CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN: How about CKM_PBE_SHA1_DES3_EDE_CBC and CKM_PBE_SHA1_DES2_EDE_CBC? ------------- PR: https://git.openjdk.org/jdk/pull/12396