1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package io.wcm.caravan.commons.httpclient.impl.helpers;
21
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.security.GeneralSecurityException;
28 import java.security.KeyManagementException;
29 import java.security.KeyStore;
30 import java.security.NoSuchAlgorithmException;
31
32 import javax.net.ssl.KeyManagerFactory;
33 import javax.net.ssl.SSLContext;
34 import javax.net.ssl.TrustManagerFactory;
35
36 import org.apache.commons.lang3.StringUtils;
37 import org.apache.http.conn.ssl.SSLInitializationException;
38 import org.jetbrains.annotations.NotNull;
39 import org.jetbrains.annotations.Nullable;
40
41 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
42 import io.wcm.caravan.commons.httpclient.HttpClientConfig;
43
44
45
46
47 public final class CertificateLoader {
48
49
50
51
52 public static final String SSL_CONTEXT_TYPE_DEFAULT = "TLS";
53
54
55
56
57 public static final String KEY_MANAGER_TYPE_DEFAULT = "SunX509";
58
59
60
61
62 public static final String KEY_STORE_TYPE_DEFAULT = "PKCS12";
63
64
65
66
67 public static final String TRUST_MANAGER_TYPE_DEFAULT = "SunX509";
68
69
70
71
72 public static final String TRUST_STORE_TYPE_DEFAULT = "JKS";
73
74
75 private CertificateLoader() {
76
77 }
78
79
80
81
82
83
84
85
86 @SuppressWarnings("null")
87 @SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
88 public static @NotNull SSLContext buildSSLContext(@NotNull HttpClientConfig config) throws IOException, GeneralSecurityException {
89
90 KeyManagerFactory kmf = null;
91 if (isSslKeyManagerEnabled(config)) {
92 kmf = getKeyManagerFactory(config.getKeyStorePath(),
93 new StoreProperties(config.getKeyStorePassword(), config.getKeyManagerType(),
94 config.getKeyStoreType(), config.getKeyStoreProvider()));
95 }
96 TrustManagerFactory tmf = null;
97 if (isSslTrustStoreEnbaled(config)) {
98 tmf = getTrustManagerFactory(config.getTrustStorePath(), new StoreProperties(config.getTrustStorePassword(),
99 config.getTrustManagerType(), config.getTrustStoreType(), config.getTrustStoreProvider()));
100 }
101
102 SSLContext sslContext = SSLContext.getInstance(config.getSslContextType());
103 sslContext.init(kmf != null ? kmf.getKeyManagers() : null,
104 tmf != null ? tmf.getTrustManagers() : null,
105 null);
106
107 return sslContext;
108 }
109
110
111
112
113
114
115
116
117
118 public static @NotNull KeyManagerFactory getKeyManagerFactory(@NotNull String keyStoreFilename, @NotNull StoreProperties storeProperties)
119 throws IOException, GeneralSecurityException {
120 InputStream is = getResourceAsStream(keyStoreFilename);
121 if (is == null) {
122 throw new FileNotFoundException("Certificate file not found: " + getFilenameInfo(keyStoreFilename));
123 }
124 try {
125 return getKeyManagerFactory(is, storeProperties);
126 }
127 finally {
128 try {
129 is.close();
130 }
131 catch (IOException ex) {
132
133 }
134 }
135 }
136
137
138
139
140
141
142
143
144
145 private static @NotNull KeyManagerFactory getKeyManagerFactory(@NotNull InputStream keyStoreStream, @NotNull StoreProperties storeProperties)
146 throws IOException, GeneralSecurityException {
147
148 final KeyStore ks;
149 if (StringUtils.isNotBlank(storeProperties.getProvider())) {
150 ks = KeyStore.getInstance(storeProperties.getType(), storeProperties.getProvider());
151 }
152 else {
153 ks = KeyStore.getInstance(storeProperties.getType());
154 }
155 ks.load(keyStoreStream, storeProperties.getPassword().toCharArray());
156 KeyManagerFactory kmf = KeyManagerFactory.getInstance(storeProperties.getManagerType());
157 kmf.init(ks, storeProperties.getPassword().toCharArray());
158 return kmf;
159 }
160
161
162
163
164
165
166
167
168
169 public static @NotNull TrustManagerFactory getTrustManagerFactory(@NotNull String trustStoreFilename, @NotNull StoreProperties storeProperties)
170 throws IOException, GeneralSecurityException {
171 InputStream is = getResourceAsStream(trustStoreFilename);
172 if (is == null) {
173 throw new FileNotFoundException("Certificate file not found: " + getFilenameInfo(trustStoreFilename));
174 }
175 try {
176 return getTrustManagerFactory(is, storeProperties);
177 }
178 finally {
179 try {
180 is.close();
181 }
182 catch (IOException ex) {
183
184 }
185 }
186 }
187
188
189
190
191
192
193
194
195
196 private static @NotNull TrustManagerFactory getTrustManagerFactory(@NotNull InputStream trustStoreStream, @NotNull StoreProperties storeProperties)
197 throws IOException, GeneralSecurityException {
198
199
200 final KeyStore ks;
201 if (StringUtils.isNotBlank(storeProperties.getProvider())) {
202 ks = KeyStore.getInstance(storeProperties.getType(), storeProperties.getProvider());
203 }
204 else {
205 ks = KeyStore.getInstance(storeProperties.getType());
206 }
207
208 ks.load(trustStoreStream, storeProperties.getPassword().toCharArray());
209 TrustManagerFactory tmf = TrustManagerFactory.getInstance(storeProperties.getManagerType());
210 tmf.init(ks);
211 return tmf;
212 }
213
214
215
216
217
218
219
220 private static @Nullable InputStream getResourceAsStream(@NotNull String path) throws IOException {
221 if (StringUtils.isEmpty(path)) {
222 return null;
223 }
224
225
226 File file = new File(path);
227 if (file.exists() && file.isFile()) {
228 return new FileInputStream(file);
229 }
230
231
232 return CertificateLoader.class.getResourceAsStream(path);
233 }
234
235
236
237
238
239
240 private static @Nullable String getFilenameInfo(@Nullable String path) {
241 if (StringUtils.isEmpty(path)) {
242 return null;
243 }
244 try {
245 return new File(path).getCanonicalPath();
246 }
247 catch (IOException ex) {
248 return new File(path).getAbsolutePath();
249 }
250 }
251
252
253
254
255
256
257 public static boolean isSslKeyManagerEnabled(@NotNull HttpClientConfig config) {
258 return StringUtils.isNotEmpty(config.getSslContextType())
259 && StringUtils.isNotEmpty(config.getKeyManagerType())
260 && StringUtils.isNotEmpty(config.getKeyStoreType())
261 && StringUtils.isNotEmpty(config.getKeyStorePath());
262 }
263
264
265
266
267
268
269 public static boolean isSslTrustStoreEnbaled(@NotNull HttpClientConfig config) {
270 return StringUtils.isNotEmpty(config.getSslContextType())
271 && StringUtils.isNotEmpty(config.getTrustManagerType())
272 && StringUtils.isNotEmpty(config.getTrustStoreType())
273 && StringUtils.isNotEmpty(config.getTrustStorePath());
274 }
275
276
277
278
279
280 public static @NotNull SSLContext createDefaultSSlContext() throws SSLInitializationException {
281 try {
282 final SSLContext sslcontext = SSLContext.getInstance(SSL_CONTEXT_TYPE_DEFAULT);
283 sslcontext.init(null, null, null);
284 return sslcontext;
285 }
286 catch (NoSuchAlgorithmException | KeyManagementException ex) {
287 throw new SSLInitializationException(ex.getMessage(), ex);
288 }
289 }
290
291 }