~ubuntu-branches/ubuntu/utopic/gridengine/utopic

« back to all changes in this revision

Viewing changes to source/libs/juti/java/com/sun/grid/security/login/GECATrustManager.java

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2008-06-25 22:36:13 UTC
  • Revision ID: james.westby@ubuntu.com-20080625223613-tvd9xlhuoct9kyhm
Tags: upstream-6.2~beta2
ImportĀ upstreamĀ versionĀ 6.2~beta2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*___INFO__MARK_BEGIN__*/
 
2
/*************************************************************************
 
3
 *
 
4
 *  The Contents of this file are made available subject to the terms of
 
5
 *  the Sun Industry Standards Source License Version 1.2
 
6
 *
 
7
 *  Sun Microsystems Inc., March, 2001
 
8
 *
 
9
 *
 
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
 
16
 *
 
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.
 
23
 *
 
24
 *   The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 
25
 *
 
26
 *   Copyright: 2006 by Sun Microsystems, Inc
 
27
 *
 
28
 *   All Rights Reserved.
 
29
 *
 
30
 ************************************************************************/
 
31
/*___INFO__MARK_END__*/
 
32
 
 
33
package com.sun.grid.security.login;
 
34
 
 
35
import java.io.File;
 
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;
 
54
import java.util.Map;
 
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;
 
63
 
 
64
/**
 
65
 * The GECATrustManager validates the certificates against the CA certificate
 
66
 * of a Grid Engine CSP system
 
67
 */
 
68
public class GECATrustManager implements X509TrustManager {
 
69
    
 
70
    private final static Logger log = Logger.getLogger(GECATrustManager.class.getName());
 
71
    
 
72
    /** alias for the ca certificate */
 
73
    public static final String CA_ALIAS = "ca";
 
74
    
 
75
    private File caTop;
 
76
    private final Map userCertMap = new HashMap();
 
77
    private final Object syncObject = new Object();
 
78
 
 
79
    private long lastUpdate;
 
80
    private X509TrustManager trustManager;
 
81
    private X509Certificate  caCertificate;
 
82
    
 
83
    
 
84
    public GECATrustManager() {
 
85
        this(null);
 
86
    }
 
87
    
 
88
    /**
 
89
     *  Creates a new instance of GECATrustManager.
 
90
     *
 
91
     * @param caTop ca top directory of the grid engine ca
 
92
     */
 
93
    public GECATrustManager(File caTop) {
 
94
        this.caTop = caTop;
 
95
    }
 
96
    
 
97
    
 
98
    private X509Certificate getUserCert(String username) {
 
99
       synchronized(syncObject) {
 
100
           if (caTop != null) {
 
101
               CertCacheElem elem = (CertCacheElem) userCertMap.get(username);
 
102
               if (elem == null) {
 
103
                   File certFile = new File(caTop, "usercerts" + File.separator + username + File.separator + "cert.pem");
 
104
                   elem = new CertCacheElem(certFile);
 
105
                   userCertMap.put(username, elem);
 
106
               }
 
107
               return elem.getCertificate();
 
108
           } else {
 
109
               return null;
 
110
           }
 
111
       }
 
112
    }
 
113
    
 
114
    
 
115
    /**
 
116
     * set a new caTop directory
 
117
     * @param caTop
 
118
     */
 
119
    public void setCaTop(File caTop) {
 
120
        synchronized(syncObject) {
 
121
            this.caTop = caTop;
 
122
            userCertMap.clear();
 
123
            trustManager = null;
 
124
        }
 
125
    }
 
126
            
 
127
    
 
128
    private class CertCacheElem {
 
129
        
 
130
        private long lastUpdate;
 
131
        private final File certFile;
 
132
        private X509Certificate cert;
 
133
        
 
134
        public CertCacheElem(File certFile) {
 
135
            this.certFile = certFile;
 
136
        }
 
137
        
 
138
        public synchronized X509Certificate getCertificate() {
 
139
            if(!certFile.exists()) {
 
140
                log.log(Level.FINE,"cert file {0} does not exist", certFile);
 
141
                return null;
 
142
            }
 
143
            if(lastUpdate < certFile.lastModified()) {
 
144
                try {
 
145
                    lastUpdate = certFile.lastModified();
 
146
                    InputStream in = new FileInputStream(certFile);
 
147
                    try {
 
148
                        CertificateFactory certFac = CertificateFactory.getInstance("X.509");
 
149
                        cert = (X509Certificate) certFac.generateCertificate(in);
 
150
                    } finally {
 
151
                        try {
 
152
                            in.close();
 
153
                        } catch (IOException ex) {
 
154
                        // Ignore
 
155
                        }
 
156
                    }                
 
157
                } catch(Exception ex) {
 
158
                    LogRecord lr = new LogRecord(Level.WARNING, "Error while reading certificate from file {0}");
 
159
                    lr.setParameters(new Object[]{certFile});
 
160
                    lr.setThrown(ex);
 
161
                    log.log(lr);
 
162
                    cert = null;
 
163
                }
 
164
            }
 
165
            return cert;
 
166
        }
 
167
        
 
168
    }
 
169
    
 
170
    private final static String [] TRUSTED_SIGNATURE_ALGORITHM = new String [] {
 
171
        "MD5withRSA"
 
172
    };
 
173
    
 
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)) {
 
177
                return true;
 
178
            }
 
