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