summaryrefslogtreecommitdiff
path: root/gnu/javax/net/ssl/provider/ServerHandshake.java
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/javax/net/ssl/provider/ServerHandshake.java')
-rw-r--r--gnu/javax/net/ssl/provider/ServerHandshake.java302
1 files changed, 224 insertions, 78 deletions
diff --git a/gnu/javax/net/ssl/provider/ServerHandshake.java b/gnu/javax/net/ssl/provider/ServerHandshake.java
index d339c1cc5..0d77bda04 100644
--- a/gnu/javax/net/ssl/provider/ServerHandshake.java
+++ b/gnu/javax/net/ssl/provider/ServerHandshake.java
@@ -38,8 +38,9 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import static gnu.javax.net.ssl.provider.ServerHandshake.State.*;
import static gnu.javax.net.ssl.provider.Handshake.Type.*;
+import static gnu.javax.net.ssl.provider.KeyExchangeAlgorithm.*;
+import static gnu.javax.net.ssl.provider.ServerHandshake.State.*;
import gnu.classpath.debug.Component;
import gnu.java.security.action.GetSecurityPropertyAction;
@@ -54,6 +55,7 @@ import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
+import java.security.KeyManagementException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
@@ -73,9 +75,11 @@ import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
@@ -192,22 +196,44 @@ class ServerHandshake extends AbstractHandshake
throws SSLException
{
// Figure out which SignatureAlgorithms we can support.
- HashSet<SignatureAlgorithm> sigs = new HashSet<SignatureAlgorithm>(2);
+ HashSet<KeyExchangeAlgorithm> kexes = new HashSet<KeyExchangeAlgorithm>(8);
+
X509ExtendedKeyManager km = engine.contextImpl.keyManager;
- if (km.getServerAliases(SignatureAlgorithm.DSA.name(), null).length != 0)
- sigs.add(SignatureAlgorithm.DSA);
- if (km.getServerAliases(SignatureAlgorithm.RSA.name(), null).length != 0)
- sigs.add(SignatureAlgorithm.RSA);
+ if (km != null)
+ {
+ if (km.getServerAliases(DH_DSS.name(), null).length > 0)
+ kexes.add(DH_DSS);
+ if (km.getServerAliases(DH_RSA.name(), null).length > 0)
+ kexes.add(DH_RSA);
+ if (km.getServerAliases(DHE_DSS.name(), null).length > 0)
+ kexes.add(DHE_DSS);
+ if (km.getServerAliases(DHE_RSA.name(), null).length > 0)
+ kexes.add(DHE_RSA);
+ if (km.getServerAliases(RSA.name(), null).length > 0)
+ kexes.add(RSA);
+ if (km.getServerAliases(RSA_PSK.name(), null).length > 0
+ && engine.contextImpl.pskManager != null)
+ kexes.add(RSA_PSK);
+ }
+ if (engine.contextImpl.pskManager != null)
+ {
+ kexes.add(DHE_PSK);
+ kexes.add(PSK);
+ }
if (Debug.DEBUG)
- logger.logv(Component.SSL_HANDSHAKE, "we have certs for signature algorithms {0}", sigs);
+ logger.logv(Component.SSL_HANDSHAKE,
+ "we have certs for key exchange algorithms {0}", kexes);
- HashSet<CipherSuite> suites = new HashSet<CipherSuite>(enabledSuites.length);
+ HashSet<CipherSuite> suites = new HashSet<CipherSuite>();
for (String s : enabledSuites)
{
CipherSuite suite = CipherSuite.forName(s);
- if (suite != null && sigs.contains(suite.signatureAlgorithm()))
- suites.add (suite);
+ if (suite == null)
+ continue;
+ if (!kexes.contains(suite.keyExchangeAlgorithm()))
+ continue;
+ suites.add (suite);
}
for (CipherSuite suite : clientSuites)
{
@@ -438,27 +464,130 @@ class ServerHandshake extends AbstractHandshake
throw new SSLException("expecting client key exchange");
ClientKeyExchange kex = (ClientKeyExchange) handshake.body();
- if (engine.session().suite.keyExchangeAlgorithm() ==
- KeyExchangeAlgorithm.DIFFIE_HELLMAN)
+ KeyExchangeAlgorithm alg = engine.session().suite.keyExchangeAlgorithm();
+ switch (alg)
{
- ClientDiffieHellmanPublic pub = (ClientDiffieHellmanPublic)
- kex.exchangeKeys();
- DHPublicKey myKey = (DHPublicKey) dhPair.getPublic();
- DHPublicKey clientKey =
- new GnuDHPublicKey(null, myKey.getParams().getP(),
- myKey.getParams().getG(),
- pub.publicValue());
- keyExchangeTask = new DHPhase(clientKey);
- tasks.add(keyExchangeTask);
- }
+ case DHE_DSS:
+ case DHE_RSA:
+ case DH_anon:
+ {
+ ClientDiffieHellmanPublic pub = (ClientDiffieHellmanPublic)
+ kex.exchangeKeys();
+ DHPublicKey myKey = (DHPublicKey) dhPair.getPublic();
+ DHPublicKey clientKey =
+ new GnuDHPublicKey(null, myKey.getParams().getP(),
+ myKey.getParams().getG(),
+ pub.publicValue());
+ keyExchangeTask = new DHPhase(clientKey);
+ tasks.add(keyExchangeTask);
+ }
+ break;
- if (engine.session().suite.keyExchangeAlgorithm() ==
- KeyExchangeAlgorithm.RSA)
- {
- EncryptedPreMasterSecret secret = (EncryptedPreMasterSecret)
- kex.exchangeKeys();
- keyExchangeTask = new RSAKeyExchange(secret.encryptedSecret());
- tasks.add(keyExchangeTask);
+ case RSA:
+ {
+ EncryptedPreMasterSecret secret = (EncryptedPreMasterSecret)
+ kex.exchangeKeys();
+ keyExchangeTask = new RSAKeyExchange(secret.encryptedSecret());
+ tasks.add(keyExchangeTask);
+ }
+ break;
+
+ case PSK:
+ {
+ ClientPSKParameters params = (ClientPSKParameters)
+ kex.exchangeKeys();
+ SecretKey key = null;
+ try
+ {
+ key = engine.contextImpl.pskManager.getKey(params.identity());
+ }
+ catch (KeyManagementException kme)
+ {
+ // Ignore; we hide the fact that a PSK identity was
+ // not found.
+ }
+ if (key != null)
+ {
+ byte[] keyb = key.getEncoded();
+ preMasterSecret = new byte[(2 * keyb.length) + 4];
+ preMasterSecret[0] = (byte) (keyb.length >>> 8);
+ preMasterSecret[1] = (byte) keyb.length;
+ preMasterSecret[keyb.length + 2]
+ = (byte) (keyb.length >>> 8);
+ preMasterSecret[keyb.length + 3]
+ = (byte) keyb.length;
+ System.arraycopy(keyb, 0, preMasterSecret,
+ keyb.length + 4, keyb.length);
+ }
+ else
+ {
+ // Generate a random, fake secret.
+ preMasterSecret = new byte[8];
+ preMasterSecret[1] = 2;
+ preMasterSecret[5] = 2;
+ preMasterSecret[6] = (byte) engine.session().random().nextInt();
+ preMasterSecret[7] = (byte) engine.session().random().nextInt();
+ }
+
+ generateMasterSecret(clientRandom, serverRandom,
+ engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom,
+ engine.session());
+ setupSecurityParameters(keys, false, engine, compression);
+ }
+ break;
+
+ case DHE_PSK:
+ {
+ ClientDHE_PSKParameters params = (ClientDHE_PSKParameters)
+ kex.exchangeKeys();
+ DHPublicKey serverKey = (DHPublicKey) dhPair.getPublic();
+ DHPublicKey clientKey =
+ new GnuDHPublicKey(null, serverKey.getParams().getP(),
+ serverKey.getParams().getG(),
+ params.params().publicValue());
+ SecretKey psk = null;
+ try
+ {
+ psk = engine.contextImpl.pskManager.getKey(params.identity());
+ }
+ catch (KeyManagementException kme)
+ {
+ }
+ if (psk == null)
+ {
+ byte[] fakeKey = new byte[16];
+ engine.session().random().nextBytes(fakeKey);
+ psk = new SecretKeySpec(fakeKey, "DHE_PSK");
+ }
+ keyExchangeTask = new DHE_PSKGen(clientKey, psk, false);
+ tasks.add(keyExchangeTask);
+ }
+ break;
+
+ case RSA_PSK:
+ {
+ ClientRSA_PSKParameters params = (ClientRSA_PSKParameters)
+ kex.exchangeKeys();
+ SecretKey psk = null;
+ try
+ {
+ psk = engine.contextImpl.pskManager.getKey(params.identity());
+ }
+ catch (KeyManagementException kme)
+ {
+ }
+ if (psk == null)
+ {
+ byte[] fakeKey = new byte[16];
+ engine.session().random().nextBytes(fakeKey);
+ psk = new SecretKeySpec(fakeKey, "DHE_PSK");
+ }
+ keyExchangeTask =
+ new RSA_PSKExchange(params.secret().encryptedSecret(), psk);
+ tasks.add(keyExchangeTask);
+ }
+ break;
}
// XXX SRP
@@ -733,7 +862,7 @@ output_loop:
fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
outBuffer.position(outBuffer.position() + l);
-
+ CipherSuite cs = engine.session().suite;
if (continuedSession)
{
byte[][] keys = generateKeys(clientRandom, serverRandom,
@@ -742,15 +871,27 @@ output_loop:
engine.changeCipherSpec();
state = WRITE_FINISHED;
}
- else if (engine.session().suite.signatureAlgorithm()
- != SignatureAlgorithm.ANONYMOUS)
+ else if (cs.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS
+ || cs.keyExchangeAlgorithm() == RSA_PSK)
{
certLoader = new CertLoader();
tasks.add(certLoader);
state = WRITE_CERTIFICATE;
+ if (cs.keyExchangeAlgorithm() == DHE_DSS
+ || cs.keyExchangeAlgorithm() == DHE_RSA)
+ {
+ genDH = new GenDH();
+ tasks.add(genDH);
+ state = WRITE_SERVER_KEY_EXCHANGE;
+ }
break output_loop;
}
- else if (engine.session().suite.isEphemeralDH())
+ else if (engine.session().suite.keyExchangeAlgorithm() == PSK)
+ {
+ state = WRITE_SERVER_KEY_EXCHANGE;
+ }
+ else if (cs.keyExchangeAlgorithm() == DHE_PSK
+ || cs.keyExchangeAlgorithm() == DH_anon)
{
genDH = new GenDH();
tasks.add(genDH);
@@ -808,9 +949,8 @@ output_loop:
outBuffer.position(outBuffer.position() + l);
CipherSuite s = engine.session().suite;
- if (s.isEphemeralDH()
- || (s.keyExchangeAlgorithm() == KeyExchangeAlgorithm.DIFFIE_HELLMAN
- && s.signatureAlgorithm() == SignatureAlgorithm.ANONYMOUS))
+ KeyExchangeAlgorithm kexalg = s.keyExchangeAlgorithm();
+ if (kexalg == DHE_DSS || kexalg == DHE_RSA)
{
genDH = new GenDH();
tasks.add(genDH);
@@ -839,7 +979,8 @@ output_loop:
ByteBuffer paramBuffer = null;
ByteBuffer sigBuffer = null;
- if (kex == KeyExchangeAlgorithm.DIFFIE_HELLMAN)
+ if (kex == DHE_DSS || kex == DHE_RSA || kex == DH_anon
+ || kex == DHE_PSK)
{
assert(genDH != null);
assert(genDH.hasRun());
@@ -852,6 +993,15 @@ output_loop:
engine.session().random());
paramBuffer = genDH.paramsBuffer;
sigBuffer = genDH.sigBuffer;
+
+ if (kex == DHE_PSK)
+ {
+ String identityHint
+ = engine.contextImpl.pskManager.chooseIdentityHint();
+ ServerDHE_PSKParameters psk =
+ new ServerDHE_PSKParameters(identityHint, paramBuffer);
+ paramBuffer = psk.buffer();
+ }
}
// XXX handle SRP
@@ -1102,54 +1252,16 @@ output_loop:
public void implRun() throws SSLException
{
- String sigAlg = null;
- switch (engine.session().suite.keyExchangeAlgorithm())
- {
- case NONE:
- break;
-
- case RSA:
- sigAlg = "RSA";
- break;
-
- case DIFFIE_HELLMAN:
- if (engine.session().suite.isEphemeralDH())
- sigAlg = "DHE_";
- else
- sigAlg = "DH_";
- switch (engine.session().suite.signatureAlgorithm())
- {
- case RSA:
- sigAlg += "RSA";
- break;
-
- case DSA:
- sigAlg += "DSS";
- break;
- }
-
- case SRP:
- switch (engine.session().suite.signatureAlgorithm())
- {
- case RSA:
- sigAlg = "SRP_RSA";
- break;
-
- case DSA:
- sigAlg = "SRP_DSS";
- break;
- }
- }
+ KeyExchangeAlgorithm kexalg = engine.session().suite.keyExchangeAlgorithm();
X509ExtendedKeyManager km = engine.contextImpl.keyManager;
Principal[] issuers = null; // XXX use TrustedAuthorities extension.
- keyAlias = km.chooseEngineServerAlias(sigAlg, issuers, engine);
+ keyAlias = km.chooseEngineServerAlias(kexalg.name(), issuers, engine);
if (keyAlias == null)
throw new SSLException("no certificates available");
X509Certificate[] chain = km.getCertificateChain(keyAlias);
engine.session().setLocalCertificates(chain);
localCert = chain[0];
- if (engine.session().suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.DIFFIE_HELLMAN
- && !engine.session().suite.isEphemeralDH())
+ if (kexalg == DH_DSS || kexalg == DH_RSA)
dhPair = new KeyPair(localCert.getPublicKey(),
km.getPrivateKey(keyAlias));
}
@@ -1213,4 +1325,38 @@ output_loop:
setupSecurityParameters(keys, false, engine, compression);
}
}
+
+ class RSA_PSKExchange extends DelegatedTask
+ {
+ private final byte[] encryptedPreMasterSecret;
+ private final SecretKey psKey;
+
+ RSA_PSKExchange(byte[] encryptedPreMasterSecret, SecretKey psKey)
+ {
+ this.encryptedPreMasterSecret = encryptedPreMasterSecret;
+ this.psKey = psKey;
+ }
+
+ public @Override void implRun()
+ throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
+ NoSuchAlgorithmException, NoSuchPaddingException, SSLException
+ {
+ Cipher rsa = Cipher.getInstance("RSA");
+ rsa.init(Cipher.DECRYPT_MODE, localCert);
+ byte[] rsaSecret = rsa.doFinal(encryptedPreMasterSecret);
+ byte[] psSecret = psKey.getEncoded();
+ preMasterSecret = new byte[rsaSecret.length + psSecret.length + 4];
+ preMasterSecret[0] = (byte) (rsaSecret.length >>> 8);
+ preMasterSecret[1] = (byte) rsaSecret.length;
+ System.arraycopy(rsaSecret, 0, preMasterSecret, 2, rsaSecret.length);
+ preMasterSecret[rsaSecret.length + 2] = (byte) (psSecret.length >>> 8);
+ preMasterSecret[rsaSecret.length + 3] = (byte) psSecret.length;
+ System.arraycopy(psSecret, 0, preMasterSecret, rsaSecret.length+4,
+ psSecret.length);
+
+ generateMasterSecret(clientRandom, serverRandom, engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+ setupSecurityParameters(keys, false, engine, compression);
+ }
+ }
} \ No newline at end of file