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 java.io.IOException;
  29 import java.nio.ByteBuffer;
  30 import java.security.GeneralSecurityException;
  31 import java.security.spec.AlgorithmParameterSpec;
  32 import javax.crypto.SecretKey;
  33 import javax.net.ssl.SSLHandshakeException;
  34 import sun.security.ssl.CipherSuite.HashAlg;
  35 
  36 final class SSLSecretDerivation implements SSLKeyDerivation {
  37     private static final byte[] sha256EmptyDigest = new byte[] {
  38         (byte)0xE3, (byte)0xB0, (byte)0xC4, (byte)0x42,
  39         (byte)0x98, (byte)0xFC, (byte)0x1C, (byte)0x14,
  40         (byte)0x9A, (byte)0xFB, (byte)0xF4, (byte)0xC8,
  41         (byte)0x99, (byte)0x6F, (byte)0xB9, (byte)0x24,
  42         (byte)0x27, (byte)0xAE, (byte)0x41, (byte)0xE4,
  43         (byte)0x64, (byte)0x9B, (byte)0x93, (byte)0x4C,
  44         (byte)0xA4, (byte)0x95, (byte)0x99, (byte)0x1B,
  45         (byte)0x78, (byte)0x52, (byte)0xB8, (byte)0x55
  46     };
  47 
  48     private static final byte[] sha384EmptyDigest = new byte[] {
  49         (byte)0x38, (byte)0xB0, (byte)0x60, (byte)0xA7,
  50         (byte)0x51, (byte)0xAC, (byte)0x96, (byte)0x38,
  51         (byte)0x4C, (byte)0xD9, (byte)0x32, (byte)0x7E,
  52         (byte)0xB1, (byte)0xB1, (byte)0xE3, (byte)0x6A,
  53         (byte)0x21, (byte)0xFD, (byte)0xB7, (byte)0x11,
  54         (byte)0x14, (byte)0xBE, (byte)0x07, (byte)0x43,
  55         (byte)0x4C, (byte)0x0C, (byte)0xC7, (byte)0xBF,
  56         (byte)0x63, (byte)0xF6, (byte)0xE1, (byte)0xDA,
  57         (byte)0x27, (byte)0x4E, (byte)0xDE, (byte)0xBF,
  58         (byte)0xE7, (byte)0x6F, (byte)0x65, (byte)0xFB,
  59         (byte)0xD5, (byte)0x1A, (byte)0xD2, (byte)0xF1,
  60         (byte)0x48, (byte)0x98, (byte)0xB9, (byte)0x5B
  61     };
  62 
  63     private final HandshakeContext context;
  64     private final String hkdfAlg;
  65     private final HashAlg hashAlg;
  66     private final SecretKey secret;
  67     private final byte[] transcriptHash;  // handshake messages transcript hash
  68 
  69     SSLSecretDerivation(
  70             HandshakeContext context, SecretKey secret) {
  71         this.context = context;
  72         this.secret = secret;
  73         // TODO: May need the hash algogorithm if the secret is a PSK.
  74         // if (secret is a PSK) {
  75         //     ...
  76         // } else {
  77             this.hashAlg = context.negotiatedCipherSuite.hashAlg;
  78             this.hkdfAlg =
  79                     "HKDF-Expand/Hmac" + hashAlg.name.replace("-", "");
  80             context.handshakeHash.update();
  81             this.transcriptHash = context.handshakeHash.digest();
  82         // }
  83     }
  84 
  85     SSLSecretDerivation forContext(HandshakeContext context) {
  86         return new SSLSecretDerivation(context, secret);
  87     }
  88 
  89     @Override
  90     public SecretKey deriveKey(String algorithm,
  91             AlgorithmParameterSpec params) throws IOException {
  92         SecretSchedule ks = SecretSchedule.valueOf(algorithm);
  93         try {
  94             byte[] expandContext;
  95             if (ks == SecretSchedule.TlsSaltSecret) {
  96                 if (hashAlg == HashAlg.H_SHA256) {
  97                     expandContext = sha256EmptyDigest;
  98                 } else if (hashAlg == HashAlg.H_SHA384) {
  99                     expandContext = sha384EmptyDigest;
 100                 } else {
 101                     // unlikely, but please update if more hash algorithm
 102                     // get supported in the future.
 103                     expandContext = new byte[0];
 104                 }
 105             } else {
 106                 expandContext = transcriptHash;
 107             }
 108             byte[] hkdfInfo = createHkdfInfo(ks.label,
 109                     expandContext, hashAlg.hashLength);
 110 
 111             HKDF hkdf = new HKDF(hashAlg.name);
 112             return hkdf.expand(secret, hkdfInfo, hashAlg.hashLength, algorithm);
 113         } catch (GeneralSecurityException gse) {
 114             throw (SSLHandshakeException) new SSLHandshakeException(
 115                 "Could not generate secret").initCause(gse);
 116         }
 117     }
 118 
 119     public static byte[] createHkdfInfo(
 120             byte[] label, byte[] context, int length) {
 121         byte[] info = new byte[4 + label.length + context.length];
 122         ByteBuffer m = ByteBuffer.wrap(info);
 123         try {
 124             Record.putInt16(m, length);
 125             Record.putBytes8(m, label);
 126             Record.putBytes8(m, context);
 127         } catch (IOException ioe) {
 128             // unlikely
 129         }
 130 
 131         return info;
 132     }
 133 
 134     private enum SecretSchedule {
 135         // Note that we use enum name as the key/secret name.
 136         TlsSaltSecret                       ("derived"),
 137         TlsExtBinderKey                     ("ext binder"),
 138         TlsResBinderKey                     ("res binder"),
 139         TlsClientEarlyTrafficSecret         ("c e traffic"),
 140         TlsEarlyExporterMasterSecret        ("e exp master"),
 141         TlsClientHandshakeTrafficSecret     ("c hs traffic"),
 142         TlsServerHandshakeTrafficSecret     ("s hs traffic"),
 143         TlsClientAppTrafficSecret           ("c ap traffic"),
 144         TlsServerAppTrafficSecret           ("s ap traffic"),
 145         TlsExporterMasterSecret             ("exp master"),
 146         TlsResumptionMasterSecret           ("res master");
 147 
 148         private final byte[] label;
 149 
 150         private SecretSchedule(String label) {
 151             this.label = ("tls13 " + label).getBytes();
 152         }
 153     }
 154 }