Skip to content

Commit f98245e

Browse files
Changes according to commits.
1 parent 05a28f7 commit f98245e

File tree

12 files changed

+200
-199
lines changed

12 files changed

+200
-199
lines changed

docs/reference-manual/native-image/JCASecurityServices.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,20 @@ The report will detail all registered service classes, the API methods that trig
3636

3737
> Note: The `--enable-all-security-services` option is now deprecated and it will be removed in a future release.
3838
39-
## Provider initialization
39+
## Provider Initialization
4040

41-
Security providers are initialized at build time by default.
41+
Currently security providers are initialized at build time.
42+
To move their initialization to run time, use the option `--future-defaults=all` or `--future-defaults=run-time-initialized-jdk`.
43+
Provider verification will still occur at build time.
44+
Run-time initialization of security providers helps reduce image heap size.
4245
To move their initialization to run time, you can use the flag `--future-defaults=all` or `--future-defaults=run-time-initialized-jdk`.
4346

4447
## Provider Registration
4548

4649
The `native-image` builder captures the list of providers and their preference order from the underlying JVM.
4750
The provider order is specified in the `java.security` file under `<java-home>/conf/security/java.security`.
4851
New security providers cannot be registered at run time by default (see the section above); all providers must be statically configured at executable build time.
49-
If the user specifies `--future-defaults=all` or `--future-defaults=run-time-initialized-jdk` (to move initialization to run time), then a specific properties file can be used via the command line flag `-Djava.security.properties=<path>`.
52+
If the user specifies `--future-defaults=all` or `--future-defaults=run-time-initialized-jdk` to move providers initialization to run time, then a specific properties file can be used via the command line option `-Djava.security.properties=<path>`.
5053

5154
## Providers Reordering at Run Time
5255

substratevm/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ This changelog summarizes major changes to GraalVM Native Image.
2929
* (GR-64619) Missing registration errors are now subclasses of `LinkageError`
3030
* (GR-63591) Resource bundle registration is now included as part of the `"resources"` section of _reachability-metadata.json_. When this is the case, the bundle name is specified using the `"bundle"` field.
3131
* (GR-57827) Move the initialization of security providers from build time to runtime.
32+
* (GR-57827) Security providers can now be initialized at run time (instead of build time) when using the option `--future-defaults=all` or `--future-defaults=run-time-initialized-jdk`.
33+
Run-time initialization of security providers helps reduce image heap size by avoiding unnecessary objects inclusion.
3234

3335
## GraalVM for JDK 24 (Internal Version 24.2.0)
3436
* (GR-59717) Added `DuringSetupAccess.registerObjectReachabilityHandler` to allow registering a callback that is executed when an object of a specified type is marked as reachable during heap scanning.

