1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package au.net.zeus.rmi.tls;
17
18 import java.lang.ref.WeakReference;
19 import java.security.GeneralSecurityException;
20 import java.security.KeyException;
21 import java.security.NoSuchAlgorithmException;
22 import java.security.NoSuchProviderException;
23 import java.security.Principal;
24 import java.security.PrivateKey;
25 import java.security.cert.CertPath;
26 import java.security.cert.CertificateException;
27 import java.security.cert.X509Certificate;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.List;
31 import java.util.logging.Logger;
32 import javax.net.ssl.X509KeyManager;
33 import javax.security.auth.Subject;
34 import javax.security.auth.x500.X500Principal;
35 import javax.security.auth.x500.X500PrivateCredential;
36 import net.jini.security.AuthenticationPermission;
37 import org.apache.river.logging.Levels;
38
39
40
41
42
43 abstract class SubjectKeyManager extends FilterX509TrustManager implements X509KeyManager {
44
45
46
47
48 final WeakReference<Subject> subjectRef;
49
50
51
52
53
54 final boolean subjectIsReadOnly;
55
56
57 protected X509Certificate serverCredential;
58
59
60 protected X500Principal serverPrincipal;
61
62
63
64
65
66 protected X500PrivateCredential clientCredential;
67
68
69 protected X500Principal clientPrincipal;
70
71
72
73
74
75 protected Exception clientCredentialException;
76
77
78
79
80
81 protected long credentialsValidUntil = 0;
82
83
84 protected AuthenticationPermission authenticationPermission;
85
86 SubjectKeyManager(Subject subject)
87 throws NoSuchAlgorithmException, NoSuchProviderException
88 {
89 subjectRef = new WeakReference<Subject>(subject);
90 subjectIsReadOnly = subject.isReadOnly();
91 }
92
93
94 abstract Logger getLogger();
95
96 synchronized Subject getSubject(){
97 return subjectRef.get();
98 }
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128 protected X500PrivateCredential checkChain(CertPath chain,
129 String keyType,
130 Principal[] issuers)
131 throws GeneralSecurityException
132 {
133 X509Certificate head = firstX509Cert(chain);
134 String certKeyType = head.getPublicKey().getAlgorithm();
135 if (!certKeyType.equals(keyType)) {
136 return null;
137 }
138 Subject subject = getSubject();
139 X500Principal principal =
140 getPrincipal(subject, head);
141 if (principal == null) {
142 throw new GeneralSecurityException(
143 "Principal not found: " + head.getSubjectDN());
144 }
145 X500Principal[] x500Issuers = null;
146 if (issuers != null) {
147 x500Issuers = new X500Principal[issuers.length];
148 for (int i = issuers.length; --i >= 0; ) {
149 x500Issuers[i] = (issuers[i] instanceof X500Principal)
150 ? (X500Principal) issuers[i]
151 : new X500Principal(issuers[i].getName());
152 }
153 }
154 checkValidity(chain, x500Issuers);
155
156
157
158
159
160 boolean[] keyUsage = head.getKeyUsage();
161 if (keyUsage != null
162 && keyUsage.length > 0
163
164 && !keyUsage[0])
165 {
166 throw new CertificateException(
167 "Certificate not permitted for digital signatures: " + head);
168 }
169
170
171 X500PrivateCredential xpc = getPrivateCredential(head);
172 if (xpc == null) {
173 throw new KeyException(
174 "Private key not found for certificate: " + head);
175 }
176
177 return xpc;
178 }
179
180
181
182
183
184
185
186
187
188
189
190 abstract X500PrivateCredential getPrivateCredential(X509Certificate cert);
191
192
193
194
195 public X509Certificate[] getCertificateChain(String alias) {
196 CertPath chain =
197 getCertificateChain(getSubject(), alias);
198 List certs = chain.getCertificates();
199 return (X509Certificate[]) certs.toArray(
200 new X509Certificate[certs.size()]);
201 }
202
203 public PrivateKey getPrivateKey(String alias) {
204 CertPath chain =
205 getCertificateChain(getSubject(), alias);
206 if (chain != null) {
207 try {
208 X500PrivateCredential xpc =
209 getPrivateCredential(firstX509Cert(chain));
210 if (xpc != null) {
211 return xpc.getPrivateKey();
212 }
213 } catch (SecurityException e) {
214 Logger logger = getLogger();
215 if (logger.isLoggable(Levels.HANDLED)) {
216 logThrow(logger, Levels.HANDLED,
217 SubjectKeyManager.class, "getPrivateKey",
218 "get private key for alias {0}\n" +
219 "caught exception",
220 new Object[] { alias },
221 e);
222 }
223 }
224 }
225 return null;
226 }
227
228
229
230
231
232
233
234 X500PrivateCredential chooseCredential(String keyType,
235 Principal[] issuers)
236 throws GeneralSecurityException
237 {
238 List certPaths = getCertificateChains(getSubject());
239 if (certPaths == null) {
240 return null;
241 }
242 List exceptions = null;
243 for (int i = certPaths.size(); --i >= 0; ) {
244 CertPath chain = (CertPath) certPaths.get(i);
245 Exception exception;
246 try {
247 X500PrivateCredential pc = checkChain(chain, keyType, issuers);
248 if (pc == null) {
249 continue;
250 } else {
251 return pc;
252 }
253 } catch (GeneralSecurityException e) {
254 exception = e;
255 } catch (SecurityException e) {
256 exception = e;
257 }
258 if (exceptions == null) {
259 exceptions = new ArrayList();
260 }
261 exceptions.add(exception);
262 Logger logger = getLogger();
263 if (logger.isLoggable(Levels.HANDLED)) {
264 logThrow(logger, Levels.HANDLED,
265 SubjectKeyManager.class, "chooseCredential",
266 "choose credential for key type {0}\n" +
267 "and issuers {1}\ncaught exception",
268 new Object[] { keyType, toString(issuers) },
269 exception);
270 }
271 }
272 if (exceptions == null) {
273 return null;
274 } else if (exceptions.size() > 1) {
275 for (int i = exceptions.size(); --i >= 0; ) {
276 Exception e = (Exception) exceptions.get(i);
277 if (!(e instanceof SecurityException)) {
278 throw new GeneralSecurityException(exceptions.toString());
279 }
280 }
281 throw new SecurityException(exceptions.toString());
282 } else if (exceptions.get(0) instanceof SecurityException) {
283 throw (SecurityException) exceptions.get(0);
284 } else {
285 throw (GeneralSecurityException) exceptions.get(0);
286 }
287 }
288
289
290
291
292
293 boolean equalPrivateCredentials(X500PrivateCredential cred1,
294 X500PrivateCredential cred2)
295 {
296 if (cred1 == null || cred2 == null) {
297 return false;
298 }
299 X509Certificate cert1 = cred1.getCertificate();
300 X509Certificate cert2 = cred2.getCertificate();
301 if (cert1 == null
302 || cert2 == null
303 || !safeEquals(cert1.getSubjectDN(), cert2.getSubjectDN()))
304 {
305 return false;
306 }
307
308
309
310
311
312
313
314 PrivateKey key1 = cred1.getPrivateKey();
315 return key1 != null && key1.equals(cred2.getPrivateKey());
316 }
317
318
319
320
321
322
323 String[] getAliases(String keyType, Principal[] issuers) {
324 List certPaths = getCertificateChains(getSubject());
325 if (certPaths == null) {
326 return null;
327 }
328 Collection result = null;
329 for (int i = certPaths.size(); --i >= 0;) {
330 CertPath chain = (CertPath) certPaths.get(i);
331 Exception exception;
332 try {
333 if (checkChain(chain, keyType, issuers) != null) {
334 if (result == null) {
335 result = new ArrayList(certPaths.size());
336 }
337 result.add(getCertificateName(firstX509Cert(chain)));
338 }
339 continue;
340 } catch (GeneralSecurityException e) {
341 exception = e;
342 } catch (SecurityException e) {
343 exception = e;
344 }
345 Logger logger = getLogger();
346 if (logger.isLoggable(Levels.HANDLED)) {
347 logThrow(logger, Levels.HANDLED,
348 SubjectKeyManager.class, "getAliases",
349 "get aliases for key type {0}\nand issuers {1}\n" +
350 "caught exception",
351 new Object[] { keyType, toString(issuers) },
352 exception);
353 }
354 }
355 if (result == null) {
356 return null;
357 } else {
358 return (String[]) result.toArray(new String[result.size()]);
359 }
360 }
361
362 }