summaryrefslogtreecommitdiff
path: root/gnu/javax/net/ssl/provider/ClientHandshake.java
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/javax/net/ssl/provider/ClientHandshake.java')
-rw-r--r--gnu/javax/net/ssl/provider/ClientHandshake.java187
1 files changed, 173 insertions, 14 deletions
diff --git a/gnu/javax/net/ssl/provider/ClientHandshake.java b/gnu/javax/net/ssl/provider/ClientHandshake.java
index 2b0ebf407..494e66dc7 100644
--- a/gnu/javax/net/ssl/provider/ClientHandshake.java
+++ b/gnu/javax/net/ssl/provider/ClientHandshake.java
@@ -39,6 +39,7 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
import static gnu.javax.net.ssl.provider.ClientHandshake.State.*;
+import static gnu.javax.net.ssl.provider.KeyExchangeAlgorithm.*;
import gnu.classpath.debug.Component;
import gnu.java.security.action.GetSecurityPropertyAction;
@@ -48,6 +49,8 @@ import gnu.javax.net.ssl.Session;
import gnu.javax.net.ssl.provider.Alert.Description;
import gnu.javax.net.ssl.provider.Alert.Level;
import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
+import gnu.javax.net.ssl.provider.ServerNameList.NameType;
+import gnu.javax.net.ssl.provider.ServerNameList.ServerName;
import java.nio.ByteBuffer;
import java.security.AccessController;
@@ -61,7 +64,9 @@ import java.security.PrivateKey;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
import java.util.Arrays;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -125,6 +130,9 @@ public class ClientHandshake extends AbstractHandshake
private KeyPair dhPair;
private String keyAlias;
private PrivateKey privateKey;
+ private MaxFragmentLength maxFragmentLengthSent;
+ private boolean truncatedHMacSent;
+ private ProtocolVersion sentVersion;
// Delegated tasks.
private CertVerifier certVerifier;
@@ -190,7 +198,31 @@ public class ClientHandshake extends AbstractHandshake
((AbstractSessionContext) engine.contextImpl
.engineGetClientSessionContext()).put(engine.session());
}
-
+ ExtensionList extensions = hello.extensions();
+ if (extensions != null)
+ {
+ for (Extension extension : extensions)
+ {
+ Extension.Type type = extension.type();
+ if (type == null)
+ continue;
+ switch (type)
+ {
+ case MAX_FRAGMENT_LENGTH:
+ MaxFragmentLength mfl
+ = (MaxFragmentLength) extension.value();
+ if (maxFragmentLengthSent == mfl)
+ engine.session().setApplicationBufferSize(mfl.maxLength());
+ break;
+
+ case TRUNCATED_HMAC:
+ if (truncatedHMacSent)
+ engine.session().setTruncatedMac(true);
+ break;
+ }
+ }
+ }
+
if (continuedSession)
{
byte[][] keys = generateKeys(clientRandom, serverRandom,
@@ -253,16 +285,16 @@ public class ClientHandshake extends AbstractHandshake
case READ_SERVER_KEY_EXCHANGE:
{
CipherSuite s = engine.session().suite;
+ KeyExchangeAlgorithm kexalg = s.keyExchangeAlgorithm();
// XXX also SRP.
- if (!s.isEphemeralDH() &&
- !(s.keyExchangeAlgorithm() == KeyExchangeAlgorithm.DIFFIE_HELLMAN
- && s.signatureAlgorithm() == SignatureAlgorithm.ANONYMOUS))
+ if (kexalg != DHE_DSS && kexalg != DHE_RSA && kexalg != DH_anon
+ && kexalg != DHE_PSK && kexalg != PSK && kexalg != RSA_PSK)
throw new AlertException(new Alert(Level.FATAL,
Description.UNEXPECTED_MESSAGE));
ServerKeyExchange skex = (ServerKeyExchange) handshake.body();
ByteBuffer paramsBuffer = null;
- if (s.keyExchangeAlgorithm() == KeyExchangeAlgorithm.DIFFIE_HELLMAN)
+ if (kexalg == DHE_DSS || kexalg == DHE_RSA || kexalg == DH_anon)
{
ServerDHParams dhParams = (ServerDHParams) skex.params();
ByteBuffer b = dhParams.buffer();
@@ -277,7 +309,7 @@ public class ClientHandshake extends AbstractHandshake
tasks.add(paramsVerifier);
}
- if (s.keyExchangeAlgorithm() == KeyExchangeAlgorithm.DIFFIE_HELLMAN)
+ if (kexalg == DHE_DSS || kexalg == DHE_RSA || kexalg == DH_anon)
{
ServerDHParams dhParams = (ServerDHParams) skex.params();
DHPublicKey serverKey = new GnuDHPublicKey(null,
@@ -455,7 +487,8 @@ outer_loop:
sid = continued.id();
hello.setSessionId(sid.id());
- hello.setVersion(chooseVersion());
+ sentVersion = chooseVersion();
+ hello.setVersion(sentVersion);
hello.setCipherSuites(getSuites());
hello.setCompressionMethods(getCompressionMethods());
Random r = hello.random();
@@ -464,8 +497,44 @@ outer_loop:
engine.session().random().nextBytes(nonce);
r.setRandomBytes(nonce);
clientRandom = r.copy();
- // XXX extensions?
+ if (enableExtensions())
+ {
+ List<Extension> extensions = new LinkedList<Extension>();
+ MaxFragmentLength fraglen = maxFragmentLength();
+ if (fraglen != null)
+ {
+ extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH,
+ fraglen));
+ maxFragmentLengthSent = fraglen;
+ }
+
+ String host = engine.getPeerHost();
+ if (host != null)
+ {
+ ServerName name
+ = new ServerName(NameType.HOST_NAME, host);
+ ServerNameList names
+ = new ServerNameList(Collections.singletonList(name));
+ extensions.add(new Extension(Extension.Type.SERVER_NAME,
+ names));
+ }
+
+ if (truncatedHMac())
+ {
+ extensions.add(new Extension(Extension.Type.TRUNCATED_HMAC,
+ new TruncatedHMAC()));
+ truncatedHMacSent = true;
+ }
+
+ ExtensionList elist = new ExtensionList(extensions);
+ hello.setExtensions(elist.buffer());
+ }
+ else
+ hello.setDisableExtensions(true);
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "{0}", hello);
+
fragment.putInt((Handshake.Type.CLIENT_HELLO.getValue() << 24)
| (hello.length() & 0xFFFFFF));
outBuffer = hello.buffer();
@@ -517,7 +586,8 @@ outer_loop:
ClientKeyExchangeBuilder ckex
= new ClientKeyExchangeBuilder(engine.session().suite,
engine.session().version);
- if (kea == KeyExchangeAlgorithm.DIFFIE_HELLMAN)
+ if (kea == DHE_DSS || kea == DHE_RSA || kea == DH_anon
+ || kea == DH_DSS || kea == DH_RSA)
{
assert(dhPair != null);
DHPublicKey pubkey = (DHPublicKey) dhPair.getPublic();
@@ -525,7 +595,7 @@ outer_loop:
= new ClientDiffieHellmanPublic(pubkey.getY());
ckex.setExchangeKeys(pub.buffer());
}
- if (kea == KeyExchangeAlgorithm.RSA)
+ if (kea == RSA || kea == RSA_PSK)
{
assert(keyExchange instanceof RSAGen);
assert(keyExchange.hasRun());
@@ -536,7 +606,44 @@ outer_loop:
EncryptedPreMasterSecret epms
= new EncryptedPreMasterSecret(((RSAGen) keyExchange).encryptedSecret(),
engine.session().version);
- ckex.setExchangeKeys(epms.buffer());
+ if (kea == RSA)
+ ckex.setExchangeKeys(epms.buffer());
+ else
+ {
+ String identity = getPSKIdentity();
+ if (identity == null)
+ throw new SSLException("no pre-shared-key identity;"
+ + " set the security property"
+ + " \"jessie.client.psk.identity\"");
+ ClientRSA_PSKParameters params =
+ new ClientRSA_PSKParameters(identity, epms,
+ engine.session().version);
+ ckex.setExchangeKeys(params.buffer());
+ }
+ }
+ if (kea == DHE_PSK)
+ {
+ assert(dhPair != null);
+ String identity = getPSKIdentity();
+ if (identity == null)
+ throw new SSLException("no pre-shared key identity; set"
+ + " the security property"
+ + " \"jessie.client.psk.identity\"");
+ DHPublicKey pubkey = (DHPublicKey) dhPair.getPublic();
+ ClientDHE_PSKParameters params =
+ new ClientDHE_PSKParameters(identity,
+ new ClientDiffieHellmanPublic(pubkey.getY()));
+ ckex.setExchangeKeys(params.buffer());
+ }
+ if (kea == PSK)
+ {
+ String identity = getPSKIdentity();
+ if (identity == null)
+ throw new SSLException("no pre-shared key identity; set"
+ + " the security property"
+ + " \"jessie.client.psk.identity\"");
+ ClientPSKParameters params = new ClientPSKParameters(identity);
+ ckex.setExchangeKeys(params.buffer());
}
if (Debug.DEBUG)
@@ -697,6 +804,56 @@ outer_loop:
return methods;
}
+ private boolean enableExtensions()
+ {
+ GetSecurityPropertyAction action
+ = new GetSecurityPropertyAction("jessie.client.enable.extensions");
+ return Boolean.valueOf(AccessController.doPrivileged(action));
+ }
+
+ private MaxFragmentLength maxFragmentLength()
+ {
+ GetSecurityPropertyAction action
+ = new GetSecurityPropertyAction("jessie.client.maxFragmentLength");
+ String s = AccessController.doPrivileged(action);
+ if (s != null)
+ {
+ try
+ {
+ int len = Integer.parseInt(s);
+ switch (len)
+ {
+ case 9:
+ case (1 << 9): return MaxFragmentLength.LEN_2_9;
+ case 10:
+ case (1 << 10): return MaxFragmentLength.LEN_2_10;
+ case 11:
+ case (1 << 11): return MaxFragmentLength.LEN_2_11;
+ case 12:
+ case (1 << 12): return MaxFragmentLength.LEN_2_12;
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ }
+ }
+ return null;
+ }
+
+ private boolean truncatedHMac()
+ {
+ GetSecurityPropertyAction action
+ = new GetSecurityPropertyAction("jessie.client.truncatedHMac");
+ return Boolean.valueOf(AccessController.doPrivileged(action));
+ }
+
+ private String getPSKIdentity()
+ {
+ GetSecurityPropertyAction action
+ = new GetSecurityPropertyAction("jessie.client.psk.identity");
+ return AccessController.doPrivileged(action);
+ }
+
// Delegated tasks.
class ParamsVerifier extends DelegatedTask
@@ -832,10 +989,12 @@ outer_loop:
}
preMasterSecret = new byte[48];
engine.session().random().nextBytes(preMasterSecret);
- preMasterSecret[0] = (byte) engine.session().version.major();
- preMasterSecret[1] = (byte) engine.session().version.minor();
+ preMasterSecret[0] = (byte) sentVersion.major();
+ preMasterSecret[1] = (byte) sentVersion.minor();
Cipher rsa = Cipher.getInstance("RSA");
- rsa.init(Cipher.ENCRYPT_MODE, engine.session().getPeerCertificates()[0]);
+ java.security.cert.Certificate cert
+ = engine.session().getPeerCertificates()[0];
+ rsa.init(Cipher.ENCRYPT_MODE, cert);
encryptedPreMasterSecret = rsa.doFinal(preMasterSecret);
// Generate our session keys, because we can.