1
/*___INFO__MARK_BEGIN__*/
2
/*************************************************************************
4
* The Contents of this file are made available subject to the terms of
5
* the Sun Industry Standards Source License Version 1.2
7
* Sun Microsystems Inc., March, 2001
10
* Sun Industry Standards Source License Version 1.2
11
* =================================================
12
* The contents of this file are subject to the Sun Industry Standards
13
* Source License Version 1.2 (the "License"); You may not use this file
14
* except in compliance with the License. You may obtain a copy of the
15
* License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
17
* Software provided under this License is provided on an "AS IS" basis,
18
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
19
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
20
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
21
* See the License for the specific provisions governing your rights and
22
* obligations concerning the Software.
24
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
26
* Copyright: 2006 by Sun Microsystems, Inc
28
* All Rights Reserved.
30
************************************************************************/
31
/*___INFO__MARK_END__*/
33
package com.sun.grid.security.login;
36
import java.io.FileInputStream;
37
import java.io.IOException;
38
import java.io.InputStream;
39
import java.security.InvalidAlgorithmParameterException;
40
import java.security.KeyStore;
41
import java.security.KeyStoreException;
42
import java.security.NoSuchAlgorithmException;
43
import java.security.Signature;
44
import java.security.cert.CRLException;
45
import java.security.cert.CertStore;
46
import java.security.cert.CertificateException;
47
import java.security.cert.CertificateFactory;
48
import java.security.cert.CollectionCertStoreParameters;
49
import java.security.cert.PKIXBuilderParameters;
50
import java.security.cert.X509CertSelector;
51
import java.security.cert.X509Certificate;
52
import java.util.Collection;
53
import java.util.HashMap;
55
import java.util.logging.Level;
56
import java.util.logging.LogRecord;
57
import java.util.logging.Logger;
58
import javax.net.ssl.CertPathTrustManagerParameters;
59
import javax.net.ssl.ManagerFactoryParameters;
60
import javax.net.ssl.TrustManager;
61
import javax.net.ssl.TrustManagerFactory;
62
import javax.net.ssl.X509TrustManager;
65
* The GECATrustManager validates the certificates against the CA certificate
66
* of a Grid Engine CSP system
68
public class GECATrustManager implements X509TrustManager {
70
private final static Logger log = Logger.getLogger(GECATrustManager.class.getName());
72
/** alias for the ca certificate */
73
public static final String CA_ALIAS = "ca";
76
private final Map userCertMap = new HashMap();
77
private final Object syncObject = new Object();
79
private long lastUpdate;
80
private X509TrustManager trustManager;
81
private X509Certificate caCertificate;
84
public GECATrustManager() {
89
* Creates a new instance of GECATrustManager.
91
* @param caTop ca top directory of the grid engine ca
93
public GECATrustManager(File caTop) {
98
private X509Certificate getUserCert(String username) {
99
synchronized(syncObject) {
101
CertCacheElem elem = (CertCacheElem) userCertMap.get(username);
103
File certFile = new File(caTop, "usercerts" + File.separator + username + File.separator + "cert.pem");
104
elem = new CertCacheElem(certFile);
105
userCertMap.put(username, elem);
107
return elem.getCertificate();
116
* set a new caTop directory
119
public void setCaTop(File caTop) {
120
synchronized(syncObject) {
128
private class CertCacheElem {
130
private long lastUpdate;
131
private final File certFile;
132
private X509Certificate cert;
134
public CertCacheElem(File certFile) {
135
this.certFile = certFile;
138
public synchronized X509Certificate getCertificate() {
139
if(!certFile.exists()) {
140
log.log(Level.FINE,"cert file {0} does not exist", certFile);
143
if(lastUpdate < certFile.lastModified()) {
145
lastUpdate = certFile.lastModified();
146
InputStream in = new FileInputStream(certFile);
148
CertificateFactory certFac = CertificateFactory.getInstance("X.509");
149
cert = (X509Certificate) certFac.generateCertificate(in);
153
} catch (IOException ex) {
157
} catch(Exception ex) {
158
LogRecord lr = new LogRecord(Level.WARNING, "Error while reading certificate from file {0}");
159
lr.setParameters(new Object[]{certFile});
170
private final static String [] TRUSTED_SIGNATURE_ALGORITHM = new String [] {
174
private boolean isTrustedSignatureAlgorithm(String algorithm) {
175
for(int i = 0; i < TRUSTED_SIGNATURE_ALGORITHM.length; i++) {
176
if(TRUSTED_SIGNATURE_ALGORITHM[i].equals(algorithm)) {
184
* Validate a message of a user.
185
* @param username name of the user
186
* @param message the message
187
* @param signature the signature
188
* @param algorithm the digest algorithm
189
* @return <code>true</code> if the message is valid
191
public boolean isValidMessage(String username, byte [] message, byte [] signature, String algorithm) {
193
synchronized (syncObject) {
197
if(!isTrustedSignatureAlgorithm(algorithm)) {
201
X509Certificate[] chain = new X509Certificate[2];
203
chain[0] = getUserCert(username);
205
if (chain[0] == null) {
210
chain[1] = getCACertificate();
211
} catch (CertificateException ex) {
212
log.log(Level.FINE, "Can not get CA certificate", ex);
217
checkClientTrusted(chain, "RSA");
218
} catch (CertificateException ex) {
219
log.log(Level.FINE, "user certificate is not trusted", ex);
224
Signature s = Signature.getInstance(algorithm);
225
s.initVerify(chain[0]);
227
return s.verify(signature);
228
} catch (Exception ex) {
229
LogRecord lr = new LogRecord(Level.WARNING, "Error while verifing message of user {0}");
230
lr.setParameters(new Object[]{username});
239
private X509TrustManager getTrustManager() throws CertificateException {
240
log.entering("GECATrustManager", "getTrustManager");
241
X509TrustManager ret = null;
242
synchronized(syncObject) {
246
log.exiting("GECATrustManager", "getTrustManager", ret);
250
private X509Certificate getCACertificate() throws CertificateException {
251
log.entering("GECATrustManager", "getCACertificate");
252
X509Certificate ret = null;
253
synchronized(syncObject) {
257
log.exiting("GECATrustManager", "getCACertificate", ret);
262
private void reinit() throws CertificateException {
263
log.entering("GECATrustManager", "reinit");
265
throw new CertificateException("caTop not set");
267
File caCertFile = new File(caTop, "cacert.pem");
268
File caCrlFile = new File(caTop, "ca-crl.pem");
270
if (trustManager == null || lastUpdate < caCertFile.lastModified() || lastUpdate < caCrlFile.lastModified()) {
271
long alastUpdate = System.currentTimeMillis();
272
init(caCertFile, caCrlFile);
273
this.lastUpdate = alastUpdate;
275
log.exiting("GECATrustManager", "reinit");
278
private void init(File caCertFile, File caCrlFile) throws CertificateException {
279
if(log.isLoggable(Level.FINER)) {
280
log.entering("GECATrustManager", "init", new Object [] { caCertFile, caCrlFile });
284
// Initialize an new empty keystore
285
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
286
ks.load(null, new char[0]);
288
log.log(Level.FINE, "read ca certificate from {0}", caCertFile);
289
CertificateFactory certFac = CertificateFactory.getInstance("X.509");
291
InputStream in = new FileInputStream(caCertFile);
294
X509Certificate cert = (X509Certificate)certFac.generateCertificate(in);
295
ks.setCertificateEntry(CA_ALIAS, cert);
296
caCertificate = cert;
300
} catch(IOException ioe) {
305
PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(ks, new X509CertSelector());
307
if (caCrlFile.exists()) {
308
log.log(Level.FINE, "read certificate revocation list from {0}", caCrlFile);
309
in = new FileInputStream(caCrlFile);
312
Collection crls = certFac.generateCRLs(in);
314
CollectionCertStoreParameters certStoreParams = new CollectionCertStoreParameters(crls);
315
CertStore certStore = CertStore.getInstance("Collection", certStoreParams);
317
pkixParams.setRevocationEnabled(true);
318
pkixParams.addCertStore(certStore);
322
} catch(IOException ioe) {
327
// crl file does not exists, disable revocation
328
pkixParams.setRevocationEnabled(false);
331
// Wrap them as trust manager parameters
332
ManagerFactoryParameters trustParams = new CertPathTrustManagerParameters(pkixParams);
333
TrustManagerFactory fac = TrustManagerFactory.getInstance("PKIX");
335
fac.init(trustParams);
338
TrustManager [] trustManagers = fac.getTrustManagers();
339
for (int i = 0; i < trustManagers.length; i++) {
340
if (trustManagers[i] instanceof X509TrustManager) {
341
trustManager = (X509TrustManager)trustManagers[i];
346
if (trustManager == null) {
347
// This should never happen since we handle only X509 certificates
348
throw new CertificateException("Found no X509TrustManager");
353
} catch (NoSuchAlgorithmException ex) {
354
CertificateException cae = new CertificateException("Certificate algorithm is unknown", ex);
355
log.throwing("GECATrustManager", "init", cae);
357
} catch (InvalidAlgorithmParameterException ex) {
358
CertificateException cae = new CertificateException("Invalid parameters for crypte algorithms", ex);
359
log.throwing("GECATrustManager", "init", cae);
361
} catch(KeyStoreException ex) {
362
CertificateException cae = new CertificateException("Cannot create keystore for ca certificate", ex);
363
log.throwing("GECATrustManager", "init", cae);
365
} catch(IOException ex) {
366
CertificateException cae = new CertificateException("I/O error while initializing the ca certificate", ex);
367
log.throwing("GECATrustManager", "init", cae);
369
} catch(CRLException ex) {
370
CertificateException cae = new CertificateException("Error in crl file", ex);
371
log.throwing("SgeCATrustManager", "init", ex);
374
log.exiting("GECATrustManager", "init");
378
* Given the partial or complete certificate chain provided by the
379
* peer, build a certificate path to a trusted root and return if
380
* it can be validated and is trusted for client SSL
381
* authentication based on the authentication type.
383
* The authentication type is determined by the actual certificate
384
* used. For instance, if RSAPublicKey is used, the authType
385
* should be "RSA". Checking is case-sensitive.
387
* @param chain the peer certificate chain
388
* @param authType the authentication type based on the client certificate
389
* @throws IllegalArgumentException if null or zero-length chain
390
* is passed in for the chain parameter or if null or zero-length
391
* string is passed in for the authType parameter
392
* @throws CertificateException if the certificate chain is not trusted
393
* by this TrustManager.
395
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
396
if(log.isLoggable(Level.FINER)) {
397
log.entering("GECATrustManager", "checkClientTrusted", new Object [] { chain, authType });
399
getTrustManager().checkClientTrusted(chain, authType);
400
log.exiting("GECATrustManager", "checkClientTrusted");
404
* Given the partial or complete certificate chain provided by the
405
* peer, build a certificate path to a trusted root and return if
406
* it can be validated and is trusted for server SSL
407
* authentication based on the authentication type.
409
* The authentication type is the key exchange algorithm portion
410
* of the cipher suites represented as a String, such as "RSA",
411
* "DHE_DSS". Note: for some exportable cipher suites, the key
412
* exchange algorithm is determined at run time during the
413
* handshake. For instance, for TLS_RSA_EXPORT_WITH_RC4_40_MD5,
414
* the authType should be RSA_EXPORT when an ephemeral RSA key is
415
* used for the key exchange, and RSA when the key from the server
416
* certificate is used. Checking is case-sensitive.
418
* @param chain the peer certificate chain
419
* @param authType the key exchange algorithm used
420
* @throws IllegalArgumentException if null or zero-length chain
421
* is passed in for the chain parameter or if null or zero-length
422
* string is passed in for the authType parameter
423
* @throws CertificateException if the certificate chain is not trusted
424
* by this TrustManager.
426
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
427
if(log.isLoggable(Level.FINER)) {
428
log.entering("GECATrustManager", "checkServerTrusted", new Object [] { chain, authType });
430
getTrustManager().checkServerTrusted(chain, authType);
431
log.exiting("GECATrustManager", "checkServerTrusted");
435
* Return an array of certificate authority certificates
436
* which are trusted for authenticating peers.
438
* @return a non-null (possibly empty) array of acceptable
439
* CA issuer certificates.
441
public X509Certificate[] getAcceptedIssuers() {
442
log.entering("GECATrustManager", "getAcceptedIssuers");
443
X509Certificate[] ret = null;
445
ret = getTrustManager().getAcceptedIssuers();
446
} catch(CertificateException ex) {
447
ret = new X509Certificate[0];
449
log.exiting("GECATrustManager", "getAcceptedIssuers", ret);