author | ascarpino |
Wed, 08 Feb 2017 12:08:28 -0800 | |
changeset 43701 | fe8c324ba97c |
parent 42464 | 38d967704a9f |
child 44158 | 49deb8a1ed3f |
permissions | -rw-r--r-- |
2 | 1 |
/* |
43701
fe8c324ba97c
8160655: Fix denyAfter and usage types for security properties
ascarpino
parents:
42464
diff
changeset
|
2 |
* Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 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 |
* |
|
5506 | 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. |
|
2 | 24 |
*/ |
25 |
||
26 |
package sun.security.validator; |
|
27 |
||
28 |
import java.io.IOException; |
|
29 |
import java.util.*; |
|
30 |
||
31 |
import java.security.*; |
|
32 |
import java.security.cert.*; |
|
33 |
||
34 |
import javax.security.auth.x500.X500Principal; |
|
35 |
||
36 |
import sun.security.x509.X509CertImpl; |
|
42464 | 37 |
import sun.security.x509.KeyIdentifier; |
2 | 38 |
import sun.security.x509.NetscapeCertTypeExtension; |
39 |
import sun.security.util.DerValue; |
|
40 |
import sun.security.util.DerInputStream; |
|
41 |
import sun.security.util.ObjectIdentifier; |
|
42 |
||
4190 | 43 |
import sun.security.provider.certpath.AlgorithmChecker; |
11900 | 44 |
import sun.security.provider.certpath.UntrustedChecker; |
4190 | 45 |
|
2 | 46 |
/** |
47 |
* A simple validator implementation. It is based on code from the JSSE |
|
48 |
* X509TrustManagerImpl. This implementation is designed for compatibility with |
|
49 |
* deployed certificates and previous J2SE versions. It will never support |
|
50 |
* more advanced features and will be deemphasized in favor of the PKIX |
|
51 |
* validator going forward. |
|
7040
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
52 |
* <p> |
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
53 |
* {@code SimpleValidator} objects are immutable once they have been created. |
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
54 |
* Please DO NOT add methods that can change the state of an instance once |
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
55 |
* it has been created. |
2 | 56 |
* |
57 |
* @author Andreas Sterbenz |
|
58 |
*/ |
|
59 |
public final class SimpleValidator extends Validator { |
|
60 |
||
61 |
// Constants for the OIDs we need |
|
62 |
||
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
32032
diff
changeset
|
63 |
static final String OID_BASIC_CONSTRAINTS = "2.5.29.19"; |
2 | 64 |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
32032
diff
changeset
|
65 |
static final String OID_NETSCAPE_CERT_TYPE = "2.16.840.1.113730.1.1"; |
2 | 66 |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
32032
diff
changeset
|
67 |
static final String OID_KEY_USAGE = "2.5.29.15"; |
2 | 68 |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
32032
diff
changeset
|
69 |
static final String OID_EXTENDED_KEY_USAGE = "2.5.29.37"; |
2 | 70 |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
32032
diff
changeset
|
71 |
static final String OID_EKU_ANY_USAGE = "2.5.29.37.0"; |
2 | 72 |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
32032
diff
changeset
|
73 |
static final ObjectIdentifier OBJID_NETSCAPE_CERT_TYPE = |
2 | 74 |
NetscapeCertTypeExtension.NetscapeCertType_Id; |
75 |
||
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
32032
diff
changeset
|
76 |
private static final String NSCT_SSL_CA = |
2 | 77 |
NetscapeCertTypeExtension.SSL_CA; |
78 |
||
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
32032
diff
changeset
|
79 |
private static final String NSCT_CODE_SIGNING_CA = |
2 | 80 |
NetscapeCertTypeExtension.OBJECT_SIGNING_CA; |
81 |
||
82 |
/** |
|
83 |
* The trusted certificates as: |
|
84 |
* Map (X500Principal)subject of trusted cert -> List of X509Certificate |
|
85 |
* The list is used because there may be multiple certificates |
|
86 |
* with an identical subject DN. |
|
87 |
*/ |
|
7040
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
88 |
private final Map<X500Principal, List<X509Certificate>> |
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
89 |
trustedX500Principals; |
2 | 90 |
|
91 |
/** |
|
92 |
* Set of the trusted certificates. Present only for |
|
93 |
* getTrustedCertificates(). |
|
94 |
*/ |
|
7040
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
95 |
private final Collection<X509Certificate> trustedCerts; |
2 | 96 |
|
97 |
SimpleValidator(String variant, Collection<X509Certificate> trustedCerts) { |
|
98 |
super(TYPE_SIMPLE, variant); |
|
99 |
this.trustedCerts = trustedCerts; |
|
100 |
trustedX500Principals = |
|
101 |
new HashMap<X500Principal, List<X509Certificate>>(); |
|
102 |
for (X509Certificate cert : trustedCerts) { |
|
103 |
X500Principal principal = cert.getSubjectX500Principal(); |
|
104 |
List<X509Certificate> list = trustedX500Principals.get(principal); |
|
105 |
if (list == null) { |
|
106 |
// this actually should be a set, but duplicate entries |
|
107 |
// are not a problem and we can avoid the Set overhead |
|
108 |
list = new ArrayList<X509Certificate>(2); |
|
109 |
trustedX500Principals.put(principal, list); |
|
110 |
} |
|
111 |
list.add(cert); |
|
112 |
} |
|
113 |
} |
|
114 |
||
115 |
public Collection<X509Certificate> getTrustedCertificates() { |
|
116 |
return trustedCerts; |
|
117 |
} |
|
118 |
||
119 |
/** |
|
120 |
* Perform simple validation of chain. The arguments otherCerts and |
|
121 |
* parameter are ignored. |
|
122 |
*/ |
|
7040
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
123 |
@Override |
2 | 124 |
X509Certificate[] engineValidate(X509Certificate[] chain, |
7040
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
125 |
Collection<X509Certificate> otherCerts, |
32032 | 126 |
List<byte[]> responseList, |
7040
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
127 |
AlgorithmConstraints constraints, |
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
128 |
Object parameter) throws CertificateException { |
2 | 129 |
if ((chain == null) || (chain.length == 0)) { |
130 |
throw new CertificateException |
|
131 |
("null or zero-length certificate chain"); |
|
132 |
} |
|
133 |
||
134 |
// make sure chain includes a trusted cert |
|
135 |
chain = buildTrustedChain(chain); |
|
136 |
||
10709
d865c9f21240
7092375: Security Libraries don't build with javac -Werror
xuelei
parents:
10336
diff
changeset
|
137 |
@SuppressWarnings("deprecation") |
2 | 138 |
Date date = validationDate; |
139 |
if (date == null) { |
|
140 |
date = new Date(); |
|
141 |
} |
|
7040
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
142 |
|
11900 | 143 |
// create distrusted certificates checker |
144 |
UntrustedChecker untrustedChecker = new UntrustedChecker(); |
|
145 |
||
31688
42c9b194a469
8073894: Getting to the root of certificate chains
mullan
parents:
25859
diff
changeset
|
146 |
// check if anchor is untrusted |
42c9b194a469
8073894: Getting to the root of certificate chains
mullan
parents:
25859
diff
changeset
|
147 |
X509Certificate anchorCert = chain[chain.length - 1]; |
42c9b194a469
8073894: Getting to the root of certificate chains
mullan
parents:
25859
diff
changeset
|
148 |
try { |
42c9b194a469
8073894: Getting to the root of certificate chains
mullan
parents:
25859
diff
changeset
|
149 |
untrustedChecker.check(anchorCert); |
42c9b194a469
8073894: Getting to the root of certificate chains
mullan
parents:
25859
diff
changeset
|
150 |
} catch (CertPathValidatorException cpve) { |
42c9b194a469
8073894: Getting to the root of certificate chains
mullan
parents:
25859
diff
changeset
|
151 |
throw new ValidatorException( |
42c9b194a469
8073894: Getting to the root of certificate chains
mullan
parents:
25859
diff
changeset
|
152 |
"Untrusted certificate: "+ anchorCert.getSubjectX500Principal(), |
42c9b194a469
8073894: Getting to the root of certificate chains
mullan
parents:
25859
diff
changeset
|
153 |
ValidatorException.T_UNTRUSTED_CERT, anchorCert, cpve); |
42c9b194a469
8073894: Getting to the root of certificate chains
mullan
parents:
25859
diff
changeset
|
154 |
} |
42c9b194a469
8073894: Getting to the root of certificate chains
mullan
parents:
25859
diff
changeset
|
155 |
|
7040
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
156 |
// create default algorithm constraints checker |
31688
42c9b194a469
8073894: Getting to the root of certificate chains
mullan
parents:
25859
diff
changeset
|
157 |
TrustAnchor anchor = new TrustAnchor(anchorCert, null); |
43701
fe8c324ba97c
8160655: Fix denyAfter and usage types for security properties
ascarpino
parents:
42464
diff
changeset
|
158 |
AlgorithmChecker defaultAlgChecker = |
fe8c324ba97c
8160655: Fix denyAfter and usage types for security properties
ascarpino
parents:
42464
diff
changeset
|
159 |
new AlgorithmChecker(anchor, variant); |
7040
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
160 |
|
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
161 |
// create application level algorithm constraints checker |
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
162 |
AlgorithmChecker appAlgChecker = null; |
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
163 |
if (constraints != null) { |
43701
fe8c324ba97c
8160655: Fix denyAfter and usage types for security properties
ascarpino
parents:
42464
diff
changeset
|
164 |
appAlgChecker = new AlgorithmChecker(anchor, constraints, null, |
fe8c324ba97c
8160655: Fix denyAfter and usage types for security properties
ascarpino
parents:
42464
diff
changeset
|
165 |
variant); |
7040
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
166 |
} |
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
167 |
|
2 | 168 |
// verify top down, starting at the certificate issued by |
169 |
// the trust anchor |
|
2926 | 170 |
int maxPathLength = chain.length - 1; |
2 | 171 |
for (int i = chain.length - 2; i >= 0; i--) { |
172 |
X509Certificate issuerCert = chain[i + 1]; |
|
173 |
X509Certificate cert = chain[i]; |
|
174 |
||
11900 | 175 |
// check untrusted certificate |
176 |
try { |
|
177 |
// Untrusted checker does not care about the unresolved |
|
178 |
// critical extensions. |
|
179 |
untrustedChecker.check(cert, Collections.<String>emptySet()); |
|
180 |
} catch (CertPathValidatorException cpve) { |
|
181 |
throw new ValidatorException( |
|
182 |
"Untrusted certificate: " + cert.getSubjectX500Principal(), |
|
183 |
ValidatorException.T_UNTRUSTED_CERT, cert, cpve); |
|
184 |
} |
|
185 |
||
4190 | 186 |
// check certificate algorithm |
187 |
try { |
|
8163
d9bcc1208691
7011497: new CertPathValidatorException.BasicReason enum constant for constrained algorithm
xuelei
parents:
7040
diff
changeset
|
188 |
// Algorithm checker does not care about the unresolved |
d9bcc1208691
7011497: new CertPathValidatorException.BasicReason enum constant for constrained algorithm
xuelei
parents:
7040
diff
changeset
|
189 |
// critical extensions. |
7040
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
190 |
defaultAlgChecker.check(cert, Collections.<String>emptySet()); |
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
191 |
if (appAlgChecker != null) { |
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
192 |
appAlgChecker.check(cert, Collections.<String>emptySet()); |
659824c2a550
6792180: Enhance to reject weak algorithms or conform to crypto recommendations
xuelei
parents:
5506
diff
changeset
|
193 |
} |
4190 | 194 |
} catch (CertPathValidatorException cpve) { |
195 |
throw new ValidatorException |
|
196 |
(ValidatorException.T_ALGORITHM_DISABLED, cert, cpve); |
|
197 |
} |
|
2 | 198 |
|
199 |
// no validity check for code signing certs |
|
200 |
if ((variant.equals(VAR_CODE_SIGNING) == false) |
|
201 |
&& (variant.equals(VAR_JCE_SIGNING) == false)) { |
|
202 |
cert.checkValidity(date); |
|
203 |
} |
|
204 |
||
205 |
// check name chaining |
|
206 |
if (cert.getIssuerX500Principal().equals( |
|
207 |
issuerCert.getSubjectX500Principal()) == false) { |
|
208 |
throw new ValidatorException |
|
209 |
(ValidatorException.T_NAME_CHAINING, cert); |
|
210 |
} |
|
211 |
||
212 |
// check signature |
|
213 |
try { |
|
214 |
cert.verify(issuerCert.getPublicKey()); |
|
215 |
} catch (GeneralSecurityException e) { |
|
216 |
throw new ValidatorException |
|
217 |
(ValidatorException.T_SIGNATURE_ERROR, cert, e); |
|
218 |
} |
|
219 |
||
220 |
// check extensions for CA certs |
|
221 |
if (i != 0) { |
|
2926 | 222 |
maxPathLength = checkExtensions(cert, maxPathLength); |
2 | 223 |
} |
224 |
} |
|
225 |
||
226 |
return chain; |
|
227 |
} |
|
228 |
||
2926 | 229 |
private int checkExtensions(X509Certificate cert, int maxPathLen) |
2 | 230 |
throws CertificateException { |
231 |
Set<String> critSet = cert.getCriticalExtensionOIDs(); |
|
232 |
if (critSet == null) { |
|
233 |
critSet = Collections.<String>emptySet(); |
|
234 |
} |
|
235 |
||
236 |
// Check the basic constraints extension |
|
2926 | 237 |
int pathLenConstraint = |
238 |
checkBasicConstraints(cert, critSet, maxPathLen); |
|
2 | 239 |
|
240 |
// Check the key usage and extended key usage extensions |
|
241 |
checkKeyUsage(cert, critSet); |
|
242 |
||
243 |
// check Netscape certificate type extension |
|
244 |
checkNetscapeCertType(cert, critSet); |
|
245 |
||
246 |
if (!critSet.isEmpty()) { |
|
247 |
throw new ValidatorException |
|
248 |
("Certificate contains unknown critical extensions: " + critSet, |
|
249 |
ValidatorException.T_CA_EXTENSIONS, cert); |
|
250 |
} |
|
2926 | 251 |
|
252 |
return pathLenConstraint; |
|
2 | 253 |
} |
254 |
||
255 |
private void checkNetscapeCertType(X509Certificate cert, |
|
256 |
Set<String> critSet) throws CertificateException { |
|
257 |
if (variant.equals(VAR_GENERIC)) { |
|
258 |
// nothing |
|
259 |
} else if (variant.equals(VAR_TLS_CLIENT) |
|
260 |
|| variant.equals(VAR_TLS_SERVER)) { |
|
261 |
if (getNetscapeCertTypeBit(cert, NSCT_SSL_CA) == false) { |
|
262 |
throw new ValidatorException |
|
263 |
("Invalid Netscape CertType extension for SSL CA " |
|
264 |
+ "certificate", |
|
265 |
ValidatorException.T_CA_EXTENSIONS, cert); |
|
266 |
} |
|
267 |
critSet.remove(OID_NETSCAPE_CERT_TYPE); |
|
268 |
} else if (variant.equals(VAR_CODE_SIGNING) |
|
269 |
|| variant.equals(VAR_JCE_SIGNING)) { |
|
270 |
if (getNetscapeCertTypeBit(cert, NSCT_CODE_SIGNING_CA) == false) { |
|
271 |
throw new ValidatorException |
|
272 |
("Invalid Netscape CertType extension for code " |
|
273 |
+ "signing CA certificate", |
|
274 |
ValidatorException.T_CA_EXTENSIONS, cert); |
|
275 |
} |
|
276 |
critSet.remove(OID_NETSCAPE_CERT_TYPE); |
|
277 |
} else { |
|
278 |
throw new CertificateException("Unknown variant " + variant); |
|
279 |
} |
|
280 |
} |
|
281 |
||
282 |
/** |
|
283 |
* Get the value of the specified bit in the Netscape certificate type |
|
284 |
* extension. If the extension is not present at all, we return true. |
|
285 |
*/ |
|
286 |
static boolean getNetscapeCertTypeBit(X509Certificate cert, String type) { |
|
287 |
try { |
|
288 |
NetscapeCertTypeExtension ext; |
|
289 |
if (cert instanceof X509CertImpl) { |
|
290 |
X509CertImpl certImpl = (X509CertImpl)cert; |
|
291 |
ObjectIdentifier oid = OBJID_NETSCAPE_CERT_TYPE; |
|
292 |
ext = (NetscapeCertTypeExtension)certImpl.getExtension(oid); |
|
293 |
if (ext == null) { |
|
294 |
return true; |
|
295 |
} |
|
296 |
} else { |
|
297 |
byte[] extVal = cert.getExtensionValue(OID_NETSCAPE_CERT_TYPE); |
|
298 |
if (extVal == null) { |
|
299 |
return true; |
|
300 |
} |
|
301 |
DerInputStream in = new DerInputStream(extVal); |
|
302 |
byte[] encoded = in.getOctetString(); |
|
303 |
encoded = new DerValue(encoded).getUnalignedBitString() |
|
304 |
.toByteArray(); |
|
305 |
ext = new NetscapeCertTypeExtension(encoded); |
|
306 |
} |
|
10336
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
8163
diff
changeset
|
307 |
Boolean val = ext.get(type); |
2 | 308 |
return val.booleanValue(); |
309 |
} catch (IOException e) { |
|
310 |
return false; |
|
311 |
} |
|
312 |
} |
|
313 |
||
2926 | 314 |
private int checkBasicConstraints(X509Certificate cert, |
315 |
Set<String> critSet, int maxPathLen) throws CertificateException { |
|
2 | 316 |
|
317 |
critSet.remove(OID_BASIC_CONSTRAINTS); |
|
318 |
int constraints = cert.getBasicConstraints(); |
|
319 |
// reject, if extension missing or not a CA (constraints == -1) |
|
320 |
if (constraints < 0) { |
|
321 |
throw new ValidatorException("End user tried to act as a CA", |
|
322 |
ValidatorException.T_CA_EXTENSIONS, cert); |
|
323 |
} |
|
2926 | 324 |
|
325 |
// if the certificate is self-issued, ignore the pathLenConstraint |
|
326 |
// checking. |
|
327 |
if (!X509CertImpl.isSelfIssued(cert)) { |
|
12678
e40db477dd56
7166570: JSSE certificate validation has started to fail for certificate chains
xuelei
parents:
11902
diff
changeset
|
328 |
if (maxPathLen <= 0) { |
2926 | 329 |
throw new ValidatorException("Violated path length constraints", |
330 |
ValidatorException.T_CA_EXTENSIONS, cert); |
|
331 |
} |
|
332 |
||
333 |
maxPathLen--; |
|
2 | 334 |
} |
2926 | 335 |
|
336 |
if (maxPathLen > constraints) { |
|
337 |
maxPathLen = constraints; |
|
338 |
} |
|
339 |
||
340 |
return maxPathLen; |
|
2 | 341 |
} |
342 |
||
343 |
/* |
|
344 |
* Verify the key usage and extended key usage for intermediate |
|
345 |
* certificates. |
|
346 |
*/ |
|
347 |
private void checkKeyUsage(X509Certificate cert, Set<String> critSet) |
|
348 |
throws CertificateException { |
|
349 |
||
350 |
critSet.remove(OID_KEY_USAGE); |
|
351 |
// EKU irrelevant in CA certificates |
|
352 |
critSet.remove(OID_EXTENDED_KEY_USAGE); |
|
353 |
||
354 |
// check key usage extension |
|
355 |
boolean[] keyUsageInfo = cert.getKeyUsage(); |
|
356 |
if (keyUsageInfo != null) { |
|
357 |
// keyUsageInfo[5] is for keyCertSign. |
|
358 |
if ((keyUsageInfo.length < 6) || (keyUsageInfo[5] == false)) { |
|
359 |
throw new ValidatorException |
|
360 |
("Wrong key usage: expected keyCertSign", |
|
361 |
ValidatorException.T_CA_EXTENSIONS, cert); |
|
362 |
} |
|
363 |
} |
|
364 |
} |
|
365 |
||
366 |
/** |
|
367 |
* Build a trusted certificate chain. This method always returns a chain |
|
368 |
* with a trust anchor as the final cert in the chain. If no trust anchor |
|
369 |
* could be found, a CertificateException is thrown. |
|
370 |
*/ |
|
371 |
private X509Certificate[] buildTrustedChain(X509Certificate[] chain) |
|
372 |
throws CertificateException { |
|
373 |
List<X509Certificate> c = new ArrayList<X509Certificate>(chain.length); |
|
374 |
// scan chain starting at EE cert |
|
375 |
// if a trusted certificate is found, append it and return |
|
376 |
for (int i = 0; i < chain.length; i++) { |
|
377 |
X509Certificate cert = chain[i]; |
|
378 |
X509Certificate trustedCert = getTrustedCertificate(cert); |
|
379 |
if (trustedCert != null) { |
|
380 |
c.add(trustedCert); |
|
381 |
return c.toArray(CHAIN0); |
|
382 |
} |
|
383 |
c.add(cert); |
|
384 |
} |
|
2926 | 385 |
|
2 | 386 |
// check if we can append a trusted cert |
387 |
X509Certificate cert = chain[chain.length - 1]; |
|
388 |
X500Principal subject = cert.getSubjectX500Principal(); |
|
389 |
X500Principal issuer = cert.getIssuerX500Principal(); |
|
2926 | 390 |
List<X509Certificate> list = trustedX500Principals.get(issuer); |
391 |
if (list != null) { |
|
42464 | 392 |
X509Certificate matchedCert = list.get(0); |
393 |
X509CertImpl certImpl = X509CertImpl.toImpl(cert); |
|
394 |
KeyIdentifier akid = certImpl.getAuthKeyId(); |
|
395 |
if (akid != null) { |
|
396 |
for (X509Certificate sup : list) { |
|
397 |
// Look for a best match issuer. |
|
398 |
X509CertImpl supCert = X509CertImpl.toImpl(sup); |
|
399 |
if (akid.equals(supCert.getSubjectKeyId())) { |
|
400 |
matchedCert = sup; |
|
401 |
break; |
|
402 |
} |
|
403 |
} |
|
404 |
} |
|
405 |
||
406 |
c.add(matchedCert); |
|
2926 | 407 |
return c.toArray(CHAIN0); |
2 | 408 |
} |
2926 | 409 |
|
2 | 410 |
// no trusted cert found, error |
411 |
throw new ValidatorException(ValidatorException.T_NO_TRUST_ANCHOR); |
|
412 |
} |
|
413 |
||
414 |
/** |
|
415 |
* Return a trusted certificate that matches the input certificate, |
|
416 |
* or null if no such certificate can be found. This method also handles |
|
417 |
* cases where a CA re-issues a trust anchor with the same public key and |
|
418 |
* same subject and issuer names but a new validity period, etc. |
|
419 |
*/ |
|
420 |
private X509Certificate getTrustedCertificate(X509Certificate cert) { |
|
421 |
Principal certSubjectName = cert.getSubjectX500Principal(); |
|
422 |
List<X509Certificate> list = trustedX500Principals.get(certSubjectName); |
|
423 |
if (list == null) { |
|
424 |
return null; |
|
425 |
} |
|
426 |
||
427 |
Principal certIssuerName = cert.getIssuerX500Principal(); |
|
428 |
PublicKey certPublicKey = cert.getPublicKey(); |
|
429 |
||
430 |
for (X509Certificate mycert : list) { |
|
431 |
if (mycert.equals(cert)) { |
|
432 |
return cert; |
|
433 |
} |
|
434 |
if (!mycert.getIssuerX500Principal().equals(certIssuerName)) { |
|
435 |
continue; |
|
436 |
} |
|
437 |
if (!mycert.getPublicKey().equals(certPublicKey)) { |
|
438 |
continue; |
|
439 |
} |
|
440 |
||
441 |
// All tests pass, this must be the one to use... |
|
442 |
return mycert; |
|
443 |
} |
|
444 |
return null; |
|
445 |
} |
|
446 |
||
447 |
} |