Home | History | Annotate | Download | only in certpath
      1 /*
      2  * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package sun.security.provider.certpath;
     27 
     28 import java.io.IOException;
     29 import java.util.Date;
     30 
     31 import java.security.cert.Certificate;
     32 import java.security.cert.X509Certificate;
     33 import java.security.cert.X509CertSelector;
     34 import java.security.cert.CertificateException;
     35 
     36 import sun.security.util.DerOutputStream;
     37 import sun.security.x509.SerialNumber;
     38 import sun.security.x509.KeyIdentifier;
     39 import sun.security.x509.AuthorityKeyIdentifierExtension;
     40 
     41 /**
     42  * An adaptable X509 certificate selector for forward certification path
     43  * building.
     44  *
     45  * @since 1.7
     46  */
     47 class AdaptableX509CertSelector extends X509CertSelector {
     48     // The start date of a validity period.
     49     private Date startDate;
     50 
     51     // The end date of a validity period.
     52     private Date endDate;
     53 
     54     // Is subject key identifier sensitive?
     55     private boolean isSKIDSensitive = false;
     56 
     57     // Is serial number sensitive?
     58     private boolean isSNSensitive = false;
     59 
     60     AdaptableX509CertSelector() {
     61         super();
     62     }
     63 
     64     /**
     65      * Sets the criterion of the X509Certificate validity period.
     66      *
     67      * Normally, we may not have to check that a certificate validity period
     68      * must fall within its issuer's certificate validity period. However,
     69      * when we face root CA key updates for version 1 certificates, according
     70      * to scheme of RFC 4210 or 2510, the validity periods should be checked
     71      * to determine the right issuer's certificate.
     72      *
     73      * Conservatively, we will only check the validity periods for version
     74      * 1 and version 2 certificates. For version 3 certificates, we can
     75      * determine the right issuer by authority and subject key identifier
     76      * extensions.
     77      *
     78      * @param startDate the start date of a validity period that must fall
     79      *        within the certificate validity period for the X509Certificate
     80      * @param endDate the end date of a validity period that must fall
     81      *        within the certificate validity period for the X509Certificate
     82      */
     83     void setValidityPeriod(Date startDate, Date endDate) {
     84         this.startDate = startDate;
     85         this.endDate = endDate;
     86     }
     87 
     88     /**
     89      * Parse the authority key identifier extension.
     90      *
     91      * If the keyIdentifier field of the extension is non-null, set the
     92      * subjectKeyIdentifier criterion. If the authorityCertSerialNumber
     93      * field is non-null, set the serialNumber criterion.
     94      *
     95      * Note that we will not set the subject criterion according to the
     96      * authorityCertIssuer field of the extension. The caller MUST set
     97      * the subject criterion before call match().
     98      *
     99      * @param akidext the authorityKeyIdentifier extension
    100      */
    101     void parseAuthorityKeyIdentifierExtension(
    102             AuthorityKeyIdentifierExtension akidext) throws IOException {
    103         if (akidext != null) {
    104             KeyIdentifier akid = (KeyIdentifier)akidext.get(
    105                     AuthorityKeyIdentifierExtension.KEY_ID);
    106             if (akid != null) {
    107                 // Do not override the previous setting for initial selection.
    108                 if (isSKIDSensitive || getSubjectKeyIdentifier() == null) {
    109                     DerOutputStream derout = new DerOutputStream();
    110                     derout.putOctetString(akid.getIdentifier());
    111                     super.setSubjectKeyIdentifier(derout.toByteArray());
    112 
    113                     isSKIDSensitive = true;
    114                 }
    115             }
    116 
    117             SerialNumber asn = (SerialNumber)akidext.get(
    118                     AuthorityKeyIdentifierExtension.SERIAL_NUMBER);
    119             if (asn != null) {
    120                 // Do not override the previous setting for initial selection.
    121                 if (isSNSensitive || getSerialNumber() == null) {
    122                     super.setSerialNumber(asn.getNumber());
    123                     isSNSensitive = true;
    124                 }
    125             }
    126 
    127             // the subject criterion should be set by the caller.
    128         }
    129     }
    130 
    131     /**
    132      * Decides whether a <code>Certificate</code> should be selected.
    133      *
    134      * For the purpose of compatibility, when a certificate is of
    135      * version 1 and version 2, or the certificate does not include
    136      * a subject key identifier extension, the selection criterion
    137      * of subjectKeyIdentifier will be disabled.
    138      */
    139     @Override
    140     public boolean match(Certificate cert) {
    141         if (!(cert instanceof X509Certificate)) {
    142             return false;
    143         }
    144 
    145         X509Certificate xcert = (X509Certificate)cert;
    146         int version = xcert.getVersion();
    147 
    148         // Check the validity period for version 1 and 2 certificate.
    149         if (version < 3) {
    150             if (startDate != null) {
    151                 try {
    152                     xcert.checkValidity(startDate);
    153                 } catch (CertificateException ce) {
    154                     return false;
    155                 }
    156             }
    157 
    158             if (endDate != null) {
    159                 try {
    160                     xcert.checkValidity(endDate);
    161                 } catch (CertificateException ce) {
    162                     return false;
    163                 }
    164             }
    165         }
    166 
    167         // If no SubjectKeyIdentifier extension, don't bother to check it.
    168         if (isSKIDSensitive &&
    169             (version < 3 || xcert.getExtensionValue("2.5.29.14") == null)) {
    170             setSubjectKeyIdentifier(null);
    171         }
    172 
    173         // In practice, a CA may replace its root certificate and require that
    174         // the existing certificate is still valid, even if the AKID extension
    175         // does not match the replacement root certificate fields.
    176         //
    177         // Conservatively, we only support the replacement for version 1 and
    178         // version 2 certificate. As for version 2, the certificate extension
    179         // may contain sensitive information (for example, policies), the
    180         // AKID need to be respected to seek the exact certificate in case
    181         // of key or certificate abuse.
    182         if (isSNSensitive && version < 3) {
    183             setSerialNumber(null);
    184         }
    185 
    186         return super.match(cert);
    187     }
    188 
    189     @Override
    190     public Object clone() {
    191         AdaptableX509CertSelector copy =
    192                         (AdaptableX509CertSelector)super.clone();
    193         if (startDate != null) {
    194             copy.startDate = (Date)startDate.clone();
    195         }
    196 
    197         if (endDate != null) {
    198             copy.endDate = (Date)endDate.clone();
    199         }
    200 
    201         return copy;
    202     }
    203 }
    204