mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8196584: TLS 1.3 Implementation
Co-authored-by: Adam Petcher <adam.petcher@oracle.com> Co-authored-by: Amanda Jiang <amanda.jiang@oracle.com> Co-authored-by: Anthony Scarpino <anthony.scarpino@oracle.com> Co-authored-by: Bradford Wetmore <bradford.wetmore@oracle.com> Co-authored-by: Jamil Nimeh <jamil.j.nimeh@oracle.com> Co-authored-by: John Jiang <sha.jiang@oracle.com> Co-authored-by: Rajan Halade <rajan.halade@oracle.com> Co-authored-by: Sibabrata Sahoo <sibabrata.sahoo@oracle.com> Co-authored-by: Valerie Peng <valerie.peng@oracle.com> Co-authored-by: Weijun Wang <weijun.wang@oracle.com> Reviewed-by: ascarpino, coffeys, dfuchs, jjiang, jnimeh, mullan, rhalade, ssahoo, valeriep, weijun, wetmore, xuelei
This commit is contained in:
parent
c7c819cd8b
commit
87c6761704
262 changed files with 44368 additions and 32552 deletions
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* 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 java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.ProviderException;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import sun.security.internal.spec.TlsKeyMaterialParameterSpec;
|
||||
import sun.security.internal.spec.TlsKeyMaterialSpec;
|
||||
import sun.security.ssl.CipherSuite.HashAlg;
|
||||
import static sun.security.ssl.CipherSuite.HashAlg.H_NONE;
|
||||
|
||||
enum SSLTrafficKeyDerivation implements SSLKeyDerivationGenerator {
|
||||
SSL30 ("kdf_ssl30", new S30TrafficKeyDerivationGenerator()),
|
||||
TLS10 ("kdf_tls10", new T10TrafficKeyDerivationGenerator()),
|
||||
TLS12 ("kdf_tls12", new T12TrafficKeyDerivationGenerator()),
|
||||
TLS13 ("kdf_tls13", new T13TrafficKeyDerivationGenerator());
|
||||
|
||||
final String name;
|
||||
final SSLKeyDerivationGenerator keyDerivationGenerator;
|
||||
|
||||
SSLTrafficKeyDerivation(String name,
|
||||
SSLKeyDerivationGenerator keyDerivationGenerator) {
|
||||
this.name = name;
|
||||
this.keyDerivationGenerator = keyDerivationGenerator;
|
||||
}
|
||||
|
||||
static SSLTrafficKeyDerivation valueOf(ProtocolVersion protocolVersion) {
|
||||
switch (protocolVersion) {
|
||||
case SSL30:
|
||||
return SSLTrafficKeyDerivation.SSL30;
|
||||
case TLS10:
|
||||
case TLS11:
|
||||
case DTLS10:
|
||||
return SSLTrafficKeyDerivation.TLS10;
|
||||
case TLS12:
|
||||
case DTLS12:
|
||||
return SSLTrafficKeyDerivation.TLS12;
|
||||
case TLS13:
|
||||
return SSLTrafficKeyDerivation.TLS13;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLKeyDerivation createKeyDerivation(HandshakeContext context,
|
||||
SecretKey secretKey) throws IOException {
|
||||
return keyDerivationGenerator.createKeyDerivation(context, secretKey);
|
||||
}
|
||||
|
||||
private static final class S30TrafficKeyDerivationGenerator
|
||||
implements SSLKeyDerivationGenerator {
|
||||
private S30TrafficKeyDerivationGenerator() {
|
||||
// blank
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLKeyDerivation createKeyDerivation(
|
||||
HandshakeContext context, SecretKey secretKey) throws IOException {
|
||||
return new LegacyTrafficKeyDerivation(context, secretKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class T10TrafficKeyDerivationGenerator
|
||||
implements SSLKeyDerivationGenerator {
|
||||
private T10TrafficKeyDerivationGenerator() {
|
||||
// blank
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLKeyDerivation createKeyDerivation(
|
||||
HandshakeContext context, SecretKey secretKey) throws IOException {
|
||||
return new LegacyTrafficKeyDerivation(context, secretKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class T12TrafficKeyDerivationGenerator
|
||||
implements SSLKeyDerivationGenerator {
|
||||
private T12TrafficKeyDerivationGenerator() {
|
||||
// blank
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLKeyDerivation createKeyDerivation(
|
||||
HandshakeContext context, SecretKey secretKey) throws IOException {
|
||||
return new LegacyTrafficKeyDerivation(context, secretKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class T13TrafficKeyDerivationGenerator
|
||||
implements SSLKeyDerivationGenerator {
|
||||
private T13TrafficKeyDerivationGenerator() {
|
||||
// blank
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLKeyDerivation createKeyDerivation(
|
||||
HandshakeContext context,
|
||||
SecretKey secretKey) throws IOException {
|
||||
return new T13TrafficKeyDerivation(context, secretKey);
|
||||
}
|
||||
}
|
||||
|
||||
static final class T13TrafficKeyDerivation implements SSLKeyDerivation {
|
||||
private final CipherSuite cs;
|
||||
private final SecretKey secret;
|
||||
|
||||
T13TrafficKeyDerivation(
|
||||
HandshakeContext context, SecretKey secret) {
|
||||
this.secret = secret;
|
||||
this.cs = context.negotiatedCipherSuite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretKey deriveKey(String algorithm,
|
||||
AlgorithmParameterSpec params) throws IOException {
|
||||
KeySchedule ks = KeySchedule.valueOf(algorithm);
|
||||
try {
|
||||
HKDF hkdf = new HKDF(cs.hashAlg.name);
|
||||
byte[] hkdfInfo =
|
||||
createHkdfInfo(ks.label, ks.getKeyLength(cs));
|
||||
return hkdf.expand(secret, hkdfInfo,
|
||||
ks.getKeyLength(cs),
|
||||
ks.getAlgorithm(cs, algorithm));
|
||||
} catch (GeneralSecurityException gse) {
|
||||
throw (SSLHandshakeException)(new SSLHandshakeException(
|
||||
"Could not generate secret").initCause(gse));
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] createHkdfInfo(
|
||||
byte[] label, int length) throws IOException {
|
||||
byte[] info = new byte[4 + label.length];
|
||||
ByteBuffer m = ByteBuffer.wrap(info);
|
||||
try {
|
||||
Record.putInt16(m, length);
|
||||
Record.putBytes8(m, label);
|
||||
Record.putInt8(m, 0x00); // zero-length context
|
||||
} catch (IOException ioe) {
|
||||
// unlikely
|
||||
throw new RuntimeException("Unexpected exception", ioe);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
private enum KeySchedule {
|
||||
// Note that we use enum name as the key/ name.
|
||||
TlsKey ("key", false),
|
||||
TlsIv ("iv", true),
|
||||
TlsUpdateNplus1 ("traffic upd", false);
|
||||
|
||||
private final byte[] label;
|
||||
private final boolean isIv;
|
||||
|
||||
private KeySchedule(String label, boolean isIv) {
|
||||
this.label = ("tls13 " + label).getBytes();
|
||||
this.isIv = isIv;
|
||||
}
|
||||
|
||||
int getKeyLength(CipherSuite cs) {
|
||||
if (this == KeySchedule.TlsUpdateNplus1)
|
||||
return cs.hashAlg.hashLength;
|
||||
return isIv ? cs.bulkCipher.ivSize : cs.bulkCipher.keySize;
|
||||
}
|
||||
|
||||
String getAlgorithm(CipherSuite cs, String algorithm) {
|
||||
return isIv ? algorithm : cs.bulkCipher.algorithm;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
static final class LegacyTrafficKeyDerivation implements SSLKeyDerivation {
|
||||
private final HandshakeContext context;
|
||||
private final SecretKey masterSecret;
|
||||
private final TlsKeyMaterialSpec keyMaterialSpec;
|
||||
|
||||
LegacyTrafficKeyDerivation(
|
||||
HandshakeContext context, SecretKey masterSecret) {
|
||||
this.context = context;
|
||||
this.masterSecret = masterSecret;
|
||||
|
||||
CipherSuite cipherSuite = context.negotiatedCipherSuite;
|
||||
ProtocolVersion protocolVersion = context.negotiatedProtocol;
|
||||
|
||||
/*
|
||||
* For both the read and write sides of the protocol, we use the
|
||||
* master to generate MAC secrets and cipher keying material. Block
|
||||
* ciphers need initialization vectors, which we also generate.
|
||||
*
|
||||
* First we figure out how much keying material is needed.
|
||||
*/
|
||||
int hashSize = cipherSuite.macAlg.size;
|
||||
boolean is_exportable = cipherSuite.exportable;
|
||||
SSLCipher cipher = cipherSuite.bulkCipher;
|
||||
int expandedKeySize = is_exportable ? cipher.expandedKeySize : 0;
|
||||
|
||||
// Which algs/params do we need to use?
|
||||
String keyMaterialAlg;
|
||||
HashAlg hashAlg;
|
||||
|
||||
byte majorVersion = protocolVersion.major;
|
||||
byte minorVersion = protocolVersion.minor;
|
||||
if (protocolVersion.isDTLS) {
|
||||
// Use TLS version number for DTLS key calculation
|
||||
if (protocolVersion.id == ProtocolVersion.DTLS10.id) {
|
||||
majorVersion = ProtocolVersion.TLS11.major;
|
||||
minorVersion = ProtocolVersion.TLS11.minor;
|
||||
|
||||
keyMaterialAlg = "SunTlsKeyMaterial";
|
||||
hashAlg = H_NONE;
|
||||
} else { // DTLS 1.2+
|
||||
majorVersion = ProtocolVersion.TLS12.major;
|
||||
minorVersion = ProtocolVersion.TLS12.minor;
|
||||
|
||||
keyMaterialAlg = "SunTls12KeyMaterial";
|
||||
hashAlg = cipherSuite.hashAlg;
|
||||
}
|
||||
} else {
|
||||
if (protocolVersion.id >= ProtocolVersion.TLS12.id) {
|
||||
keyMaterialAlg = "SunTls12KeyMaterial";
|
||||
hashAlg = cipherSuite.hashAlg;
|
||||
} else {
|
||||
keyMaterialAlg = "SunTlsKeyMaterial";
|
||||
hashAlg = H_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// TLS v1.1+ and DTLS use an explicit IV in CBC cipher suites to
|
||||
// protect against the CBC attacks. AEAD/GCM cipher suites in
|
||||
// TLS v1.2 or later use a fixed IV as the implicit part of the
|
||||
// partially implicit nonce technique described in RFC 5116.
|
||||
int ivSize = cipher.ivSize;
|
||||
if (cipher.cipherType == CipherType.AEAD_CIPHER) {
|
||||
ivSize = cipher.fixedIvSize;
|
||||
} else if (
|
||||
cipher.cipherType == CipherType.BLOCK_CIPHER &&
|
||||
protocolVersion.useTLS11PlusSpec()) {
|
||||
ivSize = 0;
|
||||
}
|
||||
|
||||
TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec(
|
||||
masterSecret, (majorVersion & 0xFF), (minorVersion & 0xFF),
|
||||
context.clientHelloRandom.randomBytes,
|
||||
context.serverHelloRandom.randomBytes,
|
||||
cipher.algorithm, cipher.keySize, expandedKeySize,
|
||||
ivSize, hashSize,
|
||||
hashAlg.name, hashAlg.hashLength, hashAlg.blockSize);
|
||||
|
||||
try {
|
||||
KeyGenerator kg = JsseJce.getKeyGenerator(keyMaterialAlg);
|
||||
kg.init(spec);
|
||||
|
||||
this.keyMaterialSpec = (TlsKeyMaterialSpec)kg.generateKey();
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
SecretKey getTrafficKey(String algorithm) {
|
||||
switch (algorithm) {
|
||||
case "clientMacKey":
|
||||
return keyMaterialSpec.getClientMacKey();
|
||||
case "serverMacKey":
|
||||
return keyMaterialSpec.getServerMacKey();
|
||||
case "clientWriteKey":
|
||||
return keyMaterialSpec.getClientCipherKey();
|
||||
case "serverWriteKey":
|
||||
return keyMaterialSpec.getServerCipherKey();
|
||||
case "clientWriteIv":
|
||||
IvParameterSpec cliIvSpec = keyMaterialSpec.getClientIv();
|
||||
return (cliIvSpec == null) ? null :
|
||||
new SecretKeySpec(cliIvSpec.getIV(), "TlsIv");
|
||||
case "serverWriteIv":
|
||||
IvParameterSpec srvIvSpec = keyMaterialSpec.getServerIv();
|
||||
return (srvIvSpec == null) ? null :
|
||||
new SecretKeySpec(srvIvSpec.getIV(), "TlsIv");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretKey deriveKey(String algorithm,
|
||||
AlgorithmParameterSpec params) throws IOException {
|
||||
return getTrafficKey(algorithm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue