1 /*
   2  * Copyright (c) 2005, 2009, 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     private TlsMasterSecretParameterSpec spec;
  50 
  51     private int protocolVersion;
  52 
  53     public TlsMasterSecretGenerator() {
  54     }
  55 
  56     protected void engineInit(SecureRandom random) {
  57         throw new InvalidParameterException(MSG);
  58     }
  59 
  60     protected void engineInit(AlgorithmParameterSpec params,
  61             SecureRandom random) throws InvalidAlgorithmParameterException {
  62         if (params instanceof TlsMasterSecretParameterSpec == false) {
  63             throw new InvalidAlgorithmParameterException(MSG);
  64         }
  65         this.spec = (TlsMasterSecretParameterSpec)params;
  66         if ("RAW".equals(spec.getPremasterSecret().getFormat()) == false) {
  67             throw new InvalidAlgorithmParameterException("Key format must be RAW");
  68         }
  69         protocolVersion = (spec.getMajorVersion() << 8) | spec.getMinorVersion();
  70         if ((protocolVersion < 0x0300) || (protocolVersion > 0x0302)) {
  71             throw new InvalidAlgorithmParameterException
  72                 ("Only SSL 3.0, TLS 1.0, and TLS 1.1 supported");
  73         }
  74     }
  75 
  76     protected void engineInit(int keysize, SecureRandom random) {
  77         throw new InvalidParameterException(MSG);
  78     }
  79 
  80     protected SecretKey engineGenerateKey() {
  81         if (spec == null) {
  82             throw new IllegalStateException
  83                 ("TlsMasterSecretGenerator must be initialized");
  84         }
  85         SecretKey premasterKey = spec.getPremasterSecret();
  86         byte[] premaster = premasterKey.getEncoded();
  87 
  88         int premasterMajor, premasterMinor;
  89         if (premasterKey.getAlgorithm().equals("TlsRsaPremasterSecret")) {
  90             // RSA
  91             premasterMajor = premaster[0] & 0xff;
  92             premasterMinor = premaster[1] & 0xff;
  93         } else {
  94             // DH, KRB5, others
  95             premasterMajor = -1;
  96             premasterMinor = -1;
  97         }
  98 
  99         try {
 100             byte[] master;
 101             byte[] clientRandom = spec.getClientRandom();
 102             byte[] serverRandom = spec.getServerRandom();
 103 
 104             if (protocolVersion >= 0x0301) {
 105                 byte[] seed = concat(clientRandom, serverRandom);
 106                 master = doPRF(premaster, LABEL_MASTER_SECRET, seed, 48);
 107             } else {
 108                 master = new byte[48];
 109                 MessageDigest md5 = MessageDigest.getInstance("MD5");
 110                 MessageDigest sha = MessageDigest.getInstance("SHA");
 111 
 112                 byte[] tmp = new byte[20];
 113                 for (int i = 0; i < 3; i++) {
 114                     sha.update(SSL3_CONST[i]);
 115                     sha.update(premaster);
 116                     sha.update(clientRandom);
 117                     sha.update(serverRandom);
 118                     sha.digest(tmp, 0, 20);
 119 
 120                     md5.update(premaster);
 121                     md5.update(tmp);
 122                     md5.digest(master, i << 4, 16);
 123                 }
 124 
 125             }
 126 
 127             return new TlsMasterSecretKey(master, premasterMajor, premasterMinor);
 128         } catch (NoSuchAlgorithmException e) {
 129             throw new ProviderException(e);
 130         } catch (DigestException e) {
 131             throw new ProviderException(e);
 132         }
 133     }
 134 
 135     private static final class TlsMasterSecretKey implements TlsMasterSecret {
 136 
 137         private byte[] key;
 138         private final int majorVersion, minorVersion;
 139 
 140         TlsMasterSecretKey(byte[] key, int majorVersion, int minorVersion) {
 141             this.key = key;
 142             this.majorVersion = majorVersion;
 143             this.minorVersion = minorVersion;
 144         }
 145 
 146         public int getMajorVersion() {
 147             return majorVersion;
 148         }
 149 
 150         public int getMinorVersion() {
 151             return minorVersion;
 152         }
 153 
 154         public String getAlgorithm() {
 155             return "TlsMasterSecret";
 156         }
 157 
 158         public String getFormat() {
 159             return "RAW";
 160         }
 161 
 162         public byte[] getEncoded() {
 163             return key.clone();
 164         }
 165 
 166     }
 167 
 168 }