1 package org.bouncycastle.jce.provider; 2 3 // BEGIN android-added 4 import java.math.BigInteger; 5 // END android-added 6 import java.security.InvalidAlgorithmParameterException; 7 import java.security.PublicKey; 8 import java.security.cert.CertPath; 9 import java.security.cert.CertPathParameters; 10 import java.security.cert.CertPathValidatorException; 11 import java.security.cert.CertPathValidatorResult; 12 import java.security.cert.CertPathValidatorSpi; 13 import java.security.cert.PKIXCertPathChecker; 14 import java.security.cert.PKIXCertPathValidatorResult; 15 import java.security.cert.PKIXParameters; 16 import java.security.cert.TrustAnchor; 17 import java.security.cert.X509Certificate; 18 import java.util.ArrayList; 19 import java.util.HashSet; 20 import java.util.Iterator; 21 import java.util.List; 22 import java.util.Set; 23 24 import org.bouncycastle.asn1.ASN1Encodable; 25 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 26 import org.bouncycastle.asn1.x500.X500Name; 27 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 28 import org.bouncycastle.jcajce.PKIXExtendedBuilderParameters; 29 import org.bouncycastle.jcajce.PKIXExtendedParameters; 30 import org.bouncycastle.jcajce.util.BCJcaJceHelper; 31 import org.bouncycastle.jcajce.util.JcaJceHelper; 32 import org.bouncycastle.jce.exception.ExtCertPathValidatorException; 33 import org.bouncycastle.x509.ExtendedPKIXParameters; 34 35 /** 36 * CertPathValidatorSpi implementation for X.509 Certificate validation � la RFC 37 * 3280. 38 */ 39 public class PKIXCertPathValidatorSpi 40 extends CertPathValidatorSpi 41 { 42 private final JcaJceHelper helper = new BCJcaJceHelper(); 43 PKIXCertPathValidatorSpi()44 public PKIXCertPathValidatorSpi() 45 { 46 } 47 // BEGIN android-added 48 private static class NoPreloadHolder { 49 private final static CertBlacklist blacklist = new CertBlacklist(); 50 } 51 // END android-added 52 engineValidate( CertPath certPath, CertPathParameters params)53 public CertPathValidatorResult engineValidate( 54 CertPath certPath, 55 CertPathParameters params) 56 throws CertPathValidatorException, 57 InvalidAlgorithmParameterException 58 { 59 if (!(params instanceof CertPathParameters)) 60 { 61 throw new InvalidAlgorithmParameterException("Parameters must be a " + PKIXParameters.class.getName() 62 + " instance."); 63 } 64 65 PKIXExtendedParameters paramsPKIX; 66 if (params instanceof PKIXParameters) 67 { 68 PKIXExtendedParameters.Builder paramsPKIXBldr = new PKIXExtendedParameters.Builder((PKIXParameters)params); 69 70 if (params instanceof ExtendedPKIXParameters) 71 { 72 ExtendedPKIXParameters extPKIX = (ExtendedPKIXParameters)params; 73 74 paramsPKIXBldr.setUseDeltasEnabled(extPKIX.isUseDeltasEnabled()); 75 paramsPKIXBldr.setValidityModel(extPKIX.getValidityModel()); 76 } 77 78 paramsPKIX = paramsPKIXBldr.build(); 79 } 80 else if (params instanceof PKIXExtendedBuilderParameters) 81 { 82 paramsPKIX = ((PKIXExtendedBuilderParameters)params).getBaseParameters(); 83 } 84 // BEGIN android-changed 85 // else 86 else if (params instanceof PKIXExtendedParameters) 87 // END android-changed 88 { 89 paramsPKIX = (PKIXExtendedParameters)params; 90 } 91 // BEGIN android-added 92 else { 93 throw new InvalidAlgorithmParameterException("Expecting PKIX algorithm parameters"); 94 } 95 // END android-added 96 97 if (paramsPKIX.getTrustAnchors() == null) 98 { 99 throw new InvalidAlgorithmParameterException( 100 "trustAnchors is null, this is not allowed for certification path validation."); 101 } 102 103 // 104 // 6.1.1 - inputs 105 // 106 107 // 108 // (a) 109 // 110 List certs = certPath.getCertificates(); 111 int n = certs.size(); 112 113 if (certs.isEmpty()) 114 { 115 throw new CertPathValidatorException("Certification path is empty.", null, certPath, 0); 116 } 117 // BEGIN android-added 118 { 119 X509Certificate cert = (X509Certificate) certs.get(0); 120 121 if (cert != null) { 122 BigInteger serial = cert.getSerialNumber(); 123 if (NoPreloadHolder.blacklist.isSerialNumberBlackListed(serial)) { 124 // emulate CRL exception message in RFC3280CertPathUtilities.checkCRLs 125 String message = "Certificate revocation of serial 0x" + serial.toString(16); 126 System.out.println(message); 127 AnnotatedException e = new AnnotatedException(message); 128 throw new CertPathValidatorException(e.getMessage(), e, certPath, 0); 129 } 130 } 131 } 132 // END android-added 133 134 // 135 // (b) 136 // 137 // Date validDate = CertPathValidatorUtilities.getValidDate(paramsPKIX); 138 139 // 140 // (c) 141 // 142 Set userInitialPolicySet = paramsPKIX.getInitialPolicies(); 143 144 // 145 // (d) 146 // 147 TrustAnchor trust; 148 try 149 { 150 trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1), 151 paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider()); 152 } 153 catch (AnnotatedException e) 154 { 155 throw new CertPathValidatorException(e.getMessage(), e, certPath, certs.size() - 1); 156 } 157 158 if (trust == null) 159 { 160 throw new CertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1); 161 } 162 163 // RFC 5280 - CRLs must originate from the same trust anchor as the target certificate. 164 paramsPKIX = new PKIXExtendedParameters.Builder(paramsPKIX).setTrustAnchor(trust).build(); 165 166 // 167 // (e), (f), (g) are part of the paramsPKIX object. 168 // 169 Iterator certIter; 170 int index = 0; 171 int i; 172 // Certificate for each interation of the validation loop 173 // Signature information for each iteration of the validation loop 174 // 175 // 6.1.2 - setup 176 // 177 178 // 179 // (a) 180 // 181 List[] policyNodes = new ArrayList[n + 1]; 182 for (int j = 0; j < policyNodes.length; j++) 183 { 184 policyNodes[j] = new ArrayList(); 185 } 186 187 Set policySet = new HashSet(); 188 189 policySet.add(RFC3280CertPathUtilities.ANY_POLICY); 190 191 PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0, policySet, null, new HashSet(), 192 RFC3280CertPathUtilities.ANY_POLICY, false); 193 194 policyNodes[0].add(validPolicyTree); 195 196 // 197 // (b) and (c) 198 // 199 PKIXNameConstraintValidator nameConstraintValidator = new PKIXNameConstraintValidator(); 200 201 // (d) 202 // 203 int explicitPolicy; 204 Set acceptablePolicies = new HashSet(); 205 206 if (paramsPKIX.isExplicitPolicyRequired()) 207 { 208 explicitPolicy = 0; 209 } 210 else 211 { 212 explicitPolicy = n + 1; 213 } 214 215 // 216 // (e) 217 // 218 int inhibitAnyPolicy; 219 220 if (paramsPKIX.isAnyPolicyInhibited()) 221 { 222 inhibitAnyPolicy = 0; 223 } 224 else 225 { 226 inhibitAnyPolicy = n + 1; 227 } 228 229 // 230 // (f) 231 // 232 int policyMapping; 233 234 if (paramsPKIX.isPolicyMappingInhibited()) 235 { 236 policyMapping = 0; 237 } 238 else 239 { 240 policyMapping = n + 1; 241 } 242 243 // 244 // (g), (h), (i), (j) 245 // 246 PublicKey workingPublicKey; 247 X500Name workingIssuerName; 248 249 X509Certificate sign = trust.getTrustedCert(); 250 try 251 { 252 if (sign != null) 253 { 254 workingIssuerName = PrincipalUtils.getSubjectPrincipal(sign); 255 workingPublicKey = sign.getPublicKey(); 256 } 257 else 258 { 259 workingIssuerName = PrincipalUtils.getCA(trust); 260 workingPublicKey = trust.getCAPublicKey(); 261 } 262 } 263 catch (IllegalArgumentException ex) 264 { 265 throw new ExtCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath, 266 -1); 267 } 268 269 AlgorithmIdentifier workingAlgId = null; 270 try 271 { 272 workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey); 273 } 274 catch (CertPathValidatorException e) 275 { 276 throw new ExtCertPathValidatorException( 277 "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1); 278 } 279 ASN1ObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getAlgorithm(); 280 ASN1Encodable workingPublicKeyParameters = workingAlgId.getParameters(); 281 282 // 283 // (k) 284 // 285 int maxPathLength = n; 286 287 // 288 // 6.1.3 289 // 290 291 if (paramsPKIX.getTargetConstraints() != null 292 && !paramsPKIX.getTargetConstraints().match((X509Certificate) certs.get(0))) 293 { 294 throw new ExtCertPathValidatorException( 295 "Target certificate in certification path does not match targetConstraints.", null, certPath, 0); 296 } 297 298 // 299 // initialize CertPathChecker's 300 // 301 List pathCheckers = paramsPKIX.getCertPathCheckers(); 302 certIter = pathCheckers.iterator(); 303 while (certIter.hasNext()) 304 { 305 ((PKIXCertPathChecker) certIter.next()).init(false); 306 } 307 308 X509Certificate cert = null; 309 310 for (index = certs.size() - 1; index >= 0; index--) 311 { 312 // BEGIN android-added 313 if (NoPreloadHolder.blacklist.isPublicKeyBlackListed(workingPublicKey)) { 314 // emulate CRL exception message in RFC3280CertPathUtilities.checkCRLs 315 String message = "Certificate revocation of public key " + workingPublicKey; 316 System.out.println(message); 317 AnnotatedException e = new AnnotatedException(message); 318 throw new CertPathValidatorException(e.getMessage(), e, certPath, index); 319 } 320 // END android-added 321 // try 322 // { 323 // 324 // i as defined in the algorithm description 325 // 326 i = n - index; 327 328 // 329 // set certificate to be checked in this round 330 // sign and workingPublicKey and workingIssuerName are set 331 // at the end of the for loop and initialized the 332 // first time from the TrustAnchor 333 // 334 cert = (X509Certificate) certs.get(index); 335 boolean verificationAlreadyPerformed = (index == certs.size() - 1); 336 337 // 338 // 6.1.3 339 // 340 341 RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey, 342 verificationAlreadyPerformed, workingIssuerName, sign, helper); 343 344 RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator); 345 346 validPolicyTree = RFC3280CertPathUtilities.processCertD(certPath, index, acceptablePolicies, 347 validPolicyTree, policyNodes, inhibitAnyPolicy); 348 349 validPolicyTree = RFC3280CertPathUtilities.processCertE(certPath, index, validPolicyTree); 350 351 RFC3280CertPathUtilities.processCertF(certPath, index, validPolicyTree, explicitPolicy); 352 353 // 354 // 6.1.4 355 // 356 357 if (i != n) 358 { 359 if (cert != null && cert.getVersion() == 1) 360 { 361 throw new CertPathValidatorException("Version 1 certificates can't be used as CA ones.", null, 362 certPath, index); 363 } 364 365 RFC3280CertPathUtilities.prepareNextCertA(certPath, index); 366 367 validPolicyTree = RFC3280CertPathUtilities.prepareCertB(certPath, index, policyNodes, validPolicyTree, 368 policyMapping); 369 370 RFC3280CertPathUtilities.prepareNextCertG(certPath, index, nameConstraintValidator); 371 372 // (h) 373 explicitPolicy = RFC3280CertPathUtilities.prepareNextCertH1(certPath, index, explicitPolicy); 374 policyMapping = RFC3280CertPathUtilities.prepareNextCertH2(certPath, index, policyMapping); 375 inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertH3(certPath, index, inhibitAnyPolicy); 376 377 // 378 // (i) 379 // 380 explicitPolicy = RFC3280CertPathUtilities.prepareNextCertI1(certPath, index, explicitPolicy); 381 policyMapping = RFC3280CertPathUtilities.prepareNextCertI2(certPath, index, policyMapping); 382 383 // (j) 384 inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertJ(certPath, index, inhibitAnyPolicy); 385 386 // (k) 387 RFC3280CertPathUtilities.prepareNextCertK(certPath, index); 388 389 // (l) 390 maxPathLength = RFC3280CertPathUtilities.prepareNextCertL(certPath, index, maxPathLength); 391 392 // (m) 393 maxPathLength = RFC3280CertPathUtilities.prepareNextCertM(certPath, index, maxPathLength); 394 395 // (n) 396 RFC3280CertPathUtilities.prepareNextCertN(certPath, index); 397 398 Set criticalExtensions = cert.getCriticalExtensionOIDs(); 399 if (criticalExtensions != null) 400 { 401 criticalExtensions = new HashSet(criticalExtensions); 402 403 // these extensions are handled by the algorithm 404 criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE); 405 criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES); 406 criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS); 407 criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY); 408 criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT); 409 criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR); 410 criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS); 411 criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS); 412 criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME); 413 criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS); 414 } 415 else 416 { 417 criticalExtensions = new HashSet(); 418 } 419 420 // (o) 421 RFC3280CertPathUtilities.prepareNextCertO(certPath, index, criticalExtensions, pathCheckers); 422 423 // set signing certificate for next round 424 sign = cert; 425 426 // (c) 427 workingIssuerName = PrincipalUtils.getSubjectPrincipal(sign); 428 429 // (d) 430 try 431 { 432 workingPublicKey = CertPathValidatorUtilities.getNextWorkingKey(certPath.getCertificates(), index, helper); 433 } 434 catch (CertPathValidatorException e) 435 { 436 throw new CertPathValidatorException("Next working key could not be retrieved.", e, certPath, index); 437 } 438 439 workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey); 440 // (f) 441 workingPublicKeyAlgorithm = workingAlgId.getAlgorithm(); 442 // (e) 443 workingPublicKeyParameters = workingAlgId.getParameters(); 444 } 445 } 446 447 // 448 // 6.1.5 Wrap-up procedure 449 // 450 451 explicitPolicy = RFC3280CertPathUtilities.wrapupCertA(explicitPolicy, cert); 452 453 explicitPolicy = RFC3280CertPathUtilities.wrapupCertB(certPath, index + 1, explicitPolicy); 454 455 // 456 // (c) (d) and (e) are already done 457 // 458 459 // 460 // (f) 461 // 462 Set criticalExtensions = cert.getCriticalExtensionOIDs(); 463 464 if (criticalExtensions != null) 465 { 466 criticalExtensions = new HashSet(criticalExtensions); 467 // these extensions are handled by the algorithm 468 criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE); 469 criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES); 470 criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS); 471 criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY); 472 criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT); 473 criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR); 474 criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS); 475 criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS); 476 criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME); 477 criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS); 478 criticalExtensions.remove(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS); 479 } 480 else 481 { 482 criticalExtensions = new HashSet(); 483 } 484 485 RFC3280CertPathUtilities.wrapupCertF(certPath, index + 1, pathCheckers, criticalExtensions); 486 487 PKIXPolicyNode intersection = RFC3280CertPathUtilities.wrapupCertG(certPath, paramsPKIX, userInitialPolicySet, 488 index + 1, policyNodes, validPolicyTree, acceptablePolicies); 489 490 if ((explicitPolicy > 0) || (intersection != null)) 491 { 492 return new PKIXCertPathValidatorResult(trust, intersection, cert.getPublicKey()); 493 } 494 495 throw new CertPathValidatorException("Path processing failed on policy.", null, certPath, index); 496 } 497 498 } 499