Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/util/KeyUtil.java
38830 views
/*1* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.util;2627import java.security.AlgorithmParameters;28import java.security.Key;29import java.security.PrivilegedAction;30import java.security.AccessController;31import java.security.InvalidKeyException;32import java.security.interfaces.ECKey;33import java.security.interfaces.RSAKey;34import java.security.interfaces.DSAKey;35import java.security.interfaces.DSAParams;36import java.security.SecureRandom;37import java.security.spec.KeySpec;38import java.security.spec.ECParameterSpec;39import java.security.spec.InvalidParameterSpecException;40import javax.crypto.SecretKey;41import javax.crypto.interfaces.DHKey;42import javax.crypto.interfaces.DHPublicKey;43import javax.crypto.spec.DHParameterSpec;44import javax.crypto.spec.DHPublicKeySpec;45import java.math.BigInteger;4647import sun.security.jca.JCAUtil;4849/**50* A utility class to get key length, valiate keys, etc.51*/52public final class KeyUtil {5354/**55* Returns the key size of the given key object in bits.56*57* @param key the key object, cannot be null58* @return the key size of the given key object in bits, or -1 if the59* key size is not accessible60*/61public static final int getKeySize(Key key) {62int size = -1;6364if (key instanceof Length) {65try {66Length ruler = (Length)key;67size = ruler.length();68} catch (UnsupportedOperationException usoe) {69// ignore the exception70}7172if (size >= 0) {73return size;74}75}7677// try to parse the length from key specification78if (key instanceof SecretKey) {79SecretKey sk = (SecretKey)key;80String format = sk.getFormat();81if ("RAW".equals(format) && sk.getEncoded() != null) {82size = (sk.getEncoded().length * 8);83} // Otherwise, it may be a unextractable key of PKCS#11, or84// a key we are not able to handle.85} else if (key instanceof RSAKey) {86RSAKey pubk = (RSAKey)key;87size = pubk.getModulus().bitLength();88} else if (key instanceof ECKey) {89ECKey pubk = (ECKey)key;90size = pubk.getParams().getOrder().bitLength();91} else if (key instanceof DSAKey) {92DSAKey pubk = (DSAKey)key;93DSAParams params = pubk.getParams(); // params can be null94size = (params != null) ? params.getP().bitLength() : -1;95} else if (key instanceof DHKey) {96DHKey pubk = (DHKey)key;97size = pubk.getParams().getP().bitLength();98} // Otherwise, it may be a unextractable key of PKCS#11, or99// a key we are not able to handle.100101return size;102}103104/**105* Returns the key size of the given cryptographic parameters in bits.106*107* @param parameters the cryptographic parameters, cannot be null108* @return the key size of the given cryptographic parameters in bits,109* or -1 if the key size is not accessible110*/111public static final int getKeySize(AlgorithmParameters parameters) {112113String algorithm = parameters.getAlgorithm();114switch (algorithm) {115case "EC":116try {117ECKeySizeParameterSpec ps = parameters.getParameterSpec(118ECKeySizeParameterSpec.class);119if (ps != null) {120return ps.getKeySize();121}122} catch (InvalidParameterSpecException ipse) {123// ignore124}125126try {127ECParameterSpec ps = parameters.getParameterSpec(128ECParameterSpec.class);129if (ps != null) {130return ps.getOrder().bitLength();131}132} catch (InvalidParameterSpecException ipse) {133// ignore134}135136// Note: the ECGenParameterSpec case should be covered by the137// ECParameterSpec case above.138// See ECUtil.getECParameterSpec(Provider, String).139140break;141case "DiffieHellman":142try {143DHParameterSpec ps = parameters.getParameterSpec(144DHParameterSpec.class);145if (ps != null) {146return ps.getP().bitLength();147}148} catch (InvalidParameterSpecException ipse) {149// ignore150}151break;152153// May support more AlgorithmParameters algorithms in the future.154}155156return -1;157}158159/**160* Returns whether the key is valid or not.161* <P>162* Note that this method is only apply to DHPublicKey at present.163*164* @param publicKey165* the key object, cannot be null166*167* @throws NullPointerException if {@code publicKey} is null168* @throws InvalidKeyException if {@code publicKey} is invalid169*/170public static final void validate(Key key)171throws InvalidKeyException {172if (key == null) {173throw new NullPointerException(174"The key to be validated cannot be null");175}176177if (key instanceof DHPublicKey) {178validateDHPublicKey((DHPublicKey)key);179}180}181182183/**184* Returns whether the key spec is valid or not.185* <P>186* Note that this method is only apply to DHPublicKeySpec at present.187*188* @param keySpec189* the key spec object, cannot be null190*191* @throws NullPointerException if {@code keySpec} is null192* @throws InvalidKeyException if {@code keySpec} is invalid193*/194public static final void validate(KeySpec keySpec)195throws InvalidKeyException {196if (keySpec == null) {197throw new NullPointerException(198"The key spec to be validated cannot be null");199}200201if (keySpec instanceof DHPublicKeySpec) {202validateDHPublicKey((DHPublicKeySpec)keySpec);203}204}205206/**207* Returns whether the specified provider is Oracle provider or not.208*209* @param providerName210* the provider name211* @return true if, and only if, the provider of the specified212* {@code providerName} is Oracle provider213*/214public static final boolean isOracleJCEProvider(String providerName) {215return providerName != null &&216(providerName.equals("SunJCE") ||217providerName.equals("SunMSCAPI") ||218providerName.equals("OracleUcrypto") ||219providerName.startsWith("SunPKCS11"));220}221222/**223* Check the format of TLS PreMasterSecret.224* <P>225* To avoid vulnerabilities described by section 7.4.7.1, RFC 5246,226* treating incorrectly formatted message blocks and/or mismatched227* version numbers in a manner indistinguishable from correctly228* formatted RSA blocks.229*230* RFC 5246 describes the approach as :231*232* 1. Generate a string R of 48 random bytes233*234* 2. Decrypt the message to recover the plaintext M235*236* 3. If the PKCS#1 padding is not correct, or the length of message237* M is not exactly 48 bytes:238* pre_master_secret = R239* else If ClientHello.client_version <= TLS 1.0, and version240* number check is explicitly disabled:241* premaster secret = M242* else If M[0..1] != ClientHello.client_version:243* premaster secret = R244* else:245* premaster secret = M246*247* Note that #2 should have completed before the call to this method.248*249* @param clientVersion the version of the TLS protocol by which the250* client wishes to communicate during this session251* @param serverVersion the negotiated version of the TLS protocol which252* contains the lower of that suggested by the client in the client253* hello and the highest supported by the server.254* @param encoded the encoded key in its "RAW" encoding format255* @param isFailover whether or not the previous decryption of the256* encrypted PreMasterSecret message run into problem257* @return the polished PreMasterSecret key in its "RAW" encoding format258*/259public static byte[] checkTlsPreMasterSecretKey(260int clientVersion, int serverVersion, SecureRandom random,261byte[] encoded, boolean isFailOver) {262263if (random == null) {264random = JCAUtil.getSecureRandom();265}266byte[] replacer = new byte[48];267random.nextBytes(replacer);268269if (!isFailOver && (encoded != null)) {270// check the length271if (encoded.length != 48) {272// private, don't need to clone the byte array.273return replacer;274}275276int encodedVersion =277((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF);278if (clientVersion != encodedVersion) {279if (clientVersion > 0x0301 || // 0x0301: TLSv1280serverVersion != encodedVersion) {281encoded = replacer;282} // Otherwise, For compatibility, we maintain the behavior283// that the version in pre_master_secret can be the284// negotiated version for TLS v1.0 and SSL v3.0.285}286287// private, don't need to clone the byte array.288return encoded;289}290291// private, don't need to clone the byte array.292return replacer;293}294295/**296* Returns whether the Diffie-Hellman public key is valid or not.297*298* Per RFC 2631 and NIST SP800-56A, the following algorithm is used to299* validate Diffie-Hellman public keys:300* 1. Verify that y lies within the interval [2,p-1]. If it does not,301* the key is invalid.302* 2. Compute y^q mod p. If the result == 1, the key is valid.303* Otherwise the key is invalid.304*/305private static void validateDHPublicKey(DHPublicKey publicKey)306throws InvalidKeyException {307DHParameterSpec paramSpec = publicKey.getParams();308309BigInteger p = paramSpec.getP();310BigInteger g = paramSpec.getG();311BigInteger y = publicKey.getY();312313validateDHPublicKey(p, g, y);314}315316private static void validateDHPublicKey(DHPublicKeySpec publicKeySpec)317throws InvalidKeyException {318validateDHPublicKey(publicKeySpec.getP(),319publicKeySpec.getG(), publicKeySpec.getY());320}321322private static void validateDHPublicKey(BigInteger p,323BigInteger g, BigInteger y) throws InvalidKeyException {324325// For better interoperability, the interval is limited to [2, p-2].326BigInteger leftOpen = BigInteger.ONE;327BigInteger rightOpen = p.subtract(BigInteger.ONE);328if (y.compareTo(leftOpen) <= 0) {329throw new InvalidKeyException(330"Diffie-Hellman public key is too small");331}332if (y.compareTo(rightOpen) >= 0) {333throw new InvalidKeyException(334"Diffie-Hellman public key is too large");335}336337// y^q mod p == 1?338// Unable to perform this check as q is unknown in this circumstance.339340// p is expected to be prime. However, it is too expensive to check341// that p is prime. Instead, in order to mitigate the impact of342// non-prime values, we check that y is not a factor of p.343BigInteger r = p.remainder(y);344if (r.equals(BigInteger.ZERO)) {345throw new InvalidKeyException("Invalid Diffie-Hellman parameters");346}347}348349/**350* Trim leading (most significant) zeroes from the result.351*352* @throws NullPointerException if {@code b} is null353*/354public static byte[] trimZeroes(byte[] b) {355int i = 0;356while ((i < b.length - 1) && (b[i] == 0)) {357i++;358}359if (i == 0) {360return b;361}362byte[] t = new byte[b.length - i];363System.arraycopy(b, i, t, 0, t.length);364return t;365}366367}368369370371