Skip to content

Commit

Permalink
Refactor BouncyCastleProvider to BouncyCastleFipsProvider (#2693)
Browse files Browse the repository at this point in the history
Solves issue #2230
  • Loading branch information
strehle authored Jan 31, 2024
1 parent 806ae16 commit 7fb5c56
Show file tree
Hide file tree
Showing 16 changed files with 57 additions and 46 deletions.
6 changes: 3 additions & 3 deletions dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ext {
// Versions shared between multiple dependencies
versions.aspectJVersion = "1.9.4"
versions.apacheDsVersion = "2.0.0.AM27"
versions.bouncyCastleVersion = "1.77"
versions.bouncyCastleVersion = "1.0.2.4"
versions.hamcrestVersion = "2.2"
versions.springBootVersion = "2.7.18"
versions.springFrameworkVersion = "5.3.31"
Expand Down Expand Up @@ -43,8 +43,8 @@ libraries.apacheDsProtocolLdap = "org.apache.directory.server:apacheds-protocol-
libraries.apacheLdapApi = "org.apache.directory.api:api-ldap-model:2.1.5"
libraries.aspectJRt = "org.aspectj:aspectjrt"
libraries.aspectJWeaver = "org.aspectj:aspectjweaver"
libraries.bouncyCastlePkix = "org.bouncycastle:bcpkix-jdk18on:${versions.bouncyCastleVersion}"
libraries.bouncyCastleProv = "org.bouncycastle:bcprov-jdk18on:${versions.bouncyCastleVersion}"
libraries.bouncyCastlePkix = "org.bouncycastle:bcpkix-fips:1.0.7"
libraries.bouncyCastleProv = "org.bouncycastle:bc-fips:${versions.bouncyCastleVersion}"
libraries.braveInstrumentationSpringWebmvc = "io.zipkin.brave:brave-instrumentation-spring-webmvc:${versions.braveVersion}"
libraries.braveContextSlf4j = "io.zipkin.brave:brave-context-slf4j:${versions.braveVersion}"
libraries.commonsIo = "commons-io:commons-io:2.15.1"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.cloudfoundry.identity.uaa.cypto;

import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.PasswordBasedDeriver;
import org.bouncycastle.crypto.PasswordConverter;
import org.bouncycastle.crypto.fips.FipsPBKD;
import org.bouncycastle.crypto.fips.FipsSHS;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.bouncycastle.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -12,8 +14,6 @@
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;

public class EncryptionService {
Expand All @@ -40,7 +40,7 @@ public byte[] encrypt(String plaintext) throws EncryptionServiceException {

SecretKey key = new SecretKeySpec(generateKey(newSalt), CIPHER);

Cipher myCipher = Cipher.getInstance(CIPHERSCHEME);
Cipher myCipher = Cipher.getInstance(CIPHERSCHEME, BouncyCastleFipsProvider.PROVIDER_NAME);
byte[] newNonce = generateRandomArray(GCM_IV_NONCE_SIZE_BYTES);

GCMParameterSpec spec = new GCMParameterSpec(GCM_AUTHENTICATION_TAG_SIZE_BITS, newNonce);
Expand Down Expand Up @@ -84,9 +84,12 @@ private byte[] generateRandomArray(int sizeInBytes) {
}

private byte[] generateKey(byte[] salt) {
PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());

gen.init(this.passphrase.getBytes(StandardCharsets.UTF_8), salt, PBKDF2_ITERATIONS);
return ((KeyParameter) gen.generateDerivedParameters(AES_KEY_LENGTH_BITS)).getKey();
PasswordBasedDeriver<FipsPBKD.Parameters> gen = new FipsPBKD.DeriverFactory().createDeriver(
FipsPBKD.PBKDF2.using(FipsSHS.Algorithm.SHA256_HMAC,
PasswordConverter.UTF8.convert(this.passphrase.toCharArray()))
.withIterationCount(PBKDF2_ITERATIONS)
.withSalt(salt)
);
return gen.deriveKey(PasswordBasedDeriver.KeyType.CIPHER, (AES_KEY_LENGTH_BITS + 7) / 8);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.crypto.ECDSASigner;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.crypto.bc.BouncyCastleFIPSProviderSingleton;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKParameterNames;
import com.nimbusds.jose.jwk.OctetSequenceKey;
Expand Down Expand Up @@ -81,6 +82,7 @@ public KeyInfo(String keyId, String signingKey, String keyUrl, String sigAlg, St
}
this.verifierCertificate = getValidX509Certificate(signingCert);
this.verifierKey = JsonWebKey.pemEncodePublicKey(keyPair.getPublic()).orElse(null);
this.signer.getJCAContext().setProvider(BouncyCastleFIPSProviderSingleton.getInstance());
} else {
jwk = new OctetSequenceKey.Builder(signingKey.getBytes()).build();
algorithm = Optional.ofNullable(sigAlg).orElse(JWSAlgorithm.HS256.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.KeyLengthException;
import com.nimbusds.jose.crypto.bc.BouncyCastleFIPSProviderSingleton;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
Expand Down Expand Up @@ -257,7 +258,7 @@ private JWTClaimsSet validateClientJWToken(JWT jwtAssertion, JWKSet jwkSet) {
ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
jwtProcessor.setJWSKeySelector(keySelector);
jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<>(null, null));

jwtProcessor.getJWSVerifierFactory().getJCAContext().setProvider(BouncyCastleFIPSProviderSingleton.getInstance());
try {
return jwtProcessor.process(jwtAssertion, null);
} catch (BadJWSException | BadJWTException jwtException) { // signature failed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMKeyPair;
Expand All @@ -20,6 +21,8 @@
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import static org.cloudfoundry.identity.uaa.oauth.jwt.JwtAlgorithms.DEFAULT_RSA;

public class KeyWithCert {
private X509Certificate certificate;
private PrivateKey privateKey;
Expand Down Expand Up @@ -53,16 +56,8 @@ public PrivateKey getPrivateKey() {
private boolean keysMatch(PublicKey publicKey, PrivateKey privateKey) {
byte[] data = {42};

String privateKeyAlgorithm = privateKey.getAlgorithm();
String publicKeyAlgorithm = publicKey.getAlgorithm();

if (privateKeyAlgorithm.equals("EC")) {
privateKeyAlgorithm = "ECDSA";
}

if (publicKeyAlgorithm.equals("EC")) {
publicKeyAlgorithm = "ECDSA";
}
String privateKeyAlgorithm = getJavaAlgorithm(privateKey.getAlgorithm());
String publicKeyAlgorithm = getJavaAlgorithm(publicKey.getAlgorithm());

try {
Signature sig = Signature.getInstance(privateKeyAlgorithm);
Expand All @@ -81,10 +76,19 @@ private boolean keysMatch(PublicKey publicKey, PrivateKey privateKey) {
}
}

private static String getJavaAlgorithm(String publicKeyAlgorithm) {
if ("EC".equals(publicKeyAlgorithm)) {
publicKeyAlgorithm = "ECDSA";
} else if ("RSA".equals(publicKeyAlgorithm)) {
publicKeyAlgorithm = DEFAULT_RSA;
}
return publicKeyAlgorithm;
}

private PrivateKey loadPrivateKey(String encodedPrivateKey, String passphrase) throws CertificateException {
PrivateKey privateKey = null;
try (PEMParser pemParser = new PEMParser(new InputStreamReader(new ByteArrayInputStream(encodedPrivateKey.getBytes())))) {
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BouncyCastleFipsProvider.PROVIDER_NAME);

Object object = pemParser.readObject();

Expand Down Expand Up @@ -116,7 +120,7 @@ private X509Certificate loadCertificate(String encodedCertificate) throws Certif
try (PEMParser pemParser = new PEMParser(new InputStreamReader(new ByteArrayInputStream(encodedCertificate.getBytes())))) {
Object object = pemParser.readObject();
if (object instanceof X509CertificateHolder) {
certificate = new JcaX509CertificateConverter().setProvider("BC").getCertificate((X509CertificateHolder) object);
certificate = new JcaX509CertificateConverter().setProvider(BouncyCastleFipsProvider.PROVIDER_NAME).getCertificate((X509CertificateHolder) object);
} else {
throw new CertificateException("Unsupported certificate type, not an X509CertificateHolder.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@


public class SocketUtils {
private static final String BC = org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
private static final String BC = org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider.PROVIDER_NAME;

public static X509Certificate getSelfCertificate(KeyPair keyPair, String organisation, String orgUnit, String commonName, Date issueDate,
long validForSeconds,
String signatureAlgorithm)
throws CertificateException, InvalidKeyException, SignatureException, NoSuchAlgorithmException, NoSuchProviderException {
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Security.addProvider(new org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider());

X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
builder.addRDN(BCStyle.OU, orgUnit);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.cloudfoundry.identity.uaa.config;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.cloudfoundry.identity.uaa.annotations.WithDatabaseContext;
import org.cloudfoundry.identity.uaa.impl.config.IdentityZoneConfigurationBootstrap;
import org.cloudfoundry.identity.uaa.login.Prompt;
Expand Down Expand Up @@ -94,7 +94,7 @@ void configureProvisioning(@Autowired JdbcTemplate jdbcTemplate) throws SQLExcep
bootstrap.setValidator(validator);

//For the SamlTestUtils keys we are using.
Security.addProvider(new BouncyCastleProvider());
Security.addProvider(new BouncyCastleFipsProvider());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
*******************************************************************************/
package org.cloudfoundry.identity.uaa.login;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;

import java.security.Security;

public class AddBcProvider {

static {
Security.addProvider(new BouncyCastleProvider());
Security.addProvider(new BouncyCastleFipsProvider());
}

public static void noop() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.cloudfoundry.identity.uaa.annotations.WithDatabaseContext;
import org.cloudfoundry.identity.uaa.cypto.EncryptionKeyService;
import org.cloudfoundry.identity.uaa.cypto.EncryptionServiceException;
Expand Down Expand Up @@ -54,6 +55,7 @@ class JdbcUserGoogleMfaCredentialsProvisioningTest {

@BeforeAll
static void key() {
Security.addProvider(new BouncyCastleFipsProvider());
Security.setProperty("crypto.policy", "unlimited");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public void setup() {
MockHttpServletRequest request = new MockHttpServletRequest();
ServletRequestAttributes attrs = new ServletRequestAttributes(request);
RequestContextHolder.setRequestAttributes(attrs);
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Security.addProvider(new org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider());

userAuthentication = mock(UaaAuthentication.class);
granter = new Saml2TokenGranter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
*/
package org.cloudfoundry.identity.uaa.provider.saml;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.junit.BeforeClass;
import org.junit.Test;
import org.opensaml.DefaultBootstrap;
Expand All @@ -30,7 +30,7 @@ public class SamlConfigurationBeanTest {

@BeforeClass
public static void initVM() throws Exception {
Security.addProvider(new BouncyCastleProvider());
Security.addProvider(new BouncyCastleFipsProvider());
DefaultBootstrap.bootstrap();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.cloudfoundry.identity.uaa.provider.saml;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.cloudfoundry.identity.uaa.saml.SamlKey;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.cloudfoundry.identity.uaa.zone.MultitenancyFixture;
Expand Down Expand Up @@ -169,7 +169,7 @@ public class SamlKeyManagerFactoryTests {
@BeforeAll
static void addBCProvider() {
try {
Security.addProvider(new BouncyCastleProvider());
Security.addProvider(new BouncyCastleFipsProvider());
} catch (SecurityException e) {
e.printStackTrace();
System.err.println("Ignoring provider error, may already be added.");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.cloudfoundry.identity.uaa.provider.saml;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.cloudfoundry.identity.uaa.provider.saml.idp.SamlTestUtils;
import org.cloudfoundry.identity.uaa.saml.SamlKey;
import org.cloudfoundry.identity.uaa.extensions.PollutionPreventionExtension;
Expand Down Expand Up @@ -49,7 +49,7 @@ public class ZoneAwareMetadataGeneratorTests {

@BeforeAll
static void bootstrap() throws Exception {
Security.addProvider(new BouncyCastleProvider());
Security.addProvider(new BouncyCastleFipsProvider());
DefaultBootstrap.bootstrap();
NamedKeyInfoGeneratorManager keyInfoGeneratorManager = Configuration.getGlobalSecurityConfiguration().getKeyInfoGeneratorManager();
keyInfoGeneratorManager.getManager(SAMLConstants.SAML_METADATA_KEY_INFO_GENERATOR);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
*******************************************************************************/
package org.cloudfoundry.identity.uaa.util;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.DecoderException;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.junit.BeforeClass;
import org.junit.Test;

Expand All @@ -26,7 +25,7 @@ public class KeyWithCertTest {

@BeforeClass
public static void addProvider() {
Security.addProvider(new BouncyCastleProvider());
Security.addProvider(new BouncyCastleFipsProvider());
}

public static final String key = "-----BEGIN RSA PRIVATE KEY-----\n" +
Expand Down Expand Up @@ -183,7 +182,7 @@ public static void addProvider() {
"y9mayfAcKPti4MbPR6ADAo9NxKbdsZjA138=\n" +
"-----END PRIVATE KEY-----\n";

@Test(expected = DecoderException.class)
@Test(expected = CertificateException.class)
public void testInvalidCert() throws Exception {
new KeyWithCert(key, password, invalidCert);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*******************************************************************************/
package org.cloudfoundry.identity.uaa.zone;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.cloudfoundry.identity.uaa.saml.SamlKey;
import org.junit.After;
import org.junit.Before;
Expand Down Expand Up @@ -202,7 +202,7 @@ public GeneralIdentityZoneConfigurationValidatorTests(IdentityZoneValidator.Mode
@BeforeClass
public static void addBCProvider() {
try {
Security.addProvider(new BouncyCastleProvider());
Security.addProvider(new BouncyCastleFipsProvider());
} catch (SecurityException e) {
e.printStackTrace();
System.err.println("Ignoring provider error, may already be added.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<property name="targetClass" value="java.security.Security"/>
<property name="targetMethod" value="addProvider"/>
<property name="arguments">
<bean class="org.bouncycastle.jce.provider.BouncyCastleProvider"/>
<bean class="org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider"/>
</property>
</bean>

Expand Down

0 comments on commit 7fb5c56

Please sign in to comment.