package sun.security.ssl;
import java.io.IOException;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import sun.security.ssl.DHKeyExchange.DHEPossession;
import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
import sun.security.ssl.X509Authentication.X509Possession;
final class SSLKeyExchange implements SSLKeyAgreementGenerator,
SSLHandshakeBinding {
private final SSLAuthentication authentication;
private final SSLKeyAgreement keyAgreement;
SSLKeyExchange(X509Authentication authentication,
SSLKeyAgreement keyAgreement) {
this.authentication = authentication;
this.keyAgreement = keyAgreement;
}
SSLPossession[] createPossessions(HandshakeContext context) {
SSLPossession authPossession = null;
if (authentication != null) {
authPossession = authentication.createPossession(context);
if (authPossession == null) {
return new SSLPossession[0];
} else if (context instanceof ServerHandshakeContext) {
ServerHandshakeContext shc = (ServerHandshakeContext)context;
shc.interimAuthn = authPossession;
}
}
SSLPossession kaPossession;
if (keyAgreement == T12KeyAgreement.RSA_EXPORT) {
X509Possession x509Possession = (X509Possession)authPossession;
if (JsseJce.getRSAKeyLength(
x509Possession.popCerts[0].getPublicKey()) > 512) {
kaPossession = keyAgreement.createPossession(context);
if (kaPossession == null) {
return new SSLPossession[0];
} else {
return authentication != null ?
new SSLPossession[] {authPossession, kaPossession} :
new SSLPossession[] {kaPossession};
}
} else {
return authentication != null ?
new SSLPossession[] {authPossession} :
new SSLPossession[0];
}
} else {
kaPossession = keyAgreement.createPossession(context);
if (kaPossession == null) {
if (keyAgreement == T12KeyAgreement.RSA ||
keyAgreement == T12KeyAgreement.ECDH) {
return authentication != null ?
new SSLPossession[] {authPossession} :
new SSLPossession[0];
} else {
return new SSLPossession[0];
}
} else {
return authentication != null ?
new SSLPossession[] {authPossession, kaPossession} :
new SSLPossession[] {kaPossession};
}
}
}
@Override
public SSLKeyDerivation createKeyDerivation(
HandshakeContext handshakeContext) throws IOException {
return keyAgreement.createKeyDerivation(handshakeContext);
}
@Override
public SSLHandshake[] getRelatedHandshakers(
HandshakeContext handshakeContext) {
SSLHandshake[] auHandshakes;
if (authentication != null) {
auHandshakes =
authentication.getRelatedHandshakers(handshakeContext);
} else {
auHandshakes = null;
}
SSLHandshake[] kaHandshakes =
keyAgreement.getRelatedHandshakers(handshakeContext);
if (auHandshakes == null || auHandshakes.length == 0) {
return kaHandshakes;
} else if (kaHandshakes == null || kaHandshakes.length == 0) {
return auHandshakes;
} else {
SSLHandshake[] producers = Arrays.copyOf(
auHandshakes, auHandshakes.length + kaHandshakes.length);
System.arraycopy(kaHandshakes, 0,
producers, auHandshakes.length, kaHandshakes.length);
return producers;
}
}
@Override
public Map.Entry<Byte, HandshakeProducer>[] getHandshakeProducers(
HandshakeContext handshakeContext) {
Map.Entry<Byte, HandshakeProducer>[] auProducers;
if (authentication != null) {
auProducers =
authentication.getHandshakeProducers(handshakeContext);
} else {
auProducers = null;
}
Map.Entry<Byte, HandshakeProducer>[] kaProducers =
keyAgreement.getHandshakeProducers(handshakeContext);
if (auProducers == null || auProducers.length == 0) {
return kaProducers;
} else if (kaProducers == null || kaProducers.length == 0) {
return auProducers;
} else {
Map.Entry<Byte, HandshakeProducer>[] producers = Arrays.copyOf(
auProducers, auProducers.length + kaProducers.length);
System.arraycopy(kaProducers, 0,
producers, auProducers.length, kaProducers.length);
return producers;
}
}
@Override
public Map.Entry<Byte, SSLConsumer>[] getHandshakeConsumers(
HandshakeContext handshakeContext) {
Map.Entry<Byte, SSLConsumer>[] auConsumers;
if (authentication != null) {
auConsumers =
authentication.getHandshakeConsumers(handshakeContext);
} else {
auConsumers = null;
}
Map.Entry<Byte, SSLConsumer>[] kaConsumers =
keyAgreement.getHandshakeConsumers(handshakeContext);
if (auConsumers == null || auConsumers.length == 0) {
return kaConsumers;
} else if (kaConsumers == null || kaConsumers.length == 0) {
return auConsumers;
} else {
Map.Entry<Byte, SSLConsumer>[] producers = Arrays.copyOf(
auConsumers, auConsumers.length + kaConsumers.length);
System.arraycopy(kaConsumers, 0,
producers, auConsumers.length, kaConsumers.length);
return producers;
}
}
static SSLKeyExchange valueOf(
CipherSuite.KeyExchange keyExchange,
ProtocolVersion protocolVersion) {
if (keyExchange == null || protocolVersion == null) {
return null;
}
switch (keyExchange) {
case K_RSA:
return SSLKeyExRSA.KE;
case K_RSA_EXPORT:
return SSLKeyExRSAExport.KE;
case K_DHE_DSS:
return SSLKeyExDHEDSS.KE;
case K_DHE_DSS_EXPORT:
return SSLKeyExDHEDSSExport.KE;
case K_DHE_RSA:
if (protocolVersion.useTLS12PlusSpec()) {
return SSLKeyExDHERSAOrPSS.KE;
} else {
return SSLKeyExDHERSA.KE;
}
case K_DHE_RSA_EXPORT:
return SSLKeyExDHERSAExport.KE;
case K_DH_ANON:
return SSLKeyExDHANON.KE;
case K_DH_ANON_EXPORT:
return SSLKeyExDHANONExport.KE;
case K_ECDH_ECDSA:
return SSLKeyExECDHECDSA.KE;
case K_ECDH_RSA:
return SSLKeyExECDHRSA.KE;
case K_ECDHE_ECDSA:
return SSLKeyExECDHEECDSA.KE;
case K_ECDHE_RSA:
if (protocolVersion.useTLS12PlusSpec()) {
return SSLKeyExECDHERSAOrPSS.KE;
} else {
return SSLKeyExECDHERSA.KE;
}
case K_ECDH_ANON:
return SSLKeyExECDHANON.KE;
}
return null;
}
static SSLKeyExchange valueOf(NamedGroup namedGroup) {
SSLKeyAgreement ka = T13KeyAgreement.valueOf(namedGroup);
if (ka != null) {
return new SSLKeyExchange(
null, T13KeyAgreement.valueOf(namedGroup));
}
return null;
}
private static class SSLKeyExRSA {
private static SSLKeyExchange KE = new SSLKeyExchange(
X509Authentication.RSA, T12KeyAgreement.RSA);
}
private static class SSLKeyExRSAExport {
private static SSLKeyExchange KE = new SSLKeyExchange(
X509Authentication.RSA, T12KeyAgreement.RSA_EXPORT);
}
private static class SSLKeyExDHEDSS {
private static SSLKeyExchange KE = new SSLKeyExchange(
X509Authentication.DSA, T12KeyAgreement.DHE);
}
private static class SSLKeyExDHEDSSExport {
private static SSLKeyExchange KE = new SSLKeyExchange(
X509Authentication.DSA, T12KeyAgreement.DHE_EXPORT);
}
private static class SSLKeyExDHERSA {
private static SSLKeyExchange KE = new SSLKeyExchange(
X509Authentication.RSA, T12KeyAgreement.DHE);
}
private static class SSLKeyExDHERSAOrPSS {
private static SSLKeyExchange KE = new SSLKeyExchange(
X509Authentication.RSA_OR_PSS, T12KeyAgreement.DHE);
}
private static class SSLKeyExDHERSAExport {
private static SSLKeyExchange KE = new SSLKeyExchange(
X509Authentication.RSA, T12KeyAgreement.DHE_EXPORT);
}
private static class SSLKeyExDHANON {
private static SSLKeyExchange KE = new SSLKeyExchange(
null, T12KeyAgreement.DHE);
}
private static class SSLKeyExDHANONExport {
private static SSLKeyExchange KE = new SSLKeyExchange(
null, T12KeyAgreement.DHE_EXPORT);
}
private static class SSLKeyExECDHECDSA {
private static SSLKeyExchange KE = new SSLKeyExchange(
X509Authentication.EC, T12KeyAgreement.ECDH);
}
private static class SSLKeyExECDHRSA {
private static SSLKeyExchange KE = new SSLKeyExchange(
X509Authentication.EC, T12KeyAgreement.ECDH);
}
private static class SSLKeyExECDHEECDSA {
private static SSLKeyExchange KE = new SSLKeyExchange(
X509Authentication.EC, T12KeyAgreement.ECDHE);
}
private static class SSLKeyExECDHERSA {
private static SSLKeyExchange KE = new SSLKeyExchange(
X509Authentication.RSA, T12KeyAgreement.ECDHE);
}
private static class SSLKeyExECDHERSAOrPSS {
private static SSLKeyExchange KE = new SSLKeyExchange(
X509Authentication.RSA_OR_PSS, T12KeyAgreement.ECDHE);
}
private static class SSLKeyExECDHANON {
private static SSLKeyExchange KE = new SSLKeyExchange(
null, T12KeyAgreement.ECDHE);
}
private enum T12KeyAgreement implements SSLKeyAgreement {
RSA ("rsa", null,
RSAKeyExchange.kaGenerator),
RSA_EXPORT ("rsa_export", RSAKeyExchange.poGenerator,
RSAKeyExchange.kaGenerator),
DHE ("dhe", DHKeyExchange.poGenerator,
DHKeyExchange.kaGenerator),
DHE_EXPORT ("dhe_export", DHKeyExchange.poExportableGenerator,
DHKeyExchange.kaGenerator),
ECDH ("ecdh", null,
ECDHKeyExchange.ecdhKAGenerator),
ECDHE ("ecdhe", ECDHKeyExchange.poGenerator,
ECDHKeyExchange.ecdheKAGenerator);
final String name;
final SSLPossessionGenerator possessionGenerator;
final SSLKeyAgreementGenerator keyAgreementGenerator;
T12KeyAgreement(String name,
SSLPossessionGenerator possessionGenerator,
SSLKeyAgreementGenerator keyAgreementGenerator) {
this.name = name;
this.possessionGenerator = possessionGenerator;
this.keyAgreementGenerator = keyAgreementGenerator;
}
@Override
public SSLPossession createPossession(HandshakeContext context) {
if (possessionGenerator != null) {
return possessionGenerator.createPossession(context);
}
return null;
}
@Override
public SSLKeyDerivation createKeyDerivation(
HandshakeContext context) throws IOException {
return keyAgreementGenerator.createKeyDerivation(context);
}
@Override
public SSLHandshake[] getRelatedHandshakers(
HandshakeContext handshakeContext) {
if (!handshakeContext.negotiatedProtocol.useTLS13PlusSpec()) {
if (this.possessionGenerator != null) {
return new SSLHandshake[] {
SSLHandshake.SERVER_KEY_EXCHANGE
};
}
}
return new SSLHandshake[0];
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Map.Entry<Byte, HandshakeProducer>[] getHandshakeProducers(
HandshakeContext handshakeContext) {
if (handshakeContext.negotiatedProtocol.useTLS13PlusSpec()) {
return (Map.Entry<Byte, HandshakeProducer>[])(new Map.Entry[0]);
}
if (handshakeContext.sslConfig.isClientMode) {
switch (this) {
case RSA:
case RSA_EXPORT:
return (Map.Entry<Byte,
HandshakeProducer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.CLIENT_KEY_EXCHANGE.id,
RSAClientKeyExchange.rsaHandshakeProducer
)
});
case DHE:
case DHE_EXPORT:
return (Map.Entry<Byte,
HandshakeProducer>[])(new Map.Entry[] {
new SimpleImmutableEntry<Byte, HandshakeProducer>(
SSLHandshake.CLIENT_KEY_EXCHANGE.id,
DHClientKeyExchange.dhHandshakeProducer
)
});
case ECDH:
return (Map.Entry<Byte,
HandshakeProducer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.CLIENT_KEY_EXCHANGE.id,
ECDHClientKeyExchange.ecdhHandshakeProducer
)
});
case ECDHE:
return (Map.Entry<Byte,
HandshakeProducer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.CLIENT_KEY_EXCHANGE.id,
ECDHClientKeyExchange.ecdheHandshakeProducer
)
});
}
} else {
switch (this) {
case RSA_EXPORT:
return (Map.Entry<Byte,
HandshakeProducer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.SERVER_KEY_EXCHANGE.id,
RSAServerKeyExchange.rsaHandshakeProducer
)
});
case DHE:
case DHE_EXPORT:
return (Map.Entry<Byte,
HandshakeProducer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.SERVER_KEY_EXCHANGE.id,
DHServerKeyExchange.dhHandshakeProducer
)
});
case ECDHE:
return (Map.Entry<Byte,
HandshakeProducer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.SERVER_KEY_EXCHANGE.id,
ECDHServerKeyExchange.ecdheHandshakeProducer
)
});
}
}
return (Map.Entry<Byte, HandshakeProducer>[])(new Map.Entry[0]);
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Map.Entry<Byte, SSLConsumer>[] getHandshakeConsumers(
HandshakeContext handshakeContext) {
if (handshakeContext.negotiatedProtocol.useTLS13PlusSpec()) {
return (Map.Entry<Byte, SSLConsumer>[])(new Map.Entry[0]);
}
if (handshakeContext.sslConfig.isClientMode) {
switch (this) {
case RSA_EXPORT:
return (Map.Entry<Byte,
SSLConsumer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.SERVER_KEY_EXCHANGE.id,
RSAServerKeyExchange.rsaHandshakeConsumer
)
});
case DHE:
case DHE_EXPORT:
return (Map.Entry<Byte,
SSLConsumer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.SERVER_KEY_EXCHANGE.id,
DHServerKeyExchange.dhHandshakeConsumer
)
});
case ECDHE:
return (Map.Entry<Byte,
SSLConsumer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.SERVER_KEY_EXCHANGE.id,
ECDHServerKeyExchange.ecdheHandshakeConsumer
)
});
}
} else {
switch (this) {
case RSA:
case RSA_EXPORT:
return (Map.Entry<Byte,
SSLConsumer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.CLIENT_KEY_EXCHANGE.id,
RSAClientKeyExchange.rsaHandshakeConsumer
)
});
case DHE:
case DHE_EXPORT:
return (Map.Entry<Byte,
SSLConsumer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.CLIENT_KEY_EXCHANGE.id,
DHClientKeyExchange.dhHandshakeConsumer
)
});
case ECDH:
return (Map.Entry<Byte,
SSLConsumer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.CLIENT_KEY_EXCHANGE.id,
ECDHClientKeyExchange.ecdhHandshakeConsumer
)
});
case ECDHE:
return (Map.Entry<Byte,
SSLConsumer>[])(new Map.Entry[] {
new SimpleImmutableEntry<>(
SSLHandshake.CLIENT_KEY_EXCHANGE.id,
ECDHClientKeyExchange.ecdheHandshakeConsumer
)
});
}
}
return (Map.Entry<Byte, SSLConsumer>[])(new Map.Entry[0]);
}
}
private static final class T13KeyAgreement implements SSLKeyAgreement {
private final NamedGroup namedGroup;
static final Map<NamedGroup, T13KeyAgreement>
supportedKeyShares = new HashMap<>();
static {
for (NamedGroup namedGroup :
SupportedGroups.supportedNamedGroups) {
supportedKeyShares.put(
namedGroup, new T13KeyAgreement(namedGroup));
}
}
private T13KeyAgreement(NamedGroup namedGroup) {
this.namedGroup = namedGroup;
}
static T13KeyAgreement valueOf(NamedGroup namedGroup) {
return supportedKeyShares.get(namedGroup);
}
@Override
public SSLPossession createPossession(HandshakeContext hc) {
if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
return new ECDHEPossession(
namedGroup, hc.sslContext.getSecureRandom());
} else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
return new DHEPossession(
namedGroup, hc.sslContext.getSecureRandom());
}
return null;
}
@Override
public SSLKeyDerivation createKeyDerivation(
HandshakeContext hc) throws IOException {
if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc);
} else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
return DHKeyExchange.kaGenerator.createKeyDerivation(hc);
}
return null;
}
}
}