1/* 2 * Copyright (c) 2012, 2016, 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 26package sun.security.util; 27 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 javax.crypto.SecretKey; 39import javax.crypto.interfaces.DHKey; 40import javax.crypto.interfaces.DHPublicKey; 41import javax.crypto.spec.DHParameterSpec; 42import javax.crypto.spec.DHPublicKeySpec; 43import java.math.BigInteger; 44 45import sun.security.jca.JCAUtil; 46 47/** 48 * A utility class to get key length, valiate keys, etc. 49 */ 50public final class KeyUtil { 51 52 /** 53 * Returns the key size of the given key object in bits. 54 * 55 * @param key the key object, cannot be null 56 * @return the key size of the given key object in bits, or -1 if the 57 * key size is not accessible 58 */ 59 public static final int getKeySize(Key key) { 60 int size = -1; 61 62 if (key instanceof Length) { 63 try { 64 Length ruler = (Length)key; 65 size = ruler.length(); 66 } catch (UnsupportedOperationException usoe) { 67 // ignore the exception 68 } 69 70 if (size >= 0) { 71 return size; 72 } 73 } 74 75 // try to parse the length from key specification 76 if (key instanceof SecretKey) { 77 SecretKey sk = (SecretKey)key; 78 String format = sk.getFormat(); 79 if ("RAW".equals(format) && sk.getEncoded() != null) { 80 size = (sk.getEncoded().length * 8); 81 } // Otherwise, it may be a unextractable key of PKCS#11, or 82 // a key we are not able to handle. 83 } else if (key instanceof RSAKey) { 84 RSAKey pubk = (RSAKey)key; 85 size = pubk.getModulus().bitLength(); 86 } else if (key instanceof ECKey) { 87 ECKey pubk = (ECKey)key; 88 size = pubk.getParams().getOrder().bitLength(); 89 } else if (key instanceof DSAKey) { 90 DSAKey pubk = (DSAKey)key; 91 DSAParams params = pubk.getParams(); // params can be null 92 size = (params != null) ? params.getP().bitLength() : -1; 93 } else if (key instanceof DHKey) { 94 DHKey pubk = (DHKey)key; 95 size = pubk.getParams().getP().bitLength(); 96 } // Otherwise, it may be a unextractable key of PKCS#11, or 97 // a key we are not able to handle. 98 99 return size; 100 } 101 102 /** 103 * Returns whether the key is valid or not. 104 * <P> 105 * Note that this method is only apply to DHPublicKey at present. 106 * 107 * @param key the key object, cannot be null 108 * 109 * @throws NullPointerException if {@code key} is null 110 * @throws InvalidKeyException if {@code key} is invalid 111 */ 112 public static final void validate(Key key) 113 throws InvalidKeyException { 114 if (key == null) { 115 throw new NullPointerException( 116 "The key to be validated cannot be null"); 117 } 118 119 if (key instanceof DHPublicKey) { 120 validateDHPublicKey((DHPublicKey)key); 121 } 122 } 123 124 125 /** 126 * Returns whether the key spec is valid or not. 127 * <P> 128 * Note that this method is only apply to DHPublicKeySpec at present. 129 * 130 * @param keySpec 131 * the key spec object, cannot be null 132 * 133 * @throws NullPointerException if {@code keySpec} is null 134 * @throws InvalidKeyException if {@code keySpec} is invalid 135 */ 136 public static final void validate(KeySpec keySpec) 137 throws InvalidKeyException { 138 if (keySpec == null) { 139 throw new NullPointerException( 140 "The key spec to be validated cannot be null"); 141 } 142 143 if (keySpec instanceof DHPublicKeySpec) { 144 validateDHPublicKey((DHPublicKeySpec)keySpec); 145 } 146 } 147 148 /** 149 * Returns whether the specified provider is Oracle provider or not. 150 * 151 * @param providerName 152 * the provider name 153 * @return true if, and only if, the provider of the specified 154 * {@code providerName} is Oracle provider 155 */ 156 public static final boolean isOracleJCEProvider(String providerName) { 157 return providerName != null && 158 (providerName.equals("SunJCE") || 159 providerName.equals("SunMSCAPI") || 160 providerName.equals("OracleUcrypto") || 161 providerName.startsWith("SunPKCS11")); 162 } 163 164 /** 165 * Check the format of TLS PreMasterSecret. 166 * <P> 167 * To avoid vulnerabilities described by section 7.4.7.1, RFC 5246, 168 * treating incorrectly formatted message blocks and/or mismatched 169 * version numbers in a manner indistinguishable from correctly 170 * formatted RSA blocks. 171 * 172 * RFC 5246 describes the approach as: 173 * <pre>{@literal 174 * 175 * 1. Generate a string R of 48 random bytes 176 * 177 * 2. Decrypt the message to recover the plaintext M 178 * 179 * 3. If the PKCS#1 padding is not correct, or the length of message 180 * M is not exactly 48 bytes: 181 * pre_master_secret = R 182 * else If ClientHello.client_version <= TLS 1.0, and version 183 * number check is explicitly disabled: 184 * premaster secret = M 185 * else If M[0..1] != ClientHello.client_version: 186 * premaster secret = R 187 * else: 188 * premaster secret = M 189 * 190 * Note that #2 should have completed before the call to this method. 191 * }</pre> 192 * 193 * @param clientVersion the version of the TLS protocol by which the 194 * client wishes to communicate during this session 195 * @param serverVersion the negotiated version of the TLS protocol which 196 * contains the lower of that suggested by the client in the client 197 * hello and the highest supported by the server. 198 * @param encoded the encoded key in its "RAW" encoding format 199 * @param isFailOver whether or not the previous decryption of the 200 * encrypted PreMasterSecret message run into problem 201 * @return the polished PreMasterSecret key in its "RAW" encoding format 202 */ 203 public static byte[] checkTlsPreMasterSecretKey( 204 int clientVersion, int serverVersion, SecureRandom random, 205 byte[] encoded, boolean isFailOver) { 206 207 if (random == null) { 208 random = JCAUtil.getSecureRandom(); 209 } 210 byte[] replacer = new byte[48]; 211 random.nextBytes(replacer); 212 213 if (!isFailOver && (encoded != null)) { 214 // check the length 215 if (encoded.length != 48) { 216 // private, don't need to clone the byte array. 217 return replacer; 218 } 219 220 int encodedVersion = 221 ((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF); 222 if (clientVersion != encodedVersion) { 223 if (clientVersion > 0x0301 || // 0x0301: TLSv1 224 serverVersion != encodedVersion) { 225 encoded = replacer; 226 } // Otherwise, For compatibility, we maintain the behavior 227 // that the version in pre_master_secret can be the 228 // negotiated version for TLS v1.0 and SSL v3.0. 229 } 230 231 // private, don't need to clone the byte array. 232 return encoded; 233 } 234 235 // private, don't need to clone the byte array. 236 return replacer; 237 } 238 239 /** 240 * Returns whether the Diffie-Hellman public key is valid or not. 241 * 242 * Per RFC 2631 and NIST SP800-56A, the following algorithm is used to 243 * validate Diffie-Hellman public keys: 244 * 1. Verify that y lies within the interval [2,p-1]. If it does not, 245 * the key is invalid. 246 * 2. Compute y^q mod p. If the result == 1, the key is valid. 247 * Otherwise the key is invalid. 248 */ 249 private static void validateDHPublicKey(DHPublicKey publicKey) 250 throws InvalidKeyException { 251 DHParameterSpec paramSpec = publicKey.getParams(); 252 253 BigInteger p = paramSpec.getP(); 254 BigInteger g = paramSpec.getG(); 255 BigInteger y = publicKey.getY(); 256 257 validateDHPublicKey(p, g, y); 258 } 259 260 private static void validateDHPublicKey(DHPublicKeySpec publicKeySpec) 261 throws InvalidKeyException { 262 validateDHPublicKey(publicKeySpec.getP(), 263 publicKeySpec.getG(), publicKeySpec.getY()); 264 } 265 266 private static void validateDHPublicKey(BigInteger p, 267 BigInteger g, BigInteger y) throws InvalidKeyException { 268 269 // For better interoperability, the interval is limited to [2, p-2]. 270 BigInteger leftOpen = BigInteger.ONE; 271 BigInteger rightOpen = p.subtract(BigInteger.ONE); 272 if (y.compareTo(leftOpen) <= 0) { 273 throw new InvalidKeyException( 274 "Diffie-Hellman public key is too small"); 275 } 276 if (y.compareTo(rightOpen) >= 0) { 277 throw new InvalidKeyException( 278 "Diffie-Hellman public key is too large"); 279 } 280 281 // y^q mod p == 1? 282 // Unable to perform this check as q is unknown in this circumstance. 283 284 // p is expected to be prime. However, it is too expensive to check 285 // that p is prime. Instead, in order to mitigate the impact of 286 // non-prime values, we check that y is not a factor of p. 287 BigInteger r = p.remainder(y); 288 if (r.equals(BigInteger.ZERO)) { 289 throw new InvalidKeyException("Invalid Diffie-Hellman parameters"); 290 } 291 } 292 293 /** 294 * Trim leading (most significant) zeroes from the result. 295 * 296 * @throws NullPointerException if {@code b} is null 297 */ 298 public static byte[] trimZeroes(byte[] b) { 299 int i = 0; 300 while ((i < b.length - 1) && (b[i] == 0)) { 301 i++; 302 } 303 if (i == 0) { 304 return b; 305 } 306 byte[] t = new byte[b.length - i]; 307 System.arraycopy(b, i, t, 0, t.length); 308 return t; 309 } 310 311} 312 313