src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java
changeset 50768 68fa3d4026ea
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
       
     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         this.hashAlg = context.negotiatedCipherSuite.hashAlg;
       
    74         this.hkdfAlg =
       
    75                 "HKDF-Expand/Hmac" + hashAlg.name.replace("-", "");
       
    76         context.handshakeHash.update();
       
    77         this.transcriptHash = context.handshakeHash.digest();
       
    78     }
       
    79 
       
    80     SSLSecretDerivation forContext(HandshakeContext context) {
       
    81         return new SSLSecretDerivation(context, secret);
       
    82     }
       
    83 
       
    84     @Override
       
    85     public SecretKey deriveKey(String algorithm,
       
    86             AlgorithmParameterSpec params) throws IOException {
       
    87         SecretSchedule ks = SecretSchedule.valueOf(algorithm);
       
    88         try {
       
    89             byte[] expandContext;
       
    90             if (ks == SecretSchedule.TlsSaltSecret) {
       
    91                 if (hashAlg == HashAlg.H_SHA256) {
       
    92                     expandContext = sha256EmptyDigest;
       
    93                 } else if (hashAlg == HashAlg.H_SHA384) {
       
    94                     expandContext = sha384EmptyDigest;
       
    95                 } else {
       
    96                     // unlikely, but please update if more hash algorithm
       
    97                     // get supported in the future.
       
    98                     throw new SSLHandshakeException(
       
    99                             "Unexpected unsupported hash algorithm: " +
       
   100                             algorithm);
       
   101                 }
       
   102             } else {
       
   103                 expandContext = transcriptHash;
       
   104             }
       
   105             byte[] hkdfInfo = createHkdfInfo(ks.label,
       
   106                     expandContext, hashAlg.hashLength);
       
   107 
       
   108             HKDF hkdf = new HKDF(hashAlg.name);
       
   109             return hkdf.expand(secret, hkdfInfo, hashAlg.hashLength, algorithm);
       
   110         } catch (GeneralSecurityException gse) {
       
   111             throw (SSLHandshakeException) new SSLHandshakeException(
       
   112                 "Could not generate secret").initCause(gse);
       
   113         }
       
   114     }
       
   115 
       
   116     public static byte[] createHkdfInfo(
       
   117             byte[] label, byte[] context, int length) {
       
   118         byte[] info = new byte[4 + label.length + context.length];
       
   119         ByteBuffer m = ByteBuffer.wrap(info);
       
   120         try {
       
   121             Record.putInt16(m, length);
       
   122             Record.putBytes8(m, label);
       
   123             Record.putBytes8(m, context);
       
   124         } catch (IOException ioe) {
       
   125             // unlikely
       
   126             throw new RuntimeException("Unexpected exception", ioe);
       
   127         }
       
   128 
       
   129         return info;
       
   130     }
       
   131 
       
   132     private enum SecretSchedule {
       
   133         // Note that we use enum name as the key/secret name.
       
   134         TlsSaltSecret                       ("derived"),
       
   135         TlsExtBinderKey                     ("ext binder"),
       
   136         TlsResBinderKey                     ("res binder"),
       
   137         TlsClientEarlyTrafficSecret         ("c e traffic"),
       
   138         TlsEarlyExporterMasterSecret        ("e exp master"),
       
   139         TlsClientHandshakeTrafficSecret     ("c hs traffic"),
       
   140         TlsServerHandshakeTrafficSecret     ("s hs traffic"),
       
   141         TlsClientAppTrafficSecret           ("c ap traffic"),
       
   142         TlsServerAppTrafficSecret           ("s ap traffic"),
       
   143         TlsExporterMasterSecret             ("exp master"),
       
   144         TlsResumptionMasterSecret           ("res master");
       
   145 
       
   146         private final byte[] label;
       
   147 
       
   148         private SecretSchedule(String label) {
       
   149             this.label = ("tls13 " + label).getBytes();
       
   150         }
       
   151     }
       
   152 }