1 /*
2  * Copyright (c) 2005, 2013, 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 com.sun.crypto.provider;
27 
28 import java.security.*;
29 import java.security.spec.AlgorithmParameterSpec;
30 
31 import javax.crypto.*;
32 import javax.crypto.spec.*;
33 
34 import sun.security.internal.spec.*;
35 
36 import static com.sun.crypto.provider.TlsPrfGenerator.*;
37 
38 /**
39  * KeyGenerator implementation for the SSL/TLS master secret derivation.
40  *
41  * @author  Andreas Sterbenz
42  * @since   1.6
43  */
44 public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
45 
46     private static final String MSG = "TlsKeyMaterialGenerator must be "
47         + "initialized using a TlsKeyMaterialParameterSpec";
48 
49     @SuppressWarnings("deprecation")
50     private TlsKeyMaterialParameterSpec spec;
51 
52     private int protocolVersion;
53 
TlsKeyMaterialGenerator()54     public TlsKeyMaterialGenerator() {
55     }
56 
engineInit(SecureRandom random)57     protected void engineInit(SecureRandom random) {
58         throw new InvalidParameterException(MSG);
59     }
60 
61     @SuppressWarnings("deprecation")
engineInit(AlgorithmParameterSpec params, SecureRandom random)62     protected void engineInit(AlgorithmParameterSpec params,
63             SecureRandom random) throws InvalidAlgorithmParameterException {
64         if (params instanceof TlsKeyMaterialParameterSpec == false) {
65             throw new InvalidAlgorithmParameterException(MSG);
66         }
67         this.spec = (TlsKeyMaterialParameterSpec)params;
68         if ("RAW".equals(spec.getMasterSecret().getFormat()) == false) {
69             throw new InvalidAlgorithmParameterException(
70                 "Key format must be RAW");
71         }
72         protocolVersion = (spec.getMajorVersion() << 8)
73             | spec.getMinorVersion();
74         if ((protocolVersion < 0x0300) || (protocolVersion > 0x0303)) {
75             throw new InvalidAlgorithmParameterException(
76                 "Only SSL 3.0, TLS 1.0/1.1/1.2 supported");
77         }
78     }
79 
engineInit(int keysize, SecureRandom random)80     protected void engineInit(int keysize, SecureRandom random) {
81         throw new InvalidParameterException(MSG);
82     }
83 
engineGenerateKey()84     protected SecretKey engineGenerateKey() {
85         if (spec == null) {
86             throw new IllegalStateException(
87                 "TlsKeyMaterialGenerator must be initialized");
88         }
89         try {
90             return engineGenerateKey0();
91         } catch (GeneralSecurityException e) {
92             throw new ProviderException(e);
93         }
94     }
95 
96     @SuppressWarnings("deprecation")
engineGenerateKey0()97     private SecretKey engineGenerateKey0() throws GeneralSecurityException {
98         byte[] masterSecret = spec.getMasterSecret().getEncoded();
99 
100         byte[] clientRandom = spec.getClientRandom();
101         byte[] serverRandom = spec.getServerRandom();
102 
103         SecretKey clientMacKey = null;
104         SecretKey serverMacKey = null;
105         SecretKey clientCipherKey = null;
106         SecretKey serverCipherKey = null;
107         IvParameterSpec clientIv = null;
108         IvParameterSpec serverIv = null;
109 
110         int macLength = spec.getMacKeyLength();
111         int expandedKeyLength = spec.getExpandedCipherKeyLength();
112         boolean isExportable = (expandedKeyLength != 0);
113         int keyLength = spec.getCipherKeyLength();
114         int ivLength = spec.getIvLength();
115 
116         int keyBlockLen = macLength + keyLength
117             + (isExportable ? 0 : ivLength);
118         keyBlockLen <<= 1;
119         byte[] keyBlock = new byte[keyBlockLen];
120 
121         // These may be used again later for exportable suite calculations.
122         MessageDigest md5 = null;
123         MessageDigest sha = null;
124 
125         // generate key block
126         if (protocolVersion >= 0x0303) {
127             // TLS 1.2
128             byte[] seed = concat(serverRandom, clientRandom);
129             keyBlock = doTLS12PRF(masterSecret, LABEL_KEY_EXPANSION, seed,
130                         keyBlockLen, spec.getPRFHashAlg(),
131                         spec.getPRFHashLength(), spec.getPRFBlockSize());
132         } else if (protocolVersion >= 0x0301) {
133             // TLS 1.0/1.1
134             md5 = MessageDigest.getInstance("MD5");
135             sha = MessageDigest.getInstance("SHA1");
136             byte[] seed = concat(serverRandom, clientRandom);
137             keyBlock = doTLS10PRF(masterSecret, LABEL_KEY_EXPANSION, seed,
138                         keyBlockLen, md5, sha);
139         } else {
140             // SSL
141             md5 = MessageDigest.getInstance("MD5");
142             sha = MessageDigest.getInstance("SHA1");
143             keyBlock = new byte[keyBlockLen];
144 
145             byte[] tmp = new byte[20];
146             for (int i = 0, remaining = keyBlockLen;
147                  remaining > 0;
148                  i++, remaining -= 16) {
149 
150                 sha.update(SSL3_CONST[i]);
151                 sha.update(masterSecret);
152                 sha.update(serverRandom);
153                 sha.update(clientRandom);
154                 sha.digest(tmp, 0, 20);
155 
156                 md5.update(masterSecret);
157                 md5.update(tmp);
158 
159                 if (remaining >= 16) {
160                     md5.digest(keyBlock, i << 4, 16);
161                 } else {
162                     md5.digest(tmp, 0, 16);
163                     System.arraycopy(tmp, 0, keyBlock, i << 4, remaining);
164                 }
165             }
166         }
167 
168         // partition keyblock into individual secrets
169 
170         int ofs = 0;
171         if (macLength != 0) {
172             byte[] tmp = new byte[macLength];
173 
174             // mac keys
175             System.arraycopy(keyBlock, ofs, tmp, 0, macLength);
176             ofs += macLength;
177             clientMacKey = new SecretKeySpec(tmp, "Mac");
178 
179             System.arraycopy(keyBlock, ofs, tmp, 0, macLength);
180             ofs += macLength;
181             serverMacKey = new SecretKeySpec(tmp, "Mac");
182         }
183 
184         if (keyLength == 0) { // SSL_RSA_WITH_NULL_* ciphersuites
185             return new TlsKeyMaterialSpec(clientMacKey, serverMacKey);
186         }
187 
188         String alg = spec.getCipherAlgorithm();
189 
190         // cipher keys
191         byte[] clientKeyBytes = new byte[keyLength];
192         System.arraycopy(keyBlock, ofs, clientKeyBytes, 0, keyLength);
193         ofs += keyLength;
194 
195         byte[] serverKeyBytes = new byte[keyLength];
196         System.arraycopy(keyBlock, ofs, serverKeyBytes, 0, keyLength);
197         ofs += keyLength;
198 
199         if (isExportable == false) {
200             // cipher keys
201             clientCipherKey = new SecretKeySpec(clientKeyBytes, alg);
202             serverCipherKey = new SecretKeySpec(serverKeyBytes, alg);
203 
204             // IV keys if needed.
205             if (ivLength != 0) {
206                 byte[] tmp = new byte[ivLength];
207 
208                 System.arraycopy(keyBlock, ofs, tmp, 0, ivLength);
209                 ofs += ivLength;
210                 clientIv = new IvParameterSpec(tmp);
211 
212                 System.arraycopy(keyBlock, ofs, tmp, 0, ivLength);
213                 ofs += ivLength;
214                 serverIv = new IvParameterSpec(tmp);
215             }
216         } else {
217             // if exportable suites, calculate the alternate
218             // cipher key expansion and IV generation
219             if (protocolVersion >= 0x0302) {
220                 // TLS 1.1+
221                 throw new RuntimeException(
222                     "Internal Error:  TLS 1.1+ should not be negotiating" +
223                     "exportable ciphersuites");
224             } else if (protocolVersion == 0x0301) {
225                 // TLS 1.0
226                 byte[] seed = concat(clientRandom, serverRandom);
227 
228                 byte[] tmp = doTLS10PRF(clientKeyBytes,
229                     LABEL_CLIENT_WRITE_KEY, seed, expandedKeyLength, md5, sha);
230                 clientCipherKey = new SecretKeySpec(tmp, alg);
231 
232                 tmp = doTLS10PRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed,
233                             expandedKeyLength, md5, sha);
234                 serverCipherKey = new SecretKeySpec(tmp, alg);
235 
236                 if (ivLength != 0) {
237                     tmp = new byte[ivLength];
238                     byte[] block = doTLS10PRF(null, LABEL_IV_BLOCK, seed,
239                                 ivLength << 1, md5, sha);
240                     System.arraycopy(block, 0, tmp, 0, ivLength);
241                     clientIv = new IvParameterSpec(tmp);
242                     System.arraycopy(block, ivLength, tmp, 0, ivLength);
243                     serverIv = new IvParameterSpec(tmp);
244                 }
245             } else {
246                 // SSLv3
247                 byte[] tmp = new byte[expandedKeyLength];
248 
249                 md5.update(clientKeyBytes);
250                 md5.update(clientRandom);
251                 md5.update(serverRandom);
252                 System.arraycopy(md5.digest(), 0, tmp, 0, expandedKeyLength);
253                 clientCipherKey = new SecretKeySpec(tmp, alg);
254 
255                 md5.update(serverKeyBytes);
256                 md5.update(serverRandom);
257                 md5.update(clientRandom);
258                 System.arraycopy(md5.digest(), 0, tmp, 0, expandedKeyLength);
259                 serverCipherKey = new SecretKeySpec(tmp, alg);
260 
261                 if (ivLength != 0) {
262                     tmp = new byte[ivLength];
263 
264                     md5.update(clientRandom);
265                     md5.update(serverRandom);
266                     System.arraycopy(md5.digest(), 0, tmp, 0, ivLength);
267                     clientIv = new IvParameterSpec(tmp);
268 
269                     md5.update(serverRandom);
270                     md5.update(clientRandom);
271                     System.arraycopy(md5.digest(), 0, tmp, 0, ivLength);
272                     serverIv = new IvParameterSpec(tmp);
273                 }
274             }
275         }
276 
277         return new TlsKeyMaterialSpec(clientMacKey, serverMacKey,
278             clientCipherKey, clientIv, serverCipherKey, serverIv);
279     }
280 
281 }
282