Skip to content

Commit fd36d43

Browse files
zapsterjovanstevanovic
authored andcommitted
svm: add JDKInitializedAtBuildTime
1 parent cdc96d1 commit fd36d43

File tree

2 files changed

+234
-1
lines changed

2 files changed

+234
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
/*
2+
* Copyright (c) 2025, 2025, 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.runtimeinit;
27+
28+
import java.net.URL;
29+
import java.security.Provider;
30+
import java.util.Map;
31+
import java.util.Properties;
32+
import java.util.WeakHashMap;
33+
34+
import com.oracle.svm.core.annotate.Alias;
35+
import com.oracle.svm.core.annotate.RecomputeFieldValue;
36+
import com.oracle.svm.core.annotate.Substitute;
37+
import com.oracle.svm.core.annotate.TargetClass;
38+
import com.oracle.svm.core.jdk.JDKInitializedAtRunTime;
39+
import com.oracle.svm.core.jdk.SecurityProvidersSupport;
40+
import com.oracle.svm.core.util.BasedOnJDKFile;
41+
import com.oracle.svm.core.util.VMError;
42+
43+
import jdk.graal.compiler.core.common.SuppressFBWarnings;
44+
45+
@TargetClass(value = java.security.Security.class, onlyWith = JDKInitializedAtRunTime.class)
46+
final class Target_java_security_Security {
47+
@Alias //
48+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias) //
49+
static Properties props;
50+
}
51+
52+
@TargetClass(value = java.security.Security.class, innerClass = "SecPropLoader", onlyWith = JDKInitializedAtRunTime.class)
53+
final class Target_java_security_Security_SecPropLoader {
54+
55+
@Substitute
56+
private static void loadMaster() {
57+
Target_java_security_Security.props = SecurityProvidersSupport.singleton().getSavedInitialSecurityProperties();
58+
}
59+
}
60+
61+
@TargetClass(className = "javax.crypto.JceSecurity", onlyWith = JDKInitializedAtRunTime.class)
62+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+27/src/java.base/share/classes/javax/crypto/JceSecurity.java.template")
63+
@SuppressWarnings({"unused"})
64+
final class Target_javax_crypto_JceSecurity {
65+
66+
/*
67+
* The JceSecurity.verificationResults cache is initialized by the SecurityServicesFeature at
68+
* build time, for all registered providers. The cache is used by JceSecurity.canUseProvider()
69+
* at runtime to check whether a provider is properly signed and can be used by JCE. It does
70+
* that via jar verification which we cannot support.
71+
*/
72+
73+
// Checkstyle: stop
74+
@Alias //
75+
private static Object PROVIDER_VERIFIED;
76+
// Checkstyle: resume
77+
78+
// Map<Provider,?> of the providers we already have verified
79+
// value == PROVIDER_VERIFIED is successfully verified
80+
// value is failure cause Exception in error case
81+
@Alias //
82+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) //
83+
private static Map<Object, Object> verificationResults;
84+
85+
@Alias //
86+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) //
87+
private static Map<Provider, Object> verifyingProviders;
88+
89+
@Alias //
90+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias) //
91+
private static Map<Class<?>, URL> codeBaseCacheRef = new WeakHashMap<>();
92+
93+
@Substitute
94+
static Exception getVerificationResult(Provider p) {
95+
/* Start code block copied from original method. */
96+
/* The verification results map key is an identity wrapper object. */
97+
Object o = SecurityProvidersSupport.singleton().getSecurityProviderVerificationResult(p.getName());
98+
if (o == PROVIDER_VERIFIED) {
99+
return null;
100+
} else if (o != null) {
101+
return (Exception) o;
102+
}
103+
/* End code block copied from original method. */
104+
/*
105+
* If the verification result is not found in the verificationResults map JDK proceeds to
106+
* verify it. That requires accessing the code base which we don't support. The substitution
107+
* for getCodeBase() would be enough to take care of this too, but substituting
108+
* getVerificationResult() allows for a better error message.
109+
*/
110+
throw VMError.unsupportedFeature("Trying to verify a provider that was not registered at build time: " + p + ". " +
111+
"All providers must be registered and verified in the Native Image builder. ");
112+
}
113+
}
114+
115+
@TargetClass(className = "sun.security.jca.ProviderConfig", onlyWith = JDKInitializedAtRunTime.class)
116+
@SuppressWarnings({"unused", "static-method"})
117+
final class Target_sun_security_jca_ProviderConfig {
118+
119+
@Alias //
120+
private String provName;
121+
122+
@Alias//
123+
private static sun.security.util.Debug debug;
124+
125+
@Alias//
126+
private Provider provider;
127+
128+
@Alias//
129+
private boolean isLoading;
130+
131+
@Alias//
132+
private int tries;
133+
134+
@Alias
135+
private native Provider doLoadProvider();
136+
137+
@Alias
138+
private native boolean shouldLoad();
139+
140+
/**
141+
* The `entrypoint` for allocating security providers at runtime. The implementation is copied
142+
* from the JDK with a small tweak to filter out providers that are neither user-requested nor
143+
* reachable via a security service.
144+
*/
145+
@Substitute
146+
@SuppressFBWarnings(value = "DC_DOUBLECHECK", justification = "This double-check is implemented correctly and is intentional.")
147+
Provider getProvider() {
148+
// volatile variable load
149+
Provider p = provider;
150+
if (p != null) {
151+
return p;
152+
}
153+
// DCL
154+
synchronized (this) {
155+
p = provider;
156+
if (p != null) {
157+
return p;
158+
}
159+
if (!shouldLoad()) {
160+
return null;
161+
}
162+
163+
// Create providers which are in java.base directly
164+
SecurityProvidersSupport support = SecurityProvidersSupport.singleton();
165+
switch (provName) {
166+
case "SUN", "sun.security.provider.Sun": {
167+
p = support.isSecurityProviderExpected("SUN", "sun.security.provider.Sun") ? new sun.security.provider.Sun() : null;
168+
break;
169+
}
170+
case "SunRsaSign", "sun.security.rsa.SunRsaSign": {
171+
p = support.isSecurityProviderExpected("SunRsaSign", "sun.security.rsa.SunRsaSign") ? new sun.security.rsa.SunRsaSign() : null;
172+
break;
173+
}
174+
case "SunJCE", "com.sun.crypto.provider.SunJCE": {
175+
p = support.isSecurityProviderExpected("SunJCE", "com.sun.crypto.provider.SunJCE") ? new com.sun.crypto.provider.SunJCE() : null;
176+
break;
177+
}
178+
case "SunJSSE": {
179+
p = support.isSecurityProviderExpected("SunJSSE", "sun.security.ssl.SunJSSE") ? new sun.security.ssl.SunJSSE() : null;
180+
break;
181+
}
182+
case "SunEC": {
183+
// Constructor inside method and then allocate. ModuleSupport to open.
184+
p = support.isSecurityProviderExpected("SunEC", "sun.security.ec.SunEC") ? support.allocateSunECProvider() : null;
185+
break;
186+
}
187+
case "Apple", "apple.security.AppleProvider": {
188+
// need to use reflection since this class only exists on MacOsx
189+
try {
190+
Class<?> c = Class.forName("apple.security.AppleProvider");
191+
if (Provider.class.isAssignableFrom(c)) {
192+
@SuppressWarnings("deprecation")
193+
Object newInstance = c.newInstance();
194+
p = (Provider) newInstance;
195+
}
196+
} catch (Exception ex) {
197+
if (debug != null) {
198+
debug.println("Error loading provider Apple");
199+
ex.printStackTrace();
200+
}
201+
}
202+
break;
203+
}
204+
default: {
205+
if (isLoading) {
206+
// because this method is synchronized, this can only
207+
// happen if there is recursion.
208+
if (debug != null) {
209+
debug.println("Recursion loading provider: " + this);
210+
new Exception("Call trace").printStackTrace();
211+
}
212+
return null;
213+
}
214+
try {
215+
isLoading = true;
216+
tries++;
217+
p = doLoadProvider();
218+
} finally {
219+
isLoading = false;
220+
}
221+
}
222+
}
223+
provider = p;
224+
}
225+
return p;
226+
}
227+
}
228+
229+
public class SecuritySubstitutionRuntimeInit {
230+
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ServiceLoaderFeature.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ public boolean isInConfiguration(IsInConfigurationAccess access) {
149149

150150
@Override
151151
public void afterRegistration(AfterRegistrationAccess access) {
152+
if (FutureDefaultsOptions.isJDKInitializedAtBuildTime()) {
153+
servicesToSkip.add(java.security.Provider.class.getName());
154+
}
152155
servicesToSkip.addAll(Options.ServiceLoaderFeatureExcludeServices.getValue().values());
153156
serviceProvidersToSkip.addAll(Options.ServiceLoaderFeatureExcludeServiceProviders.getValue().values());
154157
}
@@ -187,7 +190,7 @@ void handleServiceClassIsReachable(DuringAnalysisAccess access, Class<?> service
187190
if (serviceProvidersToSkip.contains(provider)) {
188191
continue;
189192
}
190-
if (serviceProvider.equals(java.security.Provider.class) && FutureDefaultsOptions.isJDKInitializedAtRunTime()) {
193+
if (serviceProvider.equals(java.security.Provider.class)) {
191194
SecurityProvidersSupport support = SecurityProvidersSupport.singleton();
192195
/* Only register the security providers that are requested. */
193196
if (support.isUserRequestedSecurityProvider(provider)) {

0 commit comments

Comments
 (0)