1 /* 2 * Copyright 2016 The Android Open Source Project 3 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package sun.security.util; 28 29 import java.security.Key; 30 import java.security.interfaces.ECKey; 31 import java.security.interfaces.RSAKey; 32 import java.security.interfaces.DSAKey; 33 import java.security.interfaces.DSAParams; 34 import java.security.SecureRandom; 35 import java.security.spec.ECParameterSpec; 36 import javax.crypto.SecretKey; 37 import javax.crypto.interfaces.DHKey; 38 39 /** 40 * A utility class to get key length, valiate keys, etc. 41 */ 42 public final class KeyUtil { 43 44 /** 45 * Returns the key size of the given key object in bits. 46 * 47 * @param key the key object, cannot be null 48 * @return the key size of the given key object in bits, or -1 if the 49 * key size is not accessible 50 */ getKeySize(Key key)51 public static final int getKeySize(Key key) { 52 int size = -1; 53 54 if (key instanceof Length) { 55 try { 56 Length ruler = (Length)key; 57 size = ruler.length(); 58 } catch (UnsupportedOperationException usoe) { 59 // ignore the exception 60 } 61 62 if (size >= 0) { 63 return size; 64 } 65 } 66 67 // try to parse the length from key specification 68 if (key instanceof SecretKey) { 69 SecretKey sk = (SecretKey)key; 70 String format = sk.getFormat(); 71 if ("RAW".equals(format) && sk.getEncoded() != null) { 72 size = (sk.getEncoded().length * 8); 73 } // Otherwise, it may be a unextractable key of PKCS#11, or 74 // a key we are not able to handle. 75 } else if (key instanceof RSAKey) { 76 RSAKey pubk = (RSAKey)key; 77 size = pubk.getModulus().bitLength(); 78 } else if (key instanceof ECKey) { 79 ECKey pubk = (ECKey)key; 80 // BEGIN Android-changed 81 // Was: size = pubk.getParams().getOrder().bitLength(); 82 ECParameterSpec params = pubk.getParams(); 83 // According to RFC 3279 section 2.3.5, EC keys are allowed 84 // to inherit parameters in an X.509 certificate issuer's 85 // key parameters, so the parameters may be null. The parent 86 // key will be rejected if its parameters don't pass, so this 87 // is okay. 88 if (params != null) { 89 size = params.getOrder().bitLength(); 90 } 91 // END Android-changed 92 } else if (key instanceof DSAKey) { 93 DSAKey pubk = (DSAKey)key; 94 // BEGIN Android-changed 95 // Was: size = pubk.getParams().getP().bitLength(); 96 DSAParams params = pubk.getParams(); 97 // According to RFC 3279 section 2.3.2, DSA keys are allowed 98 // to inherit parameters in an X.509 certificate issuer's 99 // key parameters, so the parameters may be null. The parent 100 // key will be rejected if its parameters don't pass, so this 101 // is okay. 102 if (params != null) { 103 size = params.getP().bitLength(); 104 } 105 // END Android-changed 106 } else if (key instanceof DHKey) { 107 DHKey pubk = (DHKey)key; 108 size = pubk.getParams().getP().bitLength(); 109 } // Otherwise, it may be a unextractable key of PKCS#11, or 110 // a key we are not able to handle. 111 112 return size; 113 } 114 115 // BEGIN Android-removed 116 /* 117 /** 118 * Returns whether the key is valid or not. 119 * <P> 120 * Note that this method is only apply to DHPublicKey at present. 121 * 122 * @param publicKey 123 * the key object, cannot be null 124 * 125 * @throws NullPointerException if {@code publicKey} is null 126 * @throws InvalidKeyException if {@code publicKey} is invalid 127 * 128 public static final void validate(Key key) 129 throws InvalidKeyException { 130 if (key == null) { 131 throw new NullPointerException( 132 "The key to be validated cannot be null"); 133 } 134 135 if (key instanceof DHPublicKey) { 136 validateDHPublicKey((DHPublicKey)key); 137 } 138 } 139 140 141 /** 142 * Returns whether the key spec is valid or not. 143 * <P> 144 * Note that this method is only apply to DHPublicKeySpec at present. 145 * 146 * @param keySpec 147 * the key spec object, cannot be null 148 * 149 * @throws NullPointerException if {@code keySpec} is null 150 * @throws InvalidKeyException if {@code keySpec} is invalid 151 * 152 public static final void validate(KeySpec keySpec) 153 throws InvalidKeyException { 154 if (keySpec == null) { 155 throw new NullPointerException( 156 "The key spec to be validated cannot be null"); 157 } 158 159 if (keySpec instanceof DHPublicKeySpec) { 160 validateDHPublicKey((DHPublicKeySpec)keySpec); 161 } 162 } 163 164 /** 165 * Returns whether the specified provider is Oracle provider or not. 166 * <P> 167 * Note that this method is only apply to SunJCE and SunPKCS11 at present. 168 * 169 * @param providerName 170 * the provider name 171 * @return true if, and only if, the provider of the specified 172 * {@code providerName} is Oracle provider 173 * 174 public static final boolean isOracleJCEProvider(String providerName) { 175 return providerName != null && (providerName.equals("SunJCE") || 176 providerName.startsWith("SunPKCS11")); 177 } 178 179 /** 180 * Check the format of TLS PreMasterSecret. 181 * <P> 182 * To avoid vulnerabilities described by section 7.4.7.1, RFC 5246, 183 * treating incorrectly formatted message blocks and/or mismatched 184 * version numbers in a manner indistinguishable from correctly 185 * formatted RSA blocks. 186 * 187 * RFC 5246 describes the approach as : 188 * 189 * 1. Generate a string R of 48 random bytes 190 * 191 * 2. Decrypt the message to recover the plaintext M 192 * 193 * 3. If the PKCS#1 padding is not correct, or the length of message 194 * M is not exactly 48 bytes: 195 * pre_master_secret = R 196 * else If ClientHello.client_version <= TLS 1.0, and version 197 * number check is explicitly disabled: 198 * premaster secret = M 199 * else If M[0..1] != ClientHello.client_version: 200 * premaster secret = R 201 * else: 202 * premaster secret = M 203 * 204 * Note that #2 should have completed before the call to this method. 205 * 206 * @param clientVersion the version of the TLS protocol by which the 207 * client wishes to communicate during this session 208 * @param serverVersion the negotiated version of the TLS protocol which 209 * contains the lower of that suggested by the client in the client 210 * hello and the highest supported by the server. 211 * @param encoded the encoded key in its "RAW" encoding format 212 * @param isFailover whether or not the previous decryption of the 213 * encrypted PreMasterSecret message run into problem 214 * @return the polished PreMasterSecret key in its "RAW" encoding format 215 * 216 public static byte[] checkTlsPreMasterSecretKey( 217 int clientVersion, int serverVersion, SecureRandom random, 218 byte[] encoded, boolean isFailOver) { 219 220 if (random == null) { 221 random = new SecureRandom(); 222 } 223 byte[] replacer = new byte[48]; 224 random.nextBytes(replacer); 225 226 if (!isFailOver && (encoded != null)) { 227 // check the length 228 if (encoded.length != 48) { 229 // private, don't need to clone the byte array. 230 return replacer; 231 } 232 233 int encodedVersion = 234 ((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF); 235 if (clientVersion != encodedVersion) { 236 if (clientVersion > 0x0301 || // 0x0301: TLSv1 237 serverVersion != encodedVersion) { 238 encoded = replacer; 239 } // Otherwise, For compatibility, we maintain the behavior 240 // that the version in pre_master_secret can be the 241 // negotiated version for TLS v1.0 and SSL v3.0. 242 } 243 244 // private, don't need to clone the byte array. 245 return encoded; 246 } 247 248 // private, don't need to clone the byte array. 249 return replacer; 250 } 251 252 /** 253 * Returns whether the Diffie-Hellman public key is valid or not. 254 * 255 * Per RFC 2631 and NIST SP800-56A, the following algorithm is used to 256 * validate Diffie-Hellman public keys: 257 * 1. Verify that y lies within the interval [2,p-1]. If it does not, 258 * the key is invalid. 259 * 2. Compute y^q mod p. If the result == 1, the key is valid. 260 * Otherwise the key is invalid. 261 * 262 private static void validateDHPublicKey(DHPublicKey publicKey) 263 throws InvalidKeyException { 264 DHParameterSpec paramSpec = publicKey.getParams(); 265 266 BigInteger p = paramSpec.getP(); 267 BigInteger g = paramSpec.getG(); 268 BigInteger y = publicKey.getY(); 269 270 validateDHPublicKey(p, g, y); 271 } 272 273 private static void validateDHPublicKey(DHPublicKeySpec publicKeySpec) 274 throws InvalidKeyException { 275 validateDHPublicKey(publicKeySpec.getP(), 276 publicKeySpec.getG(), publicKeySpec.getY()); 277 } 278 279 private static void validateDHPublicKey(BigInteger p, 280 BigInteger g, BigInteger y) throws InvalidKeyException { 281 282 // For better interoperability, the interval is limited to [2, p-2]. 283 BigInteger leftOpen = BigInteger.ONE; 284 BigInteger rightOpen = p.subtract(BigInteger.ONE); 285 if (y.compareTo(leftOpen) <= 0) { 286 throw new InvalidKeyException( 287 "Diffie-Hellman public key is too small"); 288 } 289 if (y.compareTo(rightOpen) >= 0) { 290 throw new InvalidKeyException( 291 "Diffie-Hellman public key is too large"); 292 } 293 294 // y^q mod p == 1? 295 // Unable to perform this check as q is unknown in this circumstance. 296 297 // p is expected to be prime. However, it is too expensive to check 298 // that p is prime. Instead, in order to mitigate the impact of 299 // non-prime values, we check that y is not a factor of p. 300 BigInteger r = p.remainder(y); 301 if (r.equals(BigInteger.ZERO)) { 302 throw new InvalidKeyException("Invalid Diffie-Hellman parameters"); 303 } 304 } 305 306 /** 307 * Trim leading (most significant) zeroes from the result. 308 * 309 * @throws NullPointerException if {@code b} is null 310 * 311 public static byte[] trimZeroes(byte[] b) { 312 int i = 0; 313 while ((i < b.length - 1) && (b[i] == 0)) { 314 i++; 315 } 316 if (i == 0) { 317 return b; 318 } 319 byte[] t = new byte[b.length - i]; 320 System.arraycopy(b, i, t, 0, t.length); 321 return t; 322 } 323 */ 324 // END Android-removed 325 } 326 327