Skip to content

Add Ability to use Config File#1167

Open
johnpeck-us-ibm wants to merge 1 commit intoIBM:mainfrom
johnpeck-us-ibm:ProvUptOpenSSLV3
Open

Add Ability to use Config File#1167
johnpeck-us-ibm wants to merge 1 commit intoIBM:mainfrom
johnpeck-us-ibm:ProvUptOpenSSLV3

Conversation

@johnpeck-us-ibm
Copy link
Copy Markdown
Member

@johnpeck-us-ibm johnpeck-us-ibm commented Feb 10, 2026

Added the ability to use a config file to create a a new OpenJCEPlus provider based on that file

Signed-off-by: John Peck 140550562+johnpeck-us-ibm@users.noreply.github.com

@johnpeck-us-ibm johnpeck-us-ibm self-assigned this Feb 10, 2026
@johnpeck-us-ibm johnpeck-us-ibm marked this pull request as draft February 10, 2026 17:03
* under the terms provided by IBM in the LICENSE file that accompanied
* this code, including the "Classpath" Exception described therein.
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general I was envisioning a file format that users could more easily modify and understand, instead of parsing java code in order to setup the provider. I think we would want to choose from xml, json, or Java properties files and use a parsing library. Java properties files seem like the most common in this area such as the java.security file.

Having the file versioned would allow us to grow into every more complex file formats and options.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do that instead. This is more like what you would have to do if you were creating a provider. So, this makes it easy to take an existing provider and add attributes etc to a new provider, which is kind of how I would see this used. Otherwise, it will be a lot of work for some one to translate what is already in a provider to create a file. Now I guess if we document this well an AI tool could be used to do the translation. This also makes is pretty obvious what the service will contain. Where property pairs may not.

Note: I am not set on the current format, and can be convinced otherwise.

@johnpeck-us-ibm
Copy link
Copy Markdown
Member Author

I got the properties working. Now just need to deal with defaults

@johnpeck-us-ibm
Copy link
Copy Markdown
Member Author

I have added two new files. to base. BackendCryptoInterface and BankendCryptoSelector. These are files we will need for the selection of the backend. The Basically when a function in base needs to determine the back end to use it can call the BankendCryptoselector with the provider, the type (cipher, message digest, etc) and the algorithm it will return the backend. All the bankend calls will be of the format in BackendCryptoInterface. We may need to remove some calls and modify the function parameters but this is a start. So for example in Digest.java in where it calls NativeInterface.DIGEST_create today in would first call (BankendCryptoSelector.selectBackend(Provider, "Digest", )).DIGEST_create

@johnpeck-us-ibm johnpeck-us-ibm force-pushed the ProvUptOpenSSLV3 branch 2 times, most recently from fb660bd to 16d4c4b Compare April 7, 2026 15:27
@johnpeck-us-ibm johnpeck-us-ibm marked this pull request as ready for review April 7, 2026 17:01
@johnpeck-us-ibm
Copy link
Copy Markdown
Member Author

Moved test cases and added documentation.

Added the ability to use a config file to create a
a new OpenJCEPlus provider based on that file. Update
the providers to use this config to create FIPS and
non-FIPS

Signed-off-by: johnpeck-us-ibm <johnpeck@us.ibm.com>
+ "KeyGenerator.kda-hkdf-with-sha256.alias.add = kda-hkdf-with-sha-256\n"
+ "Service.KeyGenerator.kda-hkdf-with-sha256 = com.ibm.crypto.plus.provider.HKDFGenerator$HKDFwithSHA256\n"

+ "KeyGenerator.kda-hkdf-with-sha384.alias.add = kkda-hkdf-with-sha-384\n"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be kkda-hkdf-with-sha-384 instead of kda-hkdf-with-sha-384 like the others.