179
        }
 
180
        return false;
 
181
    }
 
182
    
 
183
    /**
 
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
 
190
     */
 
191
    public boolean isValidMessage(String username, byte [] message, byte [] signature, String algorithm) {
 
192
 
 
193
        synchronized (syncObject) {
 
194
            if(caTop == null ) {
 
195
                return false;
 
196
            }
 
197
            if(!isTrustedSignatureAlgorithm(algorithm)) {
 
198
                return false;
 
199
            }
 
200
 
 
201
            X509Certificate[] chain = new X509Certificate[2];
 
202
 
 
203
            chain[0] = getUserCert(username);
 
204
 
 
205
            if (chain[0] == null) {
 
206
                return false;
 
207
            }
 
208
 
 
209
            try {
 
210
                chain[1] = getCACertificate();
 
211
            } catch (CertificateException ex) {
 
212
                log.log(Level.FINE, "Can not get CA certificate", ex);
 
213
                return false;
 
214
            }
 
215
 
 
216
            try {
 
217
                checkClientTrusted(chain, "RSA");
 
218
            } catch (CertificateException ex) {
 
219
                log.log(Level.FINE, "user certificate is not trusted", ex);
 
220
                return false;
 
221
            }
 
222
 
 
223
            try {
 
224
                Signature s = Signature.getInstance(algorithm);
 
225
                s.initVerify(chain[0]);
 
226
                s.update(message);
 
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});
 
231
                lr.setThrown(ex);
 
232
                log.log(lr);
 
233
                return false;
 
234
            }
 
235
        }
 
236
    }    
 
237
    
 
238
        
 
239
    private X509TrustManager getTrustManager() throws CertificateException {
 
240
        log.entering("GECATrustManager", "getTrustManager");
 
241
        X509TrustManager ret = null;
 
242
        synchronized(syncObject) {
 
243
            reinit();
 
244
            ret = trustManager;
 
245
        }
 
246
        log.exiting("GECATrustManager", "getTrustManager", ret);
 
247
        return ret;
 
248
    }
 
249
    
 
250
    private X509Certificate getCACertificate() throws CertificateException {
 
251
        log.entering("GECATrustManager", "getCACertificate");
 
252
        X509Certificate ret = null;
 
253
        synchronized(syncObject) {
 
254
            reinit();
 
255
            ret = caCertificate;
 
256
        }
 
257
        log.exiting("GECATrustManager", "getCACertificate", ret);
 
258
        return ret;
 
259
    }
 
260
        
 
261
        
 
262
    private void reinit() throws CertificateException {
 
263
        log.entering("GECATrustManager", "reinit");
 
264
        if(caTop == null) {
 
265
            throw new CertificateException("caTop not set");
 
266
        }
 
267
        File caCertFile = new File(caTop, "cacert.pem");
 
268
        File caCrlFile = new File(caTop, "ca-crl.pem");
 
269
 
 
270
        if (trustManager == null || lastUpdate < caCertFile.lastModified() || lastUpdate < caCrlFile.lastModified()) {
 
271
            long alastUpdate = System.currentTimeMillis();
 
272
            init(caCertFile, caCrlFile);
 
273
            this.lastUpdate = alastUpdate;
 
274
        }
 
275
        log.exiting("GECATrustManager", "reinit");
 
276
    }
 
277
 
 
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 });
 
281
        }
 
