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(new PrivilegedAction<Object>() {
168 @Override
169 public Object run() {
170 try {
171
172 Provider provider = Security.getProvider(BC_PROVIDER_NAME);
173 if (provider == null) {
174 provider = Security.getProvider(BC_FIPS_PROVIDER_NAME);
175 }
176 if (provider == null) {
177 ClassLoader classLoader = BouncyCastleUtil.class.getClassLoader();
178 Class<Provider> bcProviderClass;
179 try {
180 bcProviderClass = (Class<Provider>) Class.forName(BC_PROVIDER, true, classLoader);
181 } catch (ClassNotFoundException e) {
182 try {
183 bcProviderClass = (Class<Provider>) Class.forName(BC_FIPS_PROVIDER, true, classLoader);
184 } catch (ClassNotFoundException ex) {
185 ThrowableUtil.addSuppressed(e, ex);
186 throw e;
187 }
188 }
189 provider = bcProviderClass.getConstructor().newInstance();
190 }
191 bcProviderJce = provider;
192 logger.debug("Bouncy Castle provider available");
193 } catch (Throwable e) {
194 logger.debug("Cannot load Bouncy Castle provider", e);
195 unavailabilityCauseBcProv = e;
196 }
197
198 try {
199
200 ClassLoader classLoader = BouncyCastleUtil.class.getClassLoader();
201 Provider provider = bcProviderJce;
202 if (provider != null) {
203
204 classLoader = provider.getClass().getClassLoader();
205 }
206 Class.forName(BC_PEMPARSER, true, classLoader);
207 logger.debug("Bouncy Castle PKIX available");
208 } catch (Throwable e) {
209 logger.debug("Cannot load Bouncy Castle PKIX", e);
210 unavailabilityCauseBcPkix = e;
211 }
212
213 try {
214
215 ClassLoader classLoader = BouncyCastleUtil.class.getClassLoader();
216 Provider provider = Security.getProvider(BC_JSSE_PROVIDER_NAME);
217 if (provider != null) {
218
219 classLoader = provider.getClass().getClassLoader();
220 } else {
221 Class<?> providerClass = Class.forName(BC_JSSE_PROVIDER, true, classLoader);
222 provider = (Provider) providerClass.getConstructor().newInstance();
223 }
224 bcSSLEngineClass = (Class<? extends SSLEngine>) Class.forName(BC_JSSE_SSLENGINE, true, classLoader);
225 Class.forName(BC_JSSE_ALPN_SELECTOR, true, classLoader);
226 bcProviderJsse = provider;
227 logger.debug("Bouncy Castle JSSE available");
228 } catch (Throwable e) {
229 logger.debug("Cannot load Bouncy Castle TLS", e);
230 unavailabilityCauseBcTls = e;
231 }
232 attemptedLoading = true;
233 return null;
234 }
235 });
236 }
237
238 private BouncyCastleUtil() {
239 }
240 }