1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package davmail.http;
20
21 import davmail.BundleMessage;
22 import davmail.Settings;
23 import davmail.ui.PasswordPromptDialog;
24 import davmail.ui.tray.DavGatewayTray;
25 import org.apache.commons.httpclient.HttpsURL;
26 import org.apache.commons.httpclient.params.HttpConnectionParams;
27 import org.apache.commons.httpclient.protocol.Protocol;
28 import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
29 import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
30
31 import javax.net.ssl.KeyManager;
32 import javax.net.ssl.KeyManagerFactory;
33 import javax.net.ssl.KeyStoreBuilderParameters;
34 import javax.net.ssl.ManagerFactoryParameters;
35 import javax.net.ssl.SSLContext;
36 import javax.net.ssl.TrustManager;
37 import javax.net.ssl.X509KeyManager;
38 import javax.security.auth.callback.PasswordCallback;
39 import java.awt.*;
40 import java.io.BufferedReader;
41 import java.io.File;
42 import java.io.IOException;
43 import java.io.InputStreamReader;
44 import java.net.InetAddress;
45 import java.net.MalformedURLException;
46 import java.net.Socket;
47 import java.net.URL;
48 import java.security.InvalidAlgorithmParameterException;
49 import java.security.KeyManagementException;
50 import java.security.KeyStore;
51 import java.security.KeyStoreException;
52 import java.security.NoSuchAlgorithmException;
53 import java.security.Provider;
54 import java.util.ArrayList;
55
56
57
58
59
60
61 public class DavGatewaySSLProtocolSocketFactory implements SecureProtocolSocketFactory {
62
63
64
65 public static void register() {
66 String urlString = Settings.getProperty("davmail.url");
67 try {
68 URL url = new URL(urlString);
69 String protocol = url.getProtocol();
70 if ("https".equals(protocol)) {
71 int port = url.getPort();
72 if (port < 0) {
73 port = HttpsURL.DEFAULT_PORT;
74 }
75 Protocol.registerProtocol(url.getProtocol(),
76 new Protocol(protocol, (ProtocolSocketFactory) new DavGatewaySSLProtocolSocketFactory(), port));
77 }
78 } catch (MalformedURLException e) {
79 DavGatewayTray.error(new BundleMessage("LOG_INVALID_URL", urlString));
80 }
81 }
82
83 private KeyStore.ProtectionParameter getProtectionParameter(String password) {
84 if (password != null && password.length() > 0) {
85
86 return new KeyStore.PasswordProtection(password.toCharArray());
87 } else {
88
89 return new KeyStore.CallbackHandlerProtection(callbacks -> {
90 if (callbacks.length > 0 && callbacks[0] instanceof PasswordCallback) {
91 if (Settings.getBooleanProperty("davmail.server") || GraphicsEnvironment.isHeadless()) {
92
93 System.out.print(((PasswordCallback) callbacks[0]).getPrompt() + ": ");
94 String password1 = new BufferedReader(new InputStreamReader(System.in)).readLine();
95 ((PasswordCallback) callbacks[0]).setPassword(password1.toCharArray());
96 } else {
97 PasswordPromptDialog passwordPromptDialog = new PasswordPromptDialog(((PasswordCallback) callbacks[0]).getPrompt());
98 ((PasswordCallback) callbacks[0]).setPassword(passwordPromptDialog.getPassword());
99 }
100 }
101 });
102 }
103 }
104
105 private SSLContext sslcontext;
106
107 public String[] getDefaultCipherSuites() {
108 try {
109 return getSSLContext().getSocketFactory().getDefaultCipherSuites();
110 } catch (Exception e) {
111
112 }
113 return new String[]{};
114 }
115
116 public String[] getSupportedCipherSuites() {
117 try {
118 return getSSLContext().getSocketFactory().getSupportedCipherSuites();
119 } catch (Exception e) {
120
121 }
122 return new String[]{};
123 }
124
125 private SSLContext createSSLContext() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, KeyManagementException, KeyStoreException {
126
127 String pkcs11Library = Settings.getProperty("davmail.ssl.pkcs11Library");
128
129 String clientKeystoreType = Settings.getProperty("davmail.ssl.clientKeystoreType");
130
131 if (clientKeystoreType == null || clientKeystoreType.length() == 0) {
132 clientKeystoreType = "PKCS11";
133 }
134
135 if (pkcs11Library != null && pkcs11Library.length() > 0 && "PKCS11".equals(clientKeystoreType)) {
136 StringBuilder pkcs11Buffer = new StringBuilder();
137 pkcs11Buffer.append("name=DavMail\n");
138 pkcs11Buffer.append("library=").append(pkcs11Library).append('\n');
139 String pkcs11Config = Settings.getProperty("davmail.ssl.pkcs11Config");
140 if (pkcs11Config != null && pkcs11Config.length() > 0) {
141 pkcs11Buffer.append(pkcs11Config).append('\n');
142 }
143 SunPKCS11ProviderHandler.registerProvider(pkcs11Buffer.toString());
144 }
145 String algorithm = KeyManagerFactory.getDefaultAlgorithm();
146 if ("SunX509".equals(algorithm)) {
147 algorithm = "NewSunX509";
148 } else if ("IbmX509".equals(algorithm)) {
149 algorithm = "NewIbmX509";
150 }
151 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm);
152
153 ArrayList<KeyStore.Builder> keyStoreBuilders = new ArrayList<>();
154
155 KeyStore.Builder scBuilder = KeyStore.Builder.newInstance("PKCS11", null, getProtectionParameter(null));
156 keyStoreBuilders.add(scBuilder);
157
158 String clientKeystoreFile = Settings.getProperty("davmail.ssl.clientKeystoreFile");
159 String clientKeystorePass = Settings.getProperty("davmail.ssl.clientKeystorePass");
160 if (clientKeystoreFile != null && clientKeystoreFile.length() > 0
161 && ("PKCS12".equals(clientKeystoreType) || "JKS".equals(clientKeystoreType))) {
162
163 KeyStore.Builder fsBuilder = KeyStore.Builder.newInstance(clientKeystoreType, null,
164 new File(clientKeystoreFile), getProtectionParameter(clientKeystorePass));
165 keyStoreBuilders.add(fsBuilder);
166 }
167
168 if ("MSCAPI".equals(clientKeystoreType)) {
169 try {
170 Provider provider = (Provider) Class.forName("sun.security.mscapi.SunMSCAPI").newInstance();
171 KeyStore keyStore = KeyStore.getInstance("Windows-MY", provider);
172 keyStore.load(null, null);
173 keyStoreBuilders.add(KeyStore.Builder.newInstance(keyStore, new KeyStore.PasswordProtection(null)));
174 } catch (Exception e) {
175
176 }
177 }
178
179 ManagerFactoryParameters keyStoreBuilderParameters = new KeyStoreBuilderParameters(keyStoreBuilders);
180 keyManagerFactory.init(keyStoreBuilderParameters);
181
182
183 KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
184
185
186
187 for (int i = 0; i < keyManagers.length; i++) {
188 KeyManager keyManager = keyManagers[i];
189 if (keyManager instanceof X509KeyManager) {
190 keyManagers[i] = new DavMailX509KeyManager((X509KeyManager) keyManager);
191 }
192 }
193
194 SSLContext context = SSLContext.getInstance("TLS");
195 context.init(keyManagers, new TrustManager[]{new DavGatewayX509TrustManager()}, null);
196 return context;
197 }
198
199 private SSLContext getSSLContext() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, InvalidAlgorithmParameterException {
200 if (this.sslcontext == null) {
201 this.sslcontext = createSSLContext();
202 }
203 return this.sslcontext;
204 }
205
206 public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException {
207 try {
208 return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort);
209 } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | InvalidAlgorithmParameterException e) {
210 throw new IOException(e + " " + e.getMessage());
211 }
212 }
213
214 public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort, HttpConnectionParams params) throws IOException {
215 try {
216 return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort);
217 } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | InvalidAlgorithmParameterException e) {
218 throw new IOException(e + " " + e.getMessage());
219 }
220 }
221
222 public Socket createSocket(String host, int port) throws IOException {
223 try {
224 return getSSLContext().getSocketFactory().createSocket(host, port);
225 } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | InvalidAlgorithmParameterException e) {
226 throw new IOException(e + " " + e.getMessage());
227 }
228 }
229
230 public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
231 try {
232 return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
233 } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | InvalidAlgorithmParameterException e) {
234 throw new IOException(e + " " + e.getMessage());
235 }
236 }
237
238 public Socket createSocket(InetAddress host, int port) throws IOException {
239 try {
240 return getSSLContext().getSocketFactory().createSocket(host, port);
241 } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | InvalidAlgorithmParameterException e) {
242 throw new IOException(e + " " + e.getMessage());
243 }
244 }
245
246 public Socket createSocket(InetAddress host, int port, InetAddress clientHost, int clientPort) throws IOException {
247 try {
248 return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort);
249 } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | InvalidAlgorithmParameterException e) {
250 throw new IOException(e + " " + e.getMessage());
251 }
252 }
253
254
255
256
257 @Override
258 public boolean equals(Object obj) {
259 return ((obj != null) && obj.getClass().equals(this.getClass()));
260 }
261
262
263
264
265 @Override
266 public int hashCode() {
267 return this.getClass().hashCode();
268 }
269 }