View Javadoc

1   /*
2    * The MIT License
3    *
4    * Original work sponsored and donated by National Board of e-Health (NSI), Denmark (http://www.nsi.dk)
5    *
6    * Copyright (C) 2011 National Board of e-Health (NSI), Denmark (http://www.nsi.dk)
7    *
8    * Permission is hereby granted, free of charge, to any person obtaining a copy of
9    * this software and associated documentation files (the "Software"), to deal in
10   * the Software without restriction, including without limitation the rights to
11   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12   * of the Software, and to permit persons to whom the Software is furnished to do
13   * so, subject to the following conditions:
14   *
15   * The above copyright notice and this permission notice shall be included in all
16   * copies or substantial portions of the Software.
17   *
18   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24   * SOFTWARE.
25   *
26   * $HeadURL: https://svn.softwareborsen.dk/sosi/trunk/modules/seal/src/main/java/dk/sosi/seal/pki/AbstractOCESCertificationAuthority.java $
27   * $Id: AbstractOCESCertificationAuthority.java 8697 2011-09-02 10:33:55Z chg@lakeside.dk $
28   */
29  package dk.sosi.seal.pki;
30  
31  import java.security.cert.X509Certificate;
32  
33  /**
34   * Abstract implementation of the CertificationAuthority interface.
35   *
36   * @author ads@lakeside.dk
37   * @author $LastChangedBy: chg@lakeside.dk $
38   * @version $Revision: 8697 $
39   * @since 2.0
40   */
41  public abstract class AbstractOCESCertificationAuthority implements CertificationAuthority {
42  
43      private final CertificateStatusChecker certificateStatusChecker;
44      private final IntermediateCertificateCache intermediateCertificateCache;
45      private final FederationCertificateResolver federationCertificateResolver;
46      private final AuditEventHandler eventHandler;
47  
48      protected AbstractOCESCertificationAuthority(SOSIConfiguration configuration,
49                                                   CertificateStatusChecker certificateStatusChecker, IntermediateCertificateCache intermediateCertificateCache, FederationCertificateResolver federationCertificateResolver) {
50          configuration.verify();
51          if (certificateStatusChecker == null) throw new IllegalArgumentException("'certificateStatusChecker' cannot be null");
52          if (intermediateCertificateCache == null) throw new IllegalArgumentException("'intermediateCertificateCache' cannot be null");
53  
54          this.eventHandler = configuration.getAuditEventHandler();
55  
56          this.certificateStatusChecker = certificateStatusChecker;
57          this.intermediateCertificateCache = intermediateCertificateCache;
58          this.federationCertificateResolver = federationCertificateResolver;
59      }
60  
61      public final boolean isValid(X509Certificate certificate) throws PKIException {
62          return getCertificateStatus(certificate).isValid();
63      }
64  
65      public CertificateStatus getCertificateStatus(final X509Certificate cert) throws PKIException {
66          CertificateStatus certificateStatus;
67          if (checkDates(cert)) {
68              if (!(OCESUtil.isOCES1Certificate(cert) && OCESUtil.isIssuerOf(cert, getOCES1RootCertificate()) || OCESUtil.isOCES2Certificate(cert) && OCESUtil.isIssuerOf(cert, getAndValidateIntermediateCertificate(cert)))) {
69                  throw new PKIException("The supplied certificate is not a " + getCertificationAuthorityName() + " certificate");
70              }
71              certificateStatus = checkRevocation(cert);
72          } else {
73              certificateStatus = new CertificateStatus(false, null);
74          }
75          auditLogCertificationStatus(certificateStatus, cert);
76          return certificateStatus;
77      }
78  
79      private void auditLogCertificationStatus(CertificateStatus certificateStatus, Object certificate) {
80          if (certificateStatus.isValid()) {
81              eventHandler.onInformationalAuditingEvent(AuditEventHandler.EVENT_TYPE_INFO_CERTIFICATE_VALIDATED, new Object[]{certificate});
82          } else {
83              eventHandler.onErrorAuditingEvent(AuditEventHandler.EVENT_TYPE_ERROR_VALIDATING_CERTIFICATE, new Object[]{certificate});
84          }
85      }
86  
87      protected abstract X509Certificate getOCES1RootCertificate();
88  
89      //protected abstract X509Certificate getOCES2RootCertificate();
90  
91      // Temporary method - revert to the above when we no longer have to support to root certs in Test (IG- and PP-environment)
92      protected abstract X509Certificate[] getOCES2RootCertificates();
93  
94      protected abstract String getCertificationAuthorityName();
95  
96      private boolean checkDates(X509Certificate certificate) {
97          if (certificate.getNotAfter().getTime() < System.currentTimeMillis()) {
98              return false; // Certificate is expired
99          } else if (certificate.getNotBefore().getTime() > System.currentTimeMillis()) {
100             return false; // Certificate is not yet valid
101         }
102         return true;
103     }
104 
105     private X509Certificate getAndValidateIntermediateCertificate(X509Certificate certificate) throws PKIException {
106         X509Certificate intermediateCertificate = intermediateCertificateCache.getCertificate(OCESUtil.retrieveIntermediateCertificateURI(certificate));
107 
108         if (!checkDates(intermediateCertificate)) {
109             throw new PKIException("Intermediate certificate not valid in time");
110         }
111         boolean isIssuedByRoot = false;
112         for (X509Certificate rootCertificate : getOCES2RootCertificates()) {
113             isIssuedByRoot = OCESUtil.isIssuerOf(intermediateCertificate, rootCertificate);
114             if (isIssuedByRoot) break;
115         }
116         if (!isIssuedByRoot) throw new PKIException("Intermediate certificate not issued by " + getCertificationAuthorityName() + " root certificate");
117 //        if (!OCESUtil.isIssuerOf(intermediateCertificate, getOCES2RootCertificate())) {
118 //            throw new PKIException("Intermediate certificate not issued by " + getCertificationAuthorityName() + " root certificate");
119 //        }
120         if (!checkRevocation(intermediateCertificate).isValid()) {
121             throw new PKIException("Intermediate certificate is revoked");
122         }
123         return intermediateCertificate;
124     }
125 
126     private CertificateStatus checkRevocation(X509Certificate certificate) {
127         try {
128             return certificateStatusChecker.getRevocationStatus(certificate);
129         } catch (PKIException e) {
130             eventHandler.onWarningAuditingEvent(e.getMessage(), null);
131             throw e;
132         }
133     }
134 
135     public X509Certificate getFederationCertificate(FederationCertificateReference reference) {
136         return federationCertificateResolver.getFederationCertificate(reference);
137     }
138 
139 }