substratevm/mx.substratevm/suite.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@
352352
],
353353
"requiresConcealed" : {
354354
"java.base" : [
355+
"com.sun.crypto.provider",
355356
"sun.invoke.util",
356357
"sun.net",
357358
"sun.net.www",
@@ -361,12 +362,11 @@
361362
"sun.reflect.generics.reflectiveObjects",
362363
"sun.reflect.generics.repository",
363364
"sun.reflect.generics.tree",
364-
"sun.security.rsa",
365365
"sun.security.jca",
366+
"sun.security.provider",
367+
"sun.security.rsa",
366368
"sun.security.ssl",
367369
"sun.security.util",
368-
"sun.security.provider",
369-
"com.sun.crypto.provider",
370370
"sun.text.spi",
371371
"sun.util",
372372
"sun.util.locale",

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FutureDefaultsOptions.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,8 @@ public static boolean allFutureDefaults() {
119119
public static boolean isJDKInitializedAtRunTime() {
120120
return allFutureDefaults() || getFutureDefaults().contains(RUN_TIME_INITIALIZE_JDK_NAME);
121121
}
122+
123+
public static boolean treatNameAsType() {
124+
return allFutureDefaults() || getFutureDefaults().contains(TREAT_NAME_AS_TYPE_NAME);
125+
}
122126
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecurityProvidersSupport.java

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,28 @@
2828
import java.lang.reflect.Constructor;
2929
import java.lang.reflect.InvocationTargetException;
3030
import java.security.Provider;
31-
import java.util.Collections;
32-
import java.util.HashMap;
33-
import java.util.HashSet;
3431
import java.util.List;
35-
import java.util.Map;
3632
import java.util.Properties;
3733
import java.util.Set;
34+
import java.util.concurrent.ConcurrentHashMap;
3835

36+
import org.graalvm.collections.EconomicMap;
37+
import org.graalvm.collections.EconomicSet;
3938
import org.graalvm.nativeimage.ImageSingletons;
4039
import org.graalvm.nativeimage.Platform;
4140
import org.graalvm.nativeimage.Platforms;
4241

42+
import com.oracle.svm.core.util.ImageHeapMap;
4343
import com.oracle.svm.core.util.VMError;
4444

4545
import jdk.graal.compiler.api.replacements.Fold;
46+
import sun.security.util.Debug;
4647

4748
/**
48-
* The class that holds various build-time and run-time structures necessary for security providers.
49+
* The class that holds various build-time and run-time structures necessary for security providers,
50+
* but only in case they are initialized at run time (see the <a href=
51+
* "../../../../../../../../../../../../docs/reference-manual/native-image/JCASecurityServices.md">
52+
* JCA Security Services documentation</a> for details).
4953
*/
5054
public final class SecurityProvidersSupport {
5155
/**
@@ -57,18 +61,18 @@ public final class SecurityProvidersSupport {
5761
* SecurityServicesFeature#registerServiceReachabilityHandlers).
5862
*/
5963
@Platforms(Platform.HOSTED_ONLY.class)//
60-
private final Set<String> markedAsNotLoaded = Collections.synchronizedSet(new HashSet<>());
64+
private final Set<String> markedAsNotLoaded = ConcurrentHashMap.newKeySet();
6165

6266
/** Set of fully qualified provider names, required for runtime resource access. */
63-
private final Set<String> userRequestedSecurityProviders = Collections.synchronizedSet(new HashSet<>());
67+
private final EconomicSet<String> userRequestedSecurityProviders = EconomicSet.create();
6468

6569
/**
6670
* A map of providers, identified by their names (see {@link Provider#getName()}), and the
6771
* results of their verification (see javax.crypto.JceSecurity#getVerificationResult). This
6872
* structure is used instead of the (see javax.crypto.JceSecurity#verifyingProviders) map to
6973
* avoid keeping provider objects in the image heap.
7074
*/
71-
private final Map<String, Object> verifiedSecurityProviders = Collections.synchronizedMap(new HashMap<>());
75+
private final EconomicMap<String, Object> verifiedSecurityProviders = ImageHeapMap.create("verifiedSecurityProviders");
7276

7377
private Properties savedInitialSecurityProperties;
7478

@@ -85,8 +89,8 @@ public static SecurityProvidersSupport singleton() {
8589
}
8690

8791
@Platforms(Platform.HOSTED_ONLY.class)
88-
public void addVerifiedSecurityProvider(String key, Object value) {
89-
verifiedSecurityProviders.put(key, value);
92+
public void addVerifiedSecurityProvider(String key, Object verificationResult) {
93+
verifiedSecurityProviders.put(key, verificationResult);
9094
}
9195

9296
public Object getSecurityProviderVerificationResult(String key) {
@@ -113,7 +117,7 @@ public boolean isUserRequestedSecurityProvider(String provider) {
113117
* qualified name (e.g., sun.security.provider.Sun), is either user-requested or reachable via a
114118
* security service.
115119
*/
116-
public boolean isSecurityProviderExpected(String providerName, String providerFQName) {
120+
public boolean isSecurityProviderRequested(String providerName, String providerFQName) {
117121
return verifiedSecurityProviders.containsKey(providerName) || userRequestedSecurityProviders.contains(providerFQName);
118122
}
119123

@@ -130,11 +134,55 @@ public Provider allocateSunECProvider() {
130134
}
131135
}
132136

137+
@Platforms(Platform.HOSTED_ONLY.class)
133138
public void setSavedInitialSecurityProperties(Properties savedSecurityProperties) {
134139
this.savedInitialSecurityProperties = savedSecurityProperties;
135140
}
136141

137142
public Properties getSavedInitialSecurityProperties() {
138143
return savedInitialSecurityProperties;
139144
}
145+
146+
public Provider loadBuiltInProvider(String provName, Debug debug) {
147+
return switch (provName) {
148+
case "SUN", "sun.security.provider.Sun" ->
149+
isSecurityProviderRequested("SUN", "sun.security.provider.Sun") ? new sun.security.provider.Sun() : null;
150+
case "SunRsaSign", "sun.security.rsa.SunRsaSign" ->
151+
isSecurityProviderRequested("SunRsaSign", "sun.security.rsa.SunRsaSign") ? new sun.security.rsa.SunRsaSign() : null;
152+
case "SunJCE", "com.sun.crypto.provider.SunJCE" ->
153+
isSecurityProviderRequested("SunJCE", "com.sun.crypto.provider.SunJCE") ? new com.sun.crypto.provider.SunJCE() : null;
154+
case "SunJSSE" ->
155+
isSecurityProviderRequested("SunJSSE", "sun.security.ssl.SunJSSE") ? new sun.security.ssl.SunJSSE() : null;
156+
case "SunEC" ->
157+
isSecurityProviderRequested("SunEC", "sun.security.ec.SunEC") ? allocateSunECProvider() : null;
158+
case "Apple", "apple.security.AppleProvider" -> {
159+
try {
160+
Class<?> c = Class.forName("apple.security.AppleProvider");
161+
if (Provider.class.isAssignableFrom(c)) {
162+
yield (Provider) c.getDeclaredConstructor().newInstance();
163+
}
164+
} catch (Exception ex) {
165+
if (debug != null) {
166+
debug.println("Error loading provider Apple");
167+
ex.printStackTrace();
168+
}
169+
}
170+
yield null;
171+
}
172+
default -> null;
173+
};
174+
}
175+
176+
public static boolean isBuiltInProvider(String provName) {
177+
return switch (provName) {
178+
case "SUN", "sun.security.provider.Sun",
179+
"SunRsaSign", "sun.security.rsa.SunRsaSign",
180+
"SunJCE", "com.sun.crypto.provider.SunJCE",
181+
"SunJSSE",
182+
"SunEC",
183+
"Apple", "apple.security.AppleProvider" ->
184+
true;
185+
default -> false;
186+
};
187+
}
140188
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import java.security.Policy;
3737
import java.security.ProtectionDomain;
3838
import java.security.Provider;
39-
import java.security.SecureRandom;
4039
import java.util.List;
4140
import java.util.Map;
4241
import java.util.Objects;
@@ -244,26 +243,28 @@ private static void setJavaHome(String newJavaHome) {
244243
}
245244
}
246245

246+
/**
247+
* The {@code javax.crypto.JceSecurity#verificationResults} cache is initialized by the
248+
* SecurityServicesFeature at build time, for all registered providers. The cache is used by
249+
* {@code javax.crypto.JceSecurity#canUseProvider} at run time to check whether a provider is
250+
* properly signed and can be used by JCE. It does that via jar verification which we cannot
251+
* support.
252+
*/
247253
@TargetClass(className = "javax.crypto.JceSecurity", onlyWith = JDKInitializedAtBuildTime.class)
248254
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+27/src/java.base/share/classes/javax/crypto/JceSecurity.java.template")
249255
@SuppressWarnings({"unused"})
250256
final class Target_javax_crypto_JceSecurity {
251257

252-
/*
253-
* The JceSecurity.verificationResults cache is initialized by the SecurityServicesFeature at
254-
* build time, for all registered providers. The cache is used by JceSecurity.canUseProvider()
255-
* at runtime to check whether a provider is properly signed and can be used by JCE. It does
256-
* that via jar verification which we cannot support.
257-
*/
258-
259258
// Checkstyle: stop
260259
@Alias //
261260
private static Object PROVIDER_VERIFIED;
262261
// Checkstyle: resume
263262

264-
// Map<Provider,?> of the providers we already have verified
265-
// value == PROVIDER_VERIFIED is successfully verified
266-
// value is failure cause Exception in error case
263+
/*
264+
* Map<Provider, ?> of providers that have already been verified. A value of PROVIDER_VERIFIED
265+
* indicates successful verification. Otherwise, the value is the Exception that caused the
266+
* verification to fail.
267+
*/
267268
@Alias //
268269
private static Map<Object, Object> verificationResults;
269270

@@ -281,7 +282,6 @@ final class Target_javax_crypto_JceSecurity {
281282

282283
@Substitute
283284
static Exception getVerificationResult(Provider p) {
284-
/* Start code block copied from original method. */
285285
/* The verification results map key is an identity wrapper object. */
286286
Object key = new Target_javax_crypto_JceSecurity_WeakIdentityWrapper(p, queue);
287287
Object o = verificationResults.get(key);
@@ -290,15 +290,16 @@ static Exception getVerificationResult(Provider p) {
290290
} else if (o != null) {
291291
return (Exception) o;
292292
}
293-
/* End code block copied from original method. */
294293
/*
295-
* If the verification result is not found in the verificationResults map JDK proceeds to
296-
* verify it. That requires accessing the code base which we don't support. The substitution
297-
* for getCodeBase() would be enough to take care of this too, but substituting
298-
* getVerificationResult() allows for a better error message.
294+
* If the verification result is not found in the verificationResults map, HotSpot will
295+
* attempt to verify the provider. This requires accessing the code base, which isn't
296+
* supported in Native Image, so we need to fail. We could either fail here or substitute
297+
* getCodeBase() and fail there, but handling it here is a cleaner approach.
299298
*/
300-
throw VMError.unsupportedFeature("Trying to verify a provider that was not registered at build time: " + p + ". " +
301-
"All providers must be registered and verified in the Native Image builder. ");
299+
throw new SecurityException(
300+
"Attempted to verify a provider that was not registered at build time: " + p + ". " +
301+
"All security providers must be registered and verified during native image generation. " +
302+
"Try adding the option: -H:AdditionalSecurityProviders=" + p + " and rebuild the image.");
302303
}
303304
}
304305

@@ -311,31 +312,6 @@ final class Target_javax_crypto_JceSecurity_WeakIdentityWrapper {
311312
}
312313
}
313314

314-
class JceSecurityAccessor {
315-
private static volatile SecureRandom RANDOM;
316-
317-
static SecureRandom get() {
318-
SecureRandom result = RANDOM;
319-
if (result == null) {
320-
/* Lazy initialization on first access. */
321-
result = initializeOnce();
322-
}
323-
return result;
324-
}
325-
326-
private static synchronized SecureRandom initializeOnce() {
327-
SecureRandom result = RANDOM;
328-
if (result != null) {
329-
/* Double-checked locking is OK because INSTANCE is volatile. */
330-
return result;
331-
}
332-
333-
result = new SecureRandom();
334-
RANDOM = result;
335-
return result;
336-
}
337-
}
338-
339315
/**
340316
* JDK 8 has the class `javax.crypto.JarVerifier`, but in JDK 11 and later that class is only
341317
* available in Oracle builds, and not in OpenJDK builds.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_security_ssl_TrustStoreManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public void afterRegistration(AfterRegistrationAccess access) {
9090
*/
9191
RuntimeClassInitializationSupport rci = ImageSingletons.lookup(RuntimeClassInitializationSupport.class);
9292
rci.initializeAtBuildTime("sun.security.util.UntrustedCertificates", "Required for TrustStoreManager");
93-
if (FutureDefaultsOptions.isJDKInitializedAtBuildTime()) {
93+
if (!FutureDefaultsOptions.isJDKInitializedAtRunTime()) {
9494
/*
9595
* All security providers must be registered (and initialized) at buildtime (see
9696
* SecuritySubstitutions.java). XMLDSigRI is used for validating XML Signatures from

0 commit comments

Comments
 (0)