1 /*
   2  * Copyright (c) 2018, 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 sun.security.ssl;
  27 
  28 import javax.crypto.KeyAgreement;
  29 import javax.crypto.SecretKey;
  30 import javax.crypto.spec.SecretKeySpec;
  31 import javax.net.ssl.SSLHandshakeException;
  32 import java.io.IOException;
  33 import java.security.GeneralSecurityException;
  34 import java.security.PrivateKey;
  35 import java.security.PublicKey;
  36 import java.security.spec.AlgorithmParameterSpec;
  37 
  38 public class KAKeyDerivation implements SSLKeyDerivation {
  39 
  40     private final String algorithmName;
  41     private final HandshakeContext context;
  42     private final PrivateKey localPrivateKey;
  43     private final PublicKey peerPublicKey;
  44 
  45     KAKeyDerivation(String algorithmName,
  46                     HandshakeContext context,
  47                     PrivateKey localPrivateKey,
  48                     PublicKey peerPublicKey) {
  49         this.algorithmName = algorithmName;
  50         this.context = context;
  51         this.localPrivateKey = localPrivateKey;
  52         this.peerPublicKey = peerPublicKey;
  53     }
  54 
  55     @Override
  56     public
  57     SecretKey deriveKey(String algorithm,
  58                         AlgorithmParameterSpec params) throws IOException {
  59         if (!context.negotiatedProtocol.useTLS13PlusSpec()) {
  60             return t12DeriveKey(algorithm, params);
  61         } else {
  62             return t13DeriveKey(algorithm, params);
  63         }
  64     }
  65 
  66     private
  67     SecretKey t12DeriveKey(String algorithm,
  68                            AlgorithmParameterSpec params) throws IOException {
  69         try {
  70             KeyAgreement ka = JsseJce.getKeyAgreement(algorithmName);
  71             ka.init(localPrivateKey);
  72             ka.doPhase(peerPublicKey, true);
  73             SecretKey preMasterSecret =
  74             ka.generateSecret("TlsPremasterSecret");
  75             SSLMasterKeyDerivation mskd =
  76             SSLMasterKeyDerivation.valueOf(
  77             context.negotiatedProtocol);
  78             if (mskd == null) {
  79                 // unlikely
  80                 throw new SSLHandshakeException(
  81                 "No expected master key derivation for protocol: " +
  82                 context.negotiatedProtocol.name);
  83             }
  84             SSLKeyDerivation kd = mskd.createKeyDerivation(
  85             context, preMasterSecret);
  86             return kd.deriveKey("MasterSecret", params);
  87         } catch (GeneralSecurityException gse) {
  88             throw (SSLHandshakeException) new SSLHandshakeException(
  89             "Could not generate secret").initCause(gse);
  90         }
  91     }
  92 
  93     private
  94     SecretKey t13DeriveKey(String algorithm,
  95                            AlgorithmParameterSpec params) throws IOException {
  96         try {
  97             KeyAgreement ka = JsseJce.getKeyAgreement(algorithmName);
  98             ka.init(localPrivateKey);
  99             ka.doPhase(peerPublicKey, true);
 100             SecretKey sharedSecret =
 101             ka.generateSecret("TlsPremasterSecret");
 102 
 103             CipherSuite.HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg;
 104             SSLKeyDerivation kd = context.handshakeKeyDerivation;
 105             HKDF hkdf = new HKDF(hashAlg.name);
 106             if (kd == null) {   // No PSK is in use.
 107                 // If PSK is not in use Early Secret will still be
 108                 // HKDF-Extract(0, 0).
 109                 byte[] zeros = new byte[hashAlg.hashLength];
 110                 SecretKeySpec ikm =
 111                 new SecretKeySpec(zeros, "TlsPreSharedSecret");
 112                 SecretKey earlySecret =
 113                 hkdf.extract(zeros, ikm, "TlsEarlySecret");
 114                 kd = new SSLSecretDerivation(context, earlySecret);
 115             }
 116 
 117             // derive salt secret
 118             SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
 119 
 120             // derive handshake secret
 121             return hkdf.extract(saltSecret, sharedSecret, algorithm);
 122         } catch (GeneralSecurityException gse) {
 123             throw (SSLHandshakeException) new SSLHandshakeException(
 124             "Could not generate secret").initCause(gse);
 125         }
 126     }
 127 }