26
26
27
27
import static com .oracle .svm .core .snippets .KnownIntrinsics .readCallerStackPointer ;
28
28
29
- import java .lang .ref .ReferenceQueue ;
30
29
import java .lang .reflect .Constructor ;
31
30
import java .net .URL ;
32
31
import java .security .AccessControlContext ;
70
69
import com .oracle .svm .core .util .VMError ;
71
70
import com .oracle .svm .util .ReflectionUtil ;
72
71
72
+ import jdk .graal .compiler .core .common .SuppressFBWarnings ;
73
+ import jdk .graal .compiler .serviceprovider .JavaVersionUtil ;
73
74
import sun .security .util .SecurityConstants ;
74
75
75
76
/*
@@ -358,6 +359,7 @@ final class Target_javax_crypto_JceSecurity {
358
359
// value == PROVIDER_VERIFIED is successfully verified
359
360
// value is failure cause Exception in error case
360
361
@ Alias //
362
+ @ RecomputeFieldValue (kind = RecomputeFieldValue .Kind .Reset ) //
361
363
private static Map <Object , Object > verificationResults ;
362
364
363
365
@ Alias //
@@ -368,16 +370,11 @@ final class Target_javax_crypto_JceSecurity {
368
370
@ RecomputeFieldValue (kind = RecomputeFieldValue .Kind .FromAlias ) //
369
371
private static Map <Class <?>, URL > codeBaseCacheRef = new WeakHashMap <>();
370
372
371
- @ Alias //
372
- @ TargetElement //
373
- private static ReferenceQueue <Object > queue ;
374
-
375
373
@ Substitute
376
374
static Exception getVerificationResult (Provider p ) {
377
375
/* Start code block copied from original method. */
378
376
/* The verification results map key is an identity wrapper object. */
379
- Object key = new Target_javax_crypto_JceSecurity_WeakIdentityWrapper (p , queue );
380
- Object o = verificationResults .get (key );
377
+ Object o = SecurityProvidersSupport .singleton ().getSecurityProviderVerificationResult (p .getName ());
381
378
if (o == PROVIDER_VERIFIED ) {
382
379
return null ;
383
380
} else if (o != null ) {
@@ -395,15 +392,6 @@ static Exception getVerificationResult(Provider p) {
395
392
}
396
393
}
397
394
398
- @ TargetClass (className = "javax.crypto.JceSecurity" , innerClass = "WeakIdentityWrapper" )
399
- @ SuppressWarnings ({"unused" })
400
- final class Target_javax_crypto_JceSecurity_WeakIdentityWrapper {
401
-
402
- @ Alias //
403
- Target_javax_crypto_JceSecurity_WeakIdentityWrapper (Provider obj , ReferenceQueue <Object > queue ) {
404
- }
405
- }
406
-
407
395
class JceSecurityAccessor {
408
396
private static volatile SecureRandom RANDOM ;
409
397
@@ -577,19 +565,120 @@ final class Target_sun_security_jca_ProviderConfig {
577
565
@ Alias //
578
566
private String provName ;
579
567
568
+ @ Alias //
569
+ private static sun .security .util .Debug debug ;
570
+
571
+ @ Alias //
572
+ private Provider provider ;
573
+
574
+ @ Alias //
575
+ private boolean isLoading ;
576
+
577
+ @ Alias //
578
+ private int tries ;
579
+
580
+ @ Alias
581
+ private native Provider doLoadProvider ();
582
+
583
+ @ Alias
584
+ private native boolean shouldLoad ();
585
+
580
586
/**
581
- * All security providers used in a native-image must be registered during image build time. At
582
- * runtime, we shouldn't have a call to doLoadProvider. However, this method is still reachable
583
- * at runtime, and transitively includes other types in the image, among which is
584
- * sun.security.jca.ProviderConfig.ProviderLoader. This class contains a static field with a
585
- * cache of providers loaded during the image build. The contents of this cache can vary even
586
- * when building the same image due to the way services are loaded on Java 11. This cache can
587
- * increase the final image size substantially (if it contains, for example,
588
- * {@code org.jcp.xml.dsig.internal.dom.XMLDSigRI}.
587
+ * The `entrypoint` for allocating security providers at runtime. The implementation is copied
588
+ * from the JDK with a small tweak to filter out providers that are neither user-requested nor
589
+ * reachable via a security service.
589
590
*/
590
591
@ Substitute
591
- private Provider doLoadProvider () {
592
- throw VMError .unsupportedFeature ("Cannot load new security provider at runtime: " + provName + "." );
592
+ @ SuppressWarnings ("fallthrough" )
593
+ @ SuppressFBWarnings (value = "DC_DOUBLECHECK" , justification = "This double-check is implemented correctly and is intentional." )
594
+ Provider getProvider () {
595
+ // volatile variable load
596
+ Provider p = provider ;
597
+ if (p != null ) {
598
+ return p ;
599
+ }
600
+ // DCL
601
+ synchronized (this ) {
602
+ p = provider ;
603
+ if (p != null ) {
604
+ return p ;
605
+ }
606
+ if (!shouldLoad ()) {
607
+ return null ;
608
+ }
609
+
610
+ // Create providers which are in java.base directly
611
+ SecurityProvidersSupport support = SecurityProvidersSupport .singleton ();
612
+ switch (provName ) {
613
+ case "SUN" , "sun.security.provider.Sun" : {
614
+ p = support .isSecurityProviderExpected ("SUN" , "sun.security.provider.Sun" ) ? new sun .security .provider .Sun () : null ;
615
+ break ;
616
+ }
617
+ case "SunRsaSign" , "sun.security.rsa.SunRsaSign" : {
618
+ p = support .isSecurityProviderExpected ("SunRsaSign" , "sun.security.rsa.SunRsaSign" ) ? new sun .security .rsa .SunRsaSign () : null ;
619
+ break ;
620
+ }
621
+ case "SunJCE" , "com.sun.crypto.provider.SunJCE" : {
622
+ p = support .isSecurityProviderExpected ("SunJCE" , "com.sun.crypto.provider.SunJCE" ) ? new com .sun .crypto .provider .SunJCE () : null ;
623
+ break ;
624
+ }
625
+ case "SunJSSE" : {
626
+ p = support .isSecurityProviderExpected ("SunJSSE" , "sun.security.ssl.SunJSSE" ) ? new sun .security .ssl .SunJSSE () : null ;
627
+ break ;
628
+ }
629
+ case "Apple" , "apple.security.AppleProvider" : {
630
+ // need to use reflection since this class only exists on MacOsx
631
+ try {
632
+ Class <?> c = Class .forName ("apple.security.AppleProvider" );
633
+ if (Provider .class .isAssignableFrom (c )) {
634
+ @ SuppressWarnings ("deprecation" )
635
+ Object newInstance = c .newInstance ();
636
+ p = (Provider ) newInstance ;
637
+ }
638
+ } catch (Exception ex ) {
639
+ if (debug != null ) {
640
+ debug .println ("Error loading provider Apple" );
641
+ ex .printStackTrace ();
642
+ }
643
+ }
644
+ break ;
645
+ }
646
+ case "SunEC" : {
647
+ if (JavaVersionUtil .JAVA_SPEC > 21 ) {
648
+ // Constructor inside method and then allocate. ModuleSupport to open.
649
+ p = support .isSecurityProviderExpected ("SunEC" , "sun.security.ec.SunEC" ) ? support .allocateSunECProvider () : null ;
650
+ break ;
651
+ }
652
+ /*
653
+ * On older JDK versions, SunEC was part of the `jdk.crypto.ec` module and was
654
+ * allocated via the service loading mechanism, so this fallthrough is
655
+ * intentional. On newer JDK versions, SunEC is part of `java.base` and is
656
+ * allocated directly.
657
+ */
658
+ }
659
+ // fall through
660
+ default : {
661
+ if (isLoading ) {
662
+ // because this method is synchronized, this can only
663
+ // happen if there is recursion.
664
+ if (debug != null ) {
665
+ debug .println ("Recursion loading provider: " + this );
666
+ new Exception ("Call trace" ).printStackTrace ();
667
+ }
668
+ return null ;
669
+ }
670
+ try {
671
+ isLoading = true ;
672
+ tries ++;
673
+ p = doLoadProvider ();
674
+ } finally {
675
+ isLoading = false ;
676
+ }
677
+ }
678
+ }
679
+ provider = p ;
680
+ }
681
+ return p ;
593
682
}
594
683
}
595
684
0 commit comments