blob: 9b065be8564b4f53e4c13e1db42469fd6b06390a [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.security.provider.certpath;
27
28import java.util.Collection;
29import java.util.Collections;
30import java.util.Set;
31import java.util.HashSet;
32import java.io.IOException;
33import java.security.cert.Certificate;
34import java.security.cert.CertificateException;
35import java.security.cert.X509Certificate;
36import java.security.cert.PKIXCertPathChecker;
37import java.security.cert.CertPathValidatorException;
38import sun.security.util.Debug;
39import sun.security.x509.PKIXExtensions;
40import sun.security.x509.NameConstraintsExtension;
41import sun.security.x509.X509CertImpl;
42
43/**
44 * ConstraintsChecker is a <code>PKIXCertPathChecker</code> that checks
45 * constraints information on a PKIX certificate, namely basic constraints
46 * and name constraints.
47 *
48 * @since 1.4
49 * @author Yassir Elley
50 */
51class ConstraintsChecker extends PKIXCertPathChecker {
52
53 private static final Debug debug = Debug.getInstance("certpath");
54 /* length of cert path */
55 private final int certPathLength;
56 /* current maximum path length (as defined in PKIX) */
57 private int maxPathLength;
58 /* current index of cert */
59 private int i;
60 private NameConstraintsExtension prevNC;
61
62 private static Set<String> supportedExts;
63
64 /**
65 * Creates a ConstraintsChecker.
66 *
67 * @param certPathLength the length of the certification path
68 * @throws CertPathValidatorException if the checker cannot be initialized
69 */
70 ConstraintsChecker(int certPathLength) throws CertPathValidatorException {
71 this.certPathLength = certPathLength;
72 init(false);
73 }
74
75 public void init(boolean forward) throws CertPathValidatorException {
76 if (!forward) {
77 i = 0;
78 maxPathLength = certPathLength;
79 prevNC = null;
80 } else {
81 throw new CertPathValidatorException
82 ("forward checking not supported");
83 }
84 }
85
86 public boolean isForwardCheckingSupported() {
87 return false;
88 }
89
90 public Set<String> getSupportedExtensions() {
91 if (supportedExts == null) {
92 supportedExts = new HashSet<String>();
93 supportedExts.add(PKIXExtensions.BasicConstraints_Id.toString());
94 supportedExts.add(PKIXExtensions.NameConstraints_Id.toString());
95 supportedExts = Collections.unmodifiableSet(supportedExts);
96 }
97 return supportedExts;
98 }
99
100 /**
101 * Performs the basic constraints and name constraints
102 * checks on the certificate using its internal state.
103 *
104 * @param cert the <code>Certificate</code> to be checked
105 * @param unresCritExts a <code>Collection</code> of OID strings
106 * representing the current set of unresolved critical extensions
107 * @throws CertPathValidatorException if the specified certificate
108 * does not pass the check
109 */
110 public void check(Certificate cert, Collection<String> unresCritExts)
111 throws CertPathValidatorException
112 {
113 X509Certificate currCert = (X509Certificate) cert;
114
115 i++;
116 // MUST run NC check second, since it depends on BC check to
117 // update remainingCerts
118 checkBasicConstraints(currCert);
119 verifyNameConstraints(currCert);
120
121 if (unresCritExts != null && !unresCritExts.isEmpty()) {
122 unresCritExts.remove(PKIXExtensions.BasicConstraints_Id.toString());
123 unresCritExts.remove(PKIXExtensions.NameConstraints_Id.toString());
124 }
125 }
126
127 /**
128 * Internal method to check the name constraints against a cert
129 */
130 private void verifyNameConstraints(X509Certificate currCert)
131 throws CertPathValidatorException
132 {
133 String msg = "name constraints";
134 if (debug != null) {
135 debug.println("---checking " + msg + "...");
136 }
137
138 // check name constraints only if there is a previous name constraint
139 // and either the currCert is the final cert or the currCert is not
140 // self-issued
141 if (prevNC != null && ((i == certPathLength) ||
142 !X509CertImpl.isSelfIssued(currCert))) {
143 if (debug != null) {
144 debug.println("prevNC = " + prevNC);
145 debug.println("currDN = " + currCert.getSubjectX500Principal());
146 }
147
148 try {
149 if (!prevNC.verify(currCert)) {
150 throw new CertPathValidatorException(msg + " check failed");
151 }
152 } catch (IOException ioe) {
153 throw new CertPathValidatorException(ioe);
154 }
155 }
156
157 // merge name constraints regardless of whether cert is self-issued
158 prevNC = mergeNameConstraints(currCert, prevNC);
159
160 if (debug != null)
161 debug.println(msg + " verified.");
162 }
163
164 /**
165 * Helper to fold sets of name constraints together
166 */
167 static NameConstraintsExtension
168 mergeNameConstraints(X509Certificate currCert,
169 NameConstraintsExtension prevNC) throws CertPathValidatorException
170 {
171 X509CertImpl currCertImpl;
172 try {
173 currCertImpl = X509CertImpl.toImpl(currCert);
174 } catch (CertificateException ce) {
175 throw new CertPathValidatorException(ce);
176 }
177
178 NameConstraintsExtension newConstraints =
179 currCertImpl.getNameConstraintsExtension();
180
181 if (debug != null) {
182 debug.println("prevNC = " + prevNC);
183 debug.println("newNC = " + String.valueOf(newConstraints));
184 }
185
186 // if there are no previous name constraints, we just return the
187 // new name constraints.
188 if (prevNC == null) {
189 if (debug != null) {
190 debug.println("mergedNC = " + String.valueOf(newConstraints));
191 }
192 if (newConstraints == null) {
193 return newConstraints;
194 } else {
195 // Make sure we do a clone here, because we're probably
196 // going to modify this object later and we don't want to
197 // be sharing it with a Certificate object!
198 return (NameConstraintsExtension) newConstraints.clone();
199 }
200 } else {
201 try {
202 // after merge, prevNC should contain the merged constraints
203 prevNC.merge(newConstraints);
204 } catch (IOException ioe) {
205 throw new CertPathValidatorException(ioe);
206 }
207 if (debug != null) {
208 debug.println("mergedNC = " + prevNC);
209 }
210 return prevNC;
211 }
212 }
213
214 /**
215 * Internal method to check that a given cert meets basic constraints.
216 */
217 private void checkBasicConstraints(X509Certificate currCert)
218 throws CertPathValidatorException
219 {
220 String msg = "basic constraints";
221 if (debug != null) {
222 debug.println("---checking " + msg + "...");
223 debug.println("i = " + i);
224 debug.println("maxPathLength = " + maxPathLength);
225 }
226
227 /* check if intermediate cert */
228 if (i < certPathLength) {
229 int pathLenConstraint = currCert.getBasicConstraints();
230 if (pathLenConstraint == -1) {
231 throw new CertPathValidatorException(msg + " check failed: "
232 + "this is not a CA certificate");
233 }
234
235 if (!X509CertImpl.isSelfIssued(currCert)) {
236 if (maxPathLength <= 0) {
237 throw new CertPathValidatorException
238 (msg + " check failed: pathLenConstraint violated - "
239 + "this cert must be the last cert in the "
240 + "certification path");
241 }
242 maxPathLength--;
243 }
244 if (pathLenConstraint < maxPathLength)
245 maxPathLength = pathLenConstraint;
246 }
247
248 if (debug != null) {
249 debug.println("after processing, maxPathLength = " + maxPathLength);
250 debug.println(msg + " verified.");
251 }
252 }
253
254 /**
255 * Merges the specified maxPathLength with the pathLenConstraint
256 * obtained from the certificate.
257 *
258 * @param cert the <code>X509Certificate</code>
259 * @param maxPathLength the previous maximum path length
260 * @return the new maximum path length constraint (-1 means no more
261 * certificates can follow, Integer.MAX_VALUE means path length is
262 * unconstrained)
263 */
264 static int mergeBasicConstraints(X509Certificate cert, int maxPathLength) {
265
266 int pathLenConstraint = cert.getBasicConstraints();
267
268 if (!X509CertImpl.isSelfIssued(cert)) {
269 maxPathLength--;
270 }
271
272 if (pathLenConstraint < maxPathLength) {
273 maxPathLength = pathLenConstraint;
274 }
275
276 return maxPathLength;
277 }
278}