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