-
Notifications
You must be signed in to change notification settings - Fork 24.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issues with using NSS PKCS#11 Provider in FIPS mode #33459
Comments
Pinging @elastic/es-security |
As defined in the PKCS#11 reference guide https://docs.oracle.com/javase/8/docs/technotes/guides/security/p11guide.html PKCS#11 tokens can be used as the JSSE keystore and truststore and the way to indicate this is to set `javax.net.ssl.keyStore` and `javax.net.ssl.trustStore` to `NONE` (case sensitive). This commits ensures that we honor this convention and do not attempt to load the keystore or truststore if the system property is set to NONE. Relates elastic#33459
From the PKCS#11 guide:
What do you think about adding support for keyStoreProvider and trustStoreProvider? |
* Correctly handle NONE keyword for system keystore As defined in the PKCS#11 reference guide https://docs.oracle.com/javase/8/docs/technotes/guides/security/p11guide.html PKCS#11 tokens can be used as the JSSE keystore and truststore and the way to indicate this is to set `javax.net.ssl.keyStore` and `javax.net.ssl.trustStore` to `NONE` (case sensitive). This commits ensures that we honor this convention and do not attempt to load the keystore or truststore if the system property is set to NONE. * Handle password protected system truststore When a PKCS#11 token is used as the system truststore, we need to pass a password when loading it, even if only for reading certificate entries. This commit ensures that if `javax.net.ssl.trustStoreType` is set to `PKCS#11` (as it would when a PKCS#11 token is in use) the password specified in `javax.net.ssl.trustStorePassword` is passed when attempting to load the truststore. Relates #33459
* Correctly handle NONE keyword for system keystore As defined in the PKCS#11 reference guide https://docs.oracle.com/javase/8/docs/technotes/guides/security/p11guide.html PKCS#11 tokens can be used as the JSSE keystore and truststore and the way to indicate this is to set `javax.net.ssl.keyStore` and `javax.net.ssl.trustStore` to `NONE` (case sensitive). This commits ensures that we honor this convention and do not attempt to load the keystore or truststore if the system property is set to NONE. * Handle password protected system truststore When a PKCS#11 token is used as the system truststore, we need to pass a password when loading it, even if only for reading certificate entries. This commit ensures that if `javax.net.ssl.trustStoreType` is set to `PKCS#11` (as it would when a PKCS#11 token is in use) the password specified in `javax.net.ssl.trustStorePassword` is passed when attempting to load the truststore. Relates #33459
JSSE assumes that there is only one PrivateKeyEntry in the keystore that is used to initialize the
If we were to support keystores that contain multiple PrivateKeyEntry and the possibility to select the appropriate alias to use via configuration (ie Since we can only use one An alternative to the above is to support multiple Security Providers, configured in the Java security properties and use a different one for each ( |
It turns out that multiple PKCS#11 Security Providers cannot be used, as only one can be configured at a given time. |
That was misleading. Mulitple PKCS#11 (of type
with
and
What cannot be done is to initialize both. An error:
is thrown. See A minimal example that reproduces the above behavior is: public class MultipleNssProviders {
private static final String PROVIDER_ID_1 = "SunPKCS11-NSS";
private static final String PROVIDER_ID_2 = "SunPKCS11-NSSTrust";
private static final String KEYSTORE_TYPE = "PKCS11";
private static final String KEYSTORE_PWD = "ThePassword";
public static void main(String[] args) throws Exception{
KeyStore ks1 = KeyStore.getInstance(KEYSTORE_TYPE, PROVIDER_ID_1);
ks1.load(null, KEYSTORE_PWD.toCharArray());
KeyStore ks2 = KeyStore.getInstance(KEYSTORE_TYPE, PROVIDER_ID_2);
// throws java.security.ProviderException
ks2.load(null, KEYSTORE_PWD.toCharArray());
}
} As such we cannot use two PKCS#11 tokens simultaneously , i.e one for the http layer keystore and one for the transport layer one. |
That is really an unfortunate limitation. I agree then we don't need the provider support. |
* Correctly handle NONE keyword for system keystore As defined in the PKCS#11 reference guide https://docs.oracle.com/javase/8/docs/technotes/guides/security/p11guide.html PKCS#11 tokens can be used as the JSSE keystore and truststore and the way to indicate this is to set `javax.net.ssl.keyStore` and `javax.net.ssl.trustStore` to `NONE` (case sensitive). This commits ensures that we honor this convention and do not attempt to load the keystore or truststore if the system property is set to NONE. * Handle password protected system truststore When a PKCS#11 token is used as the system truststore, we need to pass a password when loading it, even if only for reading certificate entries. This commit ensures that if `javax.net.ssl.trustStoreType` is set to `PKCS#11` (as it would when a PKCS#11 token is in use) the password specified in `javax.net.ssl.trustStorePassword` is passed when attempting to load the truststore. Relates #33459
NSS >= 3.27 cannot be used
When using libnss >= 3.27 loading the PKCS11 token fails with
CKR_ATTRIBUTE_READ_ONLY
errors. There is an open BUGJDK-8180837
that affects all Java versions and the RCA is not yet complete, nor is there an indication of when this will be resolved.TLS1.2 cannot be used with PKCS11-NSS
See unresolved jdk bug
Loading system keystore/truststore from a PKCS11 token
PKCS#11
tokens can be used as keystores and truststores. To use aPKCS#11
token as the JDK Default keystore and truststore ( a.k.a.javax.net.ssl.keyStore
andjavax.net.ssk.TrustStore
), one needs to setjaxax.net.ssl.keyStore
andjavax.net.ssl.trustStore
toNONE
(case sensitive) according to thePKCS#11
Reference Guide.We do not handle the
NONE
parameter correctly, and this gets interpreted as the name of the keystore and truststore, relevant to$ES_CONF_PATH
.Issue addressed in a PR shortly (See : #33460)
Multiple PKCS#11 keystores
We can't have multiple
PKCS#11
keystores. PKCS#11 is supposed to be a wrapper to access HW/SW tokens and the token is configured in the provider's configuration that is referenced injava.security
. As such, each JVM can only point to one token, i.e. one Keystore/Trustore. PKCS#11 KeyStores/TrustStores cannot be stored on disk and when loading the KeyStore viaKeyStore.load()
we need to passnull
as the InputStream in order to access the token configured in the security properties.In practice this means that keystores cannot be used with the NSS FIPS provider and only the System Truststore(
PKCS#11
token) can be used, adding trusted certificates to it, as needed. This is NOT an option for trust configuration for TLS on the transport layer as it means that all certificates signed by the JVM trusted CAs will be able to connect to an Elasticsearch node.It can't either be used for storing key material, unless we introduce the option to define the key alias to be selected from a keystore when a keystore is configured, instead of assuming there will be only one key as we do now. (This might be a nice todo irrespective to the FIPS effort)
This is not an issue per se, just a configuration limitation.
PKCS#11 tokens as password protected keystores
PKCS#11
tokens need to be password protected (NOTE: NSS tooling by default doesn't add a password to the db), otherwise loading the store fails withPKCS#11
keystores cannot be loaded from disk and in effect one can only use a single store so this only applies to the defaultPKCS#11
token (accessed as the system default keystore) that needs to be password protected. The password for it is passed usingjavax.net.ssl.keyStorePassword
andjavax.net.ssl.TrustStorePassword
that cannot be empty.Again, a limitation rather than an issue.
Another way this affects us is that if no trust configuration is defined, we resolve to using the default JDK Trust Configuration and we do that by initializing an TrustManager with a null Keystore and no password. We need to detect that we're using a
PKCS11-NSS
Provider and that the default truststore is acually aPKCS#11
token and pass thejavax.net.ssl.TrustStorePassword
when loading the null Keystore.Issue addressed in a PR shortly
In memory keystores
When using PEM files for key and trust material, we create in memory KeyStores (of applicable type - in this case
PKCS#11
) and load these keys and certificates so that we can then initialize TrustManager and KeyManager objects using the keystores. We passnull
as the InputStream parameter to indicate that it should be initialized as an empty keystore, but in the case ofPKCS#11
this will mean that the defaultPKCS#11
token will be loaded in theKeyStore
. This, in turn, adds a number of complications:KeyStore#setCertificateEntry()
doesn't work as theCKA_ID
attribute which is required for thePKCS#11
format is not set, and this fails with an NPE. We could code around this if needed.PEM files cannot be used as is.
PKCS#12 and FIPS 140 compliance
Looking for possible solutions for the above, I revisited why
PKCS#12
keystores are not FIPS 140-2 compliant and came to the conclusion that aPKCS#12
keystore can be FIPS 140-2 compliant.To give some context, the original idea is that a
PKCS#12
is not FIPS 140-2 compliant(for example BCFIPS disallows the use of PKCS12 stores in fips-approved mode) because the algorithms required for PBE key generation (for the key that is generated from the store's password and is used to encrypt the actual keys that are stored in the keystore) are not FIPS 140-2 compliant. However, reading through the RFC, PKCS#12 defines that
PKCS#5
should be used and in particularNow, PBES2 combines a password-based key derivation function (
PBKDF2
is called out explicitly) with an underlying encryption scheme. Appendix B2 of RFC2898 definesDES-EDE3-CBC-Pad
( three-key triple-DES in CBC mode with the RFC 1423 padding operation) as one of the possible schemes of encryption. Triple-DES is a NIST Approved algorithm and as such FIPS 140-2 compliant. Additionally, common tooling (i.e. openssl) allows for creatingPKCS#12
keystores with arbitrary (even not specified inPKCS#12
RFC) (FIPS 140-2 compliant) algorithms and encryption schemes.For example
will produce a
PKCS#12
store with the following informationwhich for all effects and purposes is FIPS 140-2 compliant since it only uses approved algorithms (
AES
for encryption andPBKDF2
as the key derivation function.To remain compliant to
PKCS#12
andPKCS#5 2.0
, one could create a keystore withGranted, existing
PKCS12
stores are not FIPS 140 compliant since the default algorithms schemes arepbeWithSHA1And3-KeyTripleDES-CBC
for the inner (private key encryption) andpbeWithSHA1And40BitRC2-CBC
for the outer (PKCS#7
) encryption.The problem with the above is that the
KeyManagerImpl
specifically requires that the keystore used to initialize a KeyManager, must be created by the same Security Provider that is actually being usedhttps://github.com/frohoff/jdk8u-jdk/blob/da0da73ab82ed714dc5be94acd2f0d00fbdfe2e9/src/share/classes/sun/security/ssl/KeyManagerFactoryImpl.java#L65
Unfortunately
PKCS#12
stores created by openssl do not have a provider set and if they did, it wouldn't be the SunPKCS-NSS that will be in use in runtime, and using theSunPCKS11-NSS
provider with keytool , i.e.yields an error as this provider can't handle
PKCS12
keystores.Summary
NONE
keyword needs to be handled accordingly ( Correctly handle PKCS#11 tokens for system keystore #33460)PKCS#12
keystores ,JKS
keystores andPEM
files cannot be used for key configuration.PKCS#12
keystores can be used for trust configuration and as shown above can be FIPS 140 compliant.PKCS#11
token that is used as the system keystore and truststore must be password protected.Actions
PKCS#11
tokenand to allow to specify in configuration the alias that should be used to read a key from a PKCS#11 token that might contain multiple private key entries(edited see below for justification.)PKCS#11
case, the associated keystore/token ) when configuring a keystore or key/certificate pair in any related configuration option.The text was updated successfully, but these errors were encountered: