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