Skip to content

Commit 06824da

Browse files
Initialize security providers at run time and hide behind --feature-defaults flags.
Add a test for security provider run time registration. Add entry to a CHANGELOG.md Parse java.security.properties file at run time.
1 parent b487fd3 commit 06824da

File tree

10 files changed

+417
-150
lines changed

10 files changed

+417
-150
lines changed

substratevm/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This changelog summarizes major changes to GraalVM Native Image.
2424
* (GR-59869) Implemented initial optimization of Java Vector API (JEP 338) operations in native images. See the compiler changelog for more details.
2525
* (GR-63268) Reflection and JNI queries do not require metadata entries to throw the expected JDK exception when querying a class that doesn't exist under `--exact-reachability-metadata` if the query cannot possibly be a valid class name
2626
* (GR-47881) Remove the total number of loaded types, fields, and methods from the build output, deprecated these metrics in the build output schema, and removed already deprecated build output metrics.
27+
* (GR-57827) Move the initialization of security providers from build time to runtime.
2728

2829
## GraalVM for JDK 24 (Internal Version 24.2.0)
2930
* (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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,9 +361,12 @@
361361
"sun.reflect.generics.reflectiveObjects",
362362
"sun.reflect.generics.repository",
363363
"sun.reflect.generics.tree",
364+
"sun.security.rsa",
364365
"sun.security.jca",
365366
"sun.security.ssl",
366367
"sun.security.util",
368+
"sun.security.provider",
369+
"com.sun.crypto.provider",
367370
"sun.text.spi",
368371
"sun.util",
369372
"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
@@ -118,4 +118,8 @@ public static boolean allFutureDefaults() {
118118
public static boolean isJDKInitializedAtRunTime() {
119119
return allFutureDefaults() || getFutureDefaults().contains(RUN_TIME_INITIALIZE_JDK_NAME);
120120
}
121+
122+
public static boolean isJDKInitializedAtBuildTime() {
123+
return !isJDKInitializedAtRunTime();
124+
}
121125
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package com.oracle.svm.core.jdk;
27+
28+
import java.lang.reflect.Constructor;
29+
import java.lang.reflect.InvocationTargetException;
30+
import java.security.Provider;
31+
import java.util.Collections;
32+
import java.util.HashMap;
33+
import java.util.HashSet;
34+
import java.util.List;
35+
import java.util.Map;
36+
import java.util.Properties;
37+
import java.util.Set;
38+
39+
import org.graalvm.nativeimage.ImageSingletons;
40+
import org.graalvm.nativeimage.Platform;
41+
import org.graalvm.nativeimage.Platforms;
42+
43+
import com.oracle.svm.core.util.VMError;
44+
45+
import jdk.graal.compiler.api.replacements.Fold;
46+
47+
/**
48+
* The class that holds various build-time and run-time structures necessary for security providers.
49+
*/
50+
public final class SecurityProvidersSupport {
51+
/**
52+
* A set of providers to be loaded using the service-loading technique at runtime, but not
53+
* discoverable at build-time when processing services in the feature (see
54+
* ServiceLoaderFeature#handleServiceClassIsReachable). This occurs when the user does not
55+
* explicitly request a provider, but the provider is discovered via static analysis from a
56+
* JCA-compliant security service used by the user's code (see
57+
* SecurityServicesFeature#registerServiceReachabilityHandlers).
58+
*/
59+
@Platforms(Platform.HOSTED_ONLY.class)//
60+
private final Set<String> markedAsNotLoaded = Collections.synchronizedSet(new HashSet<>());
61+
62+
/** Set of fully qualified provider names, required for runtime resource access. */
63+
private final Set<String> userRequestedSecurityProviders = Collections.synchronizedSet(new HashSet<>());
64+
65+
/**
66+
* A map of providers, identified by their names (see {@link Provider#getName()}), and the
67+
* results of their verification (see javax.crypto.JceSecurity#getVerificationResult). This
68+
* structure is used instead of the (see javax.crypto.JceSecurity#verifyingProviders) map to
69+
* avoid keeping provider objects in the image heap.
70+
*/
71+
private final Map<String, Object> verifiedSecurityProviders = Collections.synchronizedMap(new HashMap<>());
72+
73+
private Properties savedInitialSecurityProperties;
74+
75+
private Constructor<?> sunECConstructor;
76+
77+
@Platforms(Platform.HOSTED_ONLY.class)
78+
public SecurityProvidersSupport(List<String> userRequestedSecurityProviders) {
79+
this.userRequestedSecurityProviders.addAll(userRequestedSecurityProviders);
80+
}
81+
82+
@Fold
83+
public static SecurityProvidersSupport singleton() {
84+
return ImageSingletons.lookup(SecurityProvidersSupport.class);
85+
}
86+
87+
@Platforms(Platform.HOSTED_ONLY.class)
88+
public void addVerifiedSecurityProvider(String key, Object value) {
89+
verifiedSecurityProviders.put(key, value);
90+
}
91+
92+
public Object getSecurityProviderVerificationResult(String key) {
93+
return verifiedSecurityProviders.get(key);
94+
}
95+
96+
@Platforms(Platform.HOSTED_ONLY.class)
97+
public void markSecurityProviderAsNotLoaded(String provider) {
98+
markedAsNotLoaded.add(provider);
99+
}
100+
101+
@Platforms(Platform.HOSTED_ONLY.class)
102+
public boolean isSecurityProviderNotLoaded(String provider) {
103+
return markedAsNotLoaded.contains(provider);
104+
}
105+
106+
@Platforms(Platform.HOSTED_ONLY.class)
107+
public boolean isUserRequestedSecurityProvider(String provider) {
108+
return userRequestedSecurityProviders.contains(provider);
109+
}
110+
111+
/**
112+
* Returns {@code true} if the provider, identified by either its name (e.g., SUN) or fully
113+
* qualified name (e.g., sun.security.provider.Sun), is either user-requested or reachable via a
114+
* security service.
115+
*/
116+
public boolean isSecurityProviderExpected(String providerName, String providerFQName) {
117+
return verifiedSecurityProviders.containsKey(providerName) || userRequestedSecurityProviders.contains(providerFQName);
118+
}
119+
120+
@Platforms(Platform.HOSTED_ONLY.class)
121+
public void setSunECConstructor(Constructor<?> sunECConstructor) {
122+
this.sunECConstructor = sunECConstructor;
123+
}
124+
125+
public Provider allocateSunECProvider() {
126+
try {
127+
return (Provider) sunECConstructor.newInstance();
128+
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
129+
throw VMError.shouldNotReachHere("The SunEC constructor is not present.");
130+
}
131+
}
132+
133+
public void setSavedInitialSecurityProperties(Properties savedSecurityProperties) {
134+
this.savedInitialSecurityProperties = savedSecurityProperties;
135+
}
136+
137+
public Properties getSavedInitialSecurityProperties() {
138+
return savedInitialSecurityProperties;
139+
}
140+
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ private static void setJavaHome(String newJavaHome) {
244244
}
245245
}
246246

247-
@TargetClass(className = "javax.crypto.JceSecurity")
247+
@TargetClass(className = "javax.crypto.JceSecurity", onlyWith = JDKInitializedAtBuildTime.class)
248248
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+27/src/java.base/share/classes/javax/crypto/JceSecurity.java.template")
249249
@SuppressWarnings({"unused"})
250250
final class Target_javax_crypto_JceSecurity {
@@ -302,7 +302,7 @@ static Exception getVerificationResult(Provider p) {
302302
}
303303
}
304304

305-
@TargetClass(className = "javax.crypto.JceSecurity", innerClass = "WeakIdentityWrapper")
305+
@TargetClass(className = "javax.crypto.JceSecurity", innerClass = "WeakIdentityWrapper", onlyWith = JDKInitializedAtBuildTime.class)
306306
@SuppressWarnings({"unused"})
307307
final class Target_javax_crypto_JceSecurity_WeakIdentityWrapper {
308308

@@ -401,7 +401,7 @@ public boolean implies(ProtectionDomain domain, Permission permission) {
401401
}
402402
}
403403

404-
@TargetClass(className = "sun.security.jca.ProviderConfig")
404+
@TargetClass(className = "sun.security.jca.ProviderConfig", onlyWith = JDKInitializedAtBuildTime.class)
405405
@SuppressWarnings({"unused", "static-method"})
406406
final class Target_sun_security_jca_ProviderConfig {
407407

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.security.cert.X509Certificate;
3030
import java.util.Set;
3131

32+
import com.oracle.svm.core.FutureDefaultsOptions;
3233
import org.graalvm.nativeimage.ImageSingletons;
3334
import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport;
3435

@@ -89,13 +90,15 @@ public void afterRegistration(AfterRegistrationAccess access) {
8990
*/
9091
RuntimeClassInitializationSupport rci = ImageSingletons.lookup(RuntimeClassInitializationSupport.class);
9192
rci.initializeAtBuildTime("sun.security.util.UntrustedCertificates", "Required for TrustStoreManager");
92-
/*
93-
* All security providers must be registered (and initialized) at buildtime (see
94-
* SecuritySubstitutions.java). XMLDSigRI is used for validating XML Signatures from
95-
* certificate files while generating X509Certificates.
96-
*/
97-
rci.initializeAtBuildTime("org.jcp.xml.dsig.internal.dom.XMLDSigRI", "Required for TrustStoreManager");
98-
rci.initializeAtBuildTime("org.jcp.xml.dsig.internal.dom.XMLDSigRI$ProviderService", "Required for TrustStoreManager");
93+
if(!FutureDefaultsOptions.isJDKInitializedAtRunTime()) {
94+
/*
95+
* All security providers must be registered (and initialized) at buildtime (see
96+
* SecuritySubstitutions.java). XMLDSigRI is used for validating XML Signatures from
97+
* certificate files while generating X509Certificates.
98+
*/
99+
rci.initializeAtBuildTime("org.jcp.xml.dsig.internal.dom.XMLDSigRI", "Required for TrustStoreManager");
100+
rci.initializeAtBuildTime("org.jcp.xml.dsig.internal.dom.XMLDSigRI$ProviderService", "Required for TrustStoreManager");
101+
}
99102
}
100103
}
101104

0 commit comments

Comments
 (0)