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 }