1 /* 2 * Copyright (c) 2000, 2012, 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 java.util.*; 29 import java.security.cert.*; 30 import java.security.cert.PKIXReason; 31 32 import sun.security.util.Debug; 33 import static sun.security.x509.PKIXExtensions.*; 34 35 /** 36 * KeyChecker is a <code>PKIXCertPathChecker</code> that checks that the 37 * keyCertSign bit is set in the keyUsage extension in an intermediate CA 38 * certificate. It also checks whether the final certificate in a 39 * certification path meets the specified target constraints specified as 40 * a CertSelector in the PKIXParameters passed to the CertPathValidator. 41 * 42 * @since 1.4 43 * @author Yassir Elley 44 */ 45 class KeyChecker extends PKIXCertPathChecker { 46 47 private static final Debug debug = Debug.getInstance("certpath"); 48 private final int certPathLen; 49 private final CertSelector targetConstraints; 50 private int remainingCerts; 51 52 private Set<String> supportedExts; 53 54 /** 55 * Creates a KeyChecker. 56 * 57 * @param certPathLen allowable cert path length 58 * @param targetCertSel a CertSelector object specifying the constraints 59 * on the target certificate 60 */ KeyChecker(int certPathLen, CertSelector targetCertSel)61 KeyChecker(int certPathLen, CertSelector targetCertSel) { 62 this.certPathLen = certPathLen; 63 this.targetConstraints = targetCertSel; 64 } 65 66 /** 67 * Initializes the internal state of the checker from parameters 68 * specified in the constructor 69 */ 70 @Override init(boolean forward)71 public void init(boolean forward) throws CertPathValidatorException { 72 if (!forward) { 73 remainingCerts = certPathLen; 74 } else { 75 throw new CertPathValidatorException 76 ("forward checking not supported"); 77 } 78 } 79 80 @Override isForwardCheckingSupported()81 public boolean isForwardCheckingSupported() { 82 return false; 83 } 84 85 @Override getSupportedExtensions()86 public Set<String> getSupportedExtensions() { 87 if (supportedExts == null) { 88 supportedExts = new HashSet<String>(3); 89 supportedExts.add(KeyUsage_Id.toString()); 90 supportedExts.add(ExtendedKeyUsage_Id.toString()); 91 supportedExts.add(SubjectAlternativeName_Id.toString()); 92 supportedExts = Collections.unmodifiableSet(supportedExts); 93 } 94 return supportedExts; 95 } 96 97 /** 98 * Checks that keyUsage and target constraints are satisfied by 99 * the specified certificate. 100 * 101 * @param cert the Certificate 102 * @param unresolvedCritExts the unresolved critical extensions 103 * @throws CertPathValidatorException if certificate does not verify 104 */ 105 @Override check(Certificate cert, Collection<String> unresCritExts)106 public void check(Certificate cert, Collection<String> unresCritExts) 107 throws CertPathValidatorException 108 { 109 X509Certificate currCert = (X509Certificate)cert; 110 111 remainingCerts--; 112 113 // if final certificate, check that target constraints are satisfied 114 if (remainingCerts == 0) { 115 if (targetConstraints != null && 116 targetConstraints.match(currCert) == false) { 117 throw new CertPathValidatorException("target certificate " + 118 "constraints check failed"); 119 } 120 } else { 121 // otherwise, verify that keyCertSign bit is set in CA certificate 122 verifyCAKeyUsage(currCert); 123 } 124 125 // remove the extensions that we have checked 126 if (unresCritExts != null && !unresCritExts.isEmpty()) { 127 unresCritExts.remove(KeyUsage_Id.toString()); 128 unresCritExts.remove(ExtendedKeyUsage_Id.toString()); 129 unresCritExts.remove(SubjectAlternativeName_Id.toString()); 130 } 131 } 132 133 // the index of keyCertSign in the boolean KeyUsage array 134 private static final int KEY_CERT_SIGN = 5; 135 /** 136 * Verifies the key usage extension in a CA cert. 137 * The key usage extension, if present, must assert the keyCertSign bit. 138 * The extended key usage extension is not checked (see CR 4776794 for 139 * more information). 140 */ verifyCAKeyUsage(X509Certificate cert)141 static void verifyCAKeyUsage(X509Certificate cert) 142 throws CertPathValidatorException { 143 String msg = "CA key usage"; 144 if (debug != null) { 145 debug.println("KeyChecker.verifyCAKeyUsage() ---checking " + msg 146 + "..."); 147 } 148 149 boolean[] keyUsageBits = cert.getKeyUsage(); 150 151 // getKeyUsage returns null if the KeyUsage extension is not present 152 // in the certificate - in which case there is nothing to check 153 if (keyUsageBits == null) { 154 return; 155 } 156 157 // throw an exception if the keyCertSign bit is not set 158 if (!keyUsageBits[KEY_CERT_SIGN]) { 159 throw new CertPathValidatorException 160 (msg + " check failed: keyCertSign bit is not set", null, 161 null, -1, PKIXReason.INVALID_KEY_USAGE); 162 } 163 164 if (debug != null) { 165 debug.println("KeyChecker.verifyCAKeyUsage() " + msg 166 + " verified."); 167 } 168 } 169 } 170