package com.sun.crypto.provider;
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.*;
import sun.security.internal.interfaces.TlsMasterSecret;
import sun.security.internal.spec.TlsMasterSecretParameterSpec;
import static com.sun.crypto.provider.TlsPrfGenerator.*;
public final class TlsMasterSecretGenerator extends KeyGeneratorSpi {
private final static String MSG = "TlsMasterSecretGenerator must be "
+ "initialized using a TlsMasterSecretParameterSpec";
private TlsMasterSecretParameterSpec spec;
private int protocolVersion;
public TlsMasterSecretGenerator() {
}
protected void engineInit(SecureRandom random) {
throw new InvalidParameterException(MSG);
}
protected void engineInit(AlgorithmParameterSpec params,
SecureRandom random) throws InvalidAlgorithmParameterException {
if (params instanceof TlsMasterSecretParameterSpec == false) {
throw new InvalidAlgorithmParameterException(MSG);
}
this.spec = (TlsMasterSecretParameterSpec)params;
if ("RAW".equals(spec.getPremasterSecret().getFormat()) == false) {
throw new InvalidAlgorithmParameterException(
"Key format must be RAW");
}
protocolVersion = (spec.getMajorVersion() << 8)
| spec.getMinorVersion();
if ((protocolVersion < 0x0300) || (protocolVersion > 0x0303)) {
throw new InvalidAlgorithmParameterException(
"Only SSL 3.0, TLS 1.0/1.1/1.2 supported");
}
}
protected void engineInit(int keysize, SecureRandom random) {
throw new InvalidParameterException(MSG);
}
protected SecretKey engineGenerateKey() {
if (spec == null) {
throw new IllegalStateException(
"TlsMasterSecretGenerator must be initialized");
}
SecretKey premasterKey = spec.getPremasterSecret();
byte[] premaster = premasterKey.getEncoded();
int premasterMajor, premasterMinor;
if (premasterKey.getAlgorithm().equals("TlsRsaPremasterSecret")) {
premasterMajor = premaster[0] & 0xff;
premasterMinor = premaster[1] & 0xff;
} else {
premasterMajor = -1;
premasterMinor = -1;
}
try {
byte[] master;
if (protocolVersion >= 0x0301) {
byte[] label;
byte[] seed;
byte[] extendedMasterSecretSessionHash =
spec.getExtendedMasterSecretSessionHash();
if (extendedMasterSecretSessionHash.length != 0) {
label = LABEL_EXTENDED_MASTER_SECRET;
seed = extendedMasterSecretSessionHash;
} else {
byte[] clientRandom = spec.getClientRandom();
byte[] serverRandom = spec.getServerRandom();
label = LABEL_MASTER_SECRET;
seed = concat(clientRandom, serverRandom);
}
master = ((protocolVersion >= 0x0303) ?
doTLS12PRF(premaster, label, seed, 48,
spec.getPRFHashAlg(), spec.getPRFHashLength(),
spec.getPRFBlockSize()) :
doTLS10PRF(premaster, label, seed, 48));
} else {
master = new byte[48];
MessageDigest md5 = MessageDigest.getInstance("MD5");
MessageDigest sha = MessageDigest.getInstance("SHA");
byte[] clientRandom = spec.getClientRandom();
byte[] serverRandom = spec.getServerRandom();
byte[] tmp = new byte[20];
for (int i = 0; i < 3; i++) {
sha.update(SSL3_CONST[i]);
sha.update(premaster);
sha.update(clientRandom);
sha.update(serverRandom);
sha.digest(tmp, 0, 20);
md5.update(premaster);
md5.update(tmp);
md5.digest(master, i << 4, 16);
}
}
return new TlsMasterSecretKey(master, premasterMajor,
premasterMinor);
} catch (NoSuchAlgorithmException e) {
throw new ProviderException(e);
} catch (DigestException e) {
throw new ProviderException(e);
}
}
private static final class TlsMasterSecretKey implements TlsMasterSecret {
private static final long serialVersionUID = 1019571680375368880L;
private byte[] key;
private final int majorVersion, minorVersion;
TlsMasterSecretKey(byte[] key, int majorVersion, int minorVersion) {
this.key = key;
this.majorVersion = majorVersion;
this.minorVersion = minorVersion;
}
public int getMajorVersion() {
return majorVersion;
}
public int getMinorVersion() {
return minorVersion;
}
public String getAlgorithm() {
return "TlsMasterSecret";
}
public String getFormat() {
return "RAW";
}
public byte[] getEncoded() {
return key.clone();
}
}
}