blob: e4f7d1f3d74ca52d67755b83a6a2a1142f399777 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2007 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.math.BigInteger;
29import java.util.Collection;
30import java.util.Date;
31import java.util.Set;
32import java.security.KeyFactory;
33import java.security.PublicKey;
34import java.security.cert.Certificate;
35import java.security.cert.X509Certificate;
36import java.security.cert.PKIXCertPathChecker;
37import java.security.cert.CertPathValidatorException;
38import java.security.cert.TrustAnchor;
39import java.security.interfaces.DSAParams;
40import java.security.interfaces.DSAPublicKey;
41import java.security.spec.DSAPublicKeySpec;
42import javax.security.auth.x500.X500Principal;
43import sun.security.x509.X500Name;
44import sun.security.util.Debug;
45
46/**
47 * BasicChecker is a PKIXCertPathChecker that checks the basic information
48 * on a PKIX certificate, namely the signature, timestamp, and subject/issuer
49 * name chaining.
50 *
51 * @since 1.4
52 * @author Yassir Elley
53 */
54class BasicChecker extends PKIXCertPathChecker {
55
56 private static final Debug debug = Debug.getInstance("certpath");
57 private final PublicKey trustedPubKey;
58 private final X500Principal caName;
59 private final Date testDate;
60 private final String sigProvider;
61 private final boolean sigOnly;
62 private X500Principal prevSubject;
63 private PublicKey prevPubKey;
64
65 /**
66 * Constructor that initializes the input parameters.
67 *
68 * @param anchor the anchor selected to validate the target certificate
69 * @param testDate the time for which the validity of the certificate
70 * should be determined
71 * @param sigProvider the name of the signature provider
72 * @param sigOnly true if only signature checking is to be done;
73 * if false, all checks are done
74 */
75 BasicChecker(TrustAnchor anchor, Date testDate, String sigProvider,
76 boolean sigOnly) throws CertPathValidatorException
77 {
78 if (anchor.getTrustedCert() != null) {
79 this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
80 this.caName = anchor.getTrustedCert().getSubjectX500Principal();
81 } else {
82 this.trustedPubKey = anchor.getCAPublicKey();
83 this.caName = anchor.getCA();
84 }
85 this.testDate = testDate;
86 this.sigProvider = sigProvider;
87 this.sigOnly = sigOnly;
88 init(false);
89 }
90
91 /**
92 * Initializes the internal state of the checker from parameters
93 * specified in the constructor.
94 */
95 public void init(boolean forward) throws CertPathValidatorException {
96 if (!forward) {
97 prevPubKey = trustedPubKey;
98 prevSubject = caName;
99 } else {
100 throw new
101 CertPathValidatorException("forward checking not supported");
102 }
103 }
104
105 public boolean isForwardCheckingSupported() {
106 return false;
107 }
108
109 public Set<String> getSupportedExtensions() {
110 return null;
111 }
112
113 /**
114 * Performs the signature, timestamp, and subject/issuer name chaining
115 * checks on the certificate using its internal state. This method does
116 * not remove any critical extensions from the Collection.
117 *
118 * @param cert the Certificate
119 * @param unresolvedCritExts a Collection of the unresolved critical
120 * extensions
121 * @exception CertPathValidatorException Exception thrown if certificate
122 * does not verify.
123 */
124 public void check(Certificate cert, Collection<String> unresolvedCritExts)
125 throws CertPathValidatorException
126 {
127 X509Certificate currCert = (X509Certificate) cert;
128
129 if (!sigOnly) {
130 verifyTimestamp(currCert, testDate);
131 verifyNameChaining(currCert, prevSubject);
132 }
133 verifySignature(currCert, prevPubKey, sigProvider);
134
135 updateState(currCert);
136 }
137
138 /**
139 * Verifies the signature on the certificate using the previous public key
140 * @param cert the Certificate
141 * @param prevPubKey the previous PublicKey
142 * @param sigProvider a String containing the signature provider
143 * @exception CertPathValidatorException Exception thrown if certificate
144 * does not verify.
145 */
146 private void verifySignature(X509Certificate cert, PublicKey prevPubKey,
147 String sigProvider) throws CertPathValidatorException
148 {
149 String msg = "signature";
150 if (debug != null)
151 debug.println("---checking " + msg + "...");
152
153 try {
154 cert.verify(prevPubKey, sigProvider);
155 } catch (Exception e) {
156 if (debug != null) {
157 debug.println(e.getMessage());
158 e.printStackTrace();
159 }
160 throw new CertPathValidatorException(msg + " check failed", e);
161 }
162
163 if (debug != null)
164 debug.println(msg + " verified.");
165 }
166
167 /**
168 * Internal method to verify the timestamp on a certificate
169 */
170 private void verifyTimestamp(X509Certificate cert, Date date)
171 throws CertPathValidatorException
172 {
173 String msg = "timestamp";
174 if (debug != null)
175 debug.println("---checking " + msg + ":" + date.toString() + "...");
176
177 try {
178 cert.checkValidity(date);
179 } catch (Exception e) {
180 if (debug != null) {
181 debug.println(e.getMessage());
182 e.printStackTrace();
183 }
184 throw new CertPathValidatorException(msg + " check failed", e);
185 }
186
187 if (debug != null)
188 debug.println(msg + " verified.");
189 }
190
191 /**
192 * Internal method to check that cert has a valid DN to be next in a chain
193 */
194 private void verifyNameChaining(X509Certificate cert,
195 X500Principal prevSubject) throws CertPathValidatorException
196 {
197 if (prevSubject != null) {
198
199 String msg = "subject/issuer name chaining";
200 if (debug != null)
201 debug.println("---checking " + msg + "...");
202
203 X500Principal currIssuer = cert.getIssuerX500Principal();
204 // reject null or empty issuer DNs
205
206 if (X500Name.asX500Name(currIssuer).isEmpty()) {
207 throw new CertPathValidatorException(msg + " check failed: " +
208 "empty/null issuer DN in certificate is invalid");
209 }
210
211 if (!(currIssuer.equals(prevSubject))) {
212 throw new CertPathValidatorException(msg + " check failed");
213 }
214
215 if (debug != null)
216 debug.println(msg + " verified.");
217 }
218 }
219
220 /**
221 * Internal method to manage state information at each iteration
222 */
223 private void updateState(X509Certificate currCert)
224 throws CertPathValidatorException
225 {
226 PublicKey cKey = currCert.getPublicKey();
227 if (debug != null) {
228 debug.println("BasicChecker.updateState issuer: " +
229 currCert.getIssuerX500Principal().toString() + "; subject: " +
230 currCert.getSubjectX500Principal() + "; serial#: " +
231 currCert.getSerialNumber().toString());
232 }
233 if (cKey instanceof DSAPublicKey &&
234 ((DSAPublicKey)cKey).getParams() == null) {
235 //cKey needs to inherit DSA parameters from prev key
236 cKey = makeInheritedParamsKey(cKey, prevPubKey);
237 if (debug != null) debug.println("BasicChecker.updateState Made " +
238 "key with inherited params");
239 }
240 prevPubKey = cKey;
241 prevSubject = currCert.getSubjectX500Principal();
242 }
243
244 /**
245 * Internal method to create a new key with inherited key parameters
246 *
247 * @param keyValueKey key from which to obtain key value
248 * @param keyParamsKey key from which to obtain key parameters
249 * @return new public key having value and parameters
250 * @throws CertPathValidatorException if keys are not appropriate types
251 * for this operation
252 */
253 static PublicKey makeInheritedParamsKey(PublicKey keyValueKey,
254 PublicKey keyParamsKey) throws CertPathValidatorException
255 {
256 PublicKey usableKey;
257 if (!(keyValueKey instanceof DSAPublicKey) ||
258 !(keyParamsKey instanceof DSAPublicKey))
259 throw new CertPathValidatorException("Input key is not " +
260 "appropriate type for " +
261 "inheriting parameters");
262 DSAParams params = ((DSAPublicKey)keyParamsKey).getParams();
263 if (params == null)
264 throw new CertPathValidatorException("Key parameters missing");
265 try {
266 BigInteger y = ((DSAPublicKey)keyValueKey).getY();
267 KeyFactory kf = KeyFactory.getInstance("DSA");
268 DSAPublicKeySpec ks = new DSAPublicKeySpec(y,
269 params.getP(),
270 params.getQ(),
271 params.getG());
272 usableKey = kf.generatePublic(ks);
273 } catch (Exception e) {
274 throw new CertPathValidatorException("Unable to generate key with" +
275 " inherited parameters: " +
276 e.getMessage(), e);
277 }
278 return usableKey;
279 }
280
281 /**
282 * return the public key associated with the last certificate processed
283 *
284 * @return PublicKey the last public key processed
285 */
286 PublicKey getPublicKey() {
287 return prevPubKey;
288 }
289}