1 /* 2 * Copyright (c) 2000, 2015, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 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. 24 */ 25 26 package sun.security.provider.certpath; 27 28 import sun.security.util.Debug; 29 30 import java.util.Collections; 31 import java.util.List; 32 import java.util.Set; 33 import java.util.StringJoiner; 34 import java.security.cert.CertPath; 35 import java.security.cert.CertPathValidatorException; 36 import java.security.cert.PKIXCertPathChecker; 37 import java.security.cert.PKIXReason; 38 import java.security.cert.X509Certificate; 39 40 /** 41 * This class is initialized with a list of <code>PKIXCertPathChecker</code>s 42 * and is used to verify the certificates in a <code>CertPath</code> by 43 * feeding each certificate to each <code>PKIXCertPathChecker</code>. 44 * 45 * @since 1.4 46 * @author Yassir Elley 47 */ 48 class PKIXMasterCertPathValidator { 49 50 private static final Debug debug = Debug.getInstance("certpath"); 51 52 /** 53 * Validates a certification path consisting exclusively of 54 * <code>X509Certificate</code>s using the specified 55 * <code>PKIXCertPathChecker</code>s. It is assumed that the 56 * <code>PKIXCertPathChecker</code>s 57 * have been initialized with any input parameters they may need. 58 * 59 * @param cpOriginal the original X509 CertPath passed in by the user 60 * @param reversedCertList the reversed X509 CertPath (as a List) 61 * @param certPathCheckers the PKIXCertPathCheckers 62 * @throws CertPathValidatorException if cert path does not validate 63 */ validate(CertPath cpOriginal, List<X509Certificate> reversedCertList, List<PKIXCertPathChecker> certPathCheckers)64 static void validate(CertPath cpOriginal, 65 List<X509Certificate> reversedCertList, 66 List<PKIXCertPathChecker> certPathCheckers) 67 throws CertPathValidatorException 68 { 69 // we actually process reversedCertList, but we keep cpOriginal because 70 // we need to return the original certPath when we throw an exception. 71 // we will also need to modify the index appropriately when we 72 // throw an exception. 73 74 int cpSize = reversedCertList.size(); 75 76 if (debug != null) { 77 debug.println("--------------------------------------------------" 78 + "------------"); 79 debug.println("Executing PKIX certification path validation " 80 + "algorithm."); 81 } 82 83 for (int i = 0; i < cpSize; i++) { 84 85 /* The basic loop algorithm is that we get the 86 * current certificate, we verify the current certificate using 87 * information from the previous certificate and from the state, 88 * and we modify the state for the next loop by setting the 89 * current certificate of this loop to be the previous certificate 90 * of the next loop. The state is initialized during first loop. 91 */ 92 X509Certificate currCert = reversedCertList.get(i); 93 94 if (debug != null) { 95 debug.println("Checking cert" + (i+1) + " - Subject: " + 96 currCert.getSubjectX500Principal()); 97 } 98 99 Set<String> unresCritExts = currCert.getCriticalExtensionOIDs(); 100 if (unresCritExts == null) { 101 unresCritExts = Collections.<String>emptySet(); 102 } 103 104 if (debug != null && !unresCritExts.isEmpty()) { 105 StringJoiner joiner = new StringJoiner(", ", "{", "}"); 106 for (String oid : unresCritExts) { 107 joiner.add(oid); 108 } 109 debug.println("Set of critical extensions: " + 110 joiner.toString()); 111 } 112 113 for (int j = 0; j < certPathCheckers.size(); j++) { 114 115 PKIXCertPathChecker currChecker = certPathCheckers.get(j); 116 if (debug != null) { 117 debug.println("-Using checker" + (j + 1) + " ... [" + 118 currChecker.getClass().getName() + "]"); 119 } 120 121 if (i == 0) 122 currChecker.init(false); 123 124 try { 125 currChecker.check(currCert, unresCritExts); 126 127 if (debug != null) { 128 debug.println("-checker" + (j + 1) + 129 " validation succeeded"); 130 } 131 132 } catch (CertPathValidatorException cpve) { 133 throw new CertPathValidatorException(cpve.getMessage(), 134 (cpve.getCause() != null) ? cpve.getCause() : cpve, 135 cpOriginal, cpSize - (i + 1), cpve.getReason()); 136 } 137 } 138 139 if (!unresCritExts.isEmpty()) { 140 throw new CertPathValidatorException("unrecognized " + 141 "critical extension(s)", null, cpOriginal, cpSize-(i+1), 142 PKIXReason.UNRECOGNIZED_CRIT_EXT); 143 } 144 145 if (debug != null) 146 debug.println("\ncert" + (i+1) + " validation succeeded.\n"); 147 } 148 149 if (debug != null) { 150 debug.println("Cert path validation succeeded. (PKIX validation " 151 + "algorithm)"); 152 debug.println("-------------------------------------------------" 153 + "-------------"); 154 } 155 } 156 } 157