282
 
 
283
        try {
 
284
            // Initialize an new empty keystore
 
285
            KeyStore ks  = KeyStore.getInstance(KeyStore.getDefaultType());
 
286
            ks.load(null, new char[0]);
 
287
 
 
288
            log.log(Level.FINE, "read ca certificate from {0}", caCertFile);
 
289
            CertificateFactory certFac = CertificateFactory.getInstance("X.509");
 
290
 
 
291
            InputStream in = new FileInputStream(caCertFile);
 
292
 
 
293
            try {
 
294
                X509Certificate cert = (X509Certificate)certFac.generateCertificate(in);
 
295
                ks.setCertificateEntry(CA_ALIAS, cert);
 
296
                caCertificate = cert;
 
297
            } finally {
 
298
                try {
 
299
                    in.close();
 
300
                } catch(IOException ioe) {
 
301
                    // Ignore
 
302
                }
 
303
            }
 
304
 
 
305
            PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(ks, new X509CertSelector());
 
306
 
 
307
            if (caCrlFile.exists()) {
 
308
                log.log(Level.FINE, "read certificate revocation list from {0}", caCrlFile);
 
309
                in = new FileInputStream(caCrlFile);
 
310
 
 
311
                try {
 
312
                    Collection crls = certFac.generateCRLs(in);
 
313
 
 
314
                    CollectionCertStoreParameters certStoreParams = new CollectionCertStoreParameters(crls);
 
315
                    CertStore certStore = CertStore.getInstance("Collection", certStoreParams);
 
316
 
 
317
                    pkixParams.setRevocationEnabled(true);
 
318
                    pkixParams.addCertStore(certStore);
 
319
                } finally {
 
320
                    try {
 
321
                        in.close();
 
322
                    } catch(IOException ioe) {
 
323
                        // Ignore
 
324
                    }
 
325
                }
 
326
            } else {
 
327
                // crl file does not exists, disable revocation
 
328
                pkixParams.setRevocationEnabled(false);
 
329
            }
 
330
 
 
331
            // Wrap them as trust manager parameters
 
332
            ManagerFactoryParameters trustParams = new CertPathTrustManagerParameters(pkixParams);
 
333
            TrustManagerFactory fac = TrustManagerFactory.getInstance("PKIX");
 
334
 
 
335
            fac.init(trustParams);
 
336
 
 
337
            trustManager = null;
 
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];
 
342
                    break;
 
343
                }
 
344
            }
 
345
 
 
346
            if (trustManager == null) {
 
347
                // This should never happen since we handle only X509 certificates
 
348
                throw new CertificateException("Found no X509TrustManager");
 
349
            }
 
350
 
 
351
 
 
352
 
 
353
        } catch (NoSuchAlgorithmException ex) {
 
354
            CertificateException cae = new CertificateException("Certificate algorithm is unknown", ex);
 
355
            log.throwing("GECATrustManager", "init", cae);
 
356
            throw cae;
 
357
        } catch (InvalidAlgorithmParameterException ex) {
 
358
            CertificateException cae = new CertificateException("Invalid parameters for crypte algorithms", ex);
 
359
            log.throwing("GECATrustManager", "init", cae);
 
360
            throw cae;
 
361
        } catch(KeyStoreException ex) {
 
362
            CertificateException cae = new CertificateException("Cannot create keystore for ca certificate", ex);
 
363
            log.throwing("GECATrustManager", "init", cae);
 
364
            throw 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);
 
368
            throw cae;
 
369
        } catch(CRLException ex) {
 
370
            CertificateException cae = new CertificateException("Error in crl file", ex);
 
371
            log.throwing("SgeCATrustManager", "init", ex);
 
372
            throw cae;
 
373
        }
 
374
        log.exiting("GECATrustManager", "init");
 
375
    }
 
376
    
 
377
    /**
 
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.
 
382
     *
 
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.
 
386
     *
 
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.
 
394
     */
 
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 });
 
398
        }
 
399
        getTrustManager().checkClientTrusted(chain, authType);
 
400
        log.exiting("GECATrustManager", "checkClientTrusted");
 
401
    }
 
402
    
 
403
    /**
 
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.
 
408
     *
 
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.
 
417
     *
 
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.
 
425
     */
 
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 });
 
429
        }
 
430
        getTrustManager().checkServerTrusted(chain, authType);
 
431
        log.exiting("GECATrustManager", "checkServerTrusted");
 
432
    }
 
433
    
 
434
    /**
 
435
     * Return an array of certificate authority certificates
 
436
     * which are trusted for authenticating peers.
 
437
     *
 
438
     * @return a non-null (possibly empty) array of acceptable
 
439
     *          CA issuer certificates.
 
440
     */
 
441
    public X509Certificate[] getAcceptedIssuers() {
 
442
        log.entering("GECATrustManager", "getAcceptedIssuers");
 
443
        X509Certificate[] ret = null;
 
444
        try {
 
445
            ret = getTrustManager().getAcceptedIssuers();
 
446
        } catch(CertificateException ex) {
 
447
            ret = new X509Certificate[0];
 
448
        }
 
449
        log.exiting("GECATrustManager", "getAcceptedIssuers", ret);
 
450
        return ret;
 
451
    }
 
452
    
 
453
    
 
454
}