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 .lang .reflect .InvocationTargetException ;
32
31
import java .net .URL ;
69
68
import com .oracle .svm .core .util .VMError ;
70
69
import com .oracle .svm .util .ReflectionUtil ;
71
70
71
+ import jdk .graal .compiler .core .common .SuppressFBWarnings ;
72
+ import jdk .graal .compiler .serviceprovider .JavaVersionUtil ;
72
73
import sun .security .util .SecurityConstants ;
73
74
74
75
/*
@@ -328,6 +329,7 @@ final class Target_javax_crypto_JceSecurity {
328
329
// value == PROVIDER_VERIFIED is successfully verified
329
330
// value is failure cause Exception in error case
330
331
@ Alias //
332
+ @ RecomputeFieldValue (kind = RecomputeFieldValue .Kind .Reset ) //
331
333
private static Map <Object , Object > verificationResults ;
332
334
333
335
@ Alias //
@@ -338,16 +340,11 @@ final class Target_javax_crypto_JceSecurity {
338
340
@ RecomputeFieldValue (kind = RecomputeFieldValue .Kind .FromAlias ) //
339
341
private static Map <Class <?>, URL > codeBaseCacheRef = new WeakHashMap <>();
340
342
341
- @ Alias //
342
- @ TargetElement //
343
- private static ReferenceQueue <Object > queue ;
344
-
345
343
@ Substitute
346
344
static Exception getVerificationResult (Provider p ) {
347
345
/* Start code block copied from original method. */
348
346
/* 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 ());
351
348
if (o == PROVIDER_VERIFIED ) {
352
349
return null ;
353
350
} else if (o != null ) {
@@ -365,15 +362,6 @@ static Exception getVerificationResult(Provider p) {
365
362
}
366
363
}
367
364
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
-
377
365
class JceSecurityAccessor {
378
366
private static volatile SecureRandom RANDOM ;
379
367
@@ -547,19 +535,120 @@ final class Target_sun_security_jca_ProviderConfig {
547
535
@ Alias //
548
536
private String provName ;
549
537
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
+
550
556
/**
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.
559
560
*/
560
561
@ 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 ;
563
652
}
564
653
}
565
654
0 commit comments