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