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.Settings;
22 import davmail.ui.SelectCertificateDialog;
23 import org.apache.log4j.Logger;
24
25 import javax.net.ssl.X509KeyManager;
26 import java.awt.*;
27 import java.io.BufferedReader;
28 import java.io.IOException;
29 import java.io.InputStreamReader;
30 import java.net.Socket;
31 import java.security.Principal;
32 import java.security.PrivateKey;
33 import java.security.cert.X509Certificate;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.List;
37
38
39
40
41
42
43 public class DavMailX509KeyManager implements X509KeyManager {
44
45 protected static final Logger LOGGER = Logger.getLogger(DavMailX509KeyManager.class);
46
47
48 private final X509KeyManager keyManager;
49
50
51 private String cachedAlias;
52
53
54
55
56
57
58 public DavMailX509KeyManager(X509KeyManager keyManager) {
59 this.keyManager = keyManager;
60 }
61
62
63
64
65 public String[] getClientAliases(String string, Principal[] principals) {
66 return keyManager.getClientAliases(string, principals);
67 }
68
69
70
71
72
73
74
75
76 public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
77 LOGGER.debug("Find client certificates issued by: " + Arrays.asList(issuers));
78
79 ArrayList<String> aliases = new ArrayList<>();
80 for (String keyTypeValue : keyType) {
81 String[] keyAliases = keyManager.getClientAliases(keyTypeValue, issuers);
82
83 if (keyAliases != null) {
84 aliases.addAll(Arrays.asList(keyAliases));
85 }
86 }
87
88
89 if (aliases.size() > 1) {
90
91
92 if (cachedAlias != null) {
93 for (String alias : aliases) {
94 if (cachedAlias.equals(stripAlias(alias))) {
95 LOGGER.debug(alias + " matched cached alias: " + cachedAlias);
96 return alias;
97 }
98 }
99
100
101 cachedAlias = null;
102 }
103
104 String[] aliasesArray = aliases.toArray(new String[0]);
105 String[] descriptionsArray = new String[aliasesArray.length];
106 int i = 0;
107 for (String alias : aliasesArray) {
108 X509Certificate certificate = getCertificateChain(alias)[0];
109 String subject = certificate.getSubjectX500Principal().getName();
110 if (subject.contains("=")) {
111 subject = subject.substring(subject.indexOf("=")+1);
112 }
113 if (subject.contains(",")) {
114 subject = subject.substring(0, subject.indexOf(","));
115 }
116 try {
117 for (List<?> subjectAltName:certificate.getSubjectAlternativeNames()) {
118 if (subjectAltName.get(1) instanceof String) {
119 subject = " " + subjectAltName.get(1);
120 }
121 }
122 } catch (Exception e) {
123
124 }
125 String issuer = certificate.getIssuerX500Principal().getName();
126 if (issuer.contains("=")) {
127 issuer = issuer.substring(issuer.indexOf("=")+1);
128 }
129 if (issuer.contains(",")) {
130 issuer = issuer.substring(0, issuer.indexOf(","));
131 }
132 descriptionsArray[i++] = subject + " [" + issuer + "]";
133 }
134 String selectedAlias;
135 if (Settings.getBooleanProperty("davmail.server") || GraphicsEnvironment.isHeadless()) {
136
137 selectedAlias = chooseClientAlias(aliasesArray, descriptionsArray);
138 } else {
139 SelectCertificateDialog selectCertificateDialog = new SelectCertificateDialog(aliasesArray, descriptionsArray);
140
141 selectedAlias = selectCertificateDialog.getSelectedAlias();
142 LOGGER.debug("User selected Key Alias: " + selectedAlias);
143 }
144
145 cachedAlias = stripAlias(selectedAlias);
146 LOGGER.debug("Stored Key Alias Pattern: " + cachedAlias);
147
148 return selectedAlias;
149
150
151 } else if (aliases.size() == 1) {
152 LOGGER.debug("One Private Key found, returning that");
153 return aliases.get(0);
154
155
156 } else {
157 LOGGER.debug("No Private Keys found");
158 return null;
159 }
160 }
161
162 private String chooseClientAlias(String[] aliasesArray, String[] descriptionsArray) {
163 System.out.println("Choose client alias:");
164 int i = 1;
165 for (String aliasDescription:descriptionsArray) {
166 System.out.println(i+++": "+aliasDescription);
167 }
168 BufferedReader inReader = new BufferedReader(new InputStreamReader(System.in));
169 int chosenIndex = 0;
170 while (chosenIndex == 0 || chosenIndex > descriptionsArray.length) {
171 try {
172 System.out.print("Alias: ");
173 chosenIndex = Integer.parseInt(inReader.readLine());
174 } catch (NumberFormatException | IOException e) {
175 System.out.println("Invalid");
176 }
177 }
178
179 return aliasesArray[chosenIndex - 1];
180 }
181
182
183
184
185
186
187
188
189 protected String stripAlias(String alias) {
190 String value = alias;
191 if (value != null && value.length() > 1) {
192 char firstChar = value.charAt(0);
193 int dotIndex = value.indexOf('.');
194 if (firstChar >= '0' && firstChar <= '9' && dotIndex >= 0) {
195 value = value.substring(dotIndex+1);
196 }
197 }
198 return value;
199 }
200
201
202
203
204 public String[] getServerAliases(String string, Principal[] prncpls) {
205 return keyManager.getServerAliases(string, prncpls);
206 }
207
208
209
210
211 public String chooseServerAlias(String string, Principal[] prncpls, Socket socket) {
212 return keyManager.chooseServerAlias(string, prncpls, socket);
213 }
214
215
216
217
218 public X509Certificate[] getCertificateChain(String string) {
219 X509Certificate[] certificates = keyManager.getCertificateChain(string);
220 for (X509Certificate certificate: certificates) {
221 LOGGER.debug("Certificate chain: " + certificate.getSubjectX500Principal());
222 }
223 return certificates;
224 }
225
226
227
228
229 public PrivateKey getPrivateKey(String string) {
230 return keyManager.getPrivateKey(string);
231 }
232 }