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 }