--- /dev/null 2018-08-17 14:52:30.860000000 -0400 +++ new/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java 2018-08-30 11:09:51.993608001 -0400 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import javax.crypto.KeyAgreement; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import javax.net.ssl.SSLHandshakeException; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.AlgorithmParameterSpec; + +public class KAKeyDerivation implements SSLKeyDerivation { + + private final String algorithmName; + private final HandshakeContext context; + private final PrivateKey localPrivateKey; + private final PublicKey peerPublicKey; + + KAKeyDerivation(String algorithmName, + HandshakeContext context, + PrivateKey localPrivateKey, + PublicKey peerPublicKey) { + this.algorithmName = algorithmName; + this.context = context; + this.localPrivateKey = localPrivateKey; + this.peerPublicKey = peerPublicKey; + } + + @Override + public + SecretKey deriveKey(String algorithm, + AlgorithmParameterSpec params) throws IOException { + if (!context.negotiatedProtocol.useTLS13PlusSpec()) { + return t12DeriveKey(algorithm, params); + } else { + return t13DeriveKey(algorithm, params); + } + } + + private + SecretKey t12DeriveKey(String algorithm, + AlgorithmParameterSpec params) throws IOException { + try { + KeyAgreement ka = JsseJce.getKeyAgreement(algorithmName); + ka.init(localPrivateKey); + ka.doPhase(peerPublicKey, true); + SecretKey preMasterSecret = + ka.generateSecret("TlsPremasterSecret"); + SSLMasterKeyDerivation mskd = + SSLMasterKeyDerivation.valueOf( + context.negotiatedProtocol); + if (mskd == null) { + // unlikely + throw new SSLHandshakeException( + "No expected master key derivation for protocol: " + + context.negotiatedProtocol.name); + } + SSLKeyDerivation kd = mskd.createKeyDerivation( + context, preMasterSecret); + return kd.deriveKey("MasterSecret", params); + } catch (GeneralSecurityException gse) { + throw (SSLHandshakeException) new SSLHandshakeException( + "Could not generate secret").initCause(gse); + } + } + + private + SecretKey t13DeriveKey(String algorithm, + AlgorithmParameterSpec params) throws IOException { + try { + KeyAgreement ka = JsseJce.getKeyAgreement(algorithmName); + ka.init(localPrivateKey); + ka.doPhase(peerPublicKey, true); + SecretKey sharedSecret = + ka.generateSecret("TlsPremasterSecret"); + + CipherSuite.HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg; + SSLKeyDerivation kd = context.handshakeKeyDerivation; + HKDF hkdf = new HKDF(hashAlg.name); + if (kd == null) { // No PSK is in use. + // If PSK is not in use Early Secret will still be + // HKDF-Extract(0, 0). + byte[] zeros = new byte[hashAlg.hashLength]; + SecretKeySpec ikm = + new SecretKeySpec(zeros, "TlsPreSharedSecret"); + SecretKey earlySecret = + hkdf.extract(zeros, ikm, "TlsEarlySecret"); + kd = new SSLSecretDerivation(context, earlySecret); + } + + // derive salt secret + SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null); + + // derive handshake secret + return hkdf.extract(saltSecret, sharedSecret, algorithm); + } catch (GeneralSecurityException gse) { + throw (SSLHandshakeException) new SSLHandshakeException( + "Could not generate secret").initCause(gse); + } + } +}