1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ssl.util;
17
18 import io.netty.util.internal.ThrowableUtil;
19 import io.netty.util.internal.logging.InternalLogger;
20 import io.netty.util.internal.logging.InternalLoggerFactory;
21
22 import java.security.AccessController;
23 import java.security.PrivilegedAction;
24 import java.security.Provider;
25 import java.security.Security;
26 import javax.net.ssl.SSLEngine;
27
28
29
30
31 public final class BouncyCastleUtil {
32 private static final InternalLogger logger = InternalLoggerFactory.getInstance(BouncyCastleUtil.class);
33
34 private static final String BC_PROVIDER_NAME = "BC";
35 private static final String BC_PROVIDER = "org.bouncycastle.jce.provider.BouncyCastleProvider";
36 private static final String BC_FIPS_PROVIDER_NAME = "BCFIPS";
37 private static final String BC_FIPS_PROVIDER = "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider";
38 private static final String BC_JSSE_PROVIDER_NAME = "BCJSSE";
39 private static final String BC_JSSE_PROVIDER = "org.bouncycastle.jsse.provider.BouncyCastleJsseProvider";
40 private static final String BC_PEMPARSER = "org.bouncycastle.openssl.PEMParser";
41 private static final String BC_JSSE_SSLENGINE = "org.bouncycastle.jsse.BCSSLEngine";
42 private static final String BC_JSSE_ALPN_SELECTOR = "org.bouncycastle.jsse.BCApplicationProtocolSelector";
43
44 private static volatile Throwable unavailabilityCauseBcProv;
45 private static volatile Throwable unavailabilityCauseBcPkix;
46 private static volatile Throwable unavailabilityCauseBcTls;
47 private static volatile Provider bcProviderJce;
48 private static volatile Provider bcProviderJsse;
49 private static volatile Class<? extends SSLEngine> bcSSLEngineClass;
50 private static volatile boolean attemptedLoading;
51
52
53
54
55 public static boolean isBcProvAvailable() {
56 ensureLoaded();
57 return unavailabilityCauseBcProv == null;
58 }
59
60
61
62
63 public static boolean isBcPkixAvailable() {
64 ensureLoaded();
65 return unavailabilityCauseBcPkix == null;
66 }
67
68
69
70
71 public static boolean isBcTlsAvailable() {
72 ensureLoaded();
73 return unavailabilityCauseBcTls == null;
74 }
75
76
77
78
79 public static Throwable unavailabilityCauseBcProv() {
80 ensureLoaded();
81 return unavailabilityCauseBcProv;
82 }
83
84
85
86
87 public static Throwable unavailabilityCauseBcPkix() {
88 ensureLoaded();
89 return unavailabilityCauseBcPkix;
90 }
91
92
93
94
95 public static Throwable unavailabilityCauseBcTls() {
96 ensureLoaded();
97 return unavailabilityCauseBcTls;
98 }
99
100
101
102
103 public static boolean isBcJsseInUse(SSLEngine engine) {
104 ensureLoaded();
105 Class<? extends SSLEngine> bcEngineClass = bcSSLEngineClass;
106 return bcEngineClass != null && bcEngineClass.isInstance(engine);
107 }
108
109
110
111
112 public static Provider getBcProviderJce() {
113 ensureLoaded();
114 Throwable cause = unavailabilityCauseBcProv;
115 Provider provider = bcProviderJce;
116 if (cause != null || provider == null) {
117 throw new IllegalStateException(cause);
118 }
119 return provider;
120 }
121
122
123
124
125 public static Provider getBcProviderJsse() {
126 ensureLoaded();
127 Throwable cause = unavailabilityCauseBcTls;
128 Provider provider = bcProviderJsse;
129 if (cause != null || provider == null) {
130 throw new IllegalStateException(cause);
131 }
132 return provider;
133 }
134
135
136
137
138
139
140
141 public static Class<? extends SSLEngine> getBcSSLEngineClass() {
142 ensureLoaded();
143 return bcSSLEngineClass;
144 }
145
146
147
148
149 static void reset() {
150 attemptedLoading = false;
151 unavailabilityCauseBcProv = null;
152 unavailabilityCauseBcPkix = null;
153 unavailabilityCauseBcTls = null;
154 bcProviderJce = null;
155 bcProviderJsse = null;
156 bcSSLEngineClass = null;
157 }
158
159 private static void ensureLoaded() {
160 if (!attemptedLoading) {
161 tryLoading();
162 }
163 }
164
165 @SuppressWarnings("unchecked")
166 private static void tryLoading() {
167 AccessController.doPrivileged((PrivilegedAction<?>) () -> {
168 try {
169
170 Provider provider = Security.getProvider(BC_PROVIDER_NAME);
171 if (provider == null) {
172 provider = Security.getProvider(BC_FIPS_PROVIDER_NAME);
173 }
174 if (provider == null) {
175 ClassLoader classLoader = BouncyCastleUtil.class.getClassLoader();
176 Class<Provider> bcProviderClass;
177 try {
178 bcProviderClass = (Class<Provider>) Class.forName(BC_PROVIDER, true, classLoader);
179 } catch (ClassNotFoundException e) {
180 try {
181 bcProviderClass = (Class<Provider>) Class.forName(BC_FIPS_PROVIDER, true, classLoader);
182 } catch (ClassNotFoundException ex) {
183 ThrowableUtil.addSuppressed(e, ex);
184 throw e;
185 }
186 }
187 provider = bcProviderClass.getConstructor().newInstance();
188 }
189 bcProviderJce = provider;
190 logger.debug("Bouncy Castle provider available");
191 } catch (Throwable e) {
192 logger.debug("Cannot load Bouncy Castle provider", e);
193 unavailabilityCauseBcProv = e;
194 }
195
196 try {
197
198 ClassLoader classLoader = BouncyCastleUtil.class.getClassLoader();
199 Provider provider = bcProviderJce;
200 if (provider != null) {
201
202 classLoader = provider.getClass().getClassLoader();
203 }
204 Class.forName(BC_PEMPARSER, true, classLoader);
205 logger.debug("Bouncy Castle PKIX available");
206 } catch (Throwable e) {
207 logger.debug("Cannot load Bouncy Castle PKIX", e);
208 unavailabilityCauseBcPkix = e;
209 }
210
211 try {
212
213 ClassLoader classLoader = BouncyCastleUtil.class.getClassLoader();
214 Provider provider = Security.getProvider(BC_JSSE_PROVIDER_NAME);
215 if (provider != null) {
216
217 classLoader = provider.getClass().getClassLoader();
218 } else {
219 Class<?> providerClass = Class.forName(BC_JSSE_PROVIDER, true, classLoader);
220 provider = (Provider) providerClass.getConstructor().newInstance();
221 }
222 bcSSLEngineClass = (Class<? extends SSLEngine>) Class.forName(BC_JSSE_SSLENGINE, true, classLoader);
223 Class.forName(BC_JSSE_ALPN_SELECTOR, true, classLoader);
224 bcProviderJsse = provider;
225 logger.debug("Bouncy Castle JSSE available");
226 } catch (Throwable e) {
227 logger.debug("Cannot load Bouncy Castle TLS", e);
228 unavailabilityCauseBcTls = e;
229 }
230 attemptedLoading = true;
231 return null;
232 });
233 }
234
235 private BouncyCastleUtil() {
236 }
237 }