2
|
1 |
/*
|
7043
|
2 |
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
2
|
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
|
5506
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
2
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
5506
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
2
|
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 |
*
|
5506
|
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.
|
2
|
24 |
*/
|
|
25 |
|
|
26 |
package com.sun.crypto.provider;
|
|
27 |
|
|
28 |
import java.util.Arrays;
|
|
29 |
|
|
30 |
import java.security.*;
|
|
31 |
import java.security.spec.AlgorithmParameterSpec;
|
|
32 |
|
|
33 |
import javax.crypto.*;
|
|
34 |
import javax.crypto.spec.SecretKeySpec;
|
|
35 |
|
|
36 |
import sun.security.internal.spec.TlsPrfParameterSpec;
|
|
37 |
|
|
38 |
/**
|
|
39 |
* KeyGenerator implementation for the TLS PRF function.
|
7043
|
40 |
* <p>
|
|
41 |
* This class duplicates the HMAC functionality (RFC 2104) with
|
|
42 |
* performance optimizations (e.g. XOR'ing keys with padding doesn't
|
|
43 |
* need to be redone for each HMAC operation).
|
2
|
44 |
*
|
|
45 |
* @author Andreas Sterbenz
|
|
46 |
* @since 1.6
|
|
47 |
*/
|
7043
|
48 |
abstract class TlsPrfGenerator extends KeyGeneratorSpi {
|
2
|
49 |
|
|
50 |
// magic constants and utility functions, also used by other files
|
|
51 |
// in this package
|
|
52 |
|
|
53 |
private final static byte[] B0 = new byte[0];
|
|
54 |
|
|
55 |
final static byte[] LABEL_MASTER_SECRET = // "master secret"
|
|
56 |
{ 109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116 };
|
|
57 |
|
|
58 |
final static byte[] LABEL_KEY_EXPANSION = // "key expansion"
|
|
59 |
{ 107, 101, 121, 32, 101, 120, 112, 97, 110, 115, 105, 111, 110 };
|
|
60 |
|
|
61 |
final static byte[] LABEL_CLIENT_WRITE_KEY = // "client write key"
|
|
62 |
{ 99, 108, 105, 101, 110, 116, 32, 119, 114, 105, 116, 101, 32,
|
|
63 |
107, 101, 121 };
|
|
64 |
|
|
65 |
final static byte[] LABEL_SERVER_WRITE_KEY = // "server write key"
|
|
66 |
{ 115, 101, 114, 118, 101, 114, 32, 119, 114, 105, 116, 101, 32,
|
|
67 |
107, 101, 121 };
|
|
68 |
|
|
69 |
final static byte[] LABEL_IV_BLOCK = // "IV block"
|
|
70 |
{ 73, 86, 32, 98, 108, 111, 99, 107 };
|
|
71 |
|
|
72 |
/*
|
|
73 |
* TLS HMAC "inner" and "outer" padding. This isn't a function
|
|
74 |
* of the digest algorithm.
|
|
75 |
*/
|
7043
|
76 |
private static final byte[] HMAC_ipad64 = genPad((byte)0x36, 64);
|
|
77 |
private static final byte[] HMAC_ipad128 = genPad((byte)0x36, 128);
|
|
78 |
private static final byte[] HMAC_opad64 = genPad((byte)0x5c, 64);
|
|
79 |
private static final byte[] HMAC_opad128 = genPad((byte)0x5c, 128);
|
2
|
80 |
|
|
81 |
// SSL3 magic mix constants ("A", "BB", "CCC", ...)
|
|
82 |
final static byte[][] SSL3_CONST = genConst();
|
|
83 |
|
|
84 |
static byte[] genPad(byte b, int count) {
|
|
85 |
byte[] padding = new byte[count];
|
|
86 |
Arrays.fill(padding, b);
|
|
87 |
return padding;
|
|
88 |
}
|
|
89 |
|
|
90 |
static byte[] concat(byte[] b1, byte[] b2) {
|
|
91 |
int n1 = b1.length;
|
|
92 |
int n2 = b2.length;
|
|
93 |
byte[] b = new byte[n1 + n2];
|
|
94 |
System.arraycopy(b1, 0, b, 0, n1);
|
|
95 |
System.arraycopy(b2, 0, b, n1, n2);
|
|
96 |
return b;
|
|
97 |
}
|
|
98 |
|
|
99 |
private static byte[][] genConst() {
|
|
100 |
int n = 10;
|
|
101 |
byte[][] arr = new byte[n][];
|
|
102 |
for (int i = 0; i < n; i++) {
|
|
103 |
byte[] b = new byte[i + 1];
|
|
104 |
Arrays.fill(b, (byte)('A' + i));
|
|
105 |
arr[i] = b;
|
|
106 |
}
|
|
107 |
return arr;
|
|
108 |
}
|
|
109 |
|
|
110 |
// PRF implementation
|
|
111 |
|
|
112 |
private final static String MSG = "TlsPrfGenerator must be "
|
|
113 |
+ "initialized using a TlsPrfParameterSpec";
|
|
114 |
|
|
115 |
private TlsPrfParameterSpec spec;
|
|
116 |
|
|
117 |
public TlsPrfGenerator() {
|
|
118 |
}
|
|
119 |
|
|
120 |
protected void engineInit(SecureRandom random) {
|
|
121 |
throw new InvalidParameterException(MSG);
|
|
122 |
}
|
|
123 |
|
|
124 |
protected void engineInit(AlgorithmParameterSpec params,
|
|
125 |
SecureRandom random) throws InvalidAlgorithmParameterException {
|
|
126 |
if (params instanceof TlsPrfParameterSpec == false) {
|
|
127 |
throw new InvalidAlgorithmParameterException(MSG);
|
|
128 |
}
|
|
129 |
this.spec = (TlsPrfParameterSpec)params;
|
|
130 |
SecretKey key = spec.getSecret();
|
|
131 |
if ((key != null) && ("RAW".equals(key.getFormat()) == false)) {
|
7043
|
132 |
throw new InvalidAlgorithmParameterException(
|
|
133 |
"Key encoding format must be RAW");
|
2
|
134 |
}
|
|
135 |
}
|
|
136 |
|
|
137 |
protected void engineInit(int keysize, SecureRandom random) {
|
|
138 |
throw new InvalidParameterException(MSG);
|
|
139 |
}
|
|
140 |
|
7043
|
141 |
SecretKey engineGenerateKey0(boolean tls12) {
|
2
|
142 |
if (spec == null) {
|
7043
|
143 |
throw new IllegalStateException(
|
|
144 |
"TlsPrfGenerator must be initialized");
|
2
|
145 |
}
|
|
146 |
SecretKey key = spec.getSecret();
|
|
147 |
byte[] secret = (key == null) ? null : key.getEncoded();
|
|
148 |
try {
|
|
149 |
byte[] labelBytes = spec.getLabel().getBytes("UTF8");
|
|
150 |
int n = spec.getOutputLength();
|
7043
|
151 |
byte[] prfBytes = (tls12 ?
|
|
152 |
doTLS12PRF(secret, labelBytes, spec.getSeed(), n,
|
|
153 |
spec.getPRFHashAlg(), spec.getPRFHashLength(),
|
|
154 |
spec.getPRFBlockSize()) :
|
|
155 |
doTLS10PRF(secret, labelBytes, spec.getSeed(), n));
|
2
|
156 |
return new SecretKeySpec(prfBytes, "TlsPrf");
|
|
157 |
} catch (GeneralSecurityException e) {
|
|
158 |
throw new ProviderException("Could not generate PRF", e);
|
|
159 |
} catch (java.io.UnsupportedEncodingException e) {
|
|
160 |
throw new ProviderException("Could not generate PRF", e);
|
|
161 |
}
|
|
162 |
}
|
|
163 |
|
7043
|
164 |
static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes,
|
|
165 |
byte[] seed, int outputLength,
|
|
166 |
String prfHash, int prfHashLength, int prfBlockSize)
|
|
167 |
throws NoSuchAlgorithmException, DigestException {
|
|
168 |
if (prfHash == null) {
|
|
169 |
throw new NoSuchAlgorithmException("Unspecified PRF algorithm");
|
|
170 |
}
|
|
171 |
MessageDigest prfMD = MessageDigest.getInstance(prfHash);
|
|
172 |
return doTLS12PRF(secret, labelBytes, seed, outputLength,
|
|
173 |
prfMD, prfHashLength, prfBlockSize);
|
|
174 |
}
|
|
175 |
|
|
176 |
static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes,
|
|
177 |
byte[] seed, int outputLength,
|
|
178 |
MessageDigest mdPRF, int mdPRFLen, int mdPRFBlockSize)
|
|
179 |
throws DigestException {
|
|
180 |
|
|
181 |
if (secret == null) {
|
|
182 |
secret = B0;
|
|
183 |
}
|
|
184 |
|
|
185 |
// If we have a long secret, digest it first.
|
|
186 |
if (secret.length > mdPRFBlockSize) {
|
|
187 |
secret = mdPRF.digest(secret);
|
|
188 |
}
|
|
189 |
|
|
190 |
byte[] output = new byte[outputLength];
|
|
191 |
byte [] ipad;
|
|
192 |
byte [] opad;
|
|
193 |
|
|
194 |
switch (mdPRFBlockSize) {
|
|
195 |
case 64:
|
|
196 |
ipad = HMAC_ipad64.clone();
|
|
197 |
opad = HMAC_opad64.clone();
|
|
198 |
break;
|
|
199 |
case 128:
|
|
200 |
ipad = HMAC_ipad128.clone();
|
|
201 |
opad = HMAC_opad128.clone();
|
|
202 |
break;
|
|
203 |
default:
|
|
204 |
throw new DigestException("Unexpected block size.");
|
|
205 |
}
|
|
206 |
|
|
207 |
// P_HASH(Secret, label + seed)
|
|
208 |
expand(mdPRF, mdPRFLen, secret, 0, secret.length, labelBytes,
|
|
209 |
seed, output, ipad, opad);
|
|
210 |
|
|
211 |
return output;
|
|
212 |
}
|
|
213 |
|
|
214 |
static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes,
|
|
215 |
byte[] seed, int outputLength) throws NoSuchAlgorithmException,
|
|
216 |
DigestException {
|
2
|
217 |
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
|
218 |
MessageDigest sha = MessageDigest.getInstance("SHA1");
|
7043
|
219 |
return doTLS10PRF(secret, labelBytes, seed, outputLength, md5, sha);
|
2
|
220 |
}
|
|
221 |
|
7043
|
222 |
static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes,
|
|
223 |
byte[] seed, int outputLength, MessageDigest md5,
|
|
224 |
MessageDigest sha) throws DigestException {
|
2
|
225 |
/*
|
|
226 |
* Split the secret into two halves S1 and S2 of same length.
|
|
227 |
* S1 is taken from the first half of the secret, S2 from the
|
|
228 |
* second half.
|
|
229 |
* Their length is created by rounding up the length of the
|
|
230 |
* overall secret divided by two; thus, if the original secret
|
|
231 |
* is an odd number of bytes long, the last byte of S1 will be
|
|
232 |
* the same as the first byte of S2.
|
|
233 |
*
|
|
234 |
* Note: Instead of creating S1 and S2, we determine the offset into
|
|
235 |
* the overall secret where S2 starts.
|
|
236 |
*/
|
|
237 |
|
|
238 |
if (secret == null) {
|
|
239 |
secret = B0;
|
|
240 |
}
|
|
241 |
int off = secret.length >> 1;
|
|
242 |
int seclen = off + (secret.length & 1);
|
|
243 |
|
|
244 |
byte[] output = new byte[outputLength];
|
|
245 |
|
|
246 |
// P_MD5(S1, label + seed)
|
7043
|
247 |
expand(md5, 16, secret, 0, seclen, labelBytes, seed, output,
|
|
248 |
HMAC_ipad64.clone(), HMAC_opad64.clone());
|
2
|
249 |
|
|
250 |
// P_SHA-1(S2, label + seed)
|
7043
|
251 |
expand(sha, 20, secret, off, seclen, labelBytes, seed, output,
|
|
252 |
HMAC_ipad64.clone(), HMAC_opad64.clone());
|
2
|
253 |
|
|
254 |
return output;
|
|
255 |
}
|
|
256 |
|
|
257 |
/*
|
|
258 |
* @param digest the MessageDigest to produce the HMAC
|
|
259 |
* @param hmacSize the HMAC size
|
|
260 |
* @param secret the secret
|
|
261 |
* @param secOff the offset into the secret
|
|
262 |
* @param secLen the secret length
|
|
263 |
* @param label the label
|
|
264 |
* @param seed the seed
|
|
265 |
* @param output the output array
|
|
266 |
*/
|
7043
|
267 |
private static void expand(MessageDigest digest, int hmacSize,
|
2
|
268 |
byte[] secret, int secOff, int secLen, byte[] label, byte[] seed,
|
7043
|
269 |
byte[] output, byte[] pad1, byte[] pad2) throws DigestException {
|
2
|
270 |
/*
|
|
271 |
* modify the padding used, by XORing the key into our copy of that
|
|
272 |
* padding. That's to avoid doing that for each HMAC computation.
|
|
273 |
*/
|
|
274 |
for (int i = 0; i < secLen; i++) {
|
|
275 |
pad1[i] ^= secret[i + secOff];
|
|
276 |
pad2[i] ^= secret[i + secOff];
|
|
277 |
}
|
|
278 |
|
|
279 |
byte[] tmp = new byte[hmacSize];
|
|
280 |
byte[] aBytes = null;
|
|
281 |
|
|
282 |
/*
|
|
283 |
* compute:
|
|
284 |
*
|
|
285 |
* P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
|
|
286 |
* HMAC_hash(secret, A(2) + seed) +
|
|
287 |
* HMAC_hash(secret, A(3) + seed) + ...
|
|
288 |
* A() is defined as:
|
|
289 |
*
|
|
290 |
* A(0) = seed
|
|
291 |
* A(i) = HMAC_hash(secret, A(i-1))
|
|
292 |
*/
|
|
293 |
int remaining = output.length;
|
|
294 |
int ofs = 0;
|
|
295 |
while (remaining > 0) {
|
|
296 |
/*
|
|
297 |
* compute A() ...
|
|
298 |
*/
|
|
299 |
// inner digest
|
|
300 |
digest.update(pad1);
|
|
301 |
if (aBytes == null) {
|
|
302 |
digest.update(label);
|
|
303 |
digest.update(seed);
|
|
304 |
} else {
|
|
305 |
digest.update(aBytes);
|
|
306 |
}
|
|
307 |
digest.digest(tmp, 0, hmacSize);
|
|
308 |
|
|
309 |
// outer digest
|
|
310 |
digest.update(pad2);
|
|
311 |
digest.update(tmp);
|
|
312 |
if (aBytes == null) {
|
|
313 |
aBytes = new byte[hmacSize];
|
|
314 |
}
|
|
315 |
digest.digest(aBytes, 0, hmacSize);
|
|
316 |
|
|
317 |
/*
|
|
318 |
* compute HMAC_hash() ...
|
|
319 |
*/
|
|
320 |
// inner digest
|
|
321 |
digest.update(pad1);
|
|
322 |
digest.update(aBytes);
|
|
323 |
digest.update(label);
|
|
324 |
digest.update(seed);
|
|
325 |
digest.digest(tmp, 0, hmacSize);
|
|
326 |
|
|
327 |
// outer digest
|
|
328 |
digest.update(pad2);
|
|
329 |
digest.update(tmp);
|
|
330 |
digest.digest(tmp, 0, hmacSize);
|
|
331 |
|
|
332 |
int k = Math.min(hmacSize, remaining);
|
|
333 |
for (int i = 0; i < k; i++) {
|
|
334 |
output[ofs++] ^= tmp[i];
|
|
335 |
}
|
|
336 |
remaining -= k;
|
|
337 |
}
|
|
338 |
}
|
|
339 |
|
7043
|
340 |
/**
|
|
341 |
* A KeyGenerator implementation that supports TLS 1.2.
|
|
342 |
* <p>
|
|
343 |
* TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the PRF
|
|
344 |
* calculations. As of 2010, there is no PKCS11-level support for TLS
|
|
345 |
* 1.2 PRF calculations, and no known OS's have an internal variant
|
|
346 |
* we could use. Therefore for TLS 1.2, we are updating JSSE to request
|
|
347 |
* a different provider algorithm: "SunTls12Prf". If we reused the
|
|
348 |
* name "SunTlsPrf", the PKCS11 provider would need be updated to
|
|
349 |
* fail correctly when presented with the wrong version number
|
|
350 |
* (via Provider.Service.supportsParameters()), and add the
|
|
351 |
* appropriate supportsParamters() checks into KeyGenerators (not
|
|
352 |
* currently there).
|
|
353 |
*/
|
|
354 |
static public class V12 extends TlsPrfGenerator {
|
|
355 |
protected SecretKey engineGenerateKey() {
|
|
356 |
return engineGenerateKey0(true);
|
|
357 |
}
|
|
358 |
}
|
|
359 |
|
|
360 |
/**
|
|
361 |
* A KeyGenerator implementation that supports TLS 1.0/1.1.
|
|
362 |
*/
|
|
363 |
static public class V10 extends TlsPrfGenerator {
|
|
364 |
protected SecretKey engineGenerateKey() {
|
|
365 |
return engineGenerateKey0(false);
|
|
366 |
}
|
|
367 |
}
|
2
|
368 |
}
|