2626
2727import static com .oracle .svm .core .snippets .KnownIntrinsics .readCallerStackPointer ;
2828
29- import java .lang .ref .ReferenceQueue ;
3029import java .lang .reflect .Constructor ;
3130import java .lang .reflect .InvocationTargetException ;
3231import java .net .URL ;
6968import com .oracle .svm .core .util .VMError ;
7069import com .oracle .svm .util .ReflectionUtil ;
7170
71+ import jdk .graal .compiler .core .common .SuppressFBWarnings ;
72+ import jdk .graal .compiler .serviceprovider .JavaVersionUtil ;
7273import sun .security .util .SecurityConstants ;
7374
7475/*
@@ -328,6 +329,7 @@ final class Target_javax_crypto_JceSecurity {
328329 // value == PROVIDER_VERIFIED is successfully verified
329330 // value is failure cause Exception in error case
330331 @ Alias //
332+ @ RecomputeFieldValue (kind = RecomputeFieldValue .Kind .Reset ) //
331333 private static Map <Object , Object > verificationResults ;
332334
333335 @ Alias //
@@ -338,16 +340,11 @@ final class Target_javax_crypto_JceSecurity {
338340 @ RecomputeFieldValue (kind = RecomputeFieldValue .Kind .FromAlias ) //
339341 private static Map <Class <?>, URL > codeBaseCacheRef = new WeakHashMap <>();
340342
341- @ Alias //
342- @ TargetElement //
343- private static ReferenceQueue <Object > queue ;
344-
345343 @ Substitute
346344 static Exception getVerificationResult (Provider p ) {
347345 /* Start code block copied from original method. */
348346 /* The verification results map key is an identity wrapper object. */
349- Object key = new Target_javax_crypto_JceSecurity_WeakIdentityWrapper (p , queue );
350- Object o = verificationResults .get (key );
347+ Object o = SecurityProvidersSupport .singleton ().getSecurityProviderVerificationResult (p .getName ());
351348 if (o == PROVIDER_VERIFIED ) {
352349 return null ;
353350 } else if (o != null ) {
@@ -365,15 +362,6 @@ static Exception getVerificationResult(Provider p) {
365362 }
366363}
367364
368- @ TargetClass (className = "javax.crypto.JceSecurity" , innerClass = "WeakIdentityWrapper" )
369- @ SuppressWarnings ({"unused" })
370- final class Target_javax_crypto_JceSecurity_WeakIdentityWrapper {
371-
372- @ Alias //
373- Target_javax_crypto_JceSecurity_WeakIdentityWrapper (Provider obj , ReferenceQueue <Object > queue ) {
374- }
375- }
376-
377365class JceSecurityAccessor {
378366 private static volatile SecureRandom RANDOM ;
379367
@@ -547,19 +535,120 @@ final class Target_sun_security_jca_ProviderConfig {
547535 @ Alias //
548536 private String provName ;
549537
538+ @ Alias //
539+ private static sun .security .util .Debug debug ;
540+
541+ @ Alias //
542+ private Provider provider ;
543+
544+ @ Alias //
545+ private boolean isLoading ;
546+
547+ @ Alias //
548+ private int tries ;
549+
550+ @ Alias
551+ private native Provider doLoadProvider ();
552+
553+ @ Alias
554+ private native boolean shouldLoad ();
555+
550556 /**
551- * All security providers used in a native-image must be registered during image build time. At
552- * runtime, we shouldn't have a call to doLoadProvider. However, this method is still reachable
553- * at runtime, and transitively includes other types in the image, among which is
554- * sun.security.jca.ProviderConfig.ProviderLoader. This class contains a static field with a
555- * cache of providers loaded during the image build. The contents of this cache can vary even
556- * when building the same image due to the way services are loaded on Java 11. This cache can
557- * increase the final image size substantially (if it contains, for example,
558- * {@code org.jcp.xml.dsig.internal.dom.XMLDSigRI}.
557+ * The `entrypoint` for allocating security providers at runtime. The implementation is copied
558+ * from the JDK with a small tweak to filter out providers that are neither user-requested nor
559+ * reachable via a security service.
559560 */
560561 @ Substitute
561- private Provider doLoadProvider () {
562- throw VMError .unsupportedFeature ("Cannot load new security provider at runtime: " + provName + "." );
562+ @ SuppressWarnings ("fallthrough" )
563+ @ SuppressFBWarnings (value = "DC_DOUBLECHECK" , justification = "This double-check is implemented correctly and is intentional." )
564+ Provider getProvider () {
565+ // volatile variable load
566+ Provider p = provider ;
567+ if (p != null ) {
568+ return p ;
569+ }
570+ // DCL
571+ synchronized (this ) {
572+ p = provider ;
573+ if (p != null ) {
574+ return p ;
575+ }
576+ if (!shouldLoad ()) {
577+ return null ;
578+ }
579+
580+ // Create providers which are in java.base directly
581+ SecurityProvidersSupport support = SecurityProvidersSupport .singleton ();
582+ switch (provName ) {
583+ case "SUN" , "sun.security.provider.Sun" : {
584+ p = support .isSecurityProviderExpected ("SUN" , "sun.security.provider.Sun" ) ? new sun .security .provider .Sun () : null ;
585+ break ;
586+ }
587+ case "SunRsaSign" , "sun.security.rsa.SunRsaSign" : {
588+ p = support .isSecurityProviderExpected ("SunRsaSign" , "sun.security.rsa.SunRsaSign" ) ? new sun .security .rsa .SunRsaSign () : null ;
589+ break ;
590+ }
591+ case "SunJCE" , "com.sun.crypto.provider.SunJCE" : {
592+ p = support .isSecurityProviderExpected ("SunJCE" , "com.sun.crypto.provider.SunJCE" ) ? new com .sun .crypto .provider .SunJCE () : null ;
593+ break ;
594+ }
595+ case "SunJSSE" : {
596+ p = support .isSecurityProviderExpected ("SunJSSE" , "sun.security.ssl.SunJSSE" ) ? new sun .security .ssl .SunJSSE () : null ;
597+ break ;
598+ }
599+ case "Apple" , "apple.security.AppleProvider" : {
600+ // need to use reflection since this class only exists on MacOsx
601+ try {
602+ Class <?> c = Class .forName ("apple.security.AppleProvider" );
603+ if (Provider .class .isAssignableFrom (c )) {
604+ @ SuppressWarnings ("deprecation" )
605+ Object newInstance = c .newInstance ();
606+ p = (Provider ) newInstance ;
607+ }
608+ } catch (Exception ex ) {
609+ if (debug != null ) {
610+ debug .println ("Error loading provider Apple" );
611+ ex .printStackTrace ();
612+ }
613+ }
614+ break ;
615+ }
616+ case "SunEC" : {
617+ if (JavaVersionUtil .JAVA_SPEC > 21 ) {
618+ // Constructor inside method and then allocate. ModuleSupport to open.
619+ p = support .isSecurityProviderExpected ("SunEC" , "sun.security.ec.SunEC" ) ? support .allocateSunECProvider () : null ;
620+ break ;
621+ }
622+ /*
623+ * On older JDK versions, SunEC was part of the `jdk.crypto.ec` module and was
624+ * allocated via the service loading mechanism, so this fallthrough is
625+ * intentional. On newer JDK versions, SunEC is part of `java.base` and is
626+ * allocated directly.
627+ */
628+ }
629+ // fall through
630+ default : {
631+ if (isLoading ) {
632+ // because this method is synchronized, this can only
633+ // happen if there is recursion.
634+ if (debug != null ) {
635+ debug .println ("Recursion loading provider: " + this );
636+ new Exception ("Call trace" ).printStackTrace ();
637+ }
638+ return null ;
639+ }
640+ try {
641+ isLoading = true ;
642+ tries ++;
643+ p = doLoadProvider ();
644+ } finally {
645+ isLoading = false ;
646+ }
647+ }
648+ }
649+ provider = p ;
650+ }
651+ return p ;
563652 }
564653}
565654
0 commit comments