|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.ssl; |
|
|
|
import java.io.IOException; |
|
import java.nio.ByteBuffer; |
|
import java.security.GeneralSecurityException; |
|
import java.security.spec.AlgorithmParameterSpec; |
|
import javax.crypto.SecretKey; |
|
import javax.net.ssl.SSLHandshakeException; |
|
import sun.security.ssl.CipherSuite.HashAlg; |
|
|
|
final class SSLSecretDerivation implements SSLKeyDerivation { |
|
private static final byte[] sha256EmptyDigest = new byte[] { |
|
(byte)0xE3, (byte)0xB0, (byte)0xC4, (byte)0x42, |
|
(byte)0x98, (byte)0xFC, (byte)0x1C, (byte)0x14, |
|
(byte)0x9A, (byte)0xFB, (byte)0xF4, (byte)0xC8, |
|
(byte)0x99, (byte)0x6F, (byte)0xB9, (byte)0x24, |
|
(byte)0x27, (byte)0xAE, (byte)0x41, (byte)0xE4, |
|
(byte)0x64, (byte)0x9B, (byte)0x93, (byte)0x4C, |
|
(byte)0xA4, (byte)0x95, (byte)0x99, (byte)0x1B, |
|
(byte)0x78, (byte)0x52, (byte)0xB8, (byte)0x55 |
|
}; |
|
|
|
private static final byte[] sha384EmptyDigest = new byte[] { |
|
(byte)0x38, (byte)0xB0, (byte)0x60, (byte)0xA7, |
|
(byte)0x51, (byte)0xAC, (byte)0x96, (byte)0x38, |
|
(byte)0x4C, (byte)0xD9, (byte)0x32, (byte)0x7E, |
|
(byte)0xB1, (byte)0xB1, (byte)0xE3, (byte)0x6A, |
|
(byte)0x21, (byte)0xFD, (byte)0xB7, (byte)0x11, |
|
(byte)0x14, (byte)0xBE, (byte)0x07, (byte)0x43, |
|
(byte)0x4C, (byte)0x0C, (byte)0xC7, (byte)0xBF, |
|
(byte)0x63, (byte)0xF6, (byte)0xE1, (byte)0xDA, |
|
(byte)0x27, (byte)0x4E, (byte)0xDE, (byte)0xBF, |
|
(byte)0xE7, (byte)0x6F, (byte)0x65, (byte)0xFB, |
|
(byte)0xD5, (byte)0x1A, (byte)0xD2, (byte)0xF1, |
|
(byte)0x48, (byte)0x98, (byte)0xB9, (byte)0x5B |
|
}; |
|
|
|
private final HandshakeContext context; |
|
private final String hkdfAlg; |
|
private final HashAlg hashAlg; |
|
private final SecretKey secret; |
|
private final byte[] transcriptHash; |
|
|
|
SSLSecretDerivation( |
|
HandshakeContext context, SecretKey secret) { |
|
this.context = context; |
|
this.secret = secret; |
|
this.hashAlg = context.negotiatedCipherSuite.hashAlg; |
|
this.hkdfAlg = |
|
"HKDF-Expand/Hmac" + hashAlg.name.replace("-", ""); |
|
context.handshakeHash.update(); |
|
this.transcriptHash = context.handshakeHash.digest(); |
|
} |
|
|
|
SSLSecretDerivation forContext(HandshakeContext context) { |
|
return new SSLSecretDerivation(context, secret); |
|
} |
|
|
|
@Override |
|
public SecretKey deriveKey(String algorithm, |
|
AlgorithmParameterSpec params) throws IOException { |
|
SecretSchedule ks = SecretSchedule.valueOf(algorithm); |
|
try { |
|
byte[] expandContext; |
|
if (ks == SecretSchedule.TlsSaltSecret) { |
|
if (hashAlg == HashAlg.H_SHA256) { |
|
expandContext = sha256EmptyDigest; |
|
} else if (hashAlg == HashAlg.H_SHA384) { |
|
expandContext = sha384EmptyDigest; |
|
} else { |
|
// unlikely, but please update if more hash algorithm |
|
|
|
throw new SSLHandshakeException( |
|
"Unexpected unsupported hash algorithm: " + |
|
algorithm); |
|
} |
|
} else { |
|
expandContext = transcriptHash; |
|
} |
|
byte[] hkdfInfo = createHkdfInfo(ks.label, |
|
expandContext, hashAlg.hashLength); |
|
|
|
HKDF hkdf = new HKDF(hashAlg.name); |
|
return hkdf.expand(secret, hkdfInfo, hashAlg.hashLength, algorithm); |
|
} catch (GeneralSecurityException gse) { |
|
throw (SSLHandshakeException) new SSLHandshakeException( |
|
"Could not generate secret").initCause(gse); |
|
} |
|
} |
|
|
|
public static byte[] createHkdfInfo( |
|
byte[] label, byte[] context, int length) { |
|
byte[] info = new byte[4 + label.length + context.length]; |
|
ByteBuffer m = ByteBuffer.wrap(info); |
|
try { |
|
Record.putInt16(m, length); |
|
Record.putBytes8(m, label); |
|
Record.putBytes8(m, context); |
|
} catch (IOException ioe) { |
|
|
|
throw new RuntimeException("Unexpected exception", ioe); |
|
} |
|
|
|
return info; |
|
} |
|
|
|
private enum SecretSchedule { |
|
|
|
TlsSaltSecret ("derived"), |
|
TlsExtBinderKey ("ext binder"), |
|
TlsResBinderKey ("res binder"), |
|
TlsClientEarlyTrafficSecret ("c e traffic"), |
|
TlsEarlyExporterMasterSecret ("e exp master"), |
|
TlsClientHandshakeTrafficSecret ("c hs traffic"), |
|
TlsServerHandshakeTrafficSecret ("s hs traffic"), |
|
TlsClientAppTrafficSecret ("c ap traffic"), |
|
TlsServerAppTrafficSecret ("s ap traffic"), |
|
TlsExporterMasterSecret ("exp master"), |
|
TlsResumptionMasterSecret ("res master"); |
|
|
|
private final byte[] label; |
|
|
|
private SecretSchedule(String label) { |
|
this.label = ("tls13 " + label).getBytes(); |
|
} |
|
} |
|
} |