Showing the changes to java/pkg/sun/security/provider/certpath/AlgorithmChecker.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,367 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2009, 2011, 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.security.AlgorithmConstraints; | ||
| 29 | import java.security.CryptoPrimitive; | ||
| 30 | import java.util.Collection; | ||
| 31 | import java.util.Collections; | ||
| 32 | import java.util.Set; | ||
| 33 | import java.util.EnumSet; | ||
| 34 | import java.util.HashSet; | ||
| 35 | import java.math.BigInteger; | ||
| 36 | import java.security.PublicKey; | ||
| 37 | import java.security.KeyFactory; | ||
| 38 | import java.security.AlgorithmParameters; | ||
| 39 | import java.security.NoSuchAlgorithmException; | ||
| 40 | import java.security.GeneralSecurityException; | ||
| 41 | import java.security.cert.Certificate; | ||
| 42 | import java.security.cert.X509CRL; | ||
| 43 | import java.security.cert.X509Certificate; | ||
| 44 | import java.security.cert.PKIXCertPathChecker; | ||
| 45 | import java.security.cert.TrustAnchor; | ||
| 46 | import java.security.cert.CRLException; | ||
| 47 | import java.security.cert.CertificateException; | ||
| 48 | import java.security.cert.CertPathValidatorException; | ||
| 49 | import java.security.cert.CertPathValidatorException.BasicReason; | ||
| 50 | import java.security.cert.PKIXReason; | ||
| 51 | import java.io.IOException; | ||
| 52 | import java.security.interfaces.*; | ||
| 53 | import java.security.spec.*; | ||
| 54 | |||
| 55 | import sun.security.util.DisabledAlgorithmConstraints; | ||
| 56 | import sun.security.x509.X509CertImpl; | ||
| 57 | import sun.security.x509.X509CRLImpl; | ||
| 58 | import sun.security.x509.AlgorithmId; | ||
| 59 | |||
| 60 | /** | ||
| 61 | * A <code>PKIXCertPathChecker</code> implementation to check whether a | ||
| 62 | * specified certificate contains the required algorithm constraints. | ||
| 63 | * <p> | ||
| 64 | * Certificate fields such as the subject public key, the signature | ||
| 65 | * algorithm, key usage, extended key usage, etc. need to conform to | ||
| 66 | * the specified algorithm constraints. | ||
| 67 | * | ||
| 68 | * @see PKIXCertPathChecker | ||
| 69 | * @see PKIXParameters | ||
| 70 | */ | ||
| 71 | final public class AlgorithmChecker extends PKIXCertPathChecker { | ||
| 72 | |||
| 73 | private final AlgorithmConstraints constraints; | ||
| 74 | private final PublicKey trustedPubKey; | ||
| 75 | private PublicKey prevPubKey; | ||
| 76 | |||
| 77 | private final static Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET = | ||
| 78 | EnumSet.of(CryptoPrimitive.SIGNATURE); | ||
| 79 | |||
| 80 | private final static DisabledAlgorithmConstraints | ||
| 81 | certPathDefaultConstraints = new DisabledAlgorithmConstraints( | ||
| 82 | DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS); | ||
| 83 | |||
| 84 | /** | ||
| 85 | * Create a new <code>AlgorithmChecker</code> with the algorithm | ||
| 86 | * constraints specified in security property | ||
| 87 | * "jdk.certpath.disabledAlgorithms". | ||
| 88 | * | ||
| 89 | * @param anchor the trust anchor selected to validate the target | ||
| 90 | * certificate | ||
| 91 | */ | ||
| 92 | public AlgorithmChecker(TrustAnchor anchor) { | ||
| 93 | this(anchor, certPathDefaultConstraints); | ||
| 94 | } | ||
| 95 | |||
| 96 | /** | ||
| 97 | * Create a new <code>AlgorithmChecker</code> with the | ||
| 98 | * given {@code AlgorithmConstraints}. | ||
| 99 | * <p> | ||
| 100 | * Note that this constructor will be used to check a certification | ||
| 101 | * path where the trust anchor is unknown, or a certificate list which may | ||
| 102 | * contain the trust anchor. This constructor is used by SunJSSE. | ||
| 103 | * | ||
| 104 | * @param constraints the algorithm constraints (or null) | ||
| 105 | */ | ||
| 106 | public AlgorithmChecker(AlgorithmConstraints constraints) { | ||
| 107 | this.prevPubKey = null; | ||
| 108 | this.trustedPubKey = null; | ||
| 109 | this.constraints = constraints; | ||
| 110 | } | ||
| 111 | |||
| 112 | /** | ||
| 113 | * Create a new <code>AlgorithmChecker</code> with the | ||
| 114 | * given <code>TrustAnchor</code> and <code>AlgorithmConstraints</code>. | ||
| 115 | * | ||
| 116 | * @param anchor the trust anchor selected to validate the target | ||
| 117 | * certificate | ||
| 118 | * @param constraints the algorithm constraints (or null) | ||
| 119 | * | ||
| 120 | * @throws IllegalArgumentException if the <code>anchor</code> is null | ||
| 121 | */ | ||
| 122 | public AlgorithmChecker(TrustAnchor anchor, | ||
| 123 | AlgorithmConstraints constraints) { | ||
| 124 | |||
| 125 | if (anchor == null) { | ||
| 126 | throw new IllegalArgumentException( | ||
| 127 | "The trust anchor cannot be null"); | ||
| 128 | } | ||
| 129 | |||
| 130 | if (anchor.getTrustedCert() != null) { | ||
| 131 | this.trustedPubKey = anchor.getTrustedCert().getPublicKey(); | ||
| 132 | } else { | ||
| 133 | this.trustedPubKey = anchor.getCAPublicKey(); | ||
| 134 | } | ||
| 135 | |||
| 136 | this.prevPubKey = trustedPubKey; | ||
| 137 | this.constraints = constraints; | ||
| 138 | } | ||
| 139 | |||
| 140 | @Override | ||
| 141 | public void init(boolean forward) throws CertPathValidatorException { | ||
| 142 | // Note that this class does not support forward mode. | ||
| 143 | if (!forward) { | ||
| 144 | if (trustedPubKey != null) { | ||
| 145 | prevPubKey = trustedPubKey; | ||
| 146 | } else { | ||
| 147 | prevPubKey = null; | ||
| 148 | } | ||
| 149 | } else { | ||
| 150 | throw new | ||
| 151 | CertPathValidatorException("forward checking not supported"); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | @Override | ||
| 156 | public boolean isForwardCheckingSupported() { | ||
| 157 | // Note that as this class does not support forward mode, the method | ||
| 158 | // will always returns false. | ||
| 159 | return false; | ||
| 160 | } | ||
| 161 | |||
| 162 | @Override | ||
| 163 | public Set<String> getSupportedExtensions() { | ||
| 164 | return null; | ||
| 165 | } | ||
| 166 | |||
| 167 | @Override | ||
| 168 | public void check(Certificate cert, | ||
| 169 | Collection<String> unresolvedCritExts) | ||
| 170 | throws CertPathValidatorException { | ||
| 171 | |||
| 172 | if (!(cert instanceof X509Certificate) || constraints == null) { | ||
| 173 | // ignore the check for non-x.509 certificate or null constraints | ||
| 174 | return; | ||
| 175 | } | ||
| 176 | |||
| 177 | X509CertImpl x509Cert = null; | ||
| 178 | try { | ||
| 179 | x509Cert = X509CertImpl.toImpl((X509Certificate)cert); | ||
| 180 | } catch (CertificateException ce) { | ||
| 181 | throw new CertPathValidatorException(ce); | ||
| 182 | } | ||
| 183 | |||
| 184 | PublicKey currPubKey = x509Cert.getPublicKey(); | ||
| 185 | String currSigAlg = x509Cert.getSigAlgName(); | ||
| 186 | |||
| 187 | AlgorithmId algorithmId = null; | ||
| 188 | try { | ||
| 189 | algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG); | ||
| 190 | } catch (CertificateException ce) { | ||
| 191 | throw new CertPathValidatorException(ce); | ||
| 192 | } | ||
| 193 | |||
| 194 | AlgorithmParameters currSigAlgParams = algorithmId.getParameters(); | ||
| 195 | |||
| 196 | // Check the current signature algorithm | ||
| 197 | if (!constraints.permits( | ||
| 198 | SIGNATURE_PRIMITIVE_SET, | ||
| 199 | currSigAlg, currSigAlgParams)) { | ||
| 200 | throw new CertPathValidatorException( | ||
| 201 | "Algorithm constraints check failed: " + currSigAlg, | ||
| 202 | null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); | ||
| 203 | } | ||
| 204 | |||
| 205 | // check the key usage and key size | ||
| 206 | boolean[] keyUsage = x509Cert.getKeyUsage(); | ||
| 207 | if (keyUsage != null && keyUsage.length < 9) { | ||
| 208 | throw new CertPathValidatorException( | ||
| 209 | "incorrect KeyUsage extension", | ||
| 210 | null, null, -1, PKIXReason.INVALID_KEY_USAGE); | ||
| 211 | } | ||
| 212 | |||
| 213 | if (keyUsage != null) { | ||
| 214 | Set<CryptoPrimitive> primitives = | ||
| 215 | EnumSet.noneOf(CryptoPrimitive.class); | ||
| 216 | |||
| 217 | if (keyUsage[0] || keyUsage[1] || keyUsage[5] || keyUsage[6]) { | ||
| 218 | // keyUsage[0]: KeyUsage.digitalSignature | ||
| 219 | // keyUsage[1]: KeyUsage.nonRepudiation | ||
| 220 | // keyUsage[5]: KeyUsage.keyCertSign | ||
| 221 | // keyUsage[6]: KeyUsage.cRLSign | ||
| 222 | primitives.add(CryptoPrimitive.SIGNATURE); | ||
| 223 | } | ||
| 224 | |||
| 225 | if (keyUsage[2]) { // KeyUsage.keyEncipherment | ||
| 226 | primitives.add(CryptoPrimitive.KEY_ENCAPSULATION); | ||
| 227 | } | ||
| 228 | |||
| 229 | if (keyUsage[3]) { // KeyUsage.dataEncipherment | ||
| 230 | primitives.add(CryptoPrimitive.PUBLIC_KEY_ENCRYPTION); | ||
| 231 | } | ||
| 232 | |||
| 233 | if (keyUsage[4]) { // KeyUsage.keyAgreement | ||
| 234 | primitives.add(CryptoPrimitive.KEY_AGREEMENT); | ||
| 235 | } | ||
| 236 | |||
| 237 | // KeyUsage.encipherOnly and KeyUsage.decipherOnly are | ||
| 238 | // undefined in the absence of the keyAgreement bit. | ||
| 239 | |||
| 240 | if (!primitives.isEmpty()) { | ||
| 241 | if (!constraints.permits(primitives, currPubKey)) { | ||
| 242 | throw new CertPathValidatorException( | ||
| 243 | "algorithm constraints check failed", | ||
| 244 | null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); | ||
| 245 | } | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | // Check with previous cert for signature algorithm and public key | ||
| 250 | if (prevPubKey != null) { | ||
| 251 | if (currSigAlg != null) { | ||
| 252 | if (!constraints.permits( | ||
| 253 | SIGNATURE_PRIMITIVE_SET, | ||
| 254 | currSigAlg, prevPubKey, currSigAlgParams)) { | ||
| 255 | throw new CertPathValidatorException( | ||
| 256 | "Algorithm constraints check failed: " + currSigAlg, | ||
| 257 | null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | // Inherit key parameters from previous key | ||
| 262 | if (currPubKey instanceof DSAPublicKey && | ||
| 263 | ((DSAPublicKey)currPubKey).getParams() == null) { | ||
| 264 | // Inherit DSA parameters from previous key | ||
| 265 | if (!(prevPubKey instanceof DSAPublicKey)) { | ||
| 266 | throw new CertPathValidatorException("Input key is not " + | ||
| 267 | "of a appropriate type for inheriting parameters"); | ||
| 268 | } | ||
| 269 | |||
| 270 | DSAParams params = ((DSAPublicKey)prevPubKey).getParams(); | ||
| 271 | if (params == null) { | ||
| 272 | throw new CertPathValidatorException( | ||
| 273 | "Key parameters missing"); | ||
| 274 | } | ||
| 275 | |||
| 276 | try { | ||
| 277 | BigInteger y = ((DSAPublicKey)currPubKey).getY(); | ||
| 278 | KeyFactory kf = KeyFactory.getInstance("DSA"); | ||
| 279 | DSAPublicKeySpec ks = new DSAPublicKeySpec(y, | ||
| 280 | params.getP(), | ||
| 281 | params.getQ(), | ||
| 282 | params.getG()); | ||
| 283 | currPubKey = kf.generatePublic(ks); | ||
| 284 | } catch (GeneralSecurityException e) { | ||
| 285 | throw new CertPathValidatorException("Unable to generate " + | ||
| 286 | "key with inherited parameters: " + e.getMessage(), e); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | // reset the previous public key | ||
| 292 | prevPubKey = currPubKey; | ||
| 293 | |||
| 294 | // check the extended key usage, ignore the check now | ||
| 295 | // List<String> extendedKeyUsages = x509Cert.getExtendedKeyUsage(); | ||
| 296 | |||
| 297 | // DO NOT remove any unresolved critical extensions | ||
| 298 | } | ||
| 299 | |||
| 300 | /** | ||
| 301 | * Try to set the trust anchor of the checker. | ||
| 302 | * <p> | ||
| 303 | * If there is no trust anchor specified and the checker has not started, | ||
| 304 | * set the trust anchor. | ||
| 305 | * | ||
| 306 | * @param anchor the trust anchor selected to validate the target | ||
| 307 | * certificate | ||
| 308 | */ | ||
| 309 | void trySetTrustAnchor(TrustAnchor anchor) { | ||
| 310 | // Don't bother if the check has started or trust anchor has already | ||
| 311 | // specified. | ||
| 312 | if (prevPubKey == null) { | ||
| 313 | if (anchor == null) { | ||
| 314 | throw new IllegalArgumentException( | ||
| 315 | "The trust anchor cannot be null"); | ||
| 316 | } | ||
| 317 | |||
| 318 | // Don't bother to change the trustedPubKey. | ||
| 319 | if (anchor.getTrustedCert() != null) { | ||
| 320 | prevPubKey = anchor.getTrustedCert().getPublicKey(); | ||
| 321 | } else { | ||
| 322 | prevPubKey = anchor.getCAPublicKey(); | ||
| 323 | } | ||
| 324 | } | ||
| 325 | } | ||
| 326 | |||
| 327 | /** | ||
| 328 | * Check the signature algorithm with the specified public key. | ||
| 329 | * | ||
| 330 | * @param key the public key to verify the CRL signature | ||
| 331 | * @param crl the target CRL | ||
| 332 | */ | ||
| 333 | static void check(PublicKey key, X509CRL crl) | ||
| 334 | throws CertPathValidatorException { | ||
| 335 | |||
| 336 | X509CRLImpl x509CRLImpl = null; | ||
| 337 | try { | ||
| 338 | x509CRLImpl = X509CRLImpl.toImpl(crl); | ||
| 339 | } catch (CRLException ce) { | ||
| 340 | throw new CertPathValidatorException(ce); | ||
| 341 | } | ||
| 342 | |||
| 343 | AlgorithmId algorithmId = x509CRLImpl.getSigAlgId(); | ||
| 344 | check(key, algorithmId); | ||
| 345 | } | ||
| 346 | |||
| 347 | /** | ||
| 348 | * Check the signature algorithm with the specified public key. | ||
| 349 | * | ||
| 350 | * @param key the public key to verify the CRL signature | ||
| 351 | * @param crl the target CRL | ||
| 352 | */ | ||
| 353 | static void check(PublicKey key, AlgorithmId algorithmId) | ||
| 354 | throws CertPathValidatorException { | ||
| 355 | String sigAlgName = algorithmId.getName(); | ||
| 356 | AlgorithmParameters sigAlgParams = algorithmId.getParameters(); | ||
| 357 | |||
| 358 | if (!certPathDefaultConstraints.permits( | ||
| 359 | SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) { | ||
| 360 | throw new CertPathValidatorException( | ||
| 361 | "algorithm check failed: " + sigAlgName + " is disabled", | ||
| 362 | null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); | ||
| 363 | } | ||
| 364 | } | ||
| 365 | |||
| 366 | } | ||
| 367 | |||