Task #2214
closedAllow stronger ciphers - enhance Java security policy file
0%
Description
We should be able to integrate this... so IdM can support stronger ciphers.
- https://www.oracle.com/java/technologies/javase-jce8-downloads.html (not sure if correct version for us, need to check)
- there is some license to it, so also check this https://www.oracle.com/downloads/licenses/binary-code-license.html
Related issues
Updated by Petr Fišer over 4 years ago
I think this will need a bit of testing. Currently, our images are based on CentOS7. Also, my primary goal was to enable AES-256 and not to deal with (EC)DHE but when I think about it now... it does not seem like a bad idea. We could kill two birds with one stone.
ECDHE was removed by RH from early openjdk8 but returned around ~openjdk8u90. The AES probably didn't budge and stayed on 128b version until today.
So the first thing is to assess which ciphers we currently have on our basis (RHEL/CentOS 7 latest; openjdk8 latest), both symmetrical and asymmetrical and also EC/non-EC. Just to be sure.
Next thing to do is to make it work and assess which ciphers we got and if it is what we really want.
- Java Unlimited policy file for JDK8 https://www.oracle.com/java/technologies/javase-jce8-downloads.html . The more i dig through those Oracle's licensing docs, the crazier this idea seems.
- Use Oracle's native EC library libsunec.so. Same agrument as above. Also, this does not solve our AES-256 wish.
- Go to openjdk9 (at least), there should be strong ciphers packed within, just add a crypto.policy=unlimited property and we should be good to go. This would be ideal. Not sure how we stand with Java9 support in the product.
- Go the BouncyCastle way and register it as a lower-priority security provider. This is really appealing choice. :)
# quote from one of SO links below Add the bcprov-<verion>.jar to /usr/lib/jvm/jre/lib/ext Edit /usr/lib/jvm/jre/lib/security/java.security adding the following line to the list of providers: security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider
Reading (I know those posts are like 3yo - that's why I suggest to assess ciphers first):
https://stackoverflow.com/questions/31971499/ecdhe-cipher-suites-not-supported-on-openjdk-8-installed-on-ec2-linux-machine
https://security.stackexchange.com/questions/117975/how-to-enable-ecdhe-in-openjdk-1-8-0-in-centos-6-7
http://mail.openjdk.java.net/pipermail/security-dev/2016-October/014943.html
Updated by Petr Fišer over 4 years ago
I created a CentOS7-based container and made Java8 barf its supported ciphers (default setting after installation). This actually looks like we already have what we want.
SSL ciphers there are cool. Also the AES-256 seems to be present, at least with NoPadding. I think we use PKCS5Padding in the product. Need to check.
[root@javaciphers /]# java ListCiphers SSL ciphers list: Default Cipher * TLS_DHE_DSS_WITH_AES_128_CBC_SHA * TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 * TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 * TLS_DHE_DSS_WITH_AES_256_CBC_SHA * TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 * TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 * TLS_DHE_RSA_WITH_AES_128_CBC_SHA * TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 * TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 * TLS_DHE_RSA_WITH_AES_256_CBC_SHA * TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 * TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 * TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 * TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 * TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 * TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 * TLS_EMPTY_RENEGOTIATION_INFO_SCSV * TLS_RSA_WITH_AES_128_CBC_SHA * TLS_RSA_WITH_AES_128_CBC_SHA256 * TLS_RSA_WITH_AES_128_GCM_SHA256 * TLS_RSA_WITH_AES_256_CBC_SHA * TLS_RSA_WITH_AES_256_CBC_SHA256 * TLS_RSA_WITH_AES_256_GCM_SHA384 Encryption algorithms: AES AESWrap AESWrap_128 AESWrap_192 AESWrap_256 AES_128/CBC/NoPadding AES_128/CFB/NoPadding AES_128/ECB/NoPadding AES_128/GCM/NoPadding AES_128/OFB/NoPadding AES_192/CBC/NoPadding AES_192/CFB/NoPadding AES_192/ECB/NoPadding AES_192/GCM/NoPadding AES_192/OFB/NoPadding AES_256/CBC/NoPadding AES_256/CFB/NoPadding AES_256/ECB/NoPadding AES_256/GCM/NoPadding AES_256/OFB/NoPadding ARCFOUR Blowfish DES DESede DESedeWrap PBEWithHmacSHA1AndAES_128 PBEWithHmacSHA1AndAES_256 PBEWithHmacSHA224AndAES_128 PBEWithHmacSHA224AndAES_256 PBEWithHmacSHA256AndAES_128 PBEWithHmacSHA256AndAES_256 PBEWithHmacSHA384AndAES_128 PBEWithHmacSHA384AndAES_256 PBEWithHmacSHA512AndAES_128 PBEWithHmacSHA512AndAES_256 PBEWithMD5AndDES PBEWithMD5AndTripleDES PBEWithSHA1AndDESede PBEWithSHA1AndRC2_128 PBEWithSHA1AndRC2_40 PBEWithSHA1AndRC4_128 PBEWithSHA1AndRC4_40 RC2 RSA
Updated by Petr Fišer over 4 years ago
Did a little testing with this piece of code (taken from IdM and bent for what I needed to test):
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class TestCipher {
public static void main(String[] args) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
String alg = "AES/CBC/PKCS5Padding";
//abcdefghijklmnop = 6162636465666768696a6b6c6d6e6f70 as hex
byte[] iv1 = "abcdefghijklmnop".getBytes();
byte[] sk1 = "abcdefghijklmnop".getBytes();
// this is right. AES has 128b blocks and CBC mode needs IV to be the size of a block
byte[] iv2 = "abcdefghijklmnop".getBytes();
byte[] sk2 = "abcdefghijklmnopabcdefghijklmnop".getBytes();
SecretKey sk128 = new SecretKeySpec(sk1, "AES");
testCipherInit(Cipher.ENCRYPT_MODE, sk128, alg, iv1);
SecretKey sk256 = new SecretKeySpec(sk2, "AES");
testCipherInit(Cipher.ENCRYPT_MODE, sk256, alg, iv2);
}
public static Cipher testCipherInit(int encryptMode, SecretKey key, String algo, byte[] iv) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = null;
byte[] plaintext = "test".getBytes();
try {
cipher = Cipher.getInstance(algo);
cipher.init(encryptMode, key, new IvParameterSpec(iv));
System.out.println("Cipher initialized. " + algo);
byte[] res = cipher.doFinal(plaintext);
System.out.println("enc('test'): " + DatatypeConverter.printBase64Binary(res));
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException e) {
System.out.println("Cipher can't be initialized! " + algo);
System.out.println("Exception: " + e.getMessage());
}
return cipher;
}
}
Output of java code:
Cipher initialized. AES/CBC/PKCS5Padding enc('test'): G7pg1uF/q8i9saz2yW4ecA== Cipher initialized. AES/CBC/PKCS5Padding enc('test'): UBWxzyp6dzQeumNpGZudnA==
Verification with openssl:
echo -n "test" | openssl enc -aes-128-cbc -base64 -K "6162636465666768696a6b6c6d6e6f70" -iv "6162636465666768696a6b6c6d6e6f70" G7pg1uF/q8i9saz2yW4ecA== echo -n "test" | openssl enc -aes-256-cbc -base64 -K "6162636465666768696a6b6c6d6e6f706162636465666768696a6b6c6d6e6f70" -iv "6162636465666768696a6b6c6d6e6f70" UBWxzyp6dzQeumNpGZudnA==
Then tested it on CentOS7 and Windows+Java8 IdM testing setup. Works fine everywhere.
Because the version of the cipher (128b vs. 256b) is determined by the size of secret key that is used, we should be able to use this in CzechIdM out of the box - just specify the 32B (=256b) key.
Need to test this with CzechIdM product.
Updated by Petr Fišer over 4 years ago
Tested on Docker image (i.e. Linux installation) and 32B=256b key works fine.
Need to test on Windows but I don't expect problems.
- ChangeConfidentialStorageKeyTaskExecutor LRT mandates old key to be 16B (128b) long. We will need to change that validation to accept both 16B and 32B long keys.
- The dialogue for ChangeConfidentialStorageKeyTaskExecutor configuration hides old key behind dots.
- This is extremely uncomfortable because I cannot be sure I filled out the field correctly and there is no other way to confirm (like temporary unhide button or "write again").
- It makes no sense because we are changing the key - that key was probably compromised and therefore is is already known and there is no need to hide it anymore.
- If I configure the LRT and go to its detail, I can see the key written there in plaintext anyway.
Updated by Petr Fišer over 4 years ago
Tested on Windows, it works too. However, on JDKs before 1.8u161 we need to add Unlimited Strength JCE Policy Files https://www.oracle.com/java/technologies/javase-jce8-downloads.html . Since those kinds of installation do not have policy files packed with IdM nor it is a Docker image, we are not effectively distributing them... so licensing is the same as for JDK for us and for the customer.
JDKs newer than 1.8u161 (inclusive) have strong ciphers enabled by default so we are good.On older projects we can do any one of following three depending on the goal:
- Upgrade JDK to 1.8u161 and later.
- Leave the older version and Apply JCE Policy files. We should be upgrading regularly so this is not really an option.
- Do not use AES with 256b key and stay on the 128b key. This is OK, depending on presumed threats. AES-128 is still considered secure.
Thinking about the JDK... I tested in in the container with latest JDK8. So this may affect linux installations as well.
Snippet from testing on Windows:
For JDK older than 1.8u161, we need unlimited strength policy files. - Download https://www.oracle.com/java/technologies/javase-jce8-downloads.html - install according to readme Administrator@BAK MINGW64 /c/CzechIdM/etc xxd secret.key 00000000: 536f 6d65 5365 6372 6574 584f 584f 584f SomeSecretXOXOXO 00000010: 536f 6d65 5365 6372 6574 584f 584f 584f SomeSecretXOXOXO 00000020: 0a . 2020-07-15 13:38:48.139 INFO 115094 --- [localhost-startStop-1] e.b.i.c.s.s.impl.DefaultCryptService.getKey : For crypt confidetial storage will be use key in file: [cipher.crypt.secret.keyPath]. 2020-07-15 13:38:48.827 INFO 115782 --- [localhost-startStop-1] e.b.i.c.s.s.impl.DefaultCryptService.init : Initializing Cipher succeeded - Confidetial storage will be crypted. 2020-07-15 13:38:48.827 INFO 115782 --- [localhost-startStop-1] o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker.postProcessAfterInitialization : Bean 'cryptService' of type [class eu.bcvsolutions.idm.core.security.service.impl.DefaultCryptService] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Updated by Petr Fišer over 4 years ago
- Status changed from New to Resolved
We will oficially have this in 10.6.0 including the LRT for changing confidential storage key.
Closing this ticket because it continues as #2391.
Updated by Ondřej Kopr over 4 years ago
- Related to Task #2355: Confidential storage cipher uses hardcoded initialization vector added