diff options
author | Casey Marshall <csm@gnu.org> | 2006-07-15 00:51:02 +0000 |
---|---|---|
committer | Casey Marshall <csm@gnu.org> | 2006-07-15 00:51:02 +0000 |
commit | c5b0021ff787e0b4a2c83c0d908ac008ce45215b (patch) | |
tree | 5493f567fbbde344fd140fda0efae37c22acc5e2 | |
parent | 34f553db4913a9b7810298cadf3cf8b126688aaa (diff) | |
download | classpath-c5b0021ff787e0b4a2c83c0d908ac008ce45215b.tar.gz |
2006-07-14 Casey Marshall <csm@gnu.org>
* gnu/classpath/debug/Component.java (SSL_DELEGATED_TASK): new
constant.
* gnu/classpath/debug/SystemLogger.java (getSystemLogger): new
class method.
* gnu/javax/crypto/RSACipherImpl.java (logger): make instance of
SystemLogger.
(doFinal): use `EME_PKCS1_V1_5' to pad/unpad.
* gnu/javax/net/ssl/AbstractSessionContext.java (getSession): new
method.
* gnu/javax/net/ssl/PreSharedKeyManager.java: new file.
* gnu/javax/net/ssl/PreSharedKeyManagerParameters.java: new file.
* gnu/javax/net/ssl/provider/AbstractHandshake.java: move
delegated task classes to the end.
(handleInput): don't stop processing current input if tasks are
scheduled.
(DHE_PSKGen): new class.
* gnu/javax/net/ssl/provider/CertificateStatusRequest.java
(buffer): make non-final.
(<init>): new "builder" constructor.
(buffer): new method.
* gnu/javax/net/ssl/provider/CertificateURL.java (buffer): make
non-final.
(<init>): new "builder" constructor.
(buffer): new method.
(URLAndOptionalHash): implement Builder.
(URLAndOptionalHash.<init>): set buffer order to BIG_ENDIAN.
(URLAndOptionalHash.<init>, URLAndOptionalHash.<init>): new
"builder" constructors.
(URLAndOptionalHash.buffer): new method.
* gnu/javax/net/ssl/provider/CipherSuite.java: replace
DIFFIE_HELLMAN with qualified algorithm.
(TLS_PSK_WITH_RC4_128_SHA, TLS_PSK_WITH_3DES_EDE_CBC_SHA,
TLS_PSK_WITH_AES_128_CBC_SHA, TLS_PSK_WITH_AES_256_CBC_SHA,
TLS_DHE_PSK_WITH_RC4_128_SHA, TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
TLS_RSA_PSK_WITH_RC4_128_SHA, TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
TLS_RSA_PSK_WITH_AES_256_CBC_SHA): new constants.
* gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java: new
file.
* gnu/javax/net/ssl/provider/ClientHandshake.java
(maxFragmentLengthSent, truncatedHMacSent, sentVersion): new
fields.
(implHandleInput): handle hello extensions; handle PSK key
exchange.
(implHandleOutput): send extensions if configured; handle PSK key
exchange.
(enableExtensions, maxFragmentLength, truncatedHMac,
getPSKIdentity): new methods.
(RSAGen.implRun): use the protocol version we sent in the
generated secret, not the agreed version.
* gnu/javax/net/ssl/provider/ClientHello.java: remove unused
imports.
(disableExtensions): new field.
(length): use `disableExtensions' field.
(extensions): fix telling if there are extensions.
* gnu/javax/net/ssl/provider/ClientHelloBuilder.java
(setExtensions): fix.
(setDisableExtensions): new method.
* gnu/javax/net/ssl/provider/ClientKeyExchange.java
(exchangeKeys): handle PSK exchange.
* gnu/javax/net/ssl/provider/ClientPSKParameters.java: new file.
* gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java: new
file.
* gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java
(toString): include hexdump output.
* gnu/javax/net/ssl/provider/Extension.java: implement Builder.
(buffer): mark non-final.
(<init>): make public.
(<init>): new "builder" constructor.
(length): include length of the extension type.
(buffer): new method.
(Value): implement Builder.
* gnu/javax/net/ssl/provider/ExtensionList.java: implement
Builder.
(<init>): new "builder" constructor.
(get): fix.
(length): return total length, including length field.
* gnu/javax/net/ssl/provider/InputSecurityParameters.java
(decrypt): handle stream ciphers (with no padding) properly.
* gnu/javax/net/ssl/provider/Jessie.java (<init>): add JessiePSK
key manager factory.
* gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java
(DIFFIE_HELLMAN): removed.
(DH_DSS, DH_RSA, DH_anon, DHE_DSS, DHE_RSA, PSK, DHE_PSK,
RSA_PSK): new enum constants.
* gnu/javax/net/ssl/provider/MaxFragmentLength.java (buffer): new
method.
* gnu/javax/net/ssl/provider/OutputSecurityParameters.java
(encrypt): don't use `doFinal.'
* gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java:
new file.
* gnu/javax/net/ssl/provider/SSLContextImpl.java (pskManager): new
field.
(engineInit): initialize PSK manager, if specified.
* gnu/javax/net/ssl/provider/SSLEngineImpl.java (unwrap): debug
logging; don't log warnings on closure alerts.
* gnu/javax/net/ssl/provider/SSLSocketImpl.java
(SocketOutputStream.write): throw an exception if the handshake
threw one in another thread; clear the output buffer after writing
the record.
(doHandshake): fix this; capture exceptions thrown here, for other
threads.
* gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java: new
file.
* gnu/javax/net/ssl/provider/ServerDHParams.java (algorithm): mark
deprecated (it's difficult to support this properly).
* gnu/javax/net/ssl/provider/ServerHandshake.java
(chooseSuites): select suites based on key exchange algorithm.
(implHandleInput): handle key exchange better; handle PSK
exchange.
(implHandleOutput): likewise.
(CertLoader.implRun): just use key exchange name directly.
(RSA_PSKExchange): new class.
* gnu/javax/net/ssl/provider/ServerKeyExchange.java (params):
handle PSK exchange algorithms.
(signature): likewise.
* gnu/javax/net/ssl/provider/ServerNameList.java
(buffer): make non-final.
(<init>): new "builder" constructor.
(buffer): new method.
(ServerName.buffer): make non-final.
(ServerName.<init>): new "builder" constructor.
(ServerName.length): return total length, including type and
length fields.
(ServerName.buffer): new method.
* gnu/javax/net/ssl/provider/ServerPSKParameters.java: new file.
* gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java: new
file.
* gnu/javax/net/ssl/provider/TruncatedHMAC.java (buffer): new
method.
* gnu/javax/net/ssl/provider/TrustedAuthorities.java (<init>): set
buffer order to BIG_ENDIAN.
(buffer): new method.
* gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java
(buffer): new method.
* gnu/javax/net/ssl/provider/Util.java (wrapBuffer, wrapBuffer):
new methods.
(WrappedBuffer): new class.
* gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
(getAliases): add RSA_PSK.
42 files changed, 2524 insertions, 483 deletions
diff --git a/ChangeLog-ssl-nio b/ChangeLog-ssl-nio index f65ef0a1f..a09cda046 100644 --- a/ChangeLog-ssl-nio +++ b/ChangeLog-ssl-nio @@ -1,3 +1,148 @@ +2006-07-14 Casey Marshall <csm@gnu.org> + + * gnu/classpath/debug/Component.java (SSL_DELEGATED_TASK): new + constant. + * gnu/classpath/debug/SystemLogger.java (getSystemLogger): new + class method. + * gnu/javax/crypto/RSACipherImpl.java (logger): make instance of + SystemLogger. + (doFinal): use `EME_PKCS1_V1_5' to pad/unpad. + * gnu/javax/net/ssl/AbstractSessionContext.java (getSession): new + method. + * gnu/javax/net/ssl/PreSharedKeyManager.java: new file. + * gnu/javax/net/ssl/PreSharedKeyManagerParameters.java: new file. + * gnu/javax/net/ssl/provider/AbstractHandshake.java: move + delegated task classes to the end. + (handleInput): don't stop processing current input if tasks are + scheduled. + (DHE_PSKGen): new class. + * gnu/javax/net/ssl/provider/CertificateStatusRequest.java + (buffer): make non-final. + (<init>): new "builder" constructor. + (buffer): new method. + * gnu/javax/net/ssl/provider/CertificateURL.java (buffer): make + non-final. + (<init>): new "builder" constructor. + (buffer): new method. + (URLAndOptionalHash): implement Builder. + (URLAndOptionalHash.<init>): set buffer order to BIG_ENDIAN. + (URLAndOptionalHash.<init>, URLAndOptionalHash.<init>): new + "builder" constructors. + (URLAndOptionalHash.buffer): new method. + * gnu/javax/net/ssl/provider/CipherSuite.java: replace + DIFFIE_HELLMAN with qualified algorithm. + (TLS_PSK_WITH_RC4_128_SHA, TLS_PSK_WITH_3DES_EDE_CBC_SHA, + TLS_PSK_WITH_AES_128_CBC_SHA, TLS_PSK_WITH_AES_256_CBC_SHA, + TLS_DHE_PSK_WITH_RC4_128_SHA, TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + TLS_DHE_PSK_WITH_AES_128_CBC_SHA, + TLS_DHE_PSK_WITH_AES_256_CBC_SHA, + TLS_RSA_PSK_WITH_RC4_128_SHA, TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + TLS_RSA_PSK_WITH_AES_128_CBC_SHA, + TLS_RSA_PSK_WITH_AES_256_CBC_SHA): new constants. + * gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java: new + file. + * gnu/javax/net/ssl/provider/ClientHandshake.java + (maxFragmentLengthSent, truncatedHMacSent, sentVersion): new + fields. + (implHandleInput): handle hello extensions; handle PSK key + exchange. + (implHandleOutput): send extensions if configured; handle PSK key + exchange. + (enableExtensions, maxFragmentLength, truncatedHMac, + getPSKIdentity): new methods. + (RSAGen.implRun): use the protocol version we sent in the + generated secret, not the agreed version. + * gnu/javax/net/ssl/provider/ClientHello.java: remove unused + imports. + (disableExtensions): new field. + (length): use `disableExtensions' field. + (extensions): fix telling if there are extensions. + * gnu/javax/net/ssl/provider/ClientHelloBuilder.java + (setExtensions): fix. + (setDisableExtensions): new method. + * gnu/javax/net/ssl/provider/ClientKeyExchange.java + (exchangeKeys): handle PSK exchange. + * gnu/javax/net/ssl/provider/ClientPSKParameters.java: new file. + * gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java: new + file. + * gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java + (toString): include hexdump output. + * gnu/javax/net/ssl/provider/Extension.java: implement Builder. + (buffer): mark non-final. + (<init>): make public. + (<init>): new "builder" constructor. + (length): include length of the extension type. + (buffer): new method. + (Value): implement Builder. + * gnu/javax/net/ssl/provider/ExtensionList.java: implement + Builder. + (<init>): new "builder" constructor. + (get): fix. + (length): return total length, including length field. + * gnu/javax/net/ssl/provider/InputSecurityParameters.java + (decrypt): handle stream ciphers (with no padding) properly. + * gnu/javax/net/ssl/provider/Jessie.java (<init>): add JessiePSK + key manager factory. + * gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java + (DIFFIE_HELLMAN): removed. + (DH_DSS, DH_RSA, DH_anon, DHE_DSS, DHE_RSA, PSK, DHE_PSK, + RSA_PSK): new enum constants. + * gnu/javax/net/ssl/provider/MaxFragmentLength.java (buffer): new + method. + * gnu/javax/net/ssl/provider/OutputSecurityParameters.java + (encrypt): don't use `doFinal.' + * gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java: + new file. + * gnu/javax/net/ssl/provider/SSLContextImpl.java (pskManager): new + field. + (engineInit): initialize PSK manager, if specified. + * gnu/javax/net/ssl/provider/SSLEngineImpl.java (unwrap): debug + logging; don't log warnings on closure alerts. + * gnu/javax/net/ssl/provider/SSLSocketImpl.java + (SocketOutputStream.write): throw an exception if the handshake + threw one in another thread; clear the output buffer after writing + the record. + (doHandshake): fix this; capture exceptions thrown here, for other + threads. + * gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java: new + file. + * gnu/javax/net/ssl/provider/ServerDHParams.java (algorithm): mark + deprecated (it's difficult to support this properly). + * gnu/javax/net/ssl/provider/ServerHandshake.java + (chooseSuites): select suites based on key exchange algorithm. + (implHandleInput): handle key exchange better; handle PSK + exchange. + (implHandleOutput): likewise. + (CertLoader.implRun): just use key exchange name directly. + (RSA_PSKExchange): new class. + * gnu/javax/net/ssl/provider/ServerKeyExchange.java (params): + handle PSK exchange algorithms. + (signature): likewise. + * gnu/javax/net/ssl/provider/ServerNameList.java + (buffer): make non-final. + (<init>): new "builder" constructor. + (buffer): new method. + (ServerName.buffer): make non-final. + (ServerName.<init>): new "builder" constructor. + (ServerName.length): return total length, including type and + length fields. + (ServerName.buffer): new method. + * gnu/javax/net/ssl/provider/ServerPSKParameters.java: new file. + * gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java: new + file. + * gnu/javax/net/ssl/provider/TruncatedHMAC.java (buffer): new + method. + * gnu/javax/net/ssl/provider/TrustedAuthorities.java (<init>): set + buffer order to BIG_ENDIAN. + (buffer): new method. + * gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java + (buffer): new method. + * gnu/javax/net/ssl/provider/Util.java (wrapBuffer, wrapBuffer): + new methods. + (WrappedBuffer): new class. + * gnu/javax/net/ssl/provider/X509KeyManagerFactory.java + (getAliases): add RSA_PSK. + 2006-07-12 Casey Marshall <csm@gnu.org> * gnu/javax/security/auth/callback/CertificateCallback.java: new diff --git a/gnu/classpath/debug/Component.java b/gnu/classpath/debug/Component.java index 0cc38d709..dce257502 100644 --- a/gnu/classpath/debug/Component.java +++ b/gnu/classpath/debug/Component.java @@ -97,8 +97,13 @@ public final class Component extends Level * Trace details about the SSL key exchange. */ public static final Component SSL_KEY_EXCHANGE = new Component ("SSL KEY EXCHANGE", 2); + + /** + * Trace running of delegated tasks. + */ + public static final Component SSL_DELEGATED_TASK = new Component ("SSL DELEGATED TASK", 3); - /* Indices 3 and 4 reserved for future use by SSL components. */ + /* Index 4 reserved for future use by SSL components. */ /** * Trace the operation of cryptographic primitives. diff --git a/gnu/classpath/debug/SystemLogger.java b/gnu/classpath/debug/SystemLogger.java index f341b5d9e..5813ef2f8 100644 --- a/gnu/classpath/debug/SystemLogger.java +++ b/gnu/classpath/debug/SystemLogger.java @@ -67,6 +67,18 @@ public final class SystemLogger extends Logger } /** + * Fetch the system logger instance. The logger returned is meant for debug + * and diagnostic logging for Classpath internals. + * + * @return The system logger. + */ + public static SystemLogger getSystemLogger() + { + // XXX Check some permission here? + return SYSTEM; + } + + /** * Keep only one instance of the system logger. */ private SystemLogger() diff --git a/gnu/javax/crypto/RSACipherImpl.java b/gnu/javax/crypto/RSACipherImpl.java index 0a4c29db6..05f77213e 100644 --- a/gnu/javax/crypto/RSACipherImpl.java +++ b/gnu/javax/crypto/RSACipherImpl.java @@ -41,11 +41,11 @@ package gnu.javax.crypto; import gnu.classpath.ByteArray; import gnu.classpath.debug.Component; import gnu.classpath.debug.SystemLogger; +import gnu.java.security.sig.rsa.EME_PKCS1_V1_5; import java.math.BigInteger; import java.security.AlgorithmParameters; -import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; @@ -58,8 +58,6 @@ import java.security.interfaces.RSAPublicKey; import java.security.spec.AlgorithmParameterSpec; -import java.util.logging.Logger; - import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.CipherSpi; @@ -69,7 +67,7 @@ import javax.crypto.ShortBufferException; public class RSACipherImpl extends CipherSpi { - private static final Logger logger = SystemLogger.SYSTEM; + private static final SystemLogger logger = SystemLogger.SYSTEM; private static final byte[] EMPTY = new byte[0]; private int opmode = -1; @@ -210,37 +208,25 @@ public class RSACipherImpl extends CipherSpi 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}", - new ByteArray (dec)); - if (dec[0] != 0x02) - throw new BadPaddingException ("expected padding type 2"); - int i; - for (i = 1; i < dec.length && dec[i] != 0x00; i++); - int len = dec.length - i; - byte[] result = new byte[len]; - System.arraycopy (dec, i, result, 0, len); - pos = 0; + logger.log (Component.CRYPTO, "RSA: decryption produced\n{0}", + new ByteArray (dec)); + EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(decipherKey); + byte[] result = pkcs.decode(dec); return result; } else { offset = dataBuffer.length - pos; if (offset < 3) - throw new IllegalBlockSizeException ("input is too large to encrypt"); - byte[] dec = new byte[dataBuffer.length]; - dec[0] = 0x02; + throw new IllegalBlockSizeException("input is too large to encrypt"); + EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(encipherKey); if (random == null) - random = new SecureRandom (); - byte[] pad = new byte[offset - 2]; - random.nextBytes (pad); - for (int i = 0; i < pad.length; i++) - if (pad[i] == 0) - pad[i] = 1; - System.arraycopy (pad, 0, dec, 1, pad.length); - dec[dec.length - pos] = 0x00; - System.arraycopy (dataBuffer, 0, dec, offset, pos); - logger.log (Component.CRYPTO, "RSA: produced padded plaintext\n{0}", - new ByteArray (dec)); + random = new SecureRandom(); + byte[] em = new byte[pos]; + System.arraycopy(dataBuffer, 0, em, 0, pos); + byte[] dec = pkcs.encode(em, random); + logger.log (Component.CRYPTO, "RSA: produced padded plaintext\n{0}", + new ByteArray (dec)); BigInteger x = new BigInteger (1, dec); BigInteger y = x.modPow (encipherKey.getPublicExponent (), encipherKey.getModulus ()); diff --git a/gnu/javax/net/ssl/AbstractSessionContext.java b/gnu/javax/net/ssl/AbstractSessionContext.java index 916fec089..bdd7f274e 100644 --- a/gnu/javax/net/ssl/AbstractSessionContext.java +++ b/gnu/javax/net/ssl/AbstractSessionContext.java @@ -42,6 +42,8 @@ import gnu.java.security.Requires; import gnu.javax.net.ssl.provider.SimpleSessionContext; +import java.util.Enumeration; + import javax.net.ssl.SSLException; import javax.net.ssl.SSLPermission; import javax.net.ssl.SSLSession; @@ -182,6 +184,33 @@ public abstract class AbstractSessionContext implements SSLSessionContext return s; } + public final SSLSession getSession(String host, int port) + { + for (Enumeration e = getIds(); e.hasMoreElements(); ) + { + byte[] id = (byte[]) e.nextElement(); + SSLSession s = getSession(id); + if (s == null) // session expired. + continue; + String host2 = s.getPeerHost(); + if (host == null) + { + if (host2 != null) + continue; + } + else if (!host.equals(host2)) + continue; + int port2 = s.getPeerPort(); + if (port != port2) + continue; + + // Else, a match. + return s; + } + + return null; + } + /** * To be implemented by subclasses. Subclasses do not need to check * timeouts in this method. diff --git a/gnu/javax/net/ssl/PreSharedKeyManager.java b/gnu/javax/net/ssl/PreSharedKeyManager.java new file mode 100644 index 000000000..ba6500a27 --- /dev/null +++ b/gnu/javax/net/ssl/PreSharedKeyManager.java @@ -0,0 +1,54 @@ +/* PreSharedKeyManager.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; + +import java.security.KeyManagementException; + +import javax.crypto.SecretKey; +import javax.net.ssl.KeyManager; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public interface PreSharedKeyManager extends KeyManager +{ + SecretKey getKey(String name) throws KeyManagementException; + + String chooseIdentityHint(); +}
\ No newline at end of file diff --git a/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java b/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java new file mode 100644 index 000000000..1b1d492b1 --- /dev/null +++ b/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java @@ -0,0 +1,83 @@ +/* PreSharedKeyManagerParameters.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; + +import java.util.Iterator; +import java.util.LinkedHashMap; + +import javax.crypto.SecretKey; +import javax.net.ssl.ManagerFactoryParameters; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class PreSharedKeyManagerParameters + implements ManagerFactoryParameters +{ + private final LinkedHashMap<String, SecretKey> keys; + + public PreSharedKeyManagerParameters() + { + keys = new LinkedHashMap<String, SecretKey>(); + } + + public SecretKey getKey(String name) + { + name.getClass(); + return keys.get(name); + } + + public void putKey(String name, SecretKey key) + { + name.getClass(); + key.getClass(); + keys.put(name, key); + } + + public boolean removeKey(String name) + { + name.getClass(); + return keys.remove(name) != null; + } + + public Iterator<String> identities() + { + return keys.keySet().iterator(); + } +} diff --git a/gnu/javax/net/ssl/provider/AbstractHandshake.java b/gnu/javax/net/ssl/provider/AbstractHandshake.java index f930f2301..4b4a7972b 100644 --- a/gnu/javax/net/ssl/provider/AbstractHandshake.java +++ b/gnu/javax/net/ssl/provider/AbstractHandshake.java @@ -68,6 +68,7 @@ import javax.crypto.Cipher; import javax.crypto.KeyAgreement; import javax.crypto.Mac; import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; import javax.crypto.interfaces.DHPrivateKey; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.IvParameterSpec; @@ -210,7 +211,7 @@ public abstract class AbstractHandshake if (!pollHandshake(fragment)) return HandshakeStatus.NEED_UNWRAP; - while (hasMessage() && status == HandshakeStatus.NEED_UNWRAP) + while (hasMessage() && status != HandshakeStatus.NEED_WRAP) { int pos = handshakeOffset; status = implHandleInput(); @@ -728,118 +729,6 @@ Certificate.signature.sha_hash } } - protected class DHPhase extends DelegatedTask - { - private final DHPublicKey key; - - protected DHPhase(DHPublicKey key) - { - this.key = key; - } - - protected void implRun() throws InvalidKeyException, SSLException - { - keyAgreement.doPhase(key, true); - preMasterSecret = keyAgreement.generateSecret(); - generateMasterSecret(clientRandom, serverRandom, engine.session()); - byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session()); - setupSecurityParameters(keys, engine.getUseClientMode(), engine, compression); - } - } - - protected class CertVerifier extends DelegatedTask - { - private final boolean clientSide; - private final X509Certificate[] chain; - private boolean verified; - - protected CertVerifier(boolean clientSide, X509Certificate[] chain) - { - this.clientSide = clientSide; - this.chain = chain; - } - - boolean verified() - { - return verified; - } - - protected void implRun() - { - X509TrustManager tm = engine.contextImpl.trustManager; - if (clientSide) - { - try - { - tm.checkServerTrusted(chain, null); - verified = true; - } - catch (CertificateException ce) - { - if (Debug.DEBUG) - logger.log(Component.SSL_DELEGATED_TASK, "cert verify", ce); - // For client connections, ask the user if the certificate is OK. - CallbackHandler verify = new DefaultCallbackHandler(); - GetSecurityPropertyAction gspa - = new GetSecurityPropertyAction("jessie.certificate.handler"); - String clazz = AccessController.doPrivileged(gspa); - try - { - ClassLoader cl = - AccessController.doPrivileged(new PrivilegedExceptionAction<ClassLoader>() - { - public ClassLoader run() throws Exception - { - return ClassLoader.getSystemClassLoader(); - } - }); - verify = (CallbackHandler) cl.loadClass(clazz).newInstance(); - } - catch (Exception x) - { - // Ignore. - if (Debug.DEBUG) - logger.log(Component.SSL_DELEGATED_TASK, - "callback handler loading", x); - } - // XXX Internationalize - CertificateCallback confirm = - new CertificateCallback(chain[0], - "The server's certificate could not be verified. There is no proof " + - "that this server is who it claims to be, or that their certificate " + - "is valid. Do you wish to continue connecting? "); - - try - { - verify.handle(new Callback[] { confirm }); - verified = confirm.getSelectedIndex() == ConfirmationCallback.YES; - } - catch (Exception x) - { - if (Debug.DEBUG) - logger.log(Component.SSL_DELEGATED_TASK, - "callback handler exception", x); - verified = false; - } - } - } - else - { - try - { - tm.checkClientTrusted(chain, null); - } - catch (CertificateException ce) - { - verified = false; - } - } - - if (verified) - engine.session().setPeerVerified(true); - } - } - protected void generateMasterSecret(Random clientRandom, Random serverRandom, SessionImpl session) @@ -984,4 +873,152 @@ Certificate.signature.sha_hash throw new SSLException(nspe); } } + + protected class DHPhase extends DelegatedTask + { + private final DHPublicKey key; + + protected DHPhase(DHPublicKey key) + { + this.key = key; + } + + protected void implRun() throws InvalidKeyException, SSLException + { + keyAgreement.doPhase(key, true); + preMasterSecret = keyAgreement.generateSecret(); + generateMasterSecret(clientRandom, serverRandom, engine.session()); + byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session()); + setupSecurityParameters(keys, engine.getUseClientMode(), engine, compression); + } + } + + protected class CertVerifier extends DelegatedTask + { + private final boolean clientSide; + private final X509Certificate[] chain; + private boolean verified; + + protected CertVerifier(boolean clientSide, X509Certificate[] chain) + { + this.clientSide = clientSide; + this.chain = chain; + } + + boolean verified() + { + return verified; + } + + protected void implRun() + { + X509TrustManager tm = engine.contextImpl.trustManager; + if (clientSide) + { + try + { + tm.checkServerTrusted(chain, null); + verified = true; + } + catch (CertificateException ce) + { + if (Debug.DEBUG) + logger.log(Component.SSL_DELEGATED_TASK, "cert verify", ce); + // For client connections, ask the user if the certificate is OK. + CallbackHandler verify = new DefaultCallbackHandler(); + GetSecurityPropertyAction gspa + = new GetSecurityPropertyAction("jessie.certificate.handler"); + String clazz = AccessController.doPrivileged(gspa); + try + { + ClassLoader cl = + AccessController.doPrivileged(new PrivilegedExceptionAction<ClassLoader>() + { + public ClassLoader run() throws Exception + { + return ClassLoader.getSystemClassLoader(); + } + }); + verify = (CallbackHandler) cl.loadClass(clazz).newInstance(); + } + catch (Exception x) + { + // Ignore. + if (Debug.DEBUG) + logger.log(Component.SSL_DELEGATED_TASK, + "callback handler loading", x); + } + // XXX Internationalize + CertificateCallback confirm = + new CertificateCallback(chain[0], + "The server's certificate could not be verified. There is no proof " + + "that this server is who it claims to be, or that their certificate " + + "is valid. Do you wish to continue connecting? "); + + try + { + verify.handle(new Callback[] { confirm }); + verified = confirm.getSelectedIndex() == ConfirmationCallback.YES; + } + catch (Exception x) + { + if (Debug.DEBUG) + logger.log(Component.SSL_DELEGATED_TASK, + "callback handler exception", x); + verified = false; + } + } + } + else + { + try + { + tm.checkClientTrusted(chain, null); + } + catch (CertificateException ce) + { + verified = false; + } + } + + if (verified) + engine.session().setPeerVerified(true); + } + } + + protected class DHE_PSKGen extends DelegatedTask + { + private final DHPublicKey dhKey; + private final SecretKey psKey; + private final boolean isClient; + + protected DHE_PSKGen(DHPublicKey dhKey, SecretKey psKey, boolean isClient) + { + this.dhKey = dhKey; + this.psKey = psKey; + this.isClient = isClient; + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.DelegatedTask#implRun() + */ + @Override protected void implRun() throws Throwable + { + keyAgreement.doPhase(dhKey, true); + byte[] dhSecret = keyAgreement.generateSecret(); + byte[] psSecret = psKey.getEncoded(); + preMasterSecret = new byte[dhSecret.length + psSecret.length + 4]; + preMasterSecret[0] = (byte) (dhSecret.length >>> 8); + preMasterSecret[1] = (byte) dhSecret.length; + System.arraycopy(dhSecret, 0, preMasterSecret, 2, dhSecret.length); + preMasterSecret[dhSecret.length + 2] = (byte) (psSecret.length >>> 8); + preMasterSecret[dhSecret.length + 3] = (byte) psSecret.length; + System.arraycopy(psSecret, 0, preMasterSecret, dhSecret.length + 4, + psSecret.length); + + generateMasterSecret(clientRandom, serverRandom, engine.session()); + byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session()); + setupSecurityParameters(keys, isClient, engine, compression); + } + } }
\ No newline at end of file diff --git a/gnu/javax/net/ssl/provider/CertificateStatusRequest.java b/gnu/javax/net/ssl/provider/CertificateStatusRequest.java index 8bce9d549..059c6ec47 100644 --- a/gnu/javax/net/ssl/provider/CertificateStatusRequest.java +++ b/gnu/javax/net/ssl/provider/CertificateStatusRequest.java @@ -1,3 +1,41 @@ +/* CertificateStatusRequest.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 gnu.javax.net.ssl.provider.Extension.Value; @@ -6,6 +44,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.nio.ByteBuffer; import java.util.Iterator; +import java.util.List; import java.util.NoSuchElementException; /** @@ -31,12 +70,36 @@ opaque Extensions<0..2^16-1>;</pre> */ public class CertificateStatusRequest extends Value implements Iterable<byte[]> { - private final ByteBuffer buffer; + private ByteBuffer buffer; public CertificateStatusRequest(final ByteBuffer buffer) { this.buffer = buffer; } + + public CertificateStatusRequest(CertificateStatusType type, + List<byte[]> responderIdList, + byte[] requestExtensions) + { + if (type != CertificateStatusType.OCSP) + throw new IllegalArgumentException(); + int length = 3; + int idsLength = 0; + for (byte[] responderId : responderIdList) + { + length += 2 + responderId.length; + idsLength += 2 + responderId.length; + } + length += 2 + requestExtensions.length; + buffer = ByteBuffer.allocate(length); + buffer.put((byte) 1); + buffer.putShort((short) idsLength); + for (byte[] responderId : responderIdList) + buffer.putShort((short) responderId.length).put(responderId); + buffer.putShort((short) requestExtensions.length); + buffer.put(requestExtensions); + buffer.rewind(); + } public int length() { @@ -44,6 +107,11 @@ public class CertificateStatusRequest extends Value implements Iterable<byte[]> return l + (buffer.getShort(l) & 0xFFFF) + 2; } + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + public CertificateStatusType statusType() { int x = buffer.get(0) & 0xFF; diff --git a/gnu/javax/net/ssl/provider/CertificateURL.java b/gnu/javax/net/ssl/provider/CertificateURL.java index 107b164e2..0bc1c428b 100644 --- a/gnu/javax/net/ssl/provider/CertificateURL.java +++ b/gnu/javax/net/ssl/provider/CertificateURL.java @@ -1,3 +1,41 @@ +/* CertificateURL.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 gnu.javax.net.ssl.provider.Extension.Value; @@ -5,7 +43,11 @@ import gnu.javax.net.ssl.provider.Extension.Value; import java.io.PrintWriter; import java.io.StringWriter; import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.util.List; import java.util.NoSuchElementException; /** @@ -41,17 +83,35 @@ opaque SHA1Hash[20];</pre> */ public class CertificateURL extends Value implements Iterable<CertificateURL.URLAndOptionalHash> { - private final ByteBuffer buffer; + private ByteBuffer buffer; public CertificateURL(final ByteBuffer buffer) { this.buffer = buffer; } + public CertificateURL(CertChainType type, List<URLAndOptionalHash> urls) + { + int length = 3; + for (URLAndOptionalHash url : urls) + length += url.length(); + buffer = ByteBuffer.allocate(length); + buffer.put((byte) type.getValue()); + buffer.putShort((short) (length - 1)); + for (URLAndOptionalHash url : urls) + buffer.put(url.buffer()); + buffer.rewind(); + } + public int length() { return 3 + (buffer.getShort(1) & 0xFFFF); } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } public CertChainType type() { @@ -211,13 +271,36 @@ public class CertificateURL extends Value implements Iterable<CertificateURL.URL } } - public static class URLAndOptionalHash implements Constructed + public static class URLAndOptionalHash implements Builder, Constructed { - private final ByteBuffer buffer; + private ByteBuffer buffer; public URLAndOptionalHash (final ByteBuffer buffer) { - this.buffer = buffer; + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public URLAndOptionalHash(String url) + { + this(url, null); + } + + public URLAndOptionalHash(String url, byte[] hash) + { + if (hash != null && hash.length < 20) + throw new IllegalArgumentException(); + int length = 3 + url.length(); + if (hash != null) + length += 20; + buffer = ByteBuffer.allocate(length); + buffer.putShort((short) url.length()); + Charset cs = Charset.forName("US-ASCII"); + CharsetEncoder ascii = cs.newEncoder(); + ascii.encode(CharBuffer.wrap(url), buffer, true); + buffer.put((byte) (hash != null ? 1 : 0)); + if (hash != null) + buffer.put(hash, 0, 20); + buffer.rewind(); } public int length() @@ -226,6 +309,11 @@ public class CertificateURL extends Value implements Iterable<CertificateURL.URL + (hashPresent() ? 23 : 3)); } + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + public String url() { Charset cs = Charset.forName("ASCII"); diff --git a/gnu/javax/net/ssl/provider/CipherSuite.java b/gnu/javax/net/ssl/provider/CipherSuite.java index f3fbdcbc2..ee02e8281 100644 --- a/gnu/javax/net/ssl/provider/CipherSuite.java +++ b/gnu/javax/net/ssl/provider/CipherSuite.java @@ -124,73 +124,73 @@ public final class CipherSuite implements Constructed "TLS_RSA_WITH_3DES_EDE_CBC_SHA"); public static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite (CipherAlgorithm.DES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, - SignatureAlgorithm.DSA, + KeyExchangeAlgorithm.DH_DSS, + SignatureAlgorithm.ANONYMOUS, MacAlgorithm.SHA, 5, 0x00, 0x0B, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"); public static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = new CipherSuite (CipherAlgorithm.DES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, - SignatureAlgorithm.DSA, + KeyExchangeAlgorithm.DH_DSS, + SignatureAlgorithm.ANONYMOUS, MacAlgorithm.SHA, 8, 0x00, 0x0C, "TLS_DH_DSS_WITH_DES_CBC_SHA"); public static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = new CipherSuite (CipherAlgorithm.DESede, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, - SignatureAlgorithm.DSA, + KeyExchangeAlgorithm.DH_DSS, + SignatureAlgorithm.ANONYMOUS, MacAlgorithm.SHA, 24, 0x00, 0x0D, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"); public static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite (CipherAlgorithm.DES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, - SignatureAlgorithm.RSA, + KeyExchangeAlgorithm.DH_RSA, + SignatureAlgorithm.ANONYMOUS, MacAlgorithm.SHA, 5, 0x00, 0x0E, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"); public static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = new CipherSuite (CipherAlgorithm.DES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, - SignatureAlgorithm.RSA, + KeyExchangeAlgorithm.DH_RSA, + SignatureAlgorithm.ANONYMOUS, MacAlgorithm.SHA, 8, 0x00, 0x0F, "TLS_DH_RSA_WITH_DES_CBC_SHA"); public static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = new CipherSuite (CipherAlgorithm.DESede, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, - SignatureAlgorithm.RSA, + KeyExchangeAlgorithm.DH_RSA, + SignatureAlgorithm.ANONYMOUS, MacAlgorithm.SHA, 24, 0x00, 0x10, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"); public static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite (CipherAlgorithm.DES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + KeyExchangeAlgorithm.DHE_DSS, true, SignatureAlgorithm.DSA, MacAlgorithm.SHA, 5, 0x00, 0x11, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); public static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = new CipherSuite (CipherAlgorithm.DES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + KeyExchangeAlgorithm.DHE_DSS, true, SignatureAlgorithm.DSA, MacAlgorithm.SHA, 8, 0x00, 0x12, "TLS_DHE_DSS_WITH_DES_CBC_SHA"); public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = new CipherSuite (CipherAlgorithm.DESede, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + KeyExchangeAlgorithm.DHE_DSS, true, SignatureAlgorithm.DSA, MacAlgorithm.SHA, 24, 0x00, 0x13, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"); public static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = new CipherSuite (CipherAlgorithm.DES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + KeyExchangeAlgorithm.DHE_RSA, true, SignatureAlgorithm.RSA, MacAlgorithm.SHA, 5, 0x00, 0x14, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"); public static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = new CipherSuite (CipherAlgorithm.DES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + KeyExchangeAlgorithm.DHE_RSA, true, SignatureAlgorithm.RSA, MacAlgorithm.SHA, 8, 0x00, 0x15, "TLS_DHE_RSA_WITH_DES_CBC_SHA"); public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = new CipherSuite (CipherAlgorithm.DESede, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + KeyExchangeAlgorithm.DHE_RSA, true, SignatureAlgorithm.RSA, MacAlgorithm.SHA, 24, 0x00, 0x16, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"); @@ -204,55 +204,55 @@ public final class CipherSuite implements Constructed "TLS_RSA_WITH_AES_128_CBC_SHA"); public static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA = new CipherSuite (CipherAlgorithm.AES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, - SignatureAlgorithm.DSA, + KeyExchangeAlgorithm.DH_DSS, + SignatureAlgorithm.ANONYMOUS, MacAlgorithm.SHA, 16, 0x00, 0x30, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"); public static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA = new CipherSuite (CipherAlgorithm.AES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, - SignatureAlgorithm.RSA, + KeyExchangeAlgorithm.DH_RSA, + SignatureAlgorithm.ANONYMOUS, MacAlgorithm.SHA, 16, 0x00, 0x31, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"); public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA = new CipherSuite (CipherAlgorithm.AES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + KeyExchangeAlgorithm.DHE_DSS, true, SignatureAlgorithm.DSA, MacAlgorithm.SHA, 16, 0x00, 0x32, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"); public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA = new CipherSuite (CipherAlgorithm.AES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + KeyExchangeAlgorithm.DHE_RSA, true, SignatureAlgorithm.RSA, MacAlgorithm.SHA, 16, 0x00, 0x33, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"); public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = new CipherSuite (CipherAlgorithm.AES, KeyExchangeAlgorithm.RSA, - SignatureAlgorithm.RSA, + SignatureAlgorithm.ANONYMOUS, MacAlgorithm.SHA, 32, 0x00, 0x35, "TLS_RSA_WITH_AES_256_CBC_SHA"); public static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA = new CipherSuite (CipherAlgorithm.AES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, - SignatureAlgorithm.DSA, + KeyExchangeAlgorithm.DH_DSS, + SignatureAlgorithm.ANONYMOUS, MacAlgorithm.SHA, 32, 0x00, 0x36, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"); public static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA = new CipherSuite (CipherAlgorithm.AES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, - SignatureAlgorithm.RSA, + KeyExchangeAlgorithm.DH_RSA, + SignatureAlgorithm.ANONYMOUS, MacAlgorithm.SHA, 32, 0x00, 0x37, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"); public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA = new CipherSuite (CipherAlgorithm.AES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + KeyExchangeAlgorithm.DHE_DSS, true, SignatureAlgorithm.DSA, MacAlgorithm.SHA, 32, 0x00, 0x38, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"); public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA = new CipherSuite (CipherAlgorithm.AES, - KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + KeyExchangeAlgorithm.DHE_RSA, true, SignatureAlgorithm.RSA, MacAlgorithm.SHA, 32, 0x00, 0x39, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"); @@ -312,6 +312,82 @@ public final class CipherSuite implements Constructed SignatureAlgorithm.DSA, MacAlgorithm.SHA, 32, 0x00, 0x58, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA"); + + // Pre-shared key suites. + public static final CipherSuite TLS_PSK_WITH_RC4_128_SHA = + new CipherSuite(CipherAlgorithm.RC4, + KeyExchangeAlgorithm.PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x8A, + "TLS_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite(CipherAlgorithm.DESede, + KeyExchangeAlgorithm.PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x8B, + "TLS_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x8C, + "TLS_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x8D, + "TLS_PSK_WITH_AES_256_CBC_SHA"); + + public static final CipherSuite TLS_DHE_PSK_WITH_RC4_128_SHA = + new CipherSuite(CipherAlgorithm.RC4, + KeyExchangeAlgorithm.DHE_PSK, true, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x8E, + "TLS_DHE_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite(CipherAlgorithm.DESede, + KeyExchangeAlgorithm.DHE_PSK, true, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x8F, + "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_PSK, true, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x90, + "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_PSK, true, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x91, + "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"); + + public static final CipherSuite TLS_RSA_PSK_WITH_RC4_128_SHA = + new CipherSuite(CipherAlgorithm.RC4, + KeyExchangeAlgorithm.RSA_PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x92, + "TLS_RSA_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite(CipherAlgorithm.DESede, + KeyExchangeAlgorithm.RSA_PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x93, + "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA_PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x94, + "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA_PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x95, + "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"); // Ciphersuites from the OpenPGP extension draft. // These disappeared from a more recent draft. diff --git a/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java b/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java new file mode 100644 index 000000000..a40f77ba2 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java @@ -0,0 +1,122 @@ +/* ClientDHE_PSKParameters.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; +import java.nio.charset.Charset; + +/** + * <pre> + struct { + select (KeyExchangeAlgorithm) { + /* other cases for rsa, diffie_hellman, etc. */ + case diffie_hellman_psk: /* NEW */ + opaque psk_identity<0..2^16-1>; + ClientDiffieHellmanPublic public; + } exchange_keys; + } ClientKeyExchange;</pre> + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ClientDHE_PSKParameters extends ExchangeKeys implements Builder, Constructed +{ + public ClientDHE_PSKParameters(ByteBuffer buffer) + { + super(buffer); + } + + public ClientDHE_PSKParameters(String identity, ClientDiffieHellmanPublic dh) + { + super(null); + Charset utf8 = Charset.forName("UTF-8"); + ByteBuffer idBuf = utf8.encode(identity); + buffer = ByteBuffer.allocate(2 + idBuf.remaining() + dh.length()); + buffer.putShort((short) idBuf.remaining()); + buffer.put(idBuf); + buffer.put(dh.buffer()); + buffer.rewind(); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().rewind().limit(length()); + } + + private int identityLength() + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + + public String identity() + { + Charset utf8 = Charset.forName("UTF-8"); + return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit + (identityLength())).toString(); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#length() + */ + public int length() + { + int length = (buffer.getShort(0) & 0xFFFF) + 2; + // XXX always explicit? + length += (buffer.getShort(length) & 0xFFFF) + 2; + return length; + } + + public ClientDiffieHellmanPublic params() + { + return new ClientDiffieHellmanPublic((ByteBuffer) buffer.duplicate() + .position(identityLength()).limit(length())); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String) + */ + public String toString(String prefix) + { + // TODO Auto-generated method stub + return null; + } + +} 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. diff --git a/gnu/javax/net/ssl/provider/ClientHello.java b/gnu/javax/net/ssl/provider/ClientHello.java index 9592bb8ff..cf1635db6 100644 --- a/gnu/javax/net/ssl/provider/ClientHello.java +++ b/gnu/javax/net/ssl/provider/ClientHello.java @@ -38,25 +38,12 @@ exception statement from your version. */ package gnu.javax.net.ssl.provider; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.IOException; -import java.io.OutputStream; import java.io.PrintWriter; -import java.io.StringReader; import java.io.StringWriter; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import javax.net.ssl.SSLProtocolException; - /** * A ClientHello handshake message. * @@ -87,6 +74,7 @@ public class ClientHello implements Handshake.Body protected static final int SESSID_OFFSET2 = SESSID_OFFSET + 1; protected ByteBuffer buffer; + protected boolean disableExtensions; // Constructor. // ------------------------------------------------------------------------- @@ -94,18 +82,19 @@ public class ClientHello implements Handshake.Body public ClientHello (final ByteBuffer buffer) { this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + disableExtensions = false; } // Instance methods. // ------------------------------------------------------------------------- - public int length () + public int length() { int len = SESSID_OFFSET2 + buffer.get(SESSID_OFFSET); len += (buffer.getShort(len) & 0xFFFF) + 2; len += (buffer.get(len) & 0xFF) + 1; - if (hasExtensions()) - len += (buffer.get(len) & 0xFFFF) + 2; + if (!disableExtensions && len + 1 < buffer.capacity()) + len += (buffer.getShort(len) & 0xFFFF) + 2; return len; } @@ -164,22 +153,20 @@ public class ClientHello implements Handshake.Body public boolean hasExtensions() { int offset = getExtensionsOffset(); - if (offset + 1 > buffer.limit()) - return false; - return (buffer.getShort(offset) & 0xFFFF) == 0; + return (offset + 1 > buffer.capacity()); } public ExtensionList extensions() { int offset = getExtensionsOffset (); - if (offset >= buffer.limit()) + if (offset + 1 >= buffer.limit()) return null; int len = buffer.getShort(offset) & 0xFFFF; if (len == 0) len = buffer.limit() - offset - 2; - ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate ().position (offset) - .limit (offset + len + 2)).slice (); - return new ExtensionList (ebuf); + ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate().position(offset) + .limit(offset + len + 2)).slice (); + return new ExtensionList(ebuf); } public int extensionsLength() diff --git a/gnu/javax/net/ssl/provider/ClientHelloBuilder.java b/gnu/javax/net/ssl/provider/ClientHelloBuilder.java index e82ef48b1..81e3dd72f 100644 --- a/gnu/javax/net/ssl/provider/ClientHelloBuilder.java +++ b/gnu/javax/net/ssl/provider/ClientHelloBuilder.java @@ -115,9 +115,14 @@ public class ClientHelloBuilder extends ClientHello implements Builder public void setExtensions(ByteBuffer extensions) { - extensions = (ByteBuffer) - extensions.duplicate().limit(extensions.position() + extensionsLength()); - ((ByteBuffer) buffer.duplicate().position(getExtensionsOffset() + 2)).put(extensions); + int elen = extensions.getShort(0) & 0xFFFF; + setExtensionsLength(elen); + ((ByteBuffer) buffer.duplicate().position(getExtensionsOffset())).put(extensions); + } + + public void setDisableExtensions(boolean disableExtensions) + { + this.disableExtensions = disableExtensions; } public void ensureCapacity(final int length) diff --git a/gnu/javax/net/ssl/provider/ClientKeyExchange.java b/gnu/javax/net/ssl/provider/ClientKeyExchange.java index 439725856..cc05ff736 100644 --- a/gnu/javax/net/ssl/provider/ClientKeyExchange.java +++ b/gnu/javax/net/ssl/provider/ClientKeyExchange.java @@ -86,8 +86,16 @@ public class ClientKeyExchange implements Handshake.Body KeyExchangeAlgorithm alg = suite.keyExchangeAlgorithm(); if (alg == KeyExchangeAlgorithm.RSA) return new EncryptedPreMasterSecret(buffer, version); - else if (alg == KeyExchangeAlgorithm.DIFFIE_HELLMAN) - return new ClientDiffieHellmanPublic(buffer); + else if (alg == KeyExchangeAlgorithm.DH_anon + || alg == KeyExchangeAlgorithm.DHE_DSS + || alg == KeyExchangeAlgorithm.DHE_RSA) + return new ClientDiffieHellmanPublic(buffer.duplicate()); + else if (alg == KeyExchangeAlgorithm.DHE_PSK) + return new ClientDHE_PSKParameters(buffer.duplicate()); + 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"); } diff --git a/gnu/javax/net/ssl/provider/ClientPSKParameters.java b/gnu/javax/net/ssl/provider/ClientPSKParameters.java new file mode 100644 index 000000000..4f8a3fad9 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ClientPSKParameters.java @@ -0,0 +1,122 @@ +/* ClientPSKParameters.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.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.nio.charset.Charset; + +/** + * <pre> + struct { + select (KeyExchangeAlgorithm) { + /* other cases for rsa, diffie_hellman, etc. */ + case psk: /* NEW */ + opaque psk_identity<0..2^16-1>; + } exchange_keys; + } ClientKeyExchange;</pre> + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ClientPSKParameters extends ExchangeKeys implements Builder, Constructed +{ + public ClientPSKParameters(ByteBuffer buffer) + { + super(buffer); + } + + public ClientPSKParameters(String identity) + { + super(null); + Charset utf8 = Charset.forName("UTF-8"); + ByteBuffer idBuf = utf8.encode(CharBuffer.wrap(identity)); + buffer = ByteBuffer.allocate(idBuf.remaining() + 2); + buffer.putShort((short) idBuf.remaining()); + buffer.put(idBuf); + buffer.rewind(); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().rewind().limit(length()); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#length() + */ + public int length() + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + + public String identity() + { + Charset utf8 = Charset.forName("UTF-8"); + return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit(length())).toString(); + } + + public @Override String toString() + { + return toString(null); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String) + */ + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.print(" identity = "); + out.print(identity()); + out.println(";"); + if (prefix != null) out.print(prefix); + out.print("} ClientPSKParameters;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java b/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java new file mode 100644 index 000000000..3023ff9a2 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java @@ -0,0 +1,128 @@ +/* ClientRSA_PSKParameters.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.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.Charset; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class ClientRSA_PSKParameters extends ExchangeKeys implements Builder, Constructed +{ + private final ProtocolVersion version; + + public ClientRSA_PSKParameters(ByteBuffer buffer, ProtocolVersion version) + { + super(buffer); + this.version = version; + } + + public ClientRSA_PSKParameters(String identity, EncryptedPreMasterSecret epms, + ProtocolVersion version) + { + super(null); + Charset utf8 = Charset.forName("UTF-8"); + ByteBuffer idBuf = utf8.encode(identity); + buffer = ByteBuffer.allocate(2 + idBuf.remaining() + epms.length()); + buffer.putShort((short) idBuf.remaining()); + buffer.put(idBuf); + buffer.put(epms.buffer()); + buffer.rewind(); + this.version = version; + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().rewind().limit(length()); + } + + public String identity() + { + Charset utf8 = Charset.forName("UTF-8"); + return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit + (identityLength())).toString(); + } + + private int identityLength() + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#length() + */ + public int length() + { + return identityLength() + secret().length(); + } + + public EncryptedPreMasterSecret secret() + { + return new EncryptedPreMasterSecret + ((ByteBuffer) buffer.duplicate().position(identityLength()) + .limit(buffer.capacity()), version); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String) + */ + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.print(" identity = "); + out.print(identity()); + if (prefix != null) out.print(prefix); + out.println(" encrypted_pre_master_secret ="); + out.println(secret().toString(prefix != null ? prefix + " " : " ")); + if (prefix != null) out.print(prefix); + out.print("} ClientRSA_PSKParameters;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java b/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java index edfc6f566..85769cffc 100644 --- a/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java +++ b/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java @@ -133,16 +133,16 @@ public final class EncryptedPreMasterSecret extends ExchangeKeys implements Buil public String toString (final String prefix) { - StringWriter str = new StringWriter (); - PrintWriter out = new PrintWriter (str); - if (prefix != null) out.print (prefix); - out.println ("struct {"); - if (prefix != null) out.print (prefix); - out.print (" pre_master_secret = "); - out.print (Util.toHexString (encryptedSecret (), ':')); - out.println (';'); - if (prefix != null) out.print (prefix); - out.print ("} EncryptedPreMasterSecret;"); - return str.toString (); + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.println(" pre_master_secret = "); + out.print(Util.hexDump(encryptedSecret(), prefix != null ? prefix + " " + : " ")); + if (prefix != null) out.print(prefix); + out.print("} EncryptedPreMasterSecret;"); + return str.toString(); } }
\ No newline at end of file diff --git a/gnu/javax/net/ssl/provider/Extension.java b/gnu/javax/net/ssl/provider/Extension.java index 5442daa02..c79e58832 100644 --- a/gnu/javax/net/ssl/provider/Extension.java +++ b/gnu/javax/net/ssl/provider/Extension.java @@ -55,28 +55,44 @@ import java.nio.ByteOrder; * * @author csm@gnu.org */ -public final class Extension implements Constructed +public final class Extension implements Builder, Constructed { // Fields. // ------------------------------------------------------------------------- - private final ByteBuffer buffer; + private ByteBuffer buffer; // Constructor. // ------------------------------------------------------------------------- - Extension(final ByteBuffer buffer) + public Extension(final ByteBuffer buffer) { this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); } + + public Extension(final Type type, final Value value) + { + ByteBuffer valueBuffer = value.buffer(); + int length = 2 + 2 + valueBuffer.remaining(); + buffer = ByteBuffer.allocate(length); + buffer.putShort((short) type.getValue()); + buffer.putShort((short) valueBuffer.remaining()); + buffer.put(valueBuffer); + buffer.rewind(); + } // Instance methods. // ------------------------------------------------------------------------- public int length () { - return (buffer.getShort (2) & 0xFFFF) + 2; + return (buffer.getShort (2) & 0xFFFF) + 4; + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); } public Type type() @@ -224,7 +240,7 @@ public final class Extension implements Constructed } } - public static abstract class Value implements Constructed + public static abstract class Value implements Builder, Constructed { } } diff --git a/gnu/javax/net/ssl/provider/ExtensionList.java b/gnu/javax/net/ssl/provider/ExtensionList.java index 07c689ae8..d5aaad621 100644 --- a/gnu/javax/net/ssl/provider/ExtensionList.java +++ b/gnu/javax/net/ssl/provider/ExtensionList.java @@ -6,6 +6,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ConcurrentModificationException; import java.util.Iterator; +import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; @@ -17,7 +18,7 @@ import java.util.NoSuchElementException; * * @author csm */ -public class ExtensionList implements Iterable<Extension> +public class ExtensionList implements Builder, Iterable<Extension> { private final ByteBuffer buffer; private int modCount; @@ -27,6 +28,23 @@ public class ExtensionList implements Iterable<Extension> this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); modCount = 0; } + + public ExtensionList(List<Extension> extensions) + { + int length = 2; + for (Extension extension : extensions) + length += extension.length(); + buffer = ByteBuffer.allocate(length); + buffer.putShort((short) (length - 2)); + for (Extension extension : extensions) + buffer.put(extension.buffer()); + buffer.rewind(); + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } public Extension get (final int index) { @@ -42,7 +60,8 @@ public class ExtensionList implements Iterable<Extension> if (n < index) throw new IndexOutOfBoundsException ("no elemenet at " + index); int el = buffer.getShort (i+2) & 0xFFFF; - return new Extension (((ByteBuffer) buffer.duplicate().position(i).limit(i+el+4)).slice()); + ByteBuffer b = (ByteBuffer) buffer.duplicate().position(i).limit(i+el+4); + return new Extension(b.slice()); } /** @@ -72,7 +91,7 @@ public class ExtensionList implements Iterable<Extension> */ public int length () { - return buffer.getShort (0) & 0xFFFF; + return (buffer.getShort (0) & 0xFFFF) + 2; } /** @@ -165,31 +184,31 @@ public class ExtensionList implements Iterable<Extension> public Iterator<Extension> iterator() { - return new ExtensionsIterator (); + return new ExtensionsIterator(); } - public String toString () + public String toString() { return toString (null); } - public String toString (final String prefix) + public String toString(final String prefix) { - StringWriter str = new StringWriter (); - PrintWriter out = new PrintWriter (str); - if (prefix != null) out.print (prefix); - out.println ("ExtensionList {"); - if (prefix != null) out.print (prefix); - out.print (" length = "); - out.print (length ()); - out.println (";"); + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("ExtensionList {"); + if (prefix != null) out.print(prefix); + out.print(" length = "); + out.print(length()); + out.println(";"); String subprefix = " "; if (prefix != null) subprefix = prefix + subprefix; for (Extension e : this) - out.println (e.toString(subprefix)); - if (prefix != null) out.print (prefix); - out.println ("};"); + out.println(e.toString(subprefix)); + if (prefix != null) out.print(prefix); + out.print("};"); return str.toString(); } diff --git a/gnu/javax/net/ssl/provider/InputSecurityParameters.java b/gnu/javax/net/ssl/provider/InputSecurityParameters.java index e1f56f052..72390b59c 100644 --- a/gnu/javax/net/ssl/provider/InputSecurityParameters.java +++ b/gnu/javax/net/ssl/provider/InputSecurityParameters.java @@ -152,9 +152,11 @@ public class InputSecurityParameters fragmentLength -= maclen; int padlen = 0; + int padRemoveLen = 0; if (!suite.isStreamCipher ()) { padlen = fragment.get(record.length() - 1) & 0xFF; + padRemoveLen = padlen + 1; if (Debug.DEBUG) logger.logv(Component.SSL_RECORD_LAYER, "padlen:{0}", padlen); @@ -183,7 +185,7 @@ public class InputSecurityParameters logger.logv(Component.SSL_RECORD_LAYER, "padding bad? {0}", badPadding); if (!badPadding) - fragmentLength = fragmentLength - padlen - 1; + fragmentLength = fragmentLength - padRemoveLen; } int ivlen = 0; @@ -234,7 +236,7 @@ public class InputSecurityParameters int produced = 0; if (inflater != null) { - ByteBufferOutputStream out = new ByteBufferOutputStream(record.length()); + ByteBufferOutputStream out = new ByteBufferOutputStream(fragmentLength); byte[] inbuffer = new byte[1024]; byte[] outbuffer = new byte[1024]; boolean done = false; @@ -243,6 +245,7 @@ public class InputSecurityParameters fragment.position (cipher.getBlockSize()); else fragment.position(0); + fragment.limit(fragmentLength); while (!done) { @@ -290,7 +293,7 @@ public class InputSecurityParameters else { ByteBuffer outbuf = (ByteBuffer) - fragment.duplicate().position(0).limit(record.length() - maclen - padlen - 1); + fragment.duplicate().position(0).limit(record.length() - maclen - padRemoveLen); if (record.version().compareTo(ProtocolVersion.TLS_1_1) >= 0 && !suite.isStreamCipher()) outbuf.position(cipher.getBlockSize()); diff --git a/gnu/javax/net/ssl/provider/Jessie.java b/gnu/javax/net/ssl/provider/Jessie.java index 66f2576b3..6bd68b385 100644 --- a/gnu/javax/net/ssl/provider/Jessie.java +++ b/gnu/javax/net/ssl/provider/Jessie.java @@ -85,6 +85,7 @@ public class Jessie extends Provider put("KeyManagerFactory.JessieX509", X509KeyManagerFactory.class.getName()); put("TrustManagerFactory.JessieX509", X509TrustManagerFactory.class.getName()); + put("KeyManagerFactory.JessiePSK", PreSharedKeyManagerFactoryImpl.class.getName()); //put("TrustManagerFactory.SRP", SRPTrustManagerFactory.class.getName()); put("Mac.SSLv3HMac-MD5", SSLv3HMacMD5Impl.class.getName()); diff --git a/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java b/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java index 555df6e95..a71d3de18 100644 --- a/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java +++ b/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java @@ -45,6 +45,13 @@ public enum KeyExchangeAlgorithm { NONE, RSA, - DIFFIE_HELLMAN, - SRP; + DH_DSS, + DH_RSA, + DH_anon, + DHE_DSS, + DHE_RSA, + SRP, + PSK, + DHE_PSK, + RSA_PSK; } diff --git a/gnu/javax/net/ssl/provider/MaxFragmentLength.java b/gnu/javax/net/ssl/provider/MaxFragmentLength.java index c680b0774..eb63958b8 100644 --- a/gnu/javax/net/ssl/provider/MaxFragmentLength.java +++ b/gnu/javax/net/ssl/provider/MaxFragmentLength.java @@ -2,6 +2,8 @@ package gnu.javax.net.ssl.provider; import gnu.javax.net.ssl.provider.Extension.Value; +import java.nio.ByteBuffer; + /** * Extension value * @author csm @@ -22,12 +24,17 @@ public class MaxFragmentLength extends Value this.length = length; } + public ByteBuffer buffer() + { + return ByteBuffer.allocate(1).put(0, (byte) value); + } + public int length() { return 1; } - public int getValue () + public int getValue() { return value; } diff --git a/gnu/javax/net/ssl/provider/OutputSecurityParameters.java b/gnu/javax/net/ssl/provider/OutputSecurityParameters.java index f940ec727..728c9bad9 100644 --- a/gnu/javax/net/ssl/provider/OutputSecurityParameters.java +++ b/gnu/javax/net/ssl/provider/OutputSecurityParameters.java @@ -266,15 +266,6 @@ public class OutputSecurityParameters cipher.update(ByteBuffer.wrap(macValue), outfragment); if (pad != null) cipher.update(ByteBuffer.wrap(pad), outfragment); - try - { - cipher.doFinal(ByteBuffer.wrap(new byte[0]), outfragment); - } - catch (BadPaddingException bpe) - { - // Should never happen; we are encrypting. - throw new Error("bad padding while encrypting", bpe); - } } else { @@ -291,7 +282,7 @@ public class OutputSecurityParameters if (macValue != null) outfragment.put(macValue); } - + // Advance the output buffer's position. output.position(output.position() + outrecord.length() + 5); sequence++; diff --git a/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java b/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java new file mode 100644 index 000000000..aa1f97853 --- /dev/null +++ b/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java @@ -0,0 +1,118 @@ +/* PreSharedKeyManagerFactory.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 gnu.javax.net.ssl.PreSharedKeyManager; +import gnu.javax.net.ssl.PreSharedKeyManagerParameters; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.util.Iterator; + +import javax.crypto.SecretKey; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactorySpi; +import javax.net.ssl.ManagerFactoryParameters; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class PreSharedKeyManagerFactoryImpl + extends KeyManagerFactorySpi +{ + PreSharedKeyManagerParameters params; + + /* (non-Javadoc) + * @see javax.net.ssl.KeyManagerFactorySpi#engineGetKeyManagers() + */ + @Override protected KeyManager[] engineGetKeyManagers() + { + if (params == null) + throw new IllegalStateException("not initialized"); + return new KeyManager[] { new Manager() }; + } + + /* (non-Javadoc) + * @see javax.net.ssl.KeyManagerFactorySpi#engineInit(javax.net.ssl.ManagerFactoryParameters) + */ + @Override protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (!(params instanceof PreSharedKeyManagerParameters)) + throw new InvalidAlgorithmParameterException("only supports gnu.javax.net.ssl.PreSharedKeyManagerParameters"); + params = (PreSharedKeyManagerParameters) params; + } + + /* (non-Javadoc) + * @see javax.net.ssl.KeyManagerFactorySpi#engineInit(java.security.KeyStore, char[]) + */ + @Override protected void engineInit(KeyStore store, char[] passwd) + throws KeyStoreException, NoSuchAlgorithmException, + UnrecoverableKeyException + { + // XXX Could implement this. + } + + class Manager implements PreSharedKeyManager + { + Manager() + { + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.PreSharedKeyManager#getKey(java.lang.String) + */ + public SecretKey getKey(String name) throws KeyManagementException + { + return params.getKey(name); + } + + public String chooseIdentityHint() + { + Iterator<String> it = params.identities(); + if (it.hasNext()) + return it.next(); + return null; + } + } +} diff --git a/gnu/javax/net/ssl/provider/SSLContextImpl.java b/gnu/javax/net/ssl/provider/SSLContextImpl.java index e1a8ea252..0c00ccb2a 100644 --- a/gnu/javax/net/ssl/provider/SSLContextImpl.java +++ b/gnu/javax/net/ssl/provider/SSLContextImpl.java @@ -41,6 +41,7 @@ package gnu.javax.net.ssl.provider; import gnu.java.security.action.GetSecurityPropertyAction; import gnu.javax.net.ssl.AbstractSessionContext; import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.PreSharedKeyManager; import gnu.javax.net.ssl.SRPTrustManager; import java.security.AccessController; @@ -75,6 +76,7 @@ public final class SSLContextImpl extends SSLContextSpi AbstractSessionContext serverContext; AbstractSessionContext clientContext; + PreSharedKeyManager pskManager; X509ExtendedKeyManager keyManager; X509TrustManager trustManager; SRPTrustManager srpTrustManager; @@ -169,17 +171,16 @@ public final class SSLContextImpl extends SSLContextSpi { for (int i = 0; i < keyManagers.length; i++) { - if (keyManagers[i] instanceof X509ExtendedKeyManager) - { - keyManager = (X509ExtendedKeyManager) keyManagers[i]; - break; - } + if ((keyManagers[i] instanceof X509ExtendedKeyManager) + && keyManager == null) + keyManager = (X509ExtendedKeyManager) keyManagers[i]; + if (keyManagers[i] instanceof PreSharedKeyManagerFactoryImpl + && pskManager == null) + pskManager = (PreSharedKeyManager) keyManagers[i]; } } if (keyManager == null) - { - keyManager = defaultKeyManager(); - } + keyManager = defaultKeyManager(); if (trustManagers != null) { for (int i = 0; i < trustManagers.length; i++) @@ -187,16 +188,12 @@ public final class SSLContextImpl extends SSLContextSpi if (trustManagers[i] instanceof X509TrustManager) { if (trustManager == null) - { - trustManager = (X509TrustManager) trustManagers[i]; - } + trustManager = (X509TrustManager) trustManagers[i]; } else if (trustManagers[i] instanceof SRPTrustManager) { if (srpTrustManager == null) - { - srpTrustManager = (SRPTrustManager) trustManagers[i]; - } + srpTrustManager = (SRPTrustManager) trustManagers[i]; } } } diff --git a/gnu/javax/net/ssl/provider/SSLEngineImpl.java b/gnu/javax/net/ssl/provider/SSLEngineImpl.java index c8c55979a..e198c3f0e 100644 --- a/gnu/javax/net/ssl/provider/SSLEngineImpl.java +++ b/gnu/javax/net/ssl/provider/SSLEngineImpl.java @@ -566,38 +566,44 @@ public final class SSLEngineImpl extends SSLEngine insec = params; result = new SSLEngineResult (SSLEngineResult.Status.OK, handshakeStatus, - record.length() + 5, 0); // XXXX + record.length() + 5, 0); } } else if (type == ContentType.ALERT) { int len = 0; - if (alertBuffer.position () > 0) + if (alertBuffer.position() > 0) { - alertBuffer.put (msg.get ()); + alertBuffer.put(msg.get()); len = 1; } - len += msg.remaining () / 2; + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "processing alerts {0}", + Util.wrapBuffer(msg)); + len += msg.remaining() / 2; Alert[] alerts = new Alert[len]; int i = 0; - if (alertBuffer.position () > 0) + if (alertBuffer.position() > 0) { - alertBuffer.flip (); - alerts[0] = new Alert (alertBuffer); + alertBuffer.flip(); + alerts[0] = new Alert(alertBuffer); i++; } while (i < alerts.length) { - alerts[i++] = new Alert (msg.duplicate ()); - msg.position (msg.position () + 2); + alerts[i++] = new Alert(msg.duplicate()); + msg.position(msg.position() + 2); } + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "alerts: {0}", alerts.length); for (i = 0; i < alerts.length; i++) { - if (alerts[i].level () == Alert.Level.FATAL) - throw new AlertException (alerts[i]); - logger.log (java.util.logging.Level.WARNING, - "received alert: {0}", alerts[i]); + if (alerts[i].level() == Alert.Level.FATAL) + throw new AlertException(alerts[i], false); + if (alerts[i].description() != Alert.Description.CLOSE_NOTIFY) + logger.log(java.util.logging.Level.WARNING, + "received alert: {0}", alerts[i]); if (alerts[i].description() == Alert.Description.CLOSE_NOTIFY) inClosed = true; } diff --git a/gnu/javax/net/ssl/provider/SSLSocketImpl.java b/gnu/javax/net/ssl/provider/SSLSocketImpl.java index 284094314..0181b66d8 100644 --- a/gnu/javax/net/ssl/provider/SSLSocketImpl.java +++ b/gnu/javax/net/ssl/provider/SSLSocketImpl.java @@ -87,7 +87,11 @@ public class SSLSocketImpl extends SSLSocket { if (!initialHandshakeDone || engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) - doHandshake(); + { + doHandshake(); + if (handshakeException != null) + throw handshakeException; + } int k = 0; while (k < len) @@ -104,6 +108,7 @@ public class SSLSocketImpl extends SSLSocket buffer.flip(); out.write(buffer.array(), 0, buffer.limit()); k += result.bytesConsumed(); + buffer.clear(); } } } @@ -141,7 +146,11 @@ public class SSLSocketImpl extends SSLSocket { if (!initialHandshakeDone || engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) - doHandshake(); + { + doHandshake(); + if (handshakeException != null) + throw handshakeException; + } if (!appBuffer.hasRemaining()) { @@ -415,115 +424,125 @@ public class SSLSocketImpl extends SSLSocket else sockOut = super.getOutputStream(); - while (status != HandshakeStatus.NOT_HANDSHAKING - && status != HandshakeStatus.FINISHED) + try { - logger.logv(Component.SSL_HANDSHAKE, "socket processing state {0}", - status); - - if (inBuffer.capacity() != getSession().getPacketBufferSize()) + while (status != HandshakeStatus.NOT_HANDSHAKING + && status != HandshakeStatus.FINISHED) { - ByteBuffer b + logger.logv(Component.SSL_HANDSHAKE, "socket processing state {0}", + status); + + if (inBuffer.capacity() != getSession().getPacketBufferSize()) + { + ByteBuffer b + = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + if (inBuffer.hasRemaining()) + b.put(inBuffer).flip(); + inBuffer = b; + } + if (outBuffer.capacity() != getSession().getPacketBufferSize()) + outBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); - if (inBuffer.hasRemaining()) - b.put(inBuffer).flip(); - inBuffer = b; - } - if (outBuffer.capacity() != getSession().getPacketBufferSize()) - outBuffer - = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); - switch (status) - { - case NEED_UNWRAP: - // Read in a single SSL record. - inBuffer.clear(); - int i = sockIn.read(); - if (i == -1) - throw new EOFException(); - if ((i & 0x80) == 0x80) // SSLv2 client hello. + switch (status) + { + case NEED_UNWRAP: + // Read in a single SSL record. + inBuffer.clear(); + int i = sockIn.read(); + if (i == -1) + throw new EOFException(); + if ((i & 0x80) == 0x80) // SSLv2 client hello. + { + inBuffer.put((byte) i); + int v2len = (i & 0x7f) << 8; + i = sockIn.read(); + v2len = v2len | (i & 0xff); + inBuffer.put((byte) i); + sockIn.readFully(inBuffer.array(), 2, v2len); + inBuffer.position(0).limit(v2len + 2); + } + else + { + inBuffer.put((byte) i); + inBuffer.putInt(sockIn.readInt()); + int reclen = inBuffer.getShort(3) & 0xFFFF; + sockIn.readFully(inBuffer.array(), 5, reclen); + inBuffer.position(0).limit(reclen + 5); + } + result = engine.unwrap(inBuffer, emptyBuffer); + status = result.getHandshakeStatus(); + if (result.getStatus() != Status.OK) + throw new SSLException("unexpected SSL status " + + result.getStatus()); + break; + + case NEED_WRAP: { - inBuffer.put((byte) i); - int v2len = (i & 0x7f) << 8; - i = sockIn.read(); - v2len = v2len | (i & 0xff); - inBuffer.put((byte) i); - sockIn.readFully(inBuffer.array(), 2, v2len); - inBuffer.position(0).limit(v2len + 2); + outBuffer.clear(); + result = engine.wrap(emptyBuffer, outBuffer); + status = result.getHandshakeStatus(); + if (result.getStatus() != Status.OK) + throw new SSLException("unexpected SSL status " + + result.getStatus()); + outBuffer.flip(); + sockOut.write(outBuffer.array(), outBuffer.position(), + outBuffer.limit()); } - else + break; + + case NEED_TASK: { - inBuffer.put((byte) i); - inBuffer.putInt(sockIn.readInt()); - int reclen = inBuffer.getShort(3) & 0xFFFF; - sockIn.readFully(inBuffer.array(), 5, reclen); - inBuffer.position(0).limit(reclen + 5); + Runnable task; + while ((task = engine.getDelegatedTask()) != null) + task.run(); + status = engine.getHandshakeStatus(); } - result = engine.unwrap(inBuffer, emptyBuffer); - status = result.getHandshakeStatus(); - if (result.getStatus() != Status.OK) - throw new SSLException("unexpected SSL status " - + result.getStatus()); - break; - - case NEED_WRAP: + break; + + case FINISHED: + break; + } + } + + initialHandshakeDone = true; + + HandshakeCompletedEvent hce = new HandshakeCompletedEvent(this, getSession()); + for (HandshakeCompletedListener l : listeners) + { + try + { + l.handshakeCompleted(hce); + } + catch (ThreadDeath td) { - outBuffer.clear(); - result = engine.wrap(emptyBuffer, outBuffer); - status = result.getHandshakeStatus(); - if (result.getStatus() != Status.OK) - throw new SSLException("unexpected SSL status " - + result.getStatus()); - outBuffer.flip(); - sockOut.write(outBuffer.array(), outBuffer.position(), - outBuffer.limit()); + throw td; } - break; - - case NEED_TASK: + catch (Throwable x) { - Runnable task; - while ((task = engine.getDelegatedTask()) != null) - task.run(); - status = engine.getHandshakeStatus(); + logger.log(Component.WARNING, + "HandshakeCompletedListener threw exception", x); } - break; - - case FINISHED: - break; } - } - - initialHandshakeDone = true; - HandshakeCompletedEvent hce = new HandshakeCompletedEvent(this, getSession()); - for (HandshakeCompletedListener l : listeners) + now += System.currentTimeMillis(); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, + "handshake completed in {0}ms in thread {1}", now, + Thread.currentThread().getName()); + } + catch (SSLException ssle) { - try - { - l.handshakeCompleted(hce); - } - catch (ThreadDeath td) - { - throw td; - } - catch (Throwable x) - { - logger.log(Component.WARNING, - "HandshakeCompletedListener threw exception", x); - } + handshakeException = ssle; + throw ssle; } - - now += System.currentTimeMillis(); - if (Debug.DEBUG) - logger.logv(Component.SSL_HANDSHAKE, - "handshake completed in {0}ms in thread {1}", now, - Thread.currentThread().getName()); - - synchronized (engine) + finally { - isHandshaking = false; - engine.notifyAll(); + synchronized (engine) + { + isHandshaking = false; + engine.notifyAll(); + } } } diff --git a/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java b/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java new file mode 100644 index 000000000..2cc42929c --- /dev/null +++ b/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java @@ -0,0 +1,148 @@ +/* ServerDHE_PSKParameters.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.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.Charset; + +/** + * <pre> + struct { + select (KeyExchangeAlgorithm) { + /* other cases for rsa, diffie_hellman, etc. */ + case diffie_hellman_psk: /* NEW */ + opaque psk_identity_hint<0..2^16-1>; + ServerDHParams params; + }; + } ServerKeyExchange;</pre> + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ServerDHE_PSKParameters implements Constructed, Builder, ServerKeyExchangeParams +{ + private ByteBuffer buffer; + + public ServerDHE_PSKParameters(ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public ServerDHE_PSKParameters(String identityHint, ServerDHParams dhParams) + { + this(identityHint, dhParams.buffer()); + } + + public ServerDHE_PSKParameters(String identityHint, ByteBuffer dhParams) + { + Charset utf8 = Charset.forName("UTF-8"); + ByteBuffer hintBuf = utf8.encode(identityHint); + buffer = ByteBuffer.allocate(2 + hintBuf.remaining() + dhParams.remaining()); + buffer.putShort((short) hintBuf.remaining()); + buffer.put(hintBuf); + buffer.put(buffer); + } + + public KeyExchangeAlgorithm algorithm() + { + return KeyExchangeAlgorithm.DHE_PSK; + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#length() + */ + public int length() + { + return (buffer.getShort(0) & 0xFFFF) + 2 + params().length(); + } + + private int hintLength() + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + + public String identityHint() + { + Charset utf8 = Charset.forName("UTF-8"); + return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit + (hintLength())).toString(); + } + + public ServerDHParams params() + { + return new ServerDHParams((ByteBuffer) buffer.duplicate().position + (hintLength()).limit(buffer.capacity())); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().rewind().limit(length()); + } + + public @Override String toString() + { + return toString(null); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String) + */ + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.print(" identity_hint = "); + out.print(identityHint()); + out.println(";"); + if (prefix != null) out.print(prefix); + out.println(" params ="); + out.println(params().toString(prefix != null ? prefix + " " : " ")); + if (prefix != null) out.print(prefix); + out.print("} ServerDHE_PSKParameters;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/ServerDHParams.java b/gnu/javax/net/ssl/provider/ServerDHParams.java index c3e06a389..38abe93bb 100644 --- a/gnu/javax/net/ssl/provider/ServerDHParams.java +++ b/gnu/javax/net/ssl/provider/ServerDHParams.java @@ -103,9 +103,9 @@ public class ServerDHParams implements Builder, ServerKeyExchangeParams buffer.put(y_bytes, y_off, y_len); } - public KeyExchangeAlgorithm algorithm () + @Deprecated public KeyExchangeAlgorithm algorithm () { - return KeyExchangeAlgorithm.DIFFIE_HELLMAN; + return null; // XXX can't support this. } public int length () 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 diff --git a/gnu/javax/net/ssl/provider/ServerKeyExchange.java b/gnu/javax/net/ssl/provider/ServerKeyExchange.java index d698156d2..6c5a72000 100644 --- a/gnu/javax/net/ssl/provider/ServerKeyExchange.java +++ b/gnu/javax/net/ssl/provider/ServerKeyExchange.java @@ -94,14 +94,22 @@ public class ServerKeyExchange implements Handshake.Body public ServerKeyExchangeParams params () { KeyExchangeAlgorithm kex = suite.keyExchangeAlgorithm (); - if (kex.equals (KeyExchangeAlgorithm.RSA)) - return new ServerRSAParams (buffer.duplicate ()); - else if (kex.equals (KeyExchangeAlgorithm.DIFFIE_HELLMAN)) - return new ServerDHParams (buffer.duplicate ()); + if (kex == KeyExchangeAlgorithm.RSA) + return new ServerRSAParams(buffer.duplicate ()); + else if (kex == KeyExchangeAlgorithm.DHE_DSS + || kex == KeyExchangeAlgorithm.DHE_RSA + || kex == KeyExchangeAlgorithm.DH_anon) + return new ServerDHParams(buffer.duplicate()); // else if (kex.equals (KeyExchangeAlgorithm.SRP)) // return new ServerSRPParams (buffer.duplicate ()); - else if (kex.equals (KeyExchangeAlgorithm.NONE)) + else if (kex == KeyExchangeAlgorithm.NONE) return null; + else if (kex == KeyExchangeAlgorithm.DHE_PSK) + return new ServerDHE_PSKParameters(buffer.duplicate()); + else if (kex == KeyExchangeAlgorithm.PSK) + return new ServerPSKParameters(buffer.duplicate()); + else if (kex == KeyExchangeAlgorithm.RSA_PSK) + return new ServerPSKParameters(buffer.duplicate()); throw new IllegalArgumentException ("unsupported key exchange: " + kex); } @@ -112,10 +120,15 @@ public class ServerKeyExchange implements Handshake.Body */ public Signature signature () { - if (suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE)) + KeyExchangeAlgorithm kex = suite.keyExchangeAlgorithm(); + if (kex == KeyExchangeAlgorithm.NONE + || kex == KeyExchangeAlgorithm.DH_anon + || kex == KeyExchangeAlgorithm.DHE_PSK + || kex == KeyExchangeAlgorithm.PSK + || kex == KeyExchangeAlgorithm.RSA_PSK) return null; - ServerKeyExchangeParams params = params (); - ByteBuffer sigbuf = ((ByteBuffer) buffer.position (params.length ())).slice (); + ServerKeyExchangeParams params = params(); + ByteBuffer sigbuf = ((ByteBuffer) buffer.position(params.length ())).slice (); return new Signature (sigbuf, suite.signatureAlgorithm ()); } diff --git a/gnu/javax/net/ssl/provider/ServerNameList.java b/gnu/javax/net/ssl/provider/ServerNameList.java index f119be637..5a268f542 100644 --- a/gnu/javax/net/ssl/provider/ServerNameList.java +++ b/gnu/javax/net/ssl/provider/ServerNameList.java @@ -1,3 +1,41 @@ +/* ServerNameList.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 gnu.javax.net.ssl.provider.Extension.Value; @@ -7,7 +45,11 @@ import java.io.StringWriter; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.util.List; import java.util.NoSuchElementException; /** @@ -39,18 +81,35 @@ struct { */ public class ServerNameList extends Value implements Iterable<ServerNameList.ServerName> { - private final ByteBuffer buffer; + private ByteBuffer buffer; public ServerNameList (final ByteBuffer buffer) { this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); } + + public ServerNameList(List<ServerName> names) + { + int length = 2; + for (ServerName name : names) + length += name.length(); + buffer = ByteBuffer.allocate(length); + buffer.putShort((short) (length - 2)); + for (ServerName name : names) + buffer.put(name.buffer()); + buffer.rewind(); + } public int length() { return (buffer.getShort(0) & 0xFFFF) + 2; } + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + public int size() { int n = 0; @@ -153,16 +212,42 @@ public class ServerNameList extends Value implements Iterable<ServerNameList.Ser public static class ServerName implements Constructed { - private final ByteBuffer buffer; + private ByteBuffer buffer; public ServerName(final ByteBuffer buffer) { this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); } + public ServerName(NameType type, String name) + { + CharsetEncoder utf8 = Charset.forName("UTF-8").newEncoder(); + ByteBuffer nameBuf = null; + try + { + nameBuf = utf8.encode(CharBuffer.wrap(name)); + } + catch (CharacterCodingException cce) + { + // We don't expect this to happen; it's UTF-8. + throw new IllegalArgumentException(cce); + } + int length = 3 + nameBuf.remaining(); + buffer = ByteBuffer.allocate(length); + buffer.put((byte) type.getValue()); + buffer.putShort((short) (length - 3)); + buffer.put(nameBuf); + buffer.rewind(); + } + public int length() { - return buffer.getShort(1) & 0xFFFF; + return (buffer.getShort(1) & 0xFFFF) + 3; + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); } public NameType type() diff --git a/gnu/javax/net/ssl/provider/ServerPSKParameters.java b/gnu/javax/net/ssl/provider/ServerPSKParameters.java new file mode 100644 index 000000000..8acce6dde --- /dev/null +++ b/gnu/javax/net/ssl/provider/ServerPSKParameters.java @@ -0,0 +1,127 @@ +/* ServerPSKParameters.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.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.Charset; + +/** + * <pre> + struct { + select (KeyExchangeAlgorithm) { + /* other cases for rsa, diffie_hellman, etc. */ + case psk: /* NEW */ + opaque psk_identity_hint<0..2^16-1>; + }; + } ServerKeyExchange;</pre> + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ServerPSKParameters implements Builder, Constructed, ServerKeyExchangeParams +{ + private ByteBuffer buffer; + + public ServerPSKParameters(ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public ServerPSKParameters(String identityHint) + { + Charset utf8 = Charset.forName("UTF-8"); + ByteBuffer identityHintBuffer = utf8.encode(identityHint); + buffer = ByteBuffer.allocate(2 + identityHintBuffer.remaining()); + buffer.putShort((short) identityHintBuffer.remaining()); + buffer.put(identityHintBuffer); + buffer.rewind(); + } + + public KeyExchangeAlgorithm algorithm() + { + return KeyExchangeAlgorithm.PSK; + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().rewind().limit(length()); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#length() + */ + public int length() + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + + public String identityHint() + { + Charset utf8 = Charset.forName("UTF-8"); + return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit(length())).toString(); + } + + public @Override String toString() + { + return toString(null); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String) + */ + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.print(" identity_hint = "); + out.print(identityHint()); + out.println(";"); + if (prefix != null) out.print(prefix); + out.print("} ServerPSKParamaters;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java b/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java new file mode 100644 index 000000000..0d7b590d2 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java @@ -0,0 +1,62 @@ +/* ServerRSA_PSKParameters.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 ServerRSA_PSKParameters extends ServerPSKParameters +{ + public ServerRSA_PSKParameters(ByteBuffer buffer) + { + super(buffer); + } + + public ServerRSA_PSKParameters(String identityHint) + { + super(identityHint); + } + + public @Override KeyExchangeAlgorithm algorithm() + { + return KeyExchangeAlgorithm.RSA_PSK; + } +} diff --git a/gnu/javax/net/ssl/provider/TruncatedHMAC.java b/gnu/javax/net/ssl/provider/TruncatedHMAC.java index 147b8ed1d..0595f87a7 100644 --- a/gnu/javax/net/ssl/provider/TruncatedHMAC.java +++ b/gnu/javax/net/ssl/provider/TruncatedHMAC.java @@ -1,7 +1,47 @@ +/* TruncatedHMAC.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 gnu.javax.net.ssl.provider.Extension.Value; +import java.nio.ByteBuffer; + /** * The value type for the {@link Extension.Type#TRUNCATED_HMAC} extension. * This extension has an empty value; this class is thusly empty. @@ -16,6 +56,11 @@ public class TruncatedHMAC extends Value return 0; } + public ByteBuffer buffer() + { + return ByteBuffer.wrap(new byte[0]); + } + public String toString() { return toString(null); diff --git a/gnu/javax/net/ssl/provider/TrustedAuthorities.java b/gnu/javax/net/ssl/provider/TrustedAuthorities.java index 89cf868b8..1e4b17359 100644 --- a/gnu/javax/net/ssl/provider/TrustedAuthorities.java +++ b/gnu/javax/net/ssl/provider/TrustedAuthorities.java @@ -1,3 +1,41 @@ +/* TrustedAuthorities.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 gnu.java.security.x509.X500DistinguishedName; @@ -6,6 +44,7 @@ import gnu.javax.net.ssl.provider.Extension.Value; import java.io.PrintWriter; import java.io.StringWriter; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.Iterator; import java.util.NoSuchElementException; @@ -45,14 +84,21 @@ public class TrustedAuthorities extends Value public TrustedAuthorities(final ByteBuffer buffer) { - this.buffer = buffer; + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); } + // XXX really implement Builder. + public int length() { return 2 + (buffer.getShort(0) & 0xFFFF); } + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + public int size() { int len = buffer.getShort(0) & 0xFFFF; diff --git a/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java b/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java index 720249e85..2094daf90 100644 --- a/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java +++ b/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java @@ -1,3 +1,41 @@ +/* UnresolvedExtensionValue.jav -- + 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 gnu.javax.net.ssl.provider.Extension.Value; @@ -20,6 +58,11 @@ public class UnresolvedExtensionValue extends Value return buffer.limit(); } + public ByteBuffer buffer() + { + return value(); + } + public ByteBuffer value() { return buffer.slice(); diff --git a/gnu/javax/net/ssl/provider/Util.java b/gnu/javax/net/ssl/provider/Util.java index 0dae5a712..ba8ea7db7 100644 --- a/gnu/javax/net/ssl/provider/Util.java +++ b/gnu/javax/net/ssl/provider/Util.java @@ -71,6 +71,33 @@ public final class Util // Class methods. // ------------------------------------------------------------------------- + public static Object wrapBuffer(ByteBuffer buffer) + { + return wrapBuffer(buffer, ""); + } + + public static Object wrapBuffer(ByteBuffer buffer, String prefix) + { + return new WrappedBuffer(buffer, prefix); + } + + private static class WrappedBuffer + { + private final ByteBuffer buffer; + private final String prefix; + + WrappedBuffer(ByteBuffer buffer, String prefix) + { + this.buffer = buffer; + this.prefix = prefix; + } + + public String toString() + { + return hexDump(buffer, prefix); + } + } + /** * Convert a hexadecimal string into its byte representation. * diff --git a/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java b/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java index b82f5b71e..dc7728866 100644 --- a/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java +++ b/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java @@ -333,7 +333,8 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi if (keyType.equalsIgnoreCase("RSA") || keyType.equalsIgnoreCase("DHE_RSA") || keyType.equalsIgnoreCase("SRP_RSA") - || keyType.equalsIgnoreCase("rsa_sign")) + || keyType.equalsIgnoreCase("rsa_sign") + || keyType.equalsIgnoreCase("RSA_PSK")) { if (!(privKey instanceof RSAPrivateKey) || !(pubKey instanceof RSAPublicKey)) |