Add support for FIPS edition of BouncyCastle#17
Add support for FIPS edition of BouncyCastle#17buleuszmatak wants to merge 5 commits intonats-io:mainfrom
Conversation
|
So your changes here are probably fine, but I think that the changes should be part of the java client as well. The idea of the nkeys library was to have it ready for the eventuality that I can break up the jnats client into pieces, which is only going to happen with a major version. So for now we need to keep the libraries in sync. |
| } else { | ||
| return Security.getProvider(property); | ||
| } | ||
| } |
There was a problem hiding this comment.
| } | |
| private static @Nullable Provider getSecurityProvider() { | |
| String property = System.getProperty("io.nats.nkey.security.provider"); | |
| if (property == null || property.isEmpty()) { | |
| // Instantiating the BouncyCastle provider to maintain backwards compatibility | |
| return DefaultSecurityProviderFactory.getProvider(); | |
| } | |
| if (property.isEmpty()) { | |
| // Use whatever is configured as the default in the JVM | |
| return null; | |
| } | |
| return Security.getProvider(property); | |
| } |
There was a problem hiding this comment.
Flattened the ifs (no else statements), but kept the conditions.
null - system property not specified - create BouncyCastle provider for backwards compatibility
empty - property with empty value - use whatever provider is configured in the JVM
other - property with non-empty value - use the provider with the specified name
src/main/java/io/nats/nkey/NKey.java
Outdated
|
|
||
| private static NKey createPair(NKeyType type, SecureRandom random) | ||
| private static @Nullable Provider getSecurityProvider() { | ||
| String property = System.getProperty("io.nats.nkey.security.provider"); |
There was a problem hiding this comment.
Can we make io.nats.nkey.security.provider a public constant, maybe in NKeyConstants?
There was a problem hiding this comment.
Done. Added SECURITY_PROVIDER_PROPERTY to NKeyConstants
Thanks for bearing with me on this process. |
8207218 to
8139a18
Compare
Will create a PR in jnats once everything here is ready to be merged. This PR adds a system property to switch between security providers. Its current name is |
Implementation of I've added assertions to nkeys.java/src/test/java/io/nats/nkey/NKeyTests.java Lines 561 to 570 in 8139a18
Comments above the constants describe what each byte means nkeys.java/src/main/java/io/nats/nkey/KeyCodec.java Lines 22 to 57 in 8139a18 As for references, here is BouncyCastle doing essentially the same thing for public key encoding They don't use that strategy for private key, but the idea is the same. As long as private/public key is valid, encoded key returned from
If you want, I can explore implementation of
Alternative strategy for security provider swappabilityMove all crypto operations to a separate class, and allow users to specify (as a system property) that their implementation should be used instead. That would in some sense be |
|
@buleuszmatak Hey - sorry this has got shelved for the holidays. I'm going to move this library to Java 21 or 25. This is preparation to upgrade the existing client to 21/25. I can still merge this PR, but wanted to get your opinion on this. |
I think that can be done, and it would make nats.java a much lighter dependency. However, I don't think there is anything like var kpg = KeyPairGenerator.getInstance("Ed25519");
kpg.initialize(256, new FixedSecureRandom(seed));
var keyPair = kpg.generateKeyPair();
var publicKey = keyPair.getPublicKey();If you care about compatibility with BCFIPS in approved mode then ...if you write your FixedSecureRandom(byte[] value) {
super(null, null);
this.value = value;
}which means
Unless there is interest in this from anyone else but me, I wouldn't. My attempt to add FIPS compatibility is not for a hobby project, and because of the dynamic environment I'm working in, my need for this has been suspended. Feel free to close. |
|
@buleuszmatak I'm working on the "alternative strategy" idea. Basically pulling out all code that does not require the BC library into one project with an interface/factory/provider idea and then I'll make a second project implements using the standard BC, and make a third project that is specifically for the fips version of the second. This provides a way to ensure only the desired bc library is around and provides a template for anyone wanting something completely on their own. |
|
@buleuszmatak So this work is ready for a FIPS implementation. #18 |
|
Closing. Replaced with new individual implementations. FIPS implementation found in PR #26 |
Problem
I want to use NATS Auth Callout in an application that has to use a FIPS-certified cryptographic module, particularly the FIPS-certified edition of BouncyCastle in approved-only mode.
To use the FIPS-certified edition, I need to first ensure that the normal edition is not on the classpath, i.e. exclude it from any transitive dependencies including from nkeys-java and jnats.
After doing that and adding the FIPS edition, the nkeys-java library fails at runtime, because it is using BouncyCastle APIs specific to the normal edition.
Example
https://github.com/nats-io/java-nats-examples/pull/18/files
It uses version of nkeys-java from this PR.
Build this PR locally to see the working version or revert
io.nats:nkeys-javato2.1.1to get the error mentioned above.Proposed solution
Use APIs that are common across the normal and the FIPS-certified editions and add a system property
io.nats.nkey.security.providerallowing users to switch to a differentjava.security.Provider.-Dio.nats.nkey.security.providerwill causenkeys-javato use the provider configured in the JVM.io.nats.nkey.security.provider=BCorio.nats.nkey.security.provider=BCFIPSwill causenkeys-javato use the configured provider.Java 15 added support for Ed25519, but I found no way to derive public key from private key, that would also work with BCFIPS in approved-only mode, assuming no security provider specific code.
That's why the only providers that can be configured are BC and BCFIPS.
Perhaps if/when NATS Java libraries raise the requirement to Java 15+, the property could be dropped and the default provider could be switched to the one configured in the JVM, which would allow to drop the BouncyCastle dependency. That would of course require the solution to the public key derivation. On Java 15+ itself the derivation can be done by using the FixedSecureRandom pattern, but that throws on the FIPS-edition in approved-only mode.