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 = KeyAgreement.getInstance(algorithmName);
ka.init(localPrivateKey);
ka.doPhase(peerPublicKey, true);
SecretKey preMasterSecret
= ka.generateSecret("TlsPremasterSecret");
SSLMasterKeyDerivation mskd
= SSLMasterKeyDerivation.valueOf(
context.negotiatedProtocol);
if (mskd == null) {
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 = KeyAgreement.getInstance(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) {
byte[] zeros = new byte[hashAlg.hashLength];
SecretKeySpec ikm
= new SecretKeySpec(zeros, "TlsPreSharedSecret");
SecretKey earlySecret
= hkdf.extract(zeros, ikm, "TlsEarlySecret");
kd = new SSLSecretDerivation(context, earlySecret);
}
SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
return hkdf.extract(saltSecret, sharedSecret, algorithm);
} catch (GeneralSecurityException gse) {
throw (SSLHandshakeException) new SSLHandshakeException(
"Could not generate secret").initCause(gse);
}
}
}