/
wstartsev
/
jdk
Обзор
Документация
Войти
/
wstartsev
/
jdk
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java
331 строка
13 KB
Daniel Jeliński
8368520: TLS 1.3 KeyUpdate fails with SunPKCS11 provider
02 окт 2025, 16:29
02 окт 2025, 16:29
56baf64
Код
Авторство
О чём код?
/* * Copyright (c) 2018, 2025, 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 javax.crypto.KDF; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.HKDFParameterSpec; import javax.crypto.spec.IvParameterSpec; 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 type) throws IOException { KeySchedule ks = KeySchedule.valueOf(type); try { KDF hkdf = KDF.getInstance(cs.hashAlg.hkdfAlgorithm); byte[] hkdfInfo = createHkdfInfo(ks.label, ks.getKeyLength(cs)); HKDFParameterSpec spec = HKDFParameterSpec.expandOnly(secret, hkdfInfo, ks.getKeyLength(cs)); return hkdf.deriveKey(ks.getAlgorithm(cs, type), spec); } catch (GeneralSecurityException gse) { throw new SSLHandshakeException( "Could not generate secret", gse); } } @Override public byte[] deriveData(String type) throws IOException { KeySchedule ks = KeySchedule.valueOf(type); try { KDF hkdf = KDF.getInstance(cs.hashAlg.hkdfAlgorithm); byte[] hkdfInfo = createHkdfInfo(ks.label, ks.getKeyLength(cs)); HKDFParameterSpec spec = HKDFParameterSpec.expandOnly(secret, hkdfInfo, ks.getKeyLength(cs)); return hkdf.deriveData(spec); } catch (GeneralSecurityException gse) { throw new SSLHandshakeException( "Could not generate secret", gse); } } private static byte[] createHkdfInfo( byte[] label, int length) { 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"), TlsIv ("iv"), TlsUpdateNplus1 ("traffic upd"); private final byte[] label; KeySchedule(String label) { this.label = ("tls13 " + label).getBytes(); } int getKeyLength(CipherSuite cs) { return switch (this) { case TlsUpdateNplus1 -> cs.hashAlg.hashLength; case TlsIv -> cs.bulkCipher.ivSize; case TlsKey -> cs.bulkCipher.keySize; }; } String getAlgorithm(CipherSuite cs, String algorithm) { return this == TlsKey ? cs.bulkCipher.algorithm : algorithm; } } @SuppressWarnings("deprecation") static final class LegacyTrafficKeyDerivation implements SSLKeyDerivation { private final TlsKeyMaterialSpec keyMaterialSpec; LegacyTrafficKeyDerivation( HandshakeContext context, SecretKey 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 = KeyGenerator.getInstance(keyMaterialAlg); kg.init(spec); this.keyMaterialSpec = (TlsKeyMaterialSpec)kg.generateKey(); } catch (GeneralSecurityException e) { throw new ProviderException(e); } } @Override public SecretKey deriveKey(String type) throws IOException { switch (type) { case "clientMacKey": return keyMaterialSpec.getClientMacKey(); case "serverMacKey": return keyMaterialSpec.getServerMacKey(); case "clientWriteKey": return keyMaterialSpec.getClientCipherKey(); case "serverWriteKey": return keyMaterialSpec.getServerCipherKey(); default: throw new SSLHandshakeException( "Cannot deriveKey for " + type); } } @Override public byte[] deriveData(String type) throws IOException { switch (type) { case "clientWriteIv": IvParameterSpec cliIvSpec = keyMaterialSpec.getClientIv(); return (cliIvSpec == null) ? null : cliIvSpec.getIV(); case "serverWriteIv": IvParameterSpec srvIvSpec = keyMaterialSpec.getServerIv(); return (srvIvSpec == null) ? null : srvIvSpec.getIV(); default: throw new SSLHandshakeException( "Cannot deriveData for " + type); } } } }