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 final static String MSG = "TlsKeyMaterialGenerator must be " 47 + "initialized using a TlsKeyMaterialParameterSpec"; 48 49 @SuppressWarnings("deprecation") 50 private TlsKeyMaterialParameterSpec spec; 51 52 private int protocolVersion; 53 54 public TlsKeyMaterialGenerator() { 55 } 56 57 protected void engineInit(SecureRandom random) { 58 throw new InvalidParameterException(MSG); 59 } 60 61 @SuppressWarnings("deprecation") 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 80 protected void engineInit(int keysize, SecureRandom random) { 81 throw new InvalidParameterException(MSG); 82 } 83 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") 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 }