Skip to content

ExceptionInInitializerError due to incorrect project.properties loaded from classpath #2114

Open
@mrhota

Description

@mrhota

Problem:

The AWS Encryption SDK fails when performing AwsCrypto#encryptData(KmsMasterKeyProvider, byte[], Map<String, String>) with an ExceptionInInitializerError when another JAR containing a project.properties file appears earlier in the classpath. This causes VersionInfo.versionNumber() to return null, leading to a NullPointerException in ApiName initialization.

Root Cause

The VersionInfo.versionNumber() method uses getResourceAsStream("project.properties"), making it vulnerable to classpath ordering issues when other JARs on the classpath contain the same resource. When another JAR containing project.properties and lacks a version property, and appears earlier in the classpath, it gets loaded instead of the SDK's own project.properties.

If another project.properties appears earlier in the class and does contain a version property, I assume the library would continue to load, but may run into extremely subtle problems if the version is not the expected value.

Environment

AWS Encryption SDK 2.4.0
Java 17
Spring Boot 2.6.x
Gradle

Stack trace

Exception in thread "grpc-default-executor-0" java.lang.ExceptionInInitializerError
	at com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider.getMasterKey(KmsMasterKeyProvider.java:335)
	at com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider.getMasterKey(KmsMasterKeyProvider.java:34)
	at com.amazonaws.encryptionsdk.MasterKeyProvider.getMasterKey(MasterKeyProvider.java:51)
	at com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider.getMasterKeysForEncryption(KmsMasterKeyProvider.java:348)
	at com.amazonaws.encryptionsdk.DefaultCryptoMaterialsManager.getMaterialsForEncrypt(DefaultCryptoMaterialsManager.java:88)
	at com.amazonaws.encryptionsdk.AwsCrypto.encryptData(AwsCrypto.java:355)
	at com.amazonaws.encryptionsdk.AwsCrypto.encryptData(AwsCrypto.java:335)
	...
Caused by: java.lang.NullPointerException: version must not be null
	at software.amazon.awssdk.utils.Validate.notNull(Validate.java:119)
	at software.amazon.awssdk.core.ApiName.<init>(ApiName.java:34)
	at software.amazon.awssdk.core.ApiName.<init>(ApiName.java:28)
	at software.amazon.awssdk.core.ApiName$BuilderImpl.build(ApiName.java:97)
	at com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKey.<clinit>(KmsMasterKey.java:47)
	...

The relevant static initializer from the KmsMasterKey class is for the API_NAME field:

  private static final ApiName API_NAME =
      ApiName.builder().name(VersionInfo.apiName()).version(VersionInfo.versionNumber()).build();

The relevant code from the VersionInfo class is:

  /*
   * String representation of the library version e.g. 2.3.3
   */
  public static String versionNumber() {
    try {
      final Properties properties = new Properties();
      final ClassLoader loader = VersionInfo.class.getClassLoader();
      properties.load(loader.getResourceAsStream("project.properties"));
      return properties.getProperty("version");
    } catch (final IOException ex) {
      return UNKNOWN_VERSION;
    }
  }

Reproduction

Include the encryption-sdk and another jar containing project.properties on your classpath. Ensure the other jar is first in the classpath.

We happen to use https://github.com/googleads/google-ads-java/releases/tag/33.0.0 which (luckily) contains an empty project.properties file.

When the JVM loads the KmsMasterKey class, the class loader will find the incorrect project.properties file.

Solution:

  • use a different class loader which prefers looking for the encryption-sdk first
  • somehow iterate over all resources named project.properties and ensure you've picked the correct one
  • use a more specific name for project.properties

Out of scope:

Is there anything the solution will intentionally NOT address?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions