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.net.Socket;
19 import java.security.AccessController;
20 import java.security.GeneralSecurityException;
21 import java.security.NoSuchAlgorithmException;
22 import java.security.NoSuchProviderException;
23 import java.security.Principal;
24 import java.security.PrivateKey;
25 import java.security.PrivilegedAction;
26 import java.security.cert.CertPath;
27 import java.security.cert.X509Certificate;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.Enumeration;
32 import java.util.HashMap;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.logging.Level;
38 import java.util.logging.Logger;
39 import javax.net.ssl.SSLSession;
40 import javax.net.ssl.SSLSessionContext;
41 import javax.security.auth.Subject;
42 import javax.security.auth.x500.X500Principal;
43 import javax.security.auth.x500.X500PrivateCredential;
44 import net.jini.security.AuthenticationPermission;
45 import org.apache.river.logging.Levels;
46
47
48
49
50
51 class ServerSubjectKeyManager extends SubjectKeyManager{
52
53
54 private static final Logger logger = SERVER_LOGGER;
55
56
57 private final SSLSessionContext sslSessionContext;
58
59
60 private final X500PrivateCredential[] readOnlyPrivateCredentials;
61
62
63
64
65
66
67 private final Map credentialCache = new HashMap(2);
68
69
70 Logger getLogger() {
71 return logger;
72 }
73
74
75
76
77
78
79
80
81
82 ServerSubjectKeyManager(Subject subject,
83 SSLSessionContext sslSessionContext)
84 throws NoSuchAlgorithmException, NoSuchProviderException
85 {
86 super(subject);
87 this.sslSessionContext = sslSessionContext;
88 readOnlyPrivateCredentials =
89 !subjectIsReadOnly || subject == null ? null
90 : (X500PrivateCredential[]) AccessController.doPrivileged(
91 new GetAllPrivateCredentialsAction(
92 subject));
93 }
94
95 public String[] getClientAliases(String keyType, Principal[] issuers) {
96 return null;
97 }
98
99 public String[] getServerAliases(String keyType, Principal[] issuers) {
100 String[] result = getAliases(keyType, issuers);
101 if (logger.isLoggable(Level.FINE)) {
102 logger.log(Level.FINE,
103 "get server aliases for key type {0}\n" +
104 "and issuers {1}\nreturns {2}",
105 new Object[] {
106 keyType, toString(issuers), toString(result)
107 });
108 }
109 return result;
110 }
111
112 public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) {
113 return null;
114 }
115
116
117
118
119
120
121 @Override
122 public String chooseServerAlias(
123 String keyType, Principal[] issuers, Socket socket)
124 {
125 X500PrivateCredential cred = null;
126 synchronized (credentialCache) {
127 Object val = credentialCache.get(keyType);
128 if (val instanceof X500PrivateCredential) {
129 cred = (X500PrivateCredential) val;
130 try {
131 checkCredentials(cred, null, "listen");
132 } catch (SecurityException e) {
133 if (logger.isLoggable(Levels.HANDLED)) {
134 logThrow(logger, Levels.HANDLED,
135 ServerSubjectKeyManager.class, "chooseServerAlias",
136 "choose server alias for key type {0}\n" +
137 "and issuers {1}\ncaught exception",
138 new Object[] { keyType, toString(issuers) },
139 e);
140 }
141
142
143
144
145
146 cred = null;
147 credentialCache.remove(keyType);
148 for (Enumeration en = sslSessionContext.getIds();
149 en.hasMoreElements(); )
150 {
151 SSLSession session =
152 sslSessionContext.getSession(
153 (byte[]) en.nextElement());
154 if (session != null) {
155 String suite = session.getCipherSuite();
156 if (keyType.equals(getKeyAlgorithm(suite))) {
157 session.invalidate();
158 }
159 }
160 }
161 }
162 }
163 if (cred == null) {
164
165 Exception exception = null;
166 try {
167 cred = chooseCredential(keyType, issuers);
168 if (cred != null) {
169 credentialCache.put(keyType, cred);
170 }
171 } catch (GeneralSecurityException e) {
172 exception = e;
173 } catch (SecurityException e) {
174 exception = e;
175 }
176 if (exception != null) {
177 credentialCache.put(keyType, exception.getMessage());
178 return null;
179 }
180 }
181 }
182 String result = (cred == null)
183 ? null
184 : getCertificateName(cred.getCertificate());
185 if (logger.isLoggable(Level.FINE)) {
186 logger.log(Level.FINE,
187 "choose server alias for key type {0}\nissuers {1}\n" +
188 "returns {2}",
189 new Object[] { keyType, toString(issuers), result });
190 }
191 return result;
192 }
193
194
195
196
197
198
199
200
201
202
203 private long checkCredentials(X500PrivateCredential cred,
204 Subject clientSubject,
205 String permissionAction)
206 {
207 Subject subject = getSubject();
208 if (subject == null) {
209 throw new SecurityException("Missing subject");
210 }
211 X509Certificate cert = cred.getCertificate();
212 if (getPrincipal(subject, cert) == null) {
213 throw new SecurityException("Missing principal");
214 }
215 CertPath chain =
216 getCertificateChain(subject, cert);
217 if (chain == null) {
218 throw new SecurityException("Missing public credentials");
219 }
220 long validUntil = certificatesValidUntil(chain);
221 if (clientSubject != null) {
222 assert clientSubject.isReadOnly();
223 CertPath clientChain = (CertPath)
224 clientSubject.getPublicCredentials().iterator().next();
225 validUntil = Math.min(
226 validUntil, certificatesValidUntil(clientChain));
227 }
228 if (System.currentTimeMillis() > validUntil) {
229 throw new SecurityException("Certificates no longer valid");
230 }
231 String peer = getPeerPrincipalName(clientSubject);
232 X500PrivateCredential pc =
233 getPrivateCredential(cert, peer, permissionAction);
234 if (pc == null) {
235 throw new SecurityException("Missing private credentials");
236 } else if (!equalPrivateCredentials(cred, pc)) {
237 throw new SecurityException("Wrong private credential");
238 }
239 return validUntil;
240 }
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255 private X500PrivateCredential getPrivateCredential(X509Certificate cert,
256 String peer,
257 String permissionAction)
258 {
259 Subject subject = getSubject();
260 if (subject == null) {
261 return null;
262 }
263
264
265
266
267
268
269
270
271
272
273
274
275
276 if (subjectIsReadOnly) {
277 for (int i = readOnlyPrivateCredentials.length; --i >= 0; ) {
278 X500PrivateCredential xpc = readOnlyPrivateCredentials[i];
279 if (cert.equals(xpc.getCertificate())) {
280 return xpc;
281 }
282 }
283 return null;
284 }
285 return (X500PrivateCredential) AccessController.doPrivileged(
286 new GetPrivateCredentialAction(subject, cert));
287 }
288
289
290
291
292
293 private AuthenticationPermission getAuthPermission(X509Certificate cert,
294 String peer,
295 String action)
296 {
297 Set server = Collections.singleton(cert.getSubjectX500Principal());
298 Set client = (peer == null)
299 ? null : Collections.singleton(new X500Principal(peer));
300 return new AuthenticationPermission(server, client, action);
301 }
302
303
304
305
306
307
308
309 private String getPeerPrincipalName(Subject peerSubject) {
310 if (peerSubject == null) {
311 return null;
312 }
313 assert peerSubject.isReadOnly();
314 Principal p =
315 (Principal) peerSubject.getPrincipals().iterator().next();
316 return p.getName();
317 }
318
319
320
321
322
323
324
325
326
327
328
329 synchronized X500PrivateCredential getPrivateCredential(X509Certificate cert) {
330 return getPrivateCredential(cert, (String) null, "listen");
331 }
332
333
334
335
336
337
338 static class GetAllPrivateCredentialsAction implements PrivilegedAction {
339 private final Subject subject;
340
341 GetAllPrivateCredentialsAction(Subject subject) {
342 this.subject = subject;
343 }
344
345 public Object run() {
346 Set pcs = subject.getPrivateCredentials();
347 List xpcs = new ArrayList(pcs.size());
348 synchronized (pcs) {
349
350
351
352
353
354
355
356 for (Iterator iter = pcs.iterator(); iter.hasNext(); ) {
357 Object pc = iter.next();
358 if (pc instanceof X500PrivateCredential) {
359 xpcs.add(pc);
360 }
361 }
362 }
363 return xpcs.toArray(new X500PrivateCredential[xpcs.size()]);
364 }
365 }
366 }