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