1 /*
   2  * Copyright (c) 2005, 2011, 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 
  33 import sun.security.internal.interfaces.TlsMasterSecret;
  34 import sun.security.internal.spec.TlsMasterSecretParameterSpec;
  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 TlsMasterSecretGenerator extends KeyGeneratorSpi {
  45 
  46     private final static String MSG = "TlsMasterSecretGenerator must be "
  47         + "initialized using a TlsMasterSecretParameterSpec";
  48 
  49     @SuppressWarnings("deprecation")
  50     private TlsMasterSecretParameterSpec spec;
  51 
  52     private int protocolVersion;
  53 
  54     public TlsMasterSecretGenerator() {
  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 TlsMasterSecretParameterSpec == false) {
  65             throw new InvalidAlgorithmParameterException(MSG);
  66         }
  67         this.spec = (TlsMasterSecretParameterSpec)params;
  68         if ("RAW".equals(spec.getPremasterSecret().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                 "TlsMasterSecretGenerator must be initialized");
  88         }
  89         SecretKey premasterKey = spec.getPremasterSecret();
  90         byte[] premaster = premasterKey.getEncoded();
  91 
  92         int premasterMajor, premasterMinor;
  93         if (premasterKey.getAlgorithm().equals("TlsRsaPremasterSecret")) {
  94             // RSA
  95             premasterMajor = premaster[0] & 0xff;
  96             premasterMinor = premaster[1] & 0xff;
  97         } else {
  98             // DH, KRB5, others
  99             premasterMajor = -1;
 100             premasterMinor = -1;
 101         }
 102 
 103         try {
 104             byte[] master;
 105             byte[] clientRandom = spec.getClientRandom();
 106             byte[] serverRandom = spec.getServerRandom();
 107 
 108             if (protocolVersion >= 0x0301) {
 109                 byte[] seed = concat(clientRandom, serverRandom);
 110                 master = ((protocolVersion >= 0x0303) ?
 111                     doTLS12PRF(premaster, LABEL_MASTER_SECRET, seed, 48,
 112                         spec.getPRFHashAlg(), spec.getPRFHashLength(),
 113                         spec.getPRFBlockSize()) :
 114                     doTLS10PRF(premaster, LABEL_MASTER_SECRET, seed, 48));
 115             } else {
 116                 master = new byte[48];
 117                 MessageDigest md5 = MessageDigest.getInstance("MD5");
 118                 MessageDigest sha = MessageDigest.getInstance("SHA");
 119 
 120                 byte[] tmp = new byte[20];
 121                 for (int i = 0; i < 3; i++) {
 122                     sha.update(SSL3_CONST[i]);
 123                     sha.update(premaster);
 124                     sha.update(clientRandom);
 125                     sha.update(serverRandom);
 126                     sha.digest(tmp, 0, 20);
 127 
 128                     md5.update(premaster);
 129                     md5.update(tmp);
 130                     md5.digest(master, i << 4, 16);
 131                 }
 132 
 133             }
 134 
 135             return new TlsMasterSecretKey(master, premasterMajor,
 136                 premasterMinor);
 137         } catch (NoSuchAlgorithmException e) {
 138             throw new ProviderException(e);
 139         } catch (DigestException e) {
 140             throw new ProviderException(e);
 141         }
 142     }
 143 
 144    @SuppressWarnings("deprecation") 
 145    private static final class TlsMasterSecretKey implements TlsMasterSecret {
 146         private static final long serialVersionUID = 1019571680375368880L;
 147 
 148         private byte[] key;
 149         private final int majorVersion, minorVersion;
 150 
 151         TlsMasterSecretKey(byte[] key, int majorVersion, int minorVersion) {
 152             this.key = key;
 153             this.majorVersion = majorVersion;
 154             this.minorVersion = minorVersion;
 155         }
 156 
 157         public int getMajorVersion() {
 158             return majorVersion;
 159         }
 160 
 161         public int getMinorVersion() {
 162             return minorVersion;
 163         }
 164 
 165         public String getAlgorithm() {
 166             return "TlsMasterSecret";
 167         }
 168 
 169         public String getFormat() {
 170             return "RAW";
 171         }
 172 
 173         public byte[] getEncoded() {
 174             return key.clone();
 175         }
 176 
 177     }
 178 
 179 }