Comment on lines +99 to +109
try {
ProviderServiceReader config = new ProviderServiceReader(new BufferedReader(new StringReader(DefaultProviderAttrs.getConfigString())));
List<ProviderServiceReader.ServiceDefinition> services = config.readServices();
for (ProviderServiceReader.ServiceDefinition service : services) {
putService(new OpenJCEPlusService(jce, service.getType(), service.getAlgorithm(),
service.getClassName(), service.getAliases().toArray(new String[service.getAliases().size()]), service.getAttributes()));
}
} catch (IOException e) {
throw new InvalidParameterException("Error configuring OpenJCEPlus provider - " + e.getMessage());
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code ( lines 99 - 108 ) is very similar if not exactly the same as the OpenJCEPlusFIPS class. Seems we could put this into a private helper method in the OpenJCEPlusProvider class that can be used in both providers.

service.getClassName(), service.getAliases().toArray(new String[service.getAliases().size()]), service.getAttributes()));
}
} catch (IOException e) {
throw new InvalidParameterException("Error configuring OpenJCEPlus provider - " + e.getMessage());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When throwing the exception on this line can we throw the entire e in the caused by for the exception instead of just the message.

@@ -140,583 +153,6 @@ public OpenJCEPlusFIPS() {
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenJCEPlus has both a configure(String) and configure(BufferedReader) method. I dont see these added here to the FIPS provider. For consistancy and for allowing support / extension / changes of the OpenJCEPlus-xxx providers in the future should these be added here also?

Comment on lines +28 to +37
* This class reads files containing putService() calls in the format:
* putService(new OpenJCEPlusService(provider, "Type", "Algorithm", "ClassName", aliases));
*
* Example usage:
* <pre>
* ProviderServiceReader reader = new ProviderServiceReader("services.txt");
* List<ServiceDefinition> services = reader.readServices();
* for (ServiceDefinition service : services) {
* System.out.println(service.getType() + ": " + service.getAlgorithm());
* }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are using properties now from the file so this javadoc should reflect that change.

* @param filePath the path to the file containing service definitions
*/
public ProviderServiceReader(String filePath) {
this.filePath = filePath;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we check for null here?

throw new IOException("File not found: " + filePath);
} else {
// this filePath != null && Files.exists(Paths.get(filePath))
rd = new BufferedReader(new FileReader(filePath));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should ensure that rd is always closed.

}
}
} catch (Exception e) {
throw new IOException("File issue: " + e.getMessage());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please throw e in the caused by of the exception so its not hidden if an error occurs.

if (value != null) {
String[] aliases = value.split("\\s*,\\s*");
for (String alias : aliases) {
Aliases.add(alias);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we ensure that the alias is not null or empty string due to the regex above?

* @return a list of alias strings
*/
private List<String> processAliases(String[] parts, Properties defaultPr, Properties configPr, Set<String> configAliases) {
List<String> Aliases = new ArrayList<>();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this should be lower case since its a local variable.

putService(new OpenJCEPlusService(jce, "KeyGenerator", "kda-hkdf-with-sha224",
"com.ibm.crypto.plus.provider.HKDFGenerator$HKDFwithSHA224", aliases));
public OpenJCEPlus(ProviderServiceReader config) {
super("OpenJCEPlus-" + config.getName(), config.getDesc());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check that the name and description is not null or empty?

Also we should add the name of the provider we use in the debug on line 138.

throw new IOException("Invalid key: " + key);
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point in the code should we validate a few of the parameters to ensure we read them from the config file. This should include description and default and name at least from above that have been expected to be parsed.

2. Config file `.add` operations are applied
3. Config file `.delete` operations are applied
4. Config file `.replace` operations are applied (clears list first)
- Only one operation (add/delete/replace) per service type and algorithm is expected
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if we dont follow this rule?

Comment on lines +401 to +413
## ServiceDefinition Class

The parser creates `ServiceDefinition` objects with:

```java
public class ServiceDefinition {
private final String type; // Service type (e.g., "Cipher")
private final String algorithm; // Algorithm name (e.g., "AES")
private final String className; // Implementation class
private final List<String> aliases; // List of alias names
private final Map<String, String> attributes; // Attribute key-value pairs
}
```
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be ok leaving code out of the user facing documenation for this feature unless there is a reason?

@@ -0,0 +1,451 @@
# Provider Configuration File Format Documentation

This document describes the format and syntax for provider configuration files used in OpenJCEPlus, based on the `ProviderServiceReader.java` implementation and example configuration files `ProviderDefAttrs.config` and `ProviderFIPSDefAttrs.config`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Giving the user a direct link in the code to these two files would be helpful for them to have as "examples". Over time we could also provide and link other test configuration files such as OpenSSL related files.


#### Key Structure:
- **Part 0**: Must be `Service` (case-insensitive)
- **Part 1**: Service type (e.g., Cipher, Signature, MessageDigest)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we give the reader all possible values here in case they are not familiar with the JCE service type definitions?

There is a section below "Common Service Types:" that seems to cover them. Maybe we link to that spot here?

@@ -111,1123 +123,45 @@ public OpenJCEPlus() {
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be great for us to print in debugs the final services that are being registered after all the parsing, replacing, and joining operations have occurred so its clear what we registered along with various other service attributes, aliases, provider name, and classes we ended up with after we are done processing. Perhaps we could add a helper function to the OpenJCEPlusProvider to print everything registered in both the OpenJCEPlus and OpenJCEPlusFIPS class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants