From ceca0e3930ab18748f1b02be3a6260c3daf4734f Mon Sep 17 00:00:00 2001 From: Casey Marshall Date: Tue, 18 Jul 2006 08:12:30 +0000 Subject: 2006-07-18 Casey Marshall * gnu/javax/net/ssl/provider/ClientHandshake.java (implHandleInput, implHandleOutput): fix PSK exchange handling. (ClientDHGen.full): new field. (ClientDHGen.implRun): run full key exchange if `full' is true. (ClientDHGen.serverKey): new method. (RSAGen.full): new field. (RSAGen.implRun): run full key exchange if `full' is true. * gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java (params): slice the buffer. * gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java (): use `dhParams,' not `buffer.' (params): slice the buffer. * gnu/javax/net/ssl/provider/ServerKeyExchange.java (length): handle case where parameters or signature are null. * gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java (version): removed. (): don't take version argument. (): don't take version argument; take buffer argument. (secret): pass TLS_1 to EncryptedPreMasterSecret constructor. * gnu/javax/net/ssl/provider/CipherSuite.java (isResolved): new field. (, ): set `isResolved.' (resolve): add PSK cipher suite detection. (isResolved): new method. * gnu/javax/net/ssl/provider/ServerHandshake.java (serverKey): new field. (chooseSuites): choose NONE key exchanges, too; omit unresolved cipher suites. (implHandleInput, implHandleOutput): fix PSK handling. (checkKeyExchange): update for NONE and PSK exchanges. (CertLoader.implRun): grab our private key here. (RSAKeyExchange.implRun): initialize RSA cipher with our private key. (RSA_PSKExchange.implRun): likewise. * gnu/javax/net/ssl/provider/ExchangeKeys.java (): duplicate and order the buffer; handle null argument. * gnu/javax/net/ssl/provider/ClientKeyExchange.java (exchangeKeys): handle NONE exchange. * gnu/javax/net/ssl/provider/SSLContextImpl.java (engineInit): handle PSK key managers properly. * gnu/javax/net/ssl/provider/SSLEngineImpl.java (): remove debug logging. * gnu/javax/net/ssl/provider/ServerDHParams.java (): duplicate and order the buffer. * gnu/javax/crypto/RSACipherImpl.java (doFinal): allow short input. (rsaDecrypt): ensure there's a leading zero. * gnu/javax/net/ssl/provider/EmptyExchangeKeys.java: new file. --- ChangeLog-ssl-nio | 51 +++++++ gnu/javax/crypto/RSACipherImpl.java | 11 +- gnu/javax/net/ssl/provider/CipherSuite.java | 22 ++- .../net/ssl/provider/ClientDHE_PSKParameters.java | 4 +- gnu/javax/net/ssl/provider/ClientHandshake.java | 106 ++++++++++++-- gnu/javax/net/ssl/provider/ClientKeyExchange.java | 6 +- .../net/ssl/provider/ClientRSA_PSKParameters.java | 20 ++- gnu/javax/net/ssl/provider/EmptyExchangeKeys.java | 77 ++++++++++ gnu/javax/net/ssl/provider/ExchangeKeys.java | 4 +- gnu/javax/net/ssl/provider/SSLContextImpl.java | 2 +- gnu/javax/net/ssl/provider/SSLEngineImpl.java | 2 - .../net/ssl/provider/ServerDHE_PSKParameters.java | 9 +- gnu/javax/net/ssl/provider/ServerDHParams.java | 3 +- gnu/javax/net/ssl/provider/ServerHandshake.java | 155 +++++++++++---------- gnu/javax/net/ssl/provider/ServerKeyExchange.java | 9 +- 15 files changed, 369 insertions(+), 112 deletions(-) create mode 100644 gnu/javax/net/ssl/provider/EmptyExchangeKeys.java diff --git a/ChangeLog-ssl-nio b/ChangeLog-ssl-nio index 771cc0d02..f15d93cac 100644 --- a/ChangeLog-ssl-nio +++ b/ChangeLog-ssl-nio @@ -1,3 +1,54 @@ +2006-07-18 Casey Marshall + + * gnu/javax/net/ssl/provider/ClientHandshake.java + (implHandleInput, implHandleOutput): fix PSK exchange handling. + (ClientDHGen.full): new field. + (ClientDHGen.implRun): run full key exchange if `full' is true. + (ClientDHGen.serverKey): new method. + (RSAGen.full): new field. + (RSAGen.implRun): run full key exchange if `full' is true. + * gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java + (params): slice the buffer. + * gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java + (): use `dhParams,' not `buffer.' + (params): slice the buffer. + * gnu/javax/net/ssl/provider/ServerKeyExchange.java (length): + handle case where parameters or signature are null. + * gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java + (version): removed. + (): don't take version argument. + (): don't take version argument; take buffer argument. + (secret): pass TLS_1 to EncryptedPreMasterSecret constructor. + * gnu/javax/net/ssl/provider/CipherSuite.java (isResolved): new + field. + (, ): set `isResolved.' + (resolve): add PSK cipher suite detection. + (isResolved): new method. + * gnu/javax/net/ssl/provider/ServerHandshake.java (serverKey): new + field. + (chooseSuites): choose NONE key exchanges, too; omit unresolved + cipher suites. + (implHandleInput, implHandleOutput): fix PSK handling. + (checkKeyExchange): update for NONE and PSK exchanges. + (CertLoader.implRun): grab our private key here. + (RSAKeyExchange.implRun): initialize RSA cipher with our private + key. + (RSA_PSKExchange.implRun): likewise. + * gnu/javax/net/ssl/provider/ExchangeKeys.java (): duplicate + and order the buffer; handle null argument. + * gnu/javax/net/ssl/provider/ClientKeyExchange.java + (exchangeKeys): handle NONE exchange. + * gnu/javax/net/ssl/provider/SSLContextImpl.java (engineInit): + handle PSK key managers properly. + * gnu/javax/net/ssl/provider/SSLEngineImpl.java (): remove + debug logging. + * gnu/javax/net/ssl/provider/ServerDHParams.java (): + duplicate and order the buffer. + * gnu/javax/crypto/RSACipherImpl.java (doFinal): allow short + input. + (rsaDecrypt): ensure there's a leading zero. + * gnu/javax/net/ssl/provider/EmptyExchangeKeys.java: new file. + 2006-07-14 Casey Marshall * gnu/java/net/protocol/http/HTTPConnection.java (getSocket): diff --git a/gnu/javax/crypto/RSACipherImpl.java b/gnu/javax/crypto/RSACipherImpl.java index 05f77213e..c6235c928 100644 --- a/gnu/javax/crypto/RSACipherImpl.java +++ b/gnu/javax/crypto/RSACipherImpl.java @@ -204,8 +204,6 @@ public class RSACipherImpl extends CipherSpi engineUpdate (in, offset, length); if (opmode == Cipher.DECRYPT_MODE) { - if (pos < dataBuffer.length) - throw new IllegalBlockSizeException ("expecting exactly " + dataBuffer.length + " bytes"); BigInteger enc = new BigInteger (1, dataBuffer); byte[] dec = rsaDecrypt (enc); logger.log (Component.CRYPTO, "RSA: decryption produced\n{0}", @@ -292,6 +290,13 @@ public class RSACipherImpl extends CipherSpi dec = dec.multiply (r.modInverse (n)).mod (n); } - return dec.toByteArray (); + byte[] decb = dec.toByteArray(); + if (decb[0] != 0x00) + { + byte[] b = new byte[decb.length + 1]; + System.arraycopy(decb, 0, b, 1, decb.length); + decb = b; + } + return decb; } } diff --git a/gnu/javax/net/ssl/provider/CipherSuite.java b/gnu/javax/net/ssl/provider/CipherSuite.java index ee02e8281..f9701bdc7 100644 --- a/gnu/javax/net/ssl/provider/CipherSuite.java +++ b/gnu/javax/net/ssl/provider/CipherSuite.java @@ -492,6 +492,7 @@ public final class CipherSuite implements Constructed private final int keyLength; private final byte[] id; private final String name; + private final boolean isResolved; // Constructors. // ------------------------------------------------------------------------- @@ -535,6 +536,7 @@ public final class CipherSuite implements Constructed { tlsSuiteNames.add(name); } + isResolved = true; } private CipherSuite(byte[] id) @@ -549,6 +551,7 @@ public final class CipherSuite implements Constructed keyLength = 0; this.id = id; name = null; + isResolved = false; } // Class methods. @@ -688,7 +691,7 @@ public final class CipherSuite implements Constructed public CipherSuite resolve() { - if (id[0] == 0x00) switch (id[1]) + if (id[0] == 0x00) switch (id[1] & 0xFF) { case 0x00: return TLS_NULL_WITH_NULL_NULL; case 0x01: return TLS_RSA_WITH_NULL_MD5; @@ -745,9 +748,26 @@ public final class CipherSuite implements Constructed case 0x7C: return TLS_RSA_WITH_3DES_EDE_CBC_RMD; case 0x7D: return TLS_RSA_WITH_AES_128_CBC_RMD; case 0x7E: return TLS_RSA_WITH_AES_256_CBC_RMD;*/ + case 0x8A: return TLS_PSK_WITH_RC4_128_SHA; + case 0x8B: return TLS_PSK_WITH_3DES_EDE_CBC_SHA; + case 0x8C: return TLS_PSK_WITH_AES_128_CBC_SHA; + case 0x8D: return TLS_PSK_WITH_AES_256_CBC_SHA; + case 0x8E: return TLS_DHE_PSK_WITH_RC4_128_SHA; + case 0x8F: return TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA; + case 0x90: return TLS_DHE_PSK_WITH_AES_128_CBC_SHA; + case 0x91: return TLS_DHE_PSK_WITH_AES_256_CBC_SHA; + case 0x92: return TLS_RSA_PSK_WITH_RC4_128_SHA; + case 0x93: return TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA; + case 0x94: return TLS_RSA_PSK_WITH_AES_128_CBC_SHA; + case 0x95: return TLS_RSA_PSK_WITH_AES_256_CBC_SHA; } return this; } + + public boolean isResolved() + { + return isResolved; + } public int keyLength() { diff --git a/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java b/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java index a40f77ba2..e63e03c0a 100644 --- a/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java +++ b/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java @@ -106,8 +106,8 @@ public class ClientDHE_PSKParameters extends ExchangeKeys implements Builder, Co public ClientDiffieHellmanPublic params() { - return new ClientDiffieHellmanPublic((ByteBuffer) buffer.duplicate() - .position(identityLength()).limit(length())); + return new ClientDiffieHellmanPublic(((ByteBuffer) buffer.duplicate() + .position(identityLength()).limit(length())).slice()); } /* (non-Javadoc) diff --git a/gnu/javax/net/ssl/provider/ClientHandshake.java b/gnu/javax/net/ssl/provider/ClientHandshake.java index 494e66dc7..123137d49 100644 --- a/gnu/javax/net/ssl/provider/ClientHandshake.java +++ b/gnu/javax/net/ssl/provider/ClientHandshake.java @@ -56,6 +56,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; @@ -69,11 +70,14 @@ import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.zip.Deflater; +import java.util.zip.Inflater; 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; @@ -223,6 +227,7 @@ public class ClientHandshake extends AbstractHandshake } } + KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm(); if (continuedSession) { byte[][] keys = generateKeys(clientRandom, serverRandom, @@ -230,8 +235,13 @@ public class ClientHandshake extends AbstractHandshake setupSecurityParameters(keys, true, engine, compression); state = READ_FINISHED; } - else + else if (kex == RSA || kex == DH_DSS || kex == DH_RSA + || kex == DHE_DSS || kex == DHE_RSA || kex == RSA_PSK) state = READ_CERTIFICATE; + else if (kex == DH_anon || kex == PSK || kex == DHE_PSK) + state = READ_SERVER_KEY_EXCHANGE; + else + state = READ_CERTIFICATE_REQUEST; } break; @@ -269,12 +279,15 @@ public class ClientHandshake extends AbstractHandshake tasks.add(certVerifier); // If we are doing an RSA key exchange, generate our parameters. - if (engine.session().suite.keyExchangeAlgorithm() - == KeyExchangeAlgorithm.RSA) + KeyExchangeAlgorithm kea = engine.session().suite.keyExchangeAlgorithm(); + if (kea == RSA || kea == RSA_PSK) { - keyExchange = new RSAGen(); + keyExchange = new RSAGen(kea == RSA); tasks.add(keyExchange); - state = READ_CERTIFICATE_REQUEST; + if (kea == RSA) + state = READ_CERTIFICATE_REQUEST; + else + state = READ_SERVER_KEY_EXCHANGE; } else state = READ_SERVER_KEY_EXCHANGE; @@ -291,6 +304,15 @@ public class ClientHandshake extends AbstractHandshake && kexalg != DHE_PSK && kexalg != PSK && kexalg != RSA_PSK) throw new AlertException(new Alert(Level.FATAL, Description.UNEXPECTED_MESSAGE)); + + if (handshake.type() != Handshake.Type.SERVER_KEY_EXCHANGE) + { + if (kexalg != RSA_PSK && kexalg != PSK) + throw new AlertException(new Alert(Level.FATAL, + Description.UNEXPECTED_MESSAGE)); + state = READ_CERTIFICATE_REQUEST; + return HandshakeStatus.NEED_UNWRAP; + } ServerKeyExchange skex = (ServerKeyExchange) handshake.body(); ByteBuffer paramsBuffer = null; @@ -318,7 +340,21 @@ public class ClientHandshake extends AbstractHandshake dhParams.y()); DHParameterSpec params = new DHParameterSpec(dhParams.p(), dhParams.g()); - keyExchange = new ClientDHGen(serverKey, params); + keyExchange = new ClientDHGen(serverKey, params, true); + tasks.add(keyExchange); + } + if (kexalg == DHE_PSK) + { + ServerDHE_PSKParameters pskParams = (ServerDHE_PSKParameters) + skex.params(); + ServerDHParams dhParams = pskParams.params(); + DHPublicKey serverKey = new GnuDHPublicKey(null, + dhParams.p(), + dhParams.g(), + dhParams.y()); + DHParameterSpec params = new DHParameterSpec(dhParams.p(), + dhParams.g()); + keyExchange = new ClientDHGen(serverKey, params, false); tasks.add(keyExchange); } state = READ_CERTIFICATE_REQUEST; @@ -616,13 +652,14 @@ outer_loop: + " set the security property" + " \"jessie.client.psk.identity\""); ClientRSA_PSKParameters params = - new ClientRSA_PSKParameters(identity, epms, - engine.session().version); + new ClientRSA_PSKParameters(identity, epms.buffer()); ckex.setExchangeKeys(params.buffer()); + generatePSKSecret(identity, preMasterSecret, true); } } if (kea == DHE_PSK) { + assert(keyExchange instanceof ClientDHGen); assert(dhPair != null); String identity = getPSKIdentity(); if (identity == null) @@ -634,6 +671,7 @@ outer_loop: new ClientDHE_PSKParameters(identity, new ClientDiffieHellmanPublic(pubkey.getY())); ckex.setExchangeKeys(params.buffer()); + generatePSKSecret(identity, preMasterSecret, true); } if (kea == PSK) { @@ -642,9 +680,27 @@ outer_loop: throw new SSLException("no pre-shared key identity; set" + " the security property" + " \"jessie.client.psk.identity\""); + generatePSKSecret(identity, null, true); ClientPSKParameters params = new ClientPSKParameters(identity); ckex.setExchangeKeys(params.buffer()); } + if (kea == NONE) + { + Inflater inflater = null; + Deflater deflater = null; + if (compression == CompressionMethod.ZLIB) + { + inflater = new Inflater(); + deflater = new Deflater(); + } + inParams = new InputSecurityParameters(null, null, inflater, + engine.session(), + engine.session().suite); + outParams = new OutputSecurityParameters(null, null, deflater, + engine.session(), + engine.session().suite); + engine.session().privateData.masterSecret = new byte[0]; + } if (Debug.DEBUG) logger.logv(Component.SSL_HANDSHAKE, "{0}", ckex); @@ -894,11 +950,13 @@ outer_loop: { private final DHPublicKey serverKey; private final DHParameterSpec params; + private final boolean full; - ClientDHGen(DHPublicKey serverKey, DHParameterSpec params) + ClientDHGen(DHPublicKey serverKey, DHParameterSpec params, boolean full) { this.serverKey = serverKey; this.params = params; + this.full = full; } public void implRun() @@ -930,13 +988,19 @@ outer_loop: "client keys public:{0} private:{1}", dhPair.getPublic(), dhPair.getPrivate()); - // We have enough info to do the full key exchange; so let's do it. initDiffieHellman((DHPrivateKey) dhPair.getPrivate(), engine.session().random()); - DHPhase phase = new DHPhase(serverKey); + + // We have enough info to do the full key exchange; so let's do it. + DHPhase phase = new DHPhase(serverKey, full); phase.run(); if (phase.thrown() != null) throw new SSLException(phase.thrown()); } + + DHPublicKey serverKey() + { + return serverKey; + } } class CertLoader extends DelegatedTask @@ -966,6 +1030,17 @@ outer_loop: class RSAGen extends DelegatedTask { private byte[] encryptedPreMasterSecret; + private final boolean full; + + RSAGen() + { + this(true); + } + + RSAGen(boolean full) + { + this.full = full; + } public void implRun() throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException, @@ -998,9 +1073,12 @@ outer_loop: encryptedPreMasterSecret = rsa.doFinal(preMasterSecret); // Generate our session keys, because we can. - generateMasterSecret(clientRandom, serverRandom, engine.session()); - byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session()); - setupSecurityParameters(keys, true, engine, compression); + if (full) + { + generateMasterSecret(clientRandom, serverRandom, engine.session()); + byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session()); + setupSecurityParameters(keys, true, engine, compression); + } } byte[] encryptedSecret() diff --git a/gnu/javax/net/ssl/provider/ClientKeyExchange.java b/gnu/javax/net/ssl/provider/ClientKeyExchange.java index cc05ff736..2006e7385 100644 --- a/gnu/javax/net/ssl/provider/ClientKeyExchange.java +++ b/gnu/javax/net/ssl/provider/ClientKeyExchange.java @@ -95,8 +95,10 @@ public class ClientKeyExchange implements Handshake.Body else if (alg == KeyExchangeAlgorithm.PSK) return new ClientPSKParameters(buffer.duplicate()); else if (alg == KeyExchangeAlgorithm.RSA_PSK) - return new ClientRSA_PSKParameters(buffer.duplicate(), version); - throw new IllegalArgumentException("unsupported key exchange"); + return new ClientRSA_PSKParameters(buffer.duplicate()); + else if (alg == KeyExchangeAlgorithm.NONE) + return new EmptyExchangeKeys(); + throw new IllegalArgumentException("unsupported key exchange: " + alg); } public int length() diff --git a/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java b/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java index 3023ff9a2..f7483a94c 100644 --- a/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java +++ b/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java @@ -38,6 +38,9 @@ exception statement from your version. */ package gnu.javax.net.ssl.provider; +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + import java.io.PrintWriter; import java.io.StringWriter; import java.nio.ByteBuffer; @@ -49,26 +52,21 @@ import java.nio.charset.Charset; */ public class ClientRSA_PSKParameters extends ExchangeKeys implements Builder, Constructed { - private final ProtocolVersion version; - - public ClientRSA_PSKParameters(ByteBuffer buffer, ProtocolVersion version) + public ClientRSA_PSKParameters(ByteBuffer buffer) { super(buffer); - this.version = version; } - public ClientRSA_PSKParameters(String identity, EncryptedPreMasterSecret epms, - ProtocolVersion version) + public ClientRSA_PSKParameters(String identity, ByteBuffer epms) { super(null); Charset utf8 = Charset.forName("UTF-8"); ByteBuffer idBuf = utf8.encode(identity); - buffer = ByteBuffer.allocate(2 + idBuf.remaining() + epms.length()); + buffer = ByteBuffer.allocate(2 + idBuf.remaining() + epms.remaining()); buffer.putShort((short) idBuf.remaining()); buffer.put(idBuf); - buffer.put(epms.buffer()); + buffer.put(epms); buffer.rewind(); - this.version = version; } /* (non-Javadoc) @@ -102,8 +100,8 @@ public class ClientRSA_PSKParameters extends ExchangeKeys implements Builder, Co public EncryptedPreMasterSecret secret() { return new EncryptedPreMasterSecret - ((ByteBuffer) buffer.duplicate().position(identityLength()) - .limit(buffer.capacity()), version); + (((ByteBuffer) buffer.duplicate().position(identityLength()) + .limit(buffer.capacity())).slice(), ProtocolVersion.TLS_1); } /* (non-Javadoc) diff --git a/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java b/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java new file mode 100644 index 000000000..acf4cfa03 --- /dev/null +++ b/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java @@ -0,0 +1,77 @@ +/* EmptyExchangeKeys.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.nio.ByteBuffer; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class EmptyExchangeKeys + extends ExchangeKeys +{ + + public EmptyExchangeKeys() + { + super(ByteBuffer.allocate(0)); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#length() + */ + public int length() + { + return 0; + } + + public String toString() + { + return toString(null); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String) + */ + public String toString(String prefix) + { + String ret = "struct { };"; + if (prefix != null) ret = prefix + ret; + return ret; + } +} diff --git a/gnu/javax/net/ssl/provider/ExchangeKeys.java b/gnu/javax/net/ssl/provider/ExchangeKeys.java index 3ee79d7d0..f161f484a 100644 --- a/gnu/javax/net/ssl/provider/ExchangeKeys.java +++ b/gnu/javax/net/ssl/provider/ExchangeKeys.java @@ -39,6 +39,7 @@ exception statement from your version. */ package gnu.javax.net.ssl.provider; import java.nio.ByteBuffer; +import java.nio.ByteOrder; public abstract class ExchangeKeys implements Constructed { @@ -47,6 +48,7 @@ public abstract class ExchangeKeys implements Constructed public ExchangeKeys (final ByteBuffer buffer) { - this.buffer = buffer; + if (buffer != null) + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); } } \ No newline at end of file diff --git a/gnu/javax/net/ssl/provider/SSLContextImpl.java b/gnu/javax/net/ssl/provider/SSLContextImpl.java index 0c00ccb2a..cf7c8e4e3 100644 --- a/gnu/javax/net/ssl/provider/SSLContextImpl.java +++ b/gnu/javax/net/ssl/provider/SSLContextImpl.java @@ -174,7 +174,7 @@ public final class SSLContextImpl extends SSLContextSpi if ((keyManagers[i] instanceof X509ExtendedKeyManager) && keyManager == null) keyManager = (X509ExtendedKeyManager) keyManagers[i]; - if (keyManagers[i] instanceof PreSharedKeyManagerFactoryImpl + if (keyManagers[i] instanceof PreSharedKeyManager && pskManager == null) pskManager = (PreSharedKeyManager) keyManagers[i]; } diff --git a/gnu/javax/net/ssl/provider/SSLEngineImpl.java b/gnu/javax/net/ssl/provider/SSLEngineImpl.java index e198c3f0e..26f02e072 100644 --- a/gnu/javax/net/ssl/provider/SSLEngineImpl.java +++ b/gnu/javax/net/ssl/provider/SSLEngineImpl.java @@ -104,8 +104,6 @@ public final class SSLEngineImpl extends SSLEngine SSLEngineImpl (SSLContextImpl contextImpl, String host, int port) { super(host, port); - logger.logv(java.util.logging.Level.INFO, "creating SSLEngine {0} {1}:{2}", - this, host, port); this.contextImpl = contextImpl; handlers = new SSLRecordHandler[256]; session = new SessionImpl(); diff --git a/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java b/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java index 2cc42929c..edc3ac259 100644 --- a/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java +++ b/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java @@ -38,6 +38,9 @@ exception statement from your version. */ package gnu.javax.net.ssl.provider; +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + import java.io.PrintWriter; import java.io.StringWriter; import java.nio.ByteBuffer; @@ -78,7 +81,7 @@ public class ServerDHE_PSKParameters implements Constructed, Builder, ServerKeyE buffer = ByteBuffer.allocate(2 + hintBuf.remaining() + dhParams.remaining()); buffer.putShort((short) hintBuf.remaining()); buffer.put(hintBuf); - buffer.put(buffer); + buffer.put(dhParams); } public KeyExchangeAlgorithm algorithm() @@ -108,8 +111,8 @@ public class ServerDHE_PSKParameters implements Constructed, Builder, ServerKeyE public ServerDHParams params() { - return new ServerDHParams((ByteBuffer) buffer.duplicate().position - (hintLength()).limit(buffer.capacity())); + return new ServerDHParams(((ByteBuffer) buffer.duplicate().position + (hintLength()).limit(buffer.capacity())).slice()); } /* (non-Javadoc) diff --git a/gnu/javax/net/ssl/provider/ServerDHParams.java b/gnu/javax/net/ssl/provider/ServerDHParams.java index 38abe93bb..55d4a41da 100644 --- a/gnu/javax/net/ssl/provider/ServerDHParams.java +++ b/gnu/javax/net/ssl/provider/ServerDHParams.java @@ -42,6 +42,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.math.BigInteger; import java.nio.ByteBuffer; +import java.nio.ByteOrder; /** * The server's Diffie-Hellman parameters message. @@ -61,7 +62,7 @@ public class ServerDHParams implements Builder, ServerKeyExchangeParams public ServerDHParams (final ByteBuffer buffer) { - this.buffer = buffer; + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); } public ServerDHParams (final BigInteger p, final BigInteger g, diff --git a/gnu/javax/net/ssl/provider/ServerHandshake.java b/gnu/javax/net/ssl/provider/ServerHandshake.java index 0d77bda04..300012a4b 100644 --- a/gnu/javax/net/ssl/provider/ServerHandshake.java +++ b/gnu/javax/net/ssl/provider/ServerHandshake.java @@ -70,6 +70,8 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.logging.Level; +import java.util.zip.Deflater; +import java.util.zip.Inflater; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -140,6 +142,7 @@ class ServerHandshake extends AbstractHandshake private X509Certificate localCert = null; private boolean helloV2 = false; private KeyPair dhPair; + private PrivateKey serverKey; // Delegated tasks we use. private GenDH genDH; @@ -198,6 +201,7 @@ class ServerHandshake extends AbstractHandshake // Figure out which SignatureAlgorithms we can support. HashSet kexes = new HashSet(8); + kexes.add(NONE); X509ExtendedKeyManager km = engine.contextImpl.keyManager; if (km != null) { @@ -233,15 +237,20 @@ class ServerHandshake extends AbstractHandshake continue; if (!kexes.contains(suite.keyExchangeAlgorithm())) continue; - suites.add (suite); + suites.add(suite); } for (CipherSuite suite : clientSuites) { - if (suites.contains (suite)) - return suite.resolve(); + CipherSuite resolved = suite.resolve(); + if (!resolved.isResolved()) + continue; + if (suites.contains(resolved)) + return resolved; } - throw new AlertException (new Alert (Alert.Level.FATAL, - Alert.Description.INSUFFICIENT_SECURITY)); + + // We didn't find a match? + throw new AlertException(new Alert(Alert.Level.FATAL, + Alert.Description.INSUFFICIENT_SECURITY)); } /** @@ -496,44 +505,7 @@ class ServerHandshake extends AbstractHandshake { 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); + generatePSKSecret(params.identity(), null, false); } break; @@ -554,12 +526,6 @@ class ServerHandshake extends AbstractHandshake 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); } @@ -588,6 +554,25 @@ class ServerHandshake extends AbstractHandshake tasks.add(keyExchangeTask); } break; + + case NONE: + { + Inflater inflater = null; + Deflater deflater = null; + if (compression == CompressionMethod.ZLIB) + { + inflater = new Inflater(); + deflater = new Deflater(); + } + inParams = new InputSecurityParameters(null, null, inflater, + engine.session(), + engine.session().suite); + outParams = new OutputSecurityParameters(null, null, deflater, + engine.session(), + engine.session().suite); + engine.session().privateData.masterSecret = new byte[0]; + } + break; } // XXX SRP @@ -863,6 +848,7 @@ output_loop: outBuffer.position(outBuffer.position() + l); CipherSuite cs = engine.session().suite; + KeyExchangeAlgorithm kex = cs.keyExchangeAlgorithm(); if (continuedSession) { byte[][] keys = generateKeys(clientRandom, serverRandom, @@ -871,27 +857,24 @@ output_loop: engine.changeCipherSpec(); state = WRITE_FINISHED; } - else if (cs.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS - || cs.keyExchangeAlgorithm() == RSA_PSK) + else if (kex == DHE_DSS || kex == DHE_RSA || kex == RSA + || kex == RSA_PSK) { certLoader = new CertLoader(); tasks.add(certLoader); state = WRITE_CERTIFICATE; - if (cs.keyExchangeAlgorithm() == DHE_DSS - || cs.keyExchangeAlgorithm() == DHE_RSA) + if (kex == DHE_DSS || kex == DHE_RSA) { genDH = new GenDH(); tasks.add(genDH); - state = WRITE_SERVER_KEY_EXCHANGE; } break output_loop; } - else if (engine.session().suite.keyExchangeAlgorithm() == PSK) + else if (kex == PSK) { state = WRITE_SERVER_KEY_EXCHANGE; } - else if (cs.keyExchangeAlgorithm() == DHE_PSK - || cs.keyExchangeAlgorithm() == DH_anon) + else if (kex == DHE_PSK || kex == DH_anon) { genDH = new GenDH(); tasks.add(genDH); @@ -957,6 +940,8 @@ output_loop: state = WRITE_SERVER_KEY_EXCHANGE; break output_loop; } + else if (kexalg == RSA_PSK) + state = WRITE_SERVER_KEY_EXCHANGE; else if (engine.getWantClientAuth() || engine.getNeedClientAuth()) { state = WRITE_CERTIFICATE_REQUEST; @@ -1003,23 +988,47 @@ output_loop: paramBuffer = psk.buffer(); } } + if (kex == RSA_PSK) + { + String idHint = engine.contextImpl.pskManager.chooseIdentityHint(); + if (idHint != null) + { + ServerRSA_PSKParameters params + = new ServerRSA_PSKParameters(idHint); + paramBuffer = params.buffer(); + } + } + if (kex == PSK) + { + String idHint = engine.contextImpl.pskManager.chooseIdentityHint(); + if (idHint != null) + { + ServerPSKParameters params + = new ServerPSKParameters(idHint); + paramBuffer = params.buffer(); + } + } // XXX handle SRP - ServerKeyExchangeBuilder ske - = new ServerKeyExchangeBuilder(engine.session().suite); - ske.setParams(paramBuffer); - if (sigBuffer != null) - ske.setSignature(sigBuffer); + if (paramBuffer != null) + { + ServerKeyExchangeBuilder ske + = new ServerKeyExchangeBuilder(engine.session().suite); + ske.setParams(paramBuffer); + if (sigBuffer != null) + ske.setSignature(sigBuffer); - if (Debug.DEBUG) - logger.log(Component.SSL_HANDSHAKE, "{0}", ske); + if (Debug.DEBUG) + logger.log(Component.SSL_HANDSHAKE, "{0}", ske); - outBuffer = ske.buffer(); - int l = Math.min(fragment.remaining(), outBuffer.remaining()); - fragment.putInt((SERVER_KEY_EXCHANGE.getValue() << 24) - | (ske.length() & 0xFFFFFF)); - fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l)); - outBuffer.position(outBuffer.position() + l); + outBuffer = ske.buffer(); + int l = Math.min(fragment.remaining(), outBuffer.remaining()); + fragment.putInt((SERVER_KEY_EXCHANGE.getValue() << 24) + | (ske.length() & 0xFFFFFF)); + fragment.put((ByteBuffer) outBuffer.duplicate().limit + (outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + } if (engine.getWantClientAuth() || engine.getNeedClientAuth()) state = WRITE_CERTIFICATE_REQUEST; @@ -1162,6 +1171,9 @@ output_loop: { if (continuedSession) // No key exchange needed. return; + KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm(); + if (kex == NONE || kex == PSK || kex == RSA_PSK) // Don't need one. + return; if (keyExchangeTask == null) // An error if we never created one. throw new AlertException(new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR)); @@ -1261,6 +1273,7 @@ output_loop: X509Certificate[] chain = km.getCertificateChain(keyAlias); engine.session().setLocalCertificates(chain); localCert = chain[0]; + serverKey = km.getPrivateKey(keyAlias); if (kexalg == DH_DSS || kexalg == DH_RSA) dhPair = new KeyPair(localCert.getPublicKey(), km.getPrivateKey(keyAlias)); @@ -1318,6 +1331,7 @@ output_loop: NoSuchAlgorithmException, NoSuchPaddingException, SSLException { Cipher rsa = Cipher.getInstance("RSA"); + rsa.init(Cipher.DECRYPT_MODE, serverKey); rsa.init(Cipher.DECRYPT_MODE, localCert); preMasterSecret = rsa.doFinal(encryptedPreMasterSecret); generateMasterSecret(clientRandom, serverRandom, engine.session()); @@ -1342,6 +1356,7 @@ output_loop: NoSuchAlgorithmException, NoSuchPaddingException, SSLException { Cipher rsa = Cipher.getInstance("RSA"); + rsa.init(Cipher.DECRYPT_MODE, serverKey); rsa.init(Cipher.DECRYPT_MODE, localCert); byte[] rsaSecret = rsa.doFinal(encryptedPreMasterSecret); byte[] psSecret = psKey.getEncoded(); diff --git a/gnu/javax/net/ssl/provider/ServerKeyExchange.java b/gnu/javax/net/ssl/provider/ServerKeyExchange.java index 6c5a72000..1206ae6b2 100644 --- a/gnu/javax/net/ssl/provider/ServerKeyExchange.java +++ b/gnu/javax/net/ssl/provider/ServerKeyExchange.java @@ -82,7 +82,14 @@ public class ServerKeyExchange implements Handshake.Body { if (suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE)) return 0; - return params().length() + signature().length(); + int len = 0; + ServerKeyExchangeParams params = params(); + Signature sig = signature(); + if (params != null) + len += params.length(); + if (sig != null) + len += sig.length(); + return len; } /** -- cgit v1.2.1