summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2013-12-17 17:34:32 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2013-12-17 17:34:32 +0700
commit33ef8acd210067b48eed37fbfb4b0c8da8921b8d (patch)
treee9b91cab27726821a4c90f923552440f039200b1
parentAdd methods for converting from BC RSAPrivateKeyStructure (diff)
downloadBouncyCastle.NET-ed25519-33ef8acd210067b48eed37fbfb4b0c8da8921b8d.tar.xz
A round of porting from Java TLS
-rw-r--r--crypto/crypto.csproj20
-rw-r--r--crypto/crypto.mdp8
-rw-r--r--crypto/src/crypto/tls/AlertDescription.cs258
-rw-r--r--crypto/src/crypto/tls/AlertLevel.cs16
-rw-r--r--crypto/src/crypto/tls/ByteQueue.cs10
-rw-r--r--crypto/src/crypto/tls/Certificate.cs228
-rw-r--r--crypto/src/crypto/tls/CertificateRequest.cs176
-rw-r--r--crypto/src/crypto/tls/ClientCertificateType.cs37
-rw-r--r--crypto/src/crypto/tls/CompressionMethod.cs32
-rw-r--r--crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs2
-rw-r--r--crypto/src/crypto/tls/DefaultTlsClient.cs322
-rw-r--r--crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs2
-rw-r--r--crypto/src/crypto/tls/HashAlgorithm.cs18
-rw-r--r--crypto/src/crypto/tls/LegacyTlsAuthentication.cs44
-rw-r--r--crypto/src/crypto/tls/PskTlsClient.cs252
-rw-r--r--crypto/src/crypto/tls/SignatureAlgorithm.cs15
-rw-r--r--crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs94
-rw-r--r--crypto/src/crypto/tls/SrpTlsClient.cs342
-rw-r--r--crypto/src/crypto/tls/TlsClient.cs6
-rw-r--r--crypto/src/crypto/tls/TlsDHKeyExchange.cs374
-rw-r--r--crypto/src/crypto/tls/TlsECDHKeyExchange.cs6
-rw-r--r--crypto/src/crypto/tls/TlsECDheKeyExchange.cs4
-rw-r--r--crypto/src/crypto/tls/TlsException.cs14
-rw-r--r--crypto/src/crypto/tls/TlsFatalAlert.cs26
-rw-r--r--crypto/src/crypto/tls/TlsProtocolHandler.cs42
-rw-r--r--crypto/src/crypto/tls/TlsPskKeyExchange.cs258
-rw-r--r--crypto/src/crypto/tls/TlsRsaKeyExchange.cs224
-rw-r--r--crypto/src/crypto/tls/TlsSrpKeyExchange.cs2
-rw-r--r--crypto/src/crypto/tls/TlsUtilities.cs112
29 files changed, 1748 insertions, 1196 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 0b81c9a6c..ac5aeb985 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -4324,6 +4324,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\HashAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\tls\ICertificateVerifyer.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4364,6 +4369,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\SignatureAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\SignatureAndHashAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\tls\SrpTlsClient.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4469,11 +4484,6 @@
                     BuildAction = "Compile"
                 />
                 <File
-                    RelPath = "src\crypto\tls\TlsException.cs"
-                    SubType = "Code"
-                    BuildAction = "Compile"
-                />
-                <File
                     RelPath = "src\crypto\tls\TlsFatalAlert.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/crypto.mdp b/crypto/crypto.mdp
index 9a8988bb8..f655dd8d3 100644
--- a/crypto/crypto.mdp
+++ b/crypto/crypto.mdp
@@ -700,7 +700,6 @@
     <File subtype="Code" buildaction="Compile" name="src/openssl/PEMUtilities.cs" />
     <File subtype="Code" buildaction="Compile" name="src/openssl/PEMWriter.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/generators/OpenSSLPBEParametersGenerator.cs" />
-    <File subtype="Code" buildaction="Compile" name="src/crypto/tls/TlsException.cs" />
     <File subtype="Code" buildaction="Compile" name="src/asn1/x509/X509ExtensionsGenerator.cs" />
     <File subtype="Code" buildaction="Compile" name="src/security/GeneratorUtilities.cs" />
     <File subtype="Code" buildaction="Compile" name="src/x509/extension/SubjectKeyIdentifierStructure.cs" />
@@ -2179,15 +2178,18 @@
     <File subtype="Code" buildaction="Compile" name="src/util/collections/UnmodifiableListProxy.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/tls/AlertDescription.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/tls/AlertLevel.cs" />
+    <File subtype="Code" buildaction="Compile" name="src/crypto/tls/CipherSuite.cs" />
+    <File subtype="Code" buildaction="Compile" name="src/crypto/tls/ClientCertificateType.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/tls/CompressionMethod.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/tls/ContentType.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/tls/ECCurveType.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/tls/ECPointFormat.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/tls/ExtensionType.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/tls/HandshakeType.cs" />
-    <File subtype="Code" buildaction="Compile" name="src/crypto/tls/ClientCertificateType.cs" />
+    <File subtype="Code" buildaction="Compile" name="src/crypto/tls/HashAlgorithm.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/tls/NamedCurve.cs" />
-    <File subtype="Code" buildaction="Compile" name="src/crypto/tls/CipherSuite.cs" />
+    <File subtype="Code" buildaction="Compile" name="src/crypto/tls/SignatureAlgorithm.cs" />
+    <File subtype="Code" buildaction="Compile" name="src/crypto/tls/SignatureAndHashAlgorithm.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/tls/TlsDheKeyExchange.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/tls/TlsDsaSigner.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/tls/TlsECDsaSigner.cs" />
diff --git a/crypto/src/crypto/tls/AlertDescription.cs b/crypto/src/crypto/tls/AlertDescription.cs
index e1229a4a3..e09da6cab 100644
--- a/crypto/src/crypto/tls/AlertDescription.cs
+++ b/crypto/src/crypto/tls/AlertDescription.cs
@@ -1,47 +1,217 @@
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 2246 7.2
-	/// </summary>
-	public enum AlertDescription : byte
-	{
-		close_notify = 0,
-		unexpected_message = 10,
-		bad_record_mac = 20,
-		decryption_failed = 21,
-		record_overflow = 22,
-		decompression_failure = 30,
-		handshake_failure = 40,
-		/* 41 is not defined, for historical reasons */
-		bad_certificate = 42,
-		unsupported_certificate = 43,
-		certificate_revoked = 44,
-		certificate_expired = 45,
-		certificate_unknown = 46,
-		illegal_parameter = 47,
-		unknown_ca = 48,
-		access_denied = 49,
-		decode_error = 50,
-		decrypt_error = 51,
-		export_restriction = 60,
-		protocol_version = 70,
-		insufficient_security = 71,
-		internal_error = 80,
-		user_canceled = 90,
-		no_renegotiation = 100,
-
-		/*
-		 *  RFC 3546
-		 */
-		unsupported_extension = 110,
-		certificate_unobtainable = 111,
-		unrecognized_name = 112,
-		bad_certificate_status_response = 113,
-		bad_certificate_hash_value = 114,
-
-		/*
-		 *  RFC 4279
-		 */
-		unknown_psk_identity = 115,
-	}
+    /// <summary>
+    /// RFC 5246 7.2
+    /// </summary>
+    public abstract class AlertDescription
+    {
+        /**
+         * This message notifies the recipient that the sender will not send any more messages on this
+         * connection. Note that as of TLS 1.1, failure to properly close a connection no longer
+         * requires that a session not be resumed. This is a change from TLS 1.0 ("The session becomes
+         * unresumable if any connection is terminated without proper close_notify messages with level
+         * equal to warning.") to conform with widespread implementation practice.
+         */
+        public const byte close_notify = 0;
+
+        /**
+         * An inappropriate message was received. This alert is always fatal and should never be
+         * observed in communication between proper implementations.
+         */
+        public const byte unexpected_message = 10;
+
+        /**
+         * This alert is returned if a record is received with an incorrect MAC. This alert also MUST be
+         * returned if an alert is sent because a TLSCiphertext decrypted in an invalid way: either it
+         * wasn't an even multiple of the block length, or its padding values, when checked, weren't
+         * correct. This message is always fatal and should never be observed in communication between
+         * proper implementations (except when messages were corrupted in the network).
+         */
+        public const byte bad_record_mac = 20;
+
+        /**
+         * This alert was used in some earlier versions of TLS, and may have permitted certain attacks
+         * against the CBC mode [CBCATT]. It MUST NOT be sent by compliant implementations.
+         */
+        public const byte decryption_failed = 21;
+
+        /**
+         * A TLSCiphertext record was received that had a length more than 2^14+2048 bytes, or a record
+         * decrypted to a TLSCompressed record with more than 2^14+1024 bytes. This message is always
+         * fatal and should never be observed in communication between proper implementations (except
+         * when messages were corrupted in the network).
+         */
+        public const byte record_overflow = 22;
+
+        /**
+         * The decompression function received improper input (e.g., data that would expand to excessive
+         * length). This message is always fatal and should never be observed in communication between
+         * proper implementations.
+         */
+        public const byte decompression_failure = 30;
+
+        /**
+         * Reception of a handshake_failure alert message indicates that the sender was unable to
+         * negotiate an acceptable set of security parameters given the options available. This is a
+         * fatal error.
+         */
+        public const byte handshake_failure = 40;
+
+        /**
+         * This alert was used in SSLv3 but not any version of TLS. It MUST NOT be sent by compliant
+         * implementations.
+         */
+        public const byte no_certificate = 41;
+
+        /**
+         * A certificate was corrupt, contained signatures that did not verify correctly, etc.
+         */
+        public const byte bad_certificate = 42;
+
+        /**
+         * A certificate was of an unsupported type.
+         */
+        public const byte unsupported_certificate = 43;
+
+        /**
+         * A certificate was revoked by its signer.
+         */
+        public const byte certificate_revoked = 44;
+
+        /**
+         * A certificate has expired or is not currently valid.
+         */
+        public const byte certificate_expired = 45;
+
+        /**
+         * Some other (unspecified) issue arose in processing the certificate, rendering it
+         * unacceptable.
+         */
+        public const byte certificate_unknown = 46;
+
+        /**
+         * A field in the handshake was out of range or inconsistent with other fields. This message is
+         * always fatal.
+         */
+        public const byte illegal_parameter = 47;
+
+        /**
+         * A valid certificate chain or partial chain was received, but the certificate was not accepted
+         * because the CA certificate could not be located or couldn't be matched with a known, trusted
+         * CA. This message is always fatal.
+         */
+        public const byte unknown_ca = 48;
+
+        /**
+         * A valid certificate was received, but when access control was applied, the sender decided not
+         * to proceed with negotiation. This message is always fatal.
+         */
+        public const byte access_denied = 49;
+
+        /**
+         * A message could not be decoded because some field was out of the specified range or the
+         * length of the message was incorrect. This message is always fatal and should never be
+         * observed in communication between proper implementations (except when messages were corrupted
+         * in the network).
+         */
+        public const byte decode_error = 50;
+
+        /**
+         * A handshake cryptographic operation failed, including being unable to correctly verify a
+         * signature or validate a Finished message. This message is always fatal.
+         */
+        public const byte decrypt_error = 51;
+
+        /**
+         * This alert was used in some earlier versions of TLS. It MUST NOT be sent by compliant
+         * implementations.
+         */
+        public const byte export_restriction = 60;
+
+        /**
+         * The protocol version the client has attempted to negotiate is recognized but not supported.
+         * (For example, old protocol versions might be avoided for security reasons.) This message is
+         * always fatal.
+         */
+        public const byte protocol_version = 70;
+
+        /**
+         * Returned instead of handshake_failure when a negotiation has failed specifically because the
+         * server requires ciphers more secure than those supported by the client. This message is
+         * always fatal.
+         */
+        public const byte insufficient_security = 71;
+
+        /**
+         * An internal error unrelated to the peer or the correctness of the protocol (such as a memory
+         * allocation failure) makes it impossible to continue. This message is always fatal.
+         */
+        public const byte internal_error = 80;
+
+        /**
+         * This handshake is being canceled for some reason unrelated to a protocol failure. If the user
+         * cancels an operation after the handshake is complete, just closing the connection by sending
+         * a close_notify is more appropriate. This alert should be followed by a close_notify. This
+         * message is generally a warning.
+         */
+        public const byte user_canceled = 90;
+
+        /**
+         * Sent by the client in response to a hello request or by the server in response to a client
+         * hello after initial handshaking. Either of these would normally lead to renegotiation; when
+         * that is not appropriate, the recipient should respond with this alert. At that point, the
+         * original requester can decide whether to proceed with the connection. One case where this
+         * would be appropriate is where a server has spawned a process to satisfy a request; the
+         * process might receive security parameters (key length, authentication, etc.) at startup, and
+         * it might be difficult to communicate changes to these parameters after that point. This
+         * message is always a warning.
+         */
+        public const byte no_renegotiation = 100;
+
+        /**
+         * Sent by clients that receive an extended server hello containing an extension that they did
+         * not put in the corresponding client hello. This message is always fatal.
+         */
+        public const byte unsupported_extension = 110;
+
+        /*
+         * RFC 3546
+         */
+
+        /**
+         * This alert is sent by servers who are unable to retrieve a certificate chain from the URL
+         * supplied by the client (see Section 3.3). This message MAY be fatal - for example if client
+         * authentication is required by the server for the handshake to continue and the server is
+         * unable to retrieve the certificate chain, it may send a fatal alert.
+         */
+        public const byte certificate_unobtainable = 111;
+
+        /**
+         * This alert is sent by servers that receive a server_name extension request, but do not
+         * recognize the server name. This message MAY be fatal.
+         */
+        public const byte unrecognized_name = 112;
+
+        /**
+         * This alert is sent by clients that receive an invalid certificate status response (see
+         * Section 3.6). This message is always fatal.
+         */
+        public const byte bad_certificate_status_response = 113;
+
+        /**
+         * This alert is sent by servers when a certificate hash does not match a client provided
+         * certificate_hash. This message is always fatal.
+         */
+        public const byte bad_certificate_hash_value = 114;
+
+        /*
+         * RFC 4279
+         */
+
+        /**
+         * If the server does not recognize the PSK identity, it MAY respond with an
+         * "unknown_psk_identity" alert message.
+         */
+        public const byte unknown_psk_identity = 115;
+    }
 }
diff --git a/crypto/src/crypto/tls/AlertLevel.cs b/crypto/src/crypto/tls/AlertLevel.cs
index afb04308b..d77251dfb 100644
--- a/crypto/src/crypto/tls/AlertLevel.cs
+++ b/crypto/src/crypto/tls/AlertLevel.cs
@@ -1,11 +1,11 @@
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 2246 7.2
-	/// </summary>
-    public enum AlertLevel : byte
-	{
-	    warning = 1,
-	    fatal = 2,
-	}
+    /// <summary>
+    /// RFC 5246 7.2
+    /// </summary>
+    public abstract class AlertLevel
+    {
+        public const byte warning = 1;
+        public const byte fatal = 2;
+    }
 }
diff --git a/crypto/src/crypto/tls/ByteQueue.cs b/crypto/src/crypto/tls/ByteQueue.cs
index c3ce91402..f9398bbaf 100644
--- a/crypto/src/crypto/tls/ByteQueue.cs
+++ b/crypto/src/crypto/tls/ByteQueue.cs
@@ -68,13 +68,13 @@ namespace Org.BouncyCastle.Crypto.Tls
             int		len,
             int		skip)
         {
-            if ((available - skip) < len)
+            if ((buf.Length - offset) < len)
             {
-                throw new TlsException("Not enough data to read");
+                throw new ArgumentException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes");
             }
-            if ((buf.Length - offset) < len)
+            if ((available - skip) < len)
             {
-                throw new TlsException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes");
+                throw new InvalidOperationException("Not enough data to read");
             }
             Array.Copy(databuf, skipped + skip, buf, offset, len);
         }
@@ -115,7 +115,7 @@ namespace Org.BouncyCastle.Crypto.Tls
         {
             if (i > available)
             {
-                throw new TlsException("Cannot remove " + i + " bytes, only got " + available);
+                throw new InvalidOperationException("Cannot remove " + i + " bytes, only got " + available);
             }
 
             /*
diff --git a/crypto/src/crypto/tls/Certificate.cs b/crypto/src/crypto/tls/Certificate.cs
index e4df041e2..95050abcd 100644
--- a/crypto/src/crypto/tls/Certificate.cs
+++ b/crypto/src/crypto/tls/Certificate.cs
@@ -8,104 +8,136 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/**
-	* A representation for a certificate chain.
-	*/
-	public class Certificate
-	{
-		public static readonly Certificate EmptyChain = new Certificate(new X509CertificateStructure[0]);
-
-		/**
-		* The certificates.
-		*/
-		internal X509CertificateStructure[] certs;
-
-		/**
-		* Parse the ServerCertificate message.
-		*
-		* @param inStr The stream where to parse from.
-		* @return A Certificate object with the certs, the server has sended.
-		* @throws IOException If something goes wrong during parsing.
-		*/
-		internal static Certificate Parse(
-			Stream inStr)
-		{
-			int left = TlsUtilities.ReadUint24(inStr);
-			if (left == 0)
-			{
-				return EmptyChain;
-			}
-			IList tmp = Platform.CreateArrayList();
-			while (left > 0)
-			{
-				int size = TlsUtilities.ReadUint24(inStr);
-				left -= 3 + size;
-				byte[] buf = new byte[size];
-				TlsUtilities.ReadFully(buf, inStr);
-				MemoryStream bis = new MemoryStream(buf, false);
-				Asn1Object o = Asn1Object.FromStream(bis);
-				tmp.Add(X509CertificateStructure.GetInstance(o));
-				if (bis.Position < bis.Length)
-				{
-					throw new ArgumentException("Sorry, there is garbage data left after the certificate");
-				}
-			}
-            X509CertificateStructure[] certs = new X509CertificateStructure[tmp.Count];
-            for (int i = 0; i < tmp.Count; ++i)
+    /**
+     * Parsing and encoding of a <i>Certificate</i> struct from RFC 4346.
+     * <p/>
+     * <pre>
+     * opaque ASN.1Cert<2^24-1>;
+     *
+     * struct {
+     *     ASN.1Cert certificate_list<0..2^24-1>;
+     * } Certificate;
+     * </pre>
+     *
+     * @see org.bouncycastle.asn1.x509.Certificate
+     */
+    public class Certificate
+    {
+        public static readonly Certificate EmptyChain = new Certificate(new X509CertificateStructure[0]);
+
+        /**
+        * The certificates.
+        */
+        protected readonly X509CertificateStructure[] mCertificateList;
+
+        public Certificate(X509CertificateStructure[] certificateList)
+        {
+            if (certificateList == null)
+                throw new ArgumentNullException("certificateList");
+
+            this.mCertificateList = certificateList;
+        }
+
+        /// <returns>An array which contains the certs, this chain contains.</returns>
+        [Obsolete("Use 'GetCertificateList' instead")]
+        public virtual X509CertificateStructure[] GetCerts()
+        {
+            return GetCertificateList();
+        }
+
+        /**
+         * @return an array of {@link org.bouncycastle.asn1.x509.Certificate} representing a certificate
+         *         chain.
+         */
+        public virtual X509CertificateStructure[] GetCertificateList()
+        {
+            return CloneCertificateList();
+        }
+
+        public virtual X509CertificateStructure GetCertificateAt(int index)
+        {
+            return mCertificateList[index];
+        }
+
+        public virtual int Length
+        {
+            get { return mCertificateList.Length; }
+        }
+
+        /**
+         * @return <code>true</code> if this certificate chain contains no certificates, or
+         *         <code>false</code> otherwise.
+         */
+        public virtual bool IsEmpty
+        {
+            get { return mCertificateList.Length == 0; }
+        }
+
+        /**
+         * Encode this {@link Certificate} to a {@link Stream}.
+         *
+         * @param output the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            IList derEncodings = Platform.CreateArrayList(mCertificateList.Length);
+
+            int totalLength = 0;
+            foreach (Asn1Encodable asn1Cert in mCertificateList)
+            {
+                byte[] derEncoding = asn1Cert.GetEncoded(Asn1Encodable.Der);
+                derEncodings.Add(derEncoding);
+                totalLength += derEncoding.Length + 3;
+            }
+
+            TlsUtilities.CheckUint24(totalLength);
+            TlsUtilities.WriteUint24(totalLength, output);
+
+            foreach (byte[] derEncoding in derEncodings)
+            {
+                TlsUtilities.WriteOpaque24(derEncoding, output);
+            }
+        }
+
+        /**
+         * Parse a {@link Certificate} from a {@link Stream}.
+         *
+         * @param input the {@link Stream} to parse from.
+         * @return a {@link Certificate} object.
+         * @throws IOException
+         */
+        public static Certificate Parse(Stream input)
+        {
+            int totalLength = TlsUtilities.ReadUint24(input);
+            if (totalLength == 0)
             {
-                certs[i] = (X509CertificateStructure)tmp[i];
+                return EmptyChain;
             }
-			return new Certificate(certs);
-		}
-
-		/**
-		 * Encodes version of the ClientCertificate message
-		 *
-		 * @param outStr stream to write the message to
-		 * @throws IOException If something goes wrong
-		 */
-		internal void Encode(
-			Stream outStr)
-		{
-			IList encCerts = Platform.CreateArrayList();
-			int totalSize = 0;
-			foreach (X509CertificateStructure cert in certs)
-			{
-				byte[] encCert = cert.GetEncoded(Asn1Encodable.Der);
-				encCerts.Add(encCert);
-				totalSize += encCert.Length + 3;
-			}
-
-			TlsUtilities.WriteUint24(totalSize, outStr);
-
-			foreach (byte[] encCert in encCerts)
-			{
-				TlsUtilities.WriteOpaque24(encCert, outStr);
-			}
-		}
-
-		/**
-		* Private constructor from a cert array.
-		*
-		* @param certs The certs the chain should contain.
-		*/
-		public Certificate(X509CertificateStructure[] certs)
-		{
-			if (certs == null)
-				throw new ArgumentNullException("certs");
-
-			this.certs = certs;
-		}
-
-		/// <returns>An array which contains the certs, this chain contains.</returns>
-		public X509CertificateStructure[] GetCerts()
-		{
-			return (X509CertificateStructure[]) certs.Clone();
-		}
-
-		public bool IsEmpty
-		{
-			get { return certs.Length == 0; }
-		}
-	}
+
+            byte[] certListData = TlsUtilities.ReadFully(totalLength, input);
+
+            MemoryStream buf = new MemoryStream(certListData, false);
+
+            IList certificate_list = Platform.CreateArrayList();
+            while (buf.Position < buf.Length)
+            {
+                byte[] derEncoding = TlsUtilities.ReadOpaque24(buf);
+                Asn1Object asn1Cert = TlsUtilities.ReadDerObject(derEncoding);
+                certificate_list.Add(X509CertificateStructure.GetInstance(asn1Cert));
+            }
+
+            X509CertificateStructure[] certificateList = new X509CertificateStructure[certificate_list.Count];
+            for (int i = 0; i < certificate_list.Count; ++i)
+            {
+                certificateList[i] = (X509CertificateStructure)certificate_list[i];
+            }
+            return new Certificate(certificateList);
+        }
+
+        protected virtual X509CertificateStructure[] CloneCertificateList()
+        {
+            return (X509CertificateStructure[])mCertificateList.Clone();
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/CertificateRequest.cs b/crypto/src/crypto/tls/CertificateRequest.cs
index 49d8ba6fb..db72a0fc1 100644
--- a/crypto/src/crypto/tls/CertificateRequest.cs
+++ b/crypto/src/crypto/tls/CertificateRequest.cs
@@ -1,28 +1,158 @@
 using System;
 using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public class CertificateRequest
-	{
-		private ClientCertificateType[] certificateTypes;
-		private IList certificateAuthorities;
-
-		public CertificateRequest(ClientCertificateType[] certificateTypes, IList certificateAuthorities)
-		{
-			this.certificateTypes = certificateTypes;
-			this.certificateAuthorities = certificateAuthorities;
-		}
-
-		public ClientCertificateType[] CertificateTypes
-		{
-			get { return certificateTypes; }
-		}
-
-		/// <returns>A <see cref="IList"/> of X509Name</returns>
-		public IList CertificateAuthorities
-		{
-			get { return certificateAuthorities; }
-		}
-	}
-}
\ No newline at end of file
+    /**
+     * Parsing and encoding of a <i>CertificateRequest</i> struct from RFC 4346.
+     * <p/>
+     * <pre>
+     * struct {
+     *     ClientCertificateType certificate_types<1..2^8-1>;
+     *     DistinguishedName certificate_authorities<3..2^16-1>;
+     * } CertificateRequest;
+     * </pre>
+     *
+     * @see ClientCertificateType
+     * @see X509Name
+     */
+    public class CertificateRequest
+    {
+        protected readonly byte[] mCertificateTypes;
+        protected readonly IList mSupportedSignatureAlgorithms;
+        protected readonly IList mCertificateAuthorities;
+
+        /**
+         * @param certificateTypes       see {@link ClientCertificateType} for valid constants.
+         * @param certificateAuthorities an {@link IList} of {@link X509Name}.
+         */
+        public CertificateRequest(byte[] certificateTypes, IList supportedSignatureAlgorithms,
+            IList certificateAuthorities)
+        {
+            this.mCertificateTypes = certificateTypes;
+            this.mSupportedSignatureAlgorithms = supportedSignatureAlgorithms;
+            this.mCertificateAuthorities = certificateAuthorities;
+        }
+
+        /**
+         * @return an array of certificate types
+         * @see {@link ClientCertificateType}
+         */
+        public virtual byte[] CertificateTypes
+        {
+            get { return mCertificateTypes; }
+        }
+
+        /**
+         * @return an {@link IList} of {@link SignatureAndHashAlgorithm} (or null before TLS 1.2).
+         */
+        public virtual IList SupportedSignatureAlgorithms
+        {
+            get { return mSupportedSignatureAlgorithms; }
+        }
+
+        /**
+         * @return an {@link IList} of {@link X509Name}
+         */
+        public virtual IList CertificateAuthorities
+        {
+            get { return mCertificateAuthorities; }
+        }
+
+        /**
+         * Encode this {@link CertificateRequest} to a {@link Stream}.
+         *
+         * @param output the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            if (mCertificateTypes == null || mCertificateTypes.Length == 0)
+            {
+                TlsUtilities.WriteUint8(0, output);
+            }
+            else
+            {
+                TlsUtilities.WriteUint8ArrayWithUint8Length(mCertificateTypes, output);
+            }
+
+            if (mSupportedSignatureAlgorithms != null)
+            {
+                // TODO Check whether SignatureAlgorithm.anonymous is allowed here
+                TlsUtilities.EncodeSupportedSignatureAlgorithms(mSupportedSignatureAlgorithms, false, output);
+            }
+
+            if (mCertificateAuthorities == null || mCertificateAuthorities.Count < 1)
+            {
+                TlsUtilities.WriteUint16(0, output);
+            }
+            else
+            {
+                IList derEncodings = Platform.CreateArrayList(mCertificateAuthorities.Count);
+
+                int totalLength = 0;
+                foreach (Asn1Encodable certificateAuthority in mCertificateAuthorities)
+                {
+                    byte[] derEncoding = certificateAuthority.GetEncoded(Asn1Encodable.Der);
+                    derEncodings.Add(derEncoding);
+                    totalLength += derEncoding.Length;
+                }
+
+                TlsUtilities.CheckUint16(totalLength);
+                TlsUtilities.WriteUint16(totalLength, output);
+
+                foreach (byte[] derEncoding in derEncodings)
+                {
+                    output.Write(derEncoding, 0, derEncoding.Length);
+                }
+            }
+        }
+
+        /**
+         * Parse a {@link CertificateRequest} from a {@link Stream}.
+         * 
+         * @param context
+         *            the {@link TlsContext} of the current connection.
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link CertificateRequest} object.
+         * @throws IOException
+         */
+        public static CertificateRequest Parse(//TlsContext context,
+            Stream input)
+        {
+            int numTypes = TlsUtilities.ReadUint8(input);
+            byte[] certificateTypes = new byte[numTypes];
+            for (int i = 0; i < numTypes; ++i)
+            {
+                certificateTypes[i] = TlsUtilities.ReadUint8(input);
+            }
+
+            // TODO Add TLS 1.2 support here
+            IList supportedSignatureAlgorithms = null;
+            //if (TlsUtilities.IsTLSv12(context))
+            //{
+            //    // TODO Check whether SignatureAlgorithm.anonymous is allowed here
+            //    supportedSignatureAlgorithms = TlsUtilities.ParseSupportedSignatureAlgorithms(false, input);
+            //}
+
+            IList certificateAuthorities = Platform.CreateArrayList();
+            byte[] certAuthData = TlsUtilities.ReadOpaque16(input);
+            MemoryStream bis = new MemoryStream(certAuthData, false);
+            while (bis.Position < bis.Length)
+            {
+                byte[] derEncoding = TlsUtilities.ReadOpaque16(bis);
+                Asn1Object asn1 = TlsUtilities.ReadDerObject(derEncoding);
+                // TODO Switch to X500Name when available
+                certificateAuthorities.Add(X509Name.GetInstance(asn1));
+            }
+
+            return new CertificateRequest(certificateTypes, supportedSignatureAlgorithms, certificateAuthorities);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/ClientCertificateType.cs b/crypto/src/crypto/tls/ClientCertificateType.cs
index 58f5d4276..a291a46e6 100644
--- a/crypto/src/crypto/tls/ClientCertificateType.cs
+++ b/crypto/src/crypto/tls/ClientCertificateType.cs
@@ -1,20 +1,23 @@
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 2246 7.4.4
-	/// </summary>
-    public enum ClientCertificateType : byte
-	{
-		rsa_sign = 1,
-		dss_sign = 2,
-		rsa_fixed_dh = 3,
-		dss_fixed_dh = 4,
+    public abstract class ClientCertificateType
+    {
+        /*
+         *  RFC 4346 7.4.4
+         */
+        public const byte rsa_sign = 1;
+        public const byte dss_sign = 2;
+        public const byte rsa_fixed_dh = 3;
+        public const byte dss_fixed_dh = 4;
+        public const byte rsa_ephemeral_dh_RESERVED = 5;
+        public const byte dss_ephemeral_dh_RESERVED = 6;
+        public const byte fortezza_dms_RESERVED = 20;
 
-		/*
-		 * RFC 4492 5.5
-		 */
-		ecdsa_sign = 64,
-		rsa_fixed_ecdh = 65,
-		ecdsa_fixed_ecdh = 66,
-	}
-}
\ No newline at end of file
+        /*
+        * RFC 4492 5.5
+        */
+        public const byte ecdsa_sign = 64;
+        public const byte rsa_fixed_ecdh = 65;
+        public const byte ecdsa_fixed_ecdh = 66;
+    }
+}
diff --git a/crypto/src/crypto/tls/CompressionMethod.cs b/crypto/src/crypto/tls/CompressionMethod.cs
index 4a127a63e..e4ee9666f 100644
--- a/crypto/src/crypto/tls/CompressionMethod.cs
+++ b/crypto/src/crypto/tls/CompressionMethod.cs
@@ -1,20 +1,22 @@
+using System;
+
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 2246 6.1
-	/// </summary>
-    public enum CompressionMethod : byte
-	{
-		NULL = 0,
+    /// <summary>
+    /// RFC 2246 6.1
+    /// </summary>
+    public abstract class CompressionMethod
+    {
+        public const byte NULL = 0;
 
-		/*
-		 * RFC 3749 2
-		 */
-		DEFLATE = 1
+        /*
+         * RFC 3749 2
+         */
+        public const byte DEFLATE = 1;
 
-		/*
-		 * Values from 224 decimal (0xE0) through 255 decimal (0xFF)
-		 * inclusive are reserved for private use.
-		 */
-	}
+        /*
+         * Values from 224 decimal (0xE0) through 255 decimal (0xFF)
+         * inclusive are reserved for private use.
+         */
+    }
 }
diff --git a/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs b/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
index 130f4c589..2bd2f40bf 100644
--- a/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
+++ b/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
@@ -22,7 +22,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             {
                 throw new ArgumentNullException("clientCertificate");
             }
-            if (clientCertificate.certs.Length == 0)
+            if (clientCertificate.Length == 0)
             {
                 throw new ArgumentException("cannot be empty", "clientCertificate");
             }
diff --git a/crypto/src/crypto/tls/DefaultTlsClient.cs b/crypto/src/crypto/tls/DefaultTlsClient.cs
index 9f30a33f4..2e850e350 100644
--- a/crypto/src/crypto/tls/DefaultTlsClient.cs
+++ b/crypto/src/crypto/tls/DefaultTlsClient.cs
@@ -11,125 +11,125 @@ using Org.BouncyCastle.Crypto.Parameters;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public abstract class DefaultTlsClient
-		: TlsClient
-	{
-		protected TlsCipherFactory cipherFactory;
+    public abstract class DefaultTlsClient
+        : TlsClient
+    {
+        protected TlsCipherFactory cipherFactory;
 
-		protected TlsClientContext context;
+        protected TlsClientContext context;
 
-        protected CompressionMethod selectedCompressionMethod;
+        protected byte selectedCompressionMethod;
         protected CipherSuite selectedCipherSuite;
 
-		public DefaultTlsClient()
-			: this(new DefaultTlsCipherFactory())
-		{
-		}
+        public DefaultTlsClient()
+            : this(new DefaultTlsCipherFactory())
+        {
+        }
 
-		public DefaultTlsClient(TlsCipherFactory cipherFactory)
-		{
-			this.cipherFactory = cipherFactory;
-		}
+        public DefaultTlsClient(TlsCipherFactory cipherFactory)
+        {
+            this.cipherFactory = cipherFactory;
+        }
 
-		public virtual void Init(TlsClientContext context)
-		{
-			this.context = context;
-		}
+        public virtual void Init(TlsClientContext context)
+        {
+            this.context = context;
+        }
 
         public virtual CipherSuite[] GetCipherSuites()
-		{
-			return new CipherSuite[] {
-				CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+        {
+            return new CipherSuite[] {
+                CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+                CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+                CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+                CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+                CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+                CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+                CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
+                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
+                CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
                 CipherSuite.TLS_RSA_WITH_RC4_128_SHA,
-			};
-		}
+            };
+        }
 
-        public virtual CompressionMethod[] GetCompressionMethods()
+        public virtual byte[] GetCompressionMethods()
         {
-			/*
-			 * To offer DEFLATE compression, override this method:
-			 *     return new CompressionMethod[] { CompressionMethod.DEFLATE, CompressionMethod.NULL };
-			 */
+            /*
+             * To offer DEFLATE compression, override this method:
+             *     return new byte[] { CompressionMethod.DEFLATE, CompressionMethod.NULL };
+             */
 
-            return new CompressionMethod[] { CompressionMethod.NULL };
+            return new byte[] { CompressionMethod.NULL };
         }
 
         public virtual IDictionary GetClientExtensions()
-		{
-			return null;
-		}
+        {
+            return null;
+        }
 
         public virtual void NotifySessionID(byte[] sessionID)
-		{
-			// Currently ignored
-		}
+        {
+            // Currently ignored
+        }
 
         public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite)
-		{
-			this.selectedCipherSuite = selectedCipherSuite;
-		}
+        {
+            this.selectedCipherSuite = selectedCipherSuite;
+        }
 
-        public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod)
+        public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod)
         {
             this.selectedCompressionMethod = selectedCompressionMethod;
         }
 
         public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
-		{
-			if (!secureRenegotiation)
-			{
-				/*
-				 * RFC 5746 3.4.
-				 * If the extension is not present, the server does not support
-				 * secure renegotiation; set secure_renegotiation flag to FALSE.
-				 * In this case, some clients may want to terminate the handshake
-				 * instead of continuing; see Section 4.1 for discussion.
-				 */
+        {
+            if (!secureRenegotiation)
+            {
+                /*
+                 * RFC 5746 3.4.
+                 * If the extension is not present, the server does not support
+                 * secure renegotiation; set secure_renegotiation flag to FALSE.
+                 * In this case, some clients may want to terminate the handshake
+                 * instead of continuing; see Section 4.1 for discussion.
+                 */
 //				throw new TlsFatalAlert(AlertDescription.handshake_failure);
-			}
-		}
+            }
+        }
 
         public virtual void ProcessServerExtensions(IDictionary serverExtensions)
-		{
-		}
+        {
+        }
 
         public virtual TlsKeyExchange GetKeyExchange()
-		{
-			switch (selectedCipherSuite)
-			{
-				case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+        {
+            switch (selectedCipherSuite)
+            {
+                case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
                 case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
-					return CreateRsaKeyExchange();
+                    return CreateRsaKeyExchange();
 
-				case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
-					return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_DSS);
+                case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+                    return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_DSS);
 
-				case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
-					return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_RSA);
+                case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+                    return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_RSA);
 
-				case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
-					return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_DSS);
+                case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+                    return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_DSS);
 
-				case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
-					return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_RSA);
+                case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+                    return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_RSA);
 
                 case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
                 case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
@@ -155,54 +155,54 @@ namespace Org.BouncyCastle.Crypto.Tls
                 case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
                     return CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_RSA);
 
-				default:
-					/*
-					* Note: internal error here; the TlsProtocolHandler verifies that the
-					* server-selected cipher suite was in the list of client-offered cipher
-					* suites, so if we now can't produce an implementation, we shouldn't have
-					* offered it!
-					*/
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		public abstract TlsAuthentication GetAuthentication();
-
-		public virtual TlsCompression GetCompression()
-		{
-			switch (selectedCompressionMethod)
-			{
-				case CompressionMethod.NULL:
-					return new TlsNullCompression();
-
-				case CompressionMethod.DEFLATE:
-					return new TlsDeflateCompression();
-
-				default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected compression method was in the list of client-offered compression
-					 * methods, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		public virtual TlsCipher GetCipher()
-		{
-			switch (selectedCipherSuite)
-			{
-				case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+                default:
+                    /*
+                    * Note: internal error here; the TlsProtocolHandler verifies that the
+                    * server-selected cipher suite was in the list of client-offered cipher
+                    * suites, so if we now can't produce an implementation, we shouldn't have
+                    * offered it!
+                    */
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public abstract TlsAuthentication GetAuthentication();
+
+        public virtual TlsCompression GetCompression()
+        {
+            switch (selectedCompressionMethod)
+            {
+                case CompressionMethod.NULL:
+                    return new TlsNullCompression();
+
+                case CompressionMethod.DEFLATE:
+                    return new TlsDeflateCompression();
+
+                default:
+                    /*
+                     * Note: internal error here; the TlsProtocolHandler verifies that the
+                     * server-selected compression method was in the list of client-offered compression
+                     * methods, so if we now can't produce an implementation, we shouldn't have
+                     * offered it!
+                     */
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public virtual TlsCipher GetCipher()
+        {
+            switch (selectedCipherSuite)
+            {
+                case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
                 case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
                 case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
                 case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
                 case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA);
+                    return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA);
 
                 case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
                 case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
@@ -212,47 +212,47 @@ namespace Org.BouncyCastle.Crypto.Tls
                     return cipherFactory.CreateCipher(context, EncryptionAlgorithm.RC4_128, DigestAlgorithm.SHA);
 
                 case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
                 case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
                 case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
                 case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
                 case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA);
+                    return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA);
 
-				case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+                case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+                case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+                case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+                case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+                case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
                 case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
                 case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
                 case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
                 case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA);
-
-				default:
-					/*
-					* Note: internal error here; the TlsProtocolHandler verifies that the
-					* server-selected cipher suite was in the list of client-offered cipher
-					* suites, so if we now can't produce an implementation, we shouldn't have
-					* offered it!
-					*/
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		protected virtual TlsKeyExchange CreateDHKeyExchange(KeyExchangeAlgorithm keyExchange)
-		{
-			return new TlsDHKeyExchange(context, keyExchange);
-		}
+                    return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA);
+
+                default:
+                    /*
+                    * Note: internal error here; the TlsProtocolHandler verifies that the
+                    * server-selected cipher suite was in the list of client-offered cipher
+                    * suites, so if we now can't produce an implementation, we shouldn't have
+                    * offered it!
+                    */
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        protected virtual TlsKeyExchange CreateDHKeyExchange(KeyExchangeAlgorithm keyExchange)
+        {
+            return new TlsDHKeyExchange(context, keyExchange);
+        }
 
         protected virtual TlsKeyExchange CreateDheKeyExchange(KeyExchangeAlgorithm keyExchange)
-		{
-			return new TlsDheKeyExchange(context, keyExchange);
-		}
+        {
+            return new TlsDheKeyExchange(context, keyExchange);
+        }
 
         protected virtual TlsKeyExchange CreateECDHKeyExchange(KeyExchangeAlgorithm keyExchange)
         {
@@ -265,8 +265,8 @@ namespace Org.BouncyCastle.Crypto.Tls
         }
 
         protected virtual TlsKeyExchange CreateRsaKeyExchange()
-		{
-			return new TlsRsaKeyExchange(context);
-		}
+        {
+            return new TlsRsaKeyExchange(context);
+        }
     }
 }
diff --git a/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs b/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
index 86c9d1a18..2c5aa3524 100644
--- a/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
+++ b/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
@@ -20,7 +20,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             {
                 throw new ArgumentNullException("clientCertificate");
             }
-            if (clientCertificate.certs.Length == 0)
+            if (clientCertificate.Length == 0)
             {
                 throw new ArgumentException("cannot be empty", "clientCertificate");
             }
diff --git a/crypto/src/crypto/tls/HashAlgorithm.cs b/crypto/src/crypto/tls/HashAlgorithm.cs
new file mode 100644
index 000000000..41818ca2c
--- /dev/null
+++ b/crypto/src/crypto/tls/HashAlgorithm.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * RFC 5246 7.4.1.4.1
+     */
+    public abstract class HashAlgorithm
+    {
+        public const byte none = 0;
+        public const byte md5 = 1;
+        public const byte sha1 = 2;
+        public const byte sha224 = 3;
+        public const byte sha256 = 4;
+        public const byte sha384 = 5;
+        public const byte sha512 = 6;
+    }
+}
diff --git a/crypto/src/crypto/tls/LegacyTlsAuthentication.cs b/crypto/src/crypto/tls/LegacyTlsAuthentication.cs
index 395f94208..bce31c0b0 100644
--- a/crypto/src/crypto/tls/LegacyTlsAuthentication.cs
+++ b/crypto/src/crypto/tls/LegacyTlsAuthentication.cs
@@ -2,29 +2,29 @@ using System;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// A temporary class to wrap old CertificateVerifyer stuff for new TlsAuthentication.
-	/// </summary>
-	[Obsolete]
-	public class LegacyTlsAuthentication
-		: TlsAuthentication
-	{
-		protected ICertificateVerifyer verifyer;
+    /// <summary>
+    /// A temporary class to wrap old CertificateVerifyer stuff for new TlsAuthentication.
+    /// </summary>
+    [Obsolete]
+    public class LegacyTlsAuthentication
+        : TlsAuthentication
+    {
+        protected ICertificateVerifyer verifyer;
 
-		public LegacyTlsAuthentication(ICertificateVerifyer verifyer)
-		{
-			this.verifyer = verifyer;
-		}
+        public LegacyTlsAuthentication(ICertificateVerifyer verifyer)
+        {
+            this.verifyer = verifyer;
+        }
 
-		public virtual void NotifyServerCertificate(Certificate serverCertificate)
-		{
-			if (!this.verifyer.IsValid(serverCertificate.GetCerts()))
-				throw new TlsFatalAlert(AlertDescription.user_canceled);
-		}
+        public virtual void NotifyServerCertificate(Certificate serverCertificate)
+        {
+            if (!this.verifyer.IsValid(serverCertificate.GetCertificateList()))
+                throw new TlsFatalAlert(AlertDescription.user_canceled);
+        }
 
-		public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
-		{
-			return null;
-		}
-	}
+        public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
+        {
+            return null;
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/PskTlsClient.cs b/crypto/src/crypto/tls/PskTlsClient.cs
index 9db7d7d90..cb42c31d8 100644
--- a/crypto/src/crypto/tls/PskTlsClient.cs
+++ b/crypto/src/crypto/tls/PskTlsClient.cs
@@ -3,168 +3,168 @@ using System.Collections;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public abstract class PskTlsClient
-		:TlsClient
-	{
-		protected TlsCipherFactory cipherFactory;
-		protected TlsPskIdentity pskIdentity;
+    public abstract class PskTlsClient
+        :TlsClient
+    {
+        protected TlsCipherFactory cipherFactory;
+        protected TlsPskIdentity pskIdentity;
 
         protected TlsClientContext context;
 
-        protected CompressionMethod selectedCompressionMethod;
-		protected CipherSuite selectedCipherSuite;
+        protected byte selectedCompressionMethod;
+        protected CipherSuite selectedCipherSuite;
 
         public PskTlsClient(TlsPskIdentity pskIdentity)
-			: this(new DefaultTlsCipherFactory(), pskIdentity)
-		{
-		}
+            : this(new DefaultTlsCipherFactory(), pskIdentity)
+        {
+        }
 
         public PskTlsClient(TlsCipherFactory cipherFactory, TlsPskIdentity pskIdentity)
-		{
-			this.cipherFactory = cipherFactory;
-			this.pskIdentity = pskIdentity;
-		}
+        {
+            this.cipherFactory = cipherFactory;
+            this.pskIdentity = pskIdentity;
+        }
 
         public virtual void Init(TlsClientContext context)
-		{
-			this.context = context;
-		}
+        {
+            this.context = context;
+        }
 
         public virtual CipherSuite[] GetCipherSuites()
-		{
-			return new CipherSuite[] {
-				CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA,
-				CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA,
-				CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_PSK_WITH_RC4_128_SHA,
-			};
-		}
+        {
+            return new CipherSuite[] {
+                CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+                CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+                CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+                CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA,
+                CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+                CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+                CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+                CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA,
+                CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA,
+                CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA,
+                CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+                CipherSuite.TLS_PSK_WITH_RC4_128_SHA,
+            };
+        }
 
         public virtual IDictionary GetClientExtensions()
-		{
-			return null;
-		}
+        {
+            return null;
+        }
 
-        public virtual CompressionMethod[] GetCompressionMethods()
-		{
-			return new CompressionMethod[] { CompressionMethod.NULL };
-		}
+        public virtual byte[] GetCompressionMethods()
+        {
+            return new byte[] { CompressionMethod.NULL };
+        }
 
         public virtual void NotifySessionID(byte[] sessionID)
-		{
-			// Currently ignored 
-		}
+        {
+            // Currently ignored 
+        }
 
         public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite)
-		{
-			this.selectedCipherSuite = selectedCipherSuite;
-		}
+        {
+            this.selectedCipherSuite = selectedCipherSuite;
+        }
 
-        public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod)
-		{
-			this.selectedCompressionMethod = selectedCompressionMethod;
-		}
+        public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod)
+        {
+            this.selectedCompressionMethod = selectedCompressionMethod;
+        }
 
         public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
-		{
-			if (!secureRenegotiation)
-			{
-				/*
-				 * RFC 5746 3.4. If the extension is not present, the server does not support
-				 * secure renegotiation; set secure_renegotiation flag to FALSE. In this case,
-				 * some clients may want to terminate the handshake instead of continuing; see
-				 * Section 4.1 for discussion.
-				 */
+        {
+            if (!secureRenegotiation)
+            {
+                /*
+                 * RFC 5746 3.4. If the extension is not present, the server does not support
+                 * secure renegotiation; set secure_renegotiation flag to FALSE. In this case,
+                 * some clients may want to terminate the handshake instead of continuing; see
+                 * Section 4.1 for discussion.
+                 */
 //				throw new TlsFatalAlert(AlertDescription.handshake_failure);
-			}
-		}
+            }
+        }
 
         public virtual void ProcessServerExtensions(IDictionary serverExtensions)
-		{
-		}
+        {
+        }
 
         public virtual TlsKeyExchange GetKeyExchange()
-		{
-			switch (selectedCipherSuite)
-			{
-				case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+        {
+            switch (selectedCipherSuite)
+            {
+                case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
                 case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
-					return CreatePskKeyExchange(KeyExchangeAlgorithm.PSK);
+                    return CreatePskKeyExchange(KeyExchangeAlgorithm.PSK);
 
                 case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+                case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
                 case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
                     return CreatePskKeyExchange(KeyExchangeAlgorithm.RSA_PSK);
 
                 case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+                case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
                 case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
                     return CreatePskKeyExchange(KeyExchangeAlgorithm.DHE_PSK);
 
                 default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected cipher suite was in the list of client-offered cipher
-					 * suites, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
+                    /*
+                     * Note: internal error here; the TlsProtocolHandler verifies that the
+                     * server-selected cipher suite was in the list of client-offered cipher
+                     * suites, so if we now can't produce an implementation, we shouldn't have
+                     * offered it!
+                     */
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
 
         public abstract TlsAuthentication GetAuthentication();
 
         public virtual TlsCompression GetCompression()
-		{
-			switch (selectedCompressionMethod)
-			{
-				case CompressionMethod.NULL:
-					return new TlsNullCompression();
+        {
+            switch (selectedCompressionMethod)
+            {
+                case CompressionMethod.NULL:
+                    return new TlsNullCompression();
 
                 default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected compression method was in the list of client-offered compression
-					 * methods, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
+                    /*
+                     * Note: internal error here; the TlsProtocolHandler verifies that the
+                     * server-selected compression method was in the list of client-offered compression
+                     * methods, so if we now can't produce an implementation, we shouldn't have
+                     * offered it!
+                     */
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
 
         public virtual TlsCipher GetCipher()
-		{
-			switch (selectedCipherSuite)
-			{
-				case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC,
-						DigestAlgorithm.SHA);
+        {
+            switch (selectedCipherSuite)
+            {
+                case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+                    return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC,
+                        DigestAlgorithm.SHA);
 
                 case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC,
-						DigestAlgorithm.SHA);
+                case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+                    return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC,
+                        DigestAlgorithm.SHA);
 
                 case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC,
-						DigestAlgorithm.SHA);
+                case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+                case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+                    return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC,
+                        DigestAlgorithm.SHA);
 
                 case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
                 case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
@@ -173,19 +173,19 @@ namespace Org.BouncyCastle.Crypto.Tls
                         DigestAlgorithm.SHA);
 
                 default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected cipher suite was in the list of client-offered cipher
-					 * suites, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
+                    /*
+                     * Note: internal error here; the TlsProtocolHandler verifies that the
+                     * server-selected cipher suite was in the list of client-offered cipher
+                     * suites, so if we now can't produce an implementation, we shouldn't have
+                     * offered it!
+                     */
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
 
         protected virtual TlsKeyExchange CreatePskKeyExchange(KeyExchangeAlgorithm keyExchange)
-		{
-			return new TlsPskKeyExchange(context, keyExchange, pskIdentity);
-		}
-	}
+        {
+            return new TlsPskKeyExchange(context, keyExchange, pskIdentity);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/SignatureAlgorithm.cs b/crypto/src/crypto/tls/SignatureAlgorithm.cs
new file mode 100644
index 000000000..35b961762
--- /dev/null
+++ b/crypto/src/crypto/tls/SignatureAlgorithm.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * RFC 5246 7.4.1.4.1 (in RFC 2246, there were no specific values assigned)
+     */
+    public abstract class SignatureAlgorithm
+    {
+        public const byte anonymous = 0;
+        public const byte rsa = 1;
+        public const byte dsa = 2;
+        public const byte ecdsa = 3;
+    }
+}
diff --git a/crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs b/crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs
new file mode 100644
index 000000000..f74205b62
--- /dev/null
+++ b/crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * RFC 5246 7.4.1.4.1
+     */
+    public class SignatureAndHashAlgorithm
+    {
+        protected readonly byte mHash;
+        protected readonly byte mSignature;
+
+        /**
+         * @param hash      {@link HashAlgorithm}
+         * @param signature {@link SignatureAlgorithm}
+         */
+        public SignatureAndHashAlgorithm(byte hash, byte signature)
+        {
+            if (!TlsUtilities.IsValidUint8(hash))
+            {
+                throw new ArgumentException("should be a uint8", "hash");
+            }
+            if (!TlsUtilities.IsValidUint8(signature))
+            {
+                throw new ArgumentException("should be a uint8", "signature");
+            }
+            if (signature == SignatureAlgorithm.anonymous)
+            {
+                throw new ArgumentException("MUST NOT be \"anonymous\"", "signature");
+            }
+
+            this.mHash = hash;
+            this.mSignature = signature;
+        }
+
+        /**
+         * @return {@link HashAlgorithm}
+         */
+        public virtual byte Hash
+        {
+            get { return mHash; }
+        }
+
+        /**
+         * @return {@link SignatureAlgorithm}
+         */
+        public virtual byte Signature
+        {
+            get { return mSignature; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (!(obj is SignatureAndHashAlgorithm))
+            {
+                return false;
+            }
+            SignatureAndHashAlgorithm other = (SignatureAndHashAlgorithm)obj;
+            return other.Hash == Hash && other.Signature == Signature;
+        }
+
+        public override int GetHashCode()
+        {
+            return ((int)Hash << 16) | (int)Signature;
+        }
+
+        /**
+         * Encode this {@link SignatureAndHashAlgorithm} to a {@link Stream}.
+         *
+         * @param output the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            TlsUtilities.WriteUint8(Hash, output);
+            TlsUtilities.WriteUint8(Signature, output);
+        }
+
+        /**
+         * Parse a {@link SignatureAndHashAlgorithm} from a {@link Stream}.
+         *
+         * @param input the {@link Stream} to parse from.
+         * @return a {@link SignatureAndHashAlgorithm} object.
+         * @throws IOException
+         */
+        public static SignatureAndHashAlgorithm Parse(Stream input)
+        {
+            byte hash = TlsUtilities.ReadUint8(input);
+            byte signature = TlsUtilities.ReadUint8(input);
+            return new SignatureAndHashAlgorithm(hash, signature);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/SrpTlsClient.cs b/crypto/src/crypto/tls/SrpTlsClient.cs
index 6c2638bb3..f487e9b21 100644
--- a/crypto/src/crypto/tls/SrpTlsClient.cs
+++ b/crypto/src/crypto/tls/SrpTlsClient.cs
@@ -6,183 +6,183 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public abstract class SrpTlsClient
-		: TlsClient
-	{
-		protected TlsCipherFactory cipherFactory;
-		protected byte[] identity;
-		protected byte[] password;
+    public abstract class SrpTlsClient
+        : TlsClient
+    {
+        protected TlsCipherFactory cipherFactory;
+        protected byte[] identity;
+        protected byte[] password;
 
-		protected TlsClientContext context;
+        protected TlsClientContext context;
 
-        protected CompressionMethod selectedCompressionMethod;
+        protected byte selectedCompressionMethod;
         protected CipherSuite selectedCipherSuite;
 
-		public SrpTlsClient(byte[] identity, byte[] password)
-			: this(new DefaultTlsCipherFactory(), identity, password)
-		{
-		}
-
-		public SrpTlsClient(TlsCipherFactory cipherFactory, byte[] identity, byte[] password)
-		{
-			this.cipherFactory = cipherFactory;
-			this.identity = Arrays.Clone(identity);
-			this.password = Arrays.Clone(password);
-		}
-
-		public virtual void Init(TlsClientContext context)
-		{
-			this.context = context;
-		}
-
-		public virtual CipherSuite[] GetCipherSuites()
-		{
-			return new CipherSuite[] {
-				CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
-			};
-		}
-
-		public virtual IDictionary GetClientExtensions()
-		{
-			IDictionary clientExtensions = Platform.CreateHashtable();
-
-			MemoryStream srpData = new MemoryStream();
-			TlsUtilities.WriteOpaque8(this.identity, srpData);
-			clientExtensions[ExtensionType.srp] = srpData.ToArray();
-
-			return clientExtensions;
-		}
-
-		public virtual CompressionMethod[] GetCompressionMethods()
-		{
-			return new CompressionMethod[] { CompressionMethod.NULL };
-		}
-
-		public virtual void NotifySessionID(byte[] sessionID)
-		{
-			// Currently ignored 
-		}
-
-		public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite)
-		{
-			this.selectedCipherSuite = selectedCipherSuite;
-		}
-
-		public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod)
-		{
+        public SrpTlsClient(byte[] identity, byte[] password)
+            : this(new DefaultTlsCipherFactory(), identity, password)
+        {
+        }
+
+        public SrpTlsClient(TlsCipherFactory cipherFactory, byte[] identity, byte[] password)
+        {
+            this.cipherFactory = cipherFactory;
+            this.identity = Arrays.Clone(identity);
+            this.password = Arrays.Clone(password);
+        }
+
+        public virtual void Init(TlsClientContext context)
+        {
+            this.context = context;
+        }
+
+        public virtual CipherSuite[] GetCipherSuites()
+        {
+            return new CipherSuite[] {
+                CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
+                CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+                CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+                CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+                CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+                CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+                CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
+                CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
+                CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
+            };
+        }
+
+        public virtual IDictionary GetClientExtensions()
+        {
+            IDictionary clientExtensions = Platform.CreateHashtable();
+
+            MemoryStream srpData = new MemoryStream();
+            TlsUtilities.WriteOpaque8(this.identity, srpData);
+            clientExtensions[ExtensionType.srp] = srpData.ToArray();
+
+            return clientExtensions;
+        }
+
+        public virtual byte[] GetCompressionMethods()
+        {
+            return new byte[] { CompressionMethod.NULL };
+        }
+
+        public virtual void NotifySessionID(byte[] sessionID)
+        {
+            // Currently ignored 
+        }
+
+        public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite)
+        {
+            this.selectedCipherSuite = selectedCipherSuite;
+        }
+
+        public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod)
+        {
             this.selectedCompressionMethod = selectedCompressionMethod;
         }
 
-		public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
-		{
-			if (!secureRenegotiation)
-			{
-				/*
-				 * RFC 5746 3.4. If the extension is not present, the server does not support
-				 * secure renegotiation; set secure_renegotiation flag to FALSE. In this case,
-				 * some clients may want to terminate the handshake instead of continuing; see
-				 * Section 4.1 for discussion.
-				 */
+        public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
+        {
+            if (!secureRenegotiation)
+            {
+                /*
+                 * RFC 5746 3.4. If the extension is not present, the server does not support
+                 * secure renegotiation; set secure_renegotiation flag to FALSE. In this case,
+                 * some clients may want to terminate the handshake instead of continuing; see
+                 * Section 4.1 for discussion.
+                 */
 //				throw new TlsFatalAlert(AlertDescription.handshake_failure);
-			}
-		}
-
-		public virtual void ProcessServerExtensions(IDictionary serverExtensions)
-		{
-			// There is no server response for the SRP extension
-		}
-
-		public virtual TlsKeyExchange GetKeyExchange()
-		{
-			switch (selectedCipherSuite)
-			{
-				case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
-					return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP);
-
-				case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
-					return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_RSA);
-
-				case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
-					return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_DSS);
-
-				default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected cipher suite was in the list of client-offered cipher
-					 * suites, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-		
-		public abstract TlsAuthentication GetAuthentication();
-
-		public virtual TlsCompression GetCompression()
-		{
-			switch (selectedCompressionMethod)
-			{
-				case CompressionMethod.NULL:
-					return new TlsNullCompression();
-
-				default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected compression method was in the list of client-offered compression
-					 * methods, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		public virtual TlsCipher GetCipher()
-		{
-			switch (selectedCipherSuite)
-			{
-				case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA);
-
-				case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA);
-
-				case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA);
-
-				default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected cipher suite was in the list of client-offered cipher
-					 * suites, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		protected virtual TlsKeyExchange CreateSrpKeyExchange(KeyExchangeAlgorithm keyExchange)
-		{
-			return new TlsSrpKeyExchange(context, keyExchange, identity, password);
-		}
-	}
+            }
+        }
+
+        public virtual void ProcessServerExtensions(IDictionary serverExtensions)
+        {
+            // There is no server response for the SRP extension
+        }
+
+        public virtual TlsKeyExchange GetKeyExchange()
+        {
+            switch (selectedCipherSuite)
+            {
+                case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+                    return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP);
+
+                case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+                    return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_RSA);
+
+                case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+                    return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_DSS);
+
+                default:
+                    /*
+                     * Note: internal error here; the TlsProtocolHandler verifies that the
+                     * server-selected cipher suite was in the list of client-offered cipher
+                     * suites, so if we now can't produce an implementation, we shouldn't have
+                     * offered it!
+                     */
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+        
+        public abstract TlsAuthentication GetAuthentication();
+
+        public virtual TlsCompression GetCompression()
+        {
+            switch (selectedCompressionMethod)
+            {
+                case CompressionMethod.NULL:
+                    return new TlsNullCompression();
+
+                default:
+                    /*
+                     * Note: internal error here; the TlsProtocolHandler verifies that the
+                     * server-selected compression method was in the list of client-offered compression
+                     * methods, so if we now can't produce an implementation, we shouldn't have
+                     * offered it!
+                     */
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public virtual TlsCipher GetCipher()
+        {
+            switch (selectedCipherSuite)
+            {
+                case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+                case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+                    return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA);
+
+                case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+                case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+                    return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA);
+
+                case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+                case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+                case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+                    return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA);
+
+                default:
+                    /*
+                     * Note: internal error here; the TlsProtocolHandler verifies that the
+                     * server-selected cipher suite was in the list of client-offered cipher
+                     * suites, so if we now can't produce an implementation, we shouldn't have
+                     * offered it!
+                     */
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        protected virtual TlsKeyExchange CreateSrpKeyExchange(KeyExchangeAlgorithm keyExchange)
+        {
+            return new TlsSrpKeyExchange(context, keyExchange, identity, password);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsClient.cs b/crypto/src/crypto/tls/TlsClient.cs
index eceaa3cd3..d32ac1547 100644
--- a/crypto/src/crypto/tls/TlsClient.cs
+++ b/crypto/src/crypto/tls/TlsClient.cs
@@ -28,9 +28,9 @@ namespace Org.BouncyCastle.Crypto.Tls
         /// <returns>
         /// An array of <see cref="CompressionMethod"/>, each specifying a supported compression method.
         /// </returns>
-        CompressionMethod[] GetCompressionMethods();
+        byte[] GetCompressionMethods();
 
-		/// <summary>
+        /// <summary>
 		/// Get the (optional) table of client extensions to be included in (extended) client hello.
 		/// </summary>
 		/// <returns>
@@ -69,7 +69,7 @@ namespace Org.BouncyCastle.Crypto.Tls
         /// <param name="selectedCompressionMethod">
         /// A <see cref="CompressionMethod"/>
         /// </param>
-        void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod);
+        void NotifySelectedCompressionMethod(byte selectedCompressionMethod);
 
 		/// <summary>
 		/// Report whether the server supports secure renegotiation
diff --git a/crypto/src/crypto/tls/TlsDHKeyExchange.cs b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
index 40ac416e0..465d8c0b2 100644
--- a/crypto/src/crypto/tls/TlsDHKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
@@ -9,193 +9,193 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// TLS 1.0 DH key exchange.
-	/// </summary>
-	internal class TlsDHKeyExchange
-		: TlsKeyExchange
-	{
-		protected TlsClientContext context;
-		protected KeyExchangeAlgorithm keyExchange;
-		protected TlsSigner tlsSigner;
-
-		protected AsymmetricKeyParameter serverPublicKey = null;
-		protected DHPublicKeyParameters dhAgreeServerPublicKey = null;
-		protected TlsAgreementCredentials agreementCredentials;
-		protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null;
-
-		internal TlsDHKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange)
-		{
-			switch (keyExchange)
-			{
-				case KeyExchangeAlgorithm.DH_RSA:
-				case KeyExchangeAlgorithm.DH_DSS:
-					this.tlsSigner = null;
-					break;
-				case KeyExchangeAlgorithm.DHE_RSA:
-					this.tlsSigner = new TlsRsaSigner();
-					break;
-				case KeyExchangeAlgorithm.DHE_DSS:
-					this.tlsSigner = new TlsDssSigner();
-					break;
-				default:
-					throw new ArgumentException("unsupported key exchange algorithm", "keyExchange");
-			}
-
-			this.context = context;
-			this.keyExchange = keyExchange;
-		}
-
-		public virtual void SkipServerCertificate()
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void ProcessServerCertificate(Certificate serverCertificate)
-		{
-			X509CertificateStructure x509Cert = serverCertificate.certs[0];
-			SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
-
-			try
-			{
-				this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
-			}
-			catch (Exception)
-			{
-				throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
-			}
-
-			if (tlsSigner == null)
-			{
-				try
-				{
-					this.dhAgreeServerPublicKey = ValidateDHPublicKey((DHPublicKeyParameters)this.serverPublicKey);
-				}
-				catch (InvalidCastException)
-				{
-					throw new TlsFatalAlert(AlertDescription.certificate_unknown);
-				}
-
-				TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
-			}
-			else
-			{
-				if (!tlsSigner.IsValidPublicKey(this.serverPublicKey))
-				{
-					throw new TlsFatalAlert(AlertDescription.certificate_unknown);
-				}
-
-				TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
-			}
-
-			// TODO
-			/*
-			* Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
-			* signing algorithm for the certificate must be the same as the algorithm for the
-			* certificate key."
-			*/
-		}
-
-		public virtual void SkipServerKeyExchange()
-		{
-			// OK
-		}
-
-		public virtual void ProcessServerKeyExchange(Stream input)
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
-		{
-			ClientCertificateType[] types = certificateRequest.CertificateTypes;
-			foreach (ClientCertificateType type in types)
-			{
-				switch (type)
-				{
-					case ClientCertificateType.rsa_sign:
-					case ClientCertificateType.dss_sign:
-					case ClientCertificateType.rsa_fixed_dh:
-					case ClientCertificateType.dss_fixed_dh:
-					case ClientCertificateType.ecdsa_sign:
-						break;
-					default:
-						throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-				}
-			}
-		}
-
-		public virtual void SkipClientCredentials()
-		{
-			this.agreementCredentials = null;
-		}
-
-		public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
-		{
-			if (clientCredentials is TlsAgreementCredentials)
-			{
-				// TODO Validate client cert has matching parameters (see 'areCompatibleParameters')?
-
-				this.agreementCredentials = (TlsAgreementCredentials)clientCredentials;
-			}
-			else if (clientCredentials is TlsSignerCredentials)
-			{
-				// OK
-			}
-			else
-			{
-				throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		public virtual void GenerateClientKeyExchange(Stream output)
-		{
-			/*
-			 * RFC 2246 7.4.7.2 If the client certificate already contains a suitable
-			 * Diffie-Hellman key, then Yc is implicit and does not need to be sent again. In
-			 * this case, the Client Key Exchange message will be sent, but will be empty.
-			 */
-			if (agreementCredentials == null)
-			{
-				GenerateEphemeralClientKeyExchange(dhAgreeServerPublicKey.Parameters, output);
-			}
-		}
+    /// <summary>
+    /// TLS 1.0 DH key exchange.
+    /// </summary>
+    internal class TlsDHKeyExchange
+        : TlsKeyExchange
+    {
+        protected TlsClientContext context;
+        protected KeyExchangeAlgorithm keyExchange;
+        protected TlsSigner tlsSigner;
+
+        protected AsymmetricKeyParameter serverPublicKey = null;
+        protected DHPublicKeyParameters dhAgreeServerPublicKey = null;
+        protected TlsAgreementCredentials agreementCredentials;
+        protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null;
+
+        internal TlsDHKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange)
+        {
+            switch (keyExchange)
+            {
+                case KeyExchangeAlgorithm.DH_RSA:
+                case KeyExchangeAlgorithm.DH_DSS:
+                    this.tlsSigner = null;
+                    break;
+                case KeyExchangeAlgorithm.DHE_RSA:
+                    this.tlsSigner = new TlsRsaSigner();
+                    break;
+                case KeyExchangeAlgorithm.DHE_DSS:
+                    this.tlsSigner = new TlsDssSigner();
+                    break;
+                default:
+                    throw new ArgumentException("unsupported key exchange algorithm", "keyExchange");
+            }
+
+            this.context = context;
+            this.keyExchange = keyExchange;
+        }
+
+        public virtual void SkipServerCertificate()
+        {
+            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public virtual void ProcessServerCertificate(Certificate serverCertificate)
+        {
+            X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
+            SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+
+            try
+            {
+                this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+            }
+            catch (Exception)
+            {
+                throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+            }
+
+            if (tlsSigner == null)
+            {
+                try
+                {
+                    this.dhAgreeServerPublicKey = ValidateDHPublicKey((DHPublicKeyParameters)this.serverPublicKey);
+                }
+                catch (InvalidCastException)
+                {
+                    throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+                }
+
+                TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
+            }
+            else
+            {
+                if (!tlsSigner.IsValidPublicKey(this.serverPublicKey))
+                {
+                    throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+                }
+
+                TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+            }
+
+            // TODO
+            /*
+            * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
+            * signing algorithm for the certificate must be the same as the algorithm for the
+            * certificate key."
+            */
+        }
+
+        public virtual void SkipServerKeyExchange()
+        {
+            // OK
+        }
+
+        public virtual void ProcessServerKeyExchange(Stream input)
+        {
+            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
+        {
+            byte[] types = certificateRequest.CertificateTypes;
+            foreach (byte type in types)
+            {
+                switch (type)
+                {
+                    case ClientCertificateType.rsa_sign:
+                    case ClientCertificateType.dss_sign:
+                    case ClientCertificateType.rsa_fixed_dh:
+                    case ClientCertificateType.dss_fixed_dh:
+                    case ClientCertificateType.ecdsa_sign:
+                        break;
+                    default:
+                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+            }
+        }
+
+        public virtual void SkipClientCredentials()
+        {
+            this.agreementCredentials = null;
+        }
+
+        public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
+        {
+            if (clientCredentials is TlsAgreementCredentials)
+            {
+                // TODO Validate client cert has matching parameters (see 'areCompatibleParameters')?
+
+                this.agreementCredentials = (TlsAgreementCredentials)clientCredentials;
+            }
+            else if (clientCredentials is TlsSignerCredentials)
+            {
+                // OK
+            }
+            else
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public virtual void GenerateClientKeyExchange(Stream output)
+        {
+            /*
+             * RFC 2246 7.4.7.2 If the client certificate already contains a suitable
+             * Diffie-Hellman key, then Yc is implicit and does not need to be sent again. In
+             * this case, the Client Key Exchange message will be sent, but will be empty.
+             */
+            if (agreementCredentials == null)
+            {
+                GenerateEphemeralClientKeyExchange(dhAgreeServerPublicKey.Parameters, output);
+            }
+        }
 
         public virtual byte[] GeneratePremasterSecret()
-		{
-			if (agreementCredentials != null)
-			{
-				return agreementCredentials.GenerateAgreement(dhAgreeServerPublicKey);
-			}
-
-			return CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey);
-		}
-		
-		protected virtual bool AreCompatibleParameters(DHParameters a, DHParameters b)
-		{
-			return a.P.Equals(b.P) && a.G.Equals(b.G);
-		}
-
-		protected virtual byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey,
-			DHPrivateKeyParameters privateKey)
-		{
-			return TlsDHUtilities.CalculateDHBasicAgreement(publicKey, privateKey);
-		}
-
-		protected virtual AsymmetricCipherKeyPair GenerateDHKeyPair(DHParameters dhParams)
-		{
-			return TlsDHUtilities.GenerateDHKeyPair(context.SecureRandom, dhParams);
-		}
-
-		protected virtual void GenerateEphemeralClientKeyExchange(DHParameters dhParams, Stream output)
-		{
-			this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(
-				context.SecureRandom, dhParams, output);
-		}
-
-		protected virtual DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key)
-		{
-			return TlsDHUtilities.ValidateDHPublicKey(key);
-		}
-	}
+        {
+            if (agreementCredentials != null)
+            {
+                return agreementCredentials.GenerateAgreement(dhAgreeServerPublicKey);
+            }
+
+            return CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey);
+        }
+        
+        protected virtual bool AreCompatibleParameters(DHParameters a, DHParameters b)
+        {
+            return a.P.Equals(b.P) && a.G.Equals(b.G);
+        }
+
+        protected virtual byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey,
+            DHPrivateKeyParameters privateKey)
+        {
+            return TlsDHUtilities.CalculateDHBasicAgreement(publicKey, privateKey);
+        }
+
+        protected virtual AsymmetricCipherKeyPair GenerateDHKeyPair(DHParameters dhParams)
+        {
+            return TlsDHUtilities.GenerateDHKeyPair(context.SecureRandom, dhParams);
+        }
+
+        protected virtual void GenerateEphemeralClientKeyExchange(DHParameters dhParams, Stream output)
+        {
+            this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(
+                context.SecureRandom, dhParams, output);
+        }
+
+        protected virtual DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key)
+        {
+            return TlsDHUtilities.ValidateDHPublicKey(key);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
index 36155346a..4c5576fca 100644
--- a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
@@ -56,7 +56,7 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         public virtual void ProcessServerCertificate(Certificate serverCertificate)
         {
-            X509CertificateStructure x509Cert = serverCertificate.certs[0];
+            X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
             SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
 
             try
@@ -117,8 +117,8 @@ namespace Org.BouncyCastle.Crypto.Tls
              * prohibited because the use of a long-term ECDH client key would jeopardize the
              * forward secrecy property of these algorithms.
              */
-            ClientCertificateType[] types = certificateRequest.CertificateTypes;
-            foreach (ClientCertificateType type in types)
+            byte[] types = certificateRequest.CertificateTypes;
+            foreach (byte type in types)
             {
                 switch (type)
                 {
diff --git a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
index 071d06b91..2dd284f12 100644
--- a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
@@ -72,8 +72,8 @@ namespace Org.BouncyCastle.Crypto.Tls
              * prohibited because the use of a long-term ECDH client key would jeopardize the
              * forward secrecy property of these algorithms.
              */
-            ClientCertificateType[] types = certificateRequest.CertificateTypes;
-            foreach (ClientCertificateType type in types)
+            byte[] types = certificateRequest.CertificateTypes;
+            foreach (byte type in types)
             {
                 switch (type)
                 {
diff --git a/crypto/src/crypto/tls/TlsException.cs b/crypto/src/crypto/tls/TlsException.cs
deleted file mode 100644
index 59c129105..000000000
--- a/crypto/src/crypto/tls/TlsException.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-
-namespace Org.BouncyCastle.Crypto.Tls
-{
-#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
-    [Serializable]
-#endif
-    public class TlsException : Exception
-	{
-		public TlsException() : base() { }
-		public TlsException(string message) : base(message) { }
-		public TlsException(string message, Exception exception) : base(message, exception) { }
-	}
-}
diff --git a/crypto/src/crypto/tls/TlsFatalAlert.cs b/crypto/src/crypto/tls/TlsFatalAlert.cs
index 0a9cc6f3a..4fb2a41bd 100644
--- a/crypto/src/crypto/tls/TlsFatalAlert.cs
+++ b/crypto/src/crypto/tls/TlsFatalAlert.cs
@@ -3,19 +3,19 @@ using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public class TlsFatalAlert
-		: IOException
-	{
-		private readonly AlertDescription alertDescription;
+    public class TlsFatalAlert
+        : IOException
+    {
+        private readonly byte alertDescription;
 
-		public TlsFatalAlert(AlertDescription alertDescription)
-		{
-			this.alertDescription = alertDescription;
-		}
+        public TlsFatalAlert(byte alertDescription)
+        {
+            this.alertDescription = alertDescription;
+        }
 
-		public AlertDescription AlertDescription
-		{
-			get { return alertDescription; }
-		}
-	}
+        public virtual byte AlertDescription
+        {
+            get { return alertDescription; }
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsProtocolHandler.cs b/crypto/src/crypto/tls/TlsProtocolHandler.cs
index 1960d3ccd..5ba42ef66 100644
--- a/crypto/src/crypto/tls/TlsProtocolHandler.cs
+++ b/crypto/src/crypto/tls/TlsProtocolHandler.cs
@@ -40,8 +40,6 @@ namespace Org.BouncyCastle.Crypto.Tls
         private const short CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED = 11;
         private const short CS_DONE = 12;
 
-        private static readonly byte[] emptybuf = new byte[0];
-
         private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack";
 
         /*
@@ -70,7 +68,7 @@ namespace Org.BouncyCastle.Crypto.Tls
         private TlsClientContextImpl tlsClientContext = null;
         private TlsClient tlsClient = null;
         private CipherSuite[] offeredCipherSuites = null;
-        private CompressionMethod[] offeredCompressionMethods = null;
+        private byte[] offeredCompressionMethods = null;
         private TlsKeyExchange keyExchange = null;
         private TlsAuthentication authentication = null;
         private CertificateRequest certificateRequest = null;
@@ -337,7 +335,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                              * Find out which CompressionMethod the server has chosen and check that
                              * it was one of the offered ones.
                              */
-                            CompressionMethod selectedCompressionMethod = (CompressionMethod)TlsUtilities.ReadUint8(inStr);
+                            byte selectedCompressionMethod = TlsUtilities.ReadUint8(inStr);
                             if (!ArrayContains(offeredCompressionMethods, selectedCompressionMethod))
                             {
                                 this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
@@ -431,7 +429,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                                     byte[] renegExtValue = (byte[])serverExtensions[ExtensionType.renegotiation_info];
 
                                     if (!Arrays.ConstantTimeAreEqual(renegExtValue,
-                                        CreateRenegotiationInfo(emptybuf)))
+                                        CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                                     {
                                         this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
                                     }
@@ -626,29 +624,11 @@ namespace Org.BouncyCastle.Crypto.Tls
                                 this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
                             }
 
-                            int numTypes = TlsUtilities.ReadUint8(inStr);
-                            ClientCertificateType[] certificateTypes = new ClientCertificateType[numTypes];
-                            for (int i = 0; i < numTypes; ++i)
-                            {
-                                certificateTypes[i] = (ClientCertificateType)TlsUtilities.ReadUint8(inStr);
-                            }
-
-                            byte[] authorities = TlsUtilities.ReadOpaque16(inStr);
+                            this.certificateRequest = CertificateRequest.Parse(//getContext(),
+                                inStr);
 
                             AssertEmpty(inStr);
 
-                            IList authorityDNs = Platform.CreateArrayList();
-
-                            MemoryStream bis = new MemoryStream(authorities, false);
-                            while (bis.Position < bis.Length)
-                            {
-                                byte[] dnBytes = TlsUtilities.ReadOpaque16(bis);
-                                // TODO Switch to X500Name when available
-                                authorityDNs.Add(X509Name.GetInstance(Asn1Object.FromByteArray(dnBytes)));
-                            }
-
-                            this.certificateRequest = new CertificateRequest(certificateTypes,
-                                authorityDNs);
                             this.keyExchange.ValidateCertificateRequest(this.certificateRequest);
 
                             break;
@@ -899,7 +879,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                 TlsUtilities.WriteUint8((byte)offeredCompressionMethods.Length, outStr);
                 for (int i = 0; i < offeredCompressionMethods.Length; ++i)
                 {
-                    TlsUtilities.WriteUint8((byte)offeredCompressionMethods[i], outStr);
+                    TlsUtilities.WriteUint8(offeredCompressionMethods[i], outStr);
                 }
             }
 
@@ -1123,7 +1103,7 @@ namespace Org.BouncyCastle.Crypto.Tls
         * @param alertDescription The exact alert message.
         * @throws IOException If alert was fatal.
         */
-        private void FailWithError(AlertLevel alertLevel, AlertDescription	alertDescription)
+        private void FailWithError(byte alertLevel, byte alertDescription)
         {
             /*
             * Check if the connection is still open.
@@ -1155,11 +1135,9 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
         }
 
-        internal void SendAlert(AlertLevel alertLevel, AlertDescription alertDescription)
+        internal void SendAlert(byte alertLevel, byte alertDescription)
         {
-            byte[] error = new byte[2];
-            error[0] = (byte)alertLevel;
-            error[1] = (byte)alertDescription;
+            byte[] error = new byte[] { alertLevel, alertDescription };
 
             rs.WriteMessage(ContentType.alert, error, 0, 2);
         }
@@ -1218,7 +1196,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             return false;
         }
 
-        private static bool ArrayContains(CompressionMethod[] a, CompressionMethod n)
+        private static bool ArrayContains(byte[] a, byte n)
         {
             for (int i = 0; i < a.Length; ++i)
             {
diff --git a/crypto/src/crypto/tls/TlsPskKeyExchange.cs b/crypto/src/crypto/tls/TlsPskKeyExchange.cs
index cadd643ca..b1f14e156 100644
--- a/crypto/src/crypto/tls/TlsPskKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsPskKeyExchange.cs
@@ -8,42 +8,42 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	internal class TlsPskKeyExchange
-		: TlsKeyExchange
-	{
-		protected TlsClientContext context;
-		protected KeyExchangeAlgorithm keyExchange;
-		protected TlsPskIdentity pskIdentity;
+    internal class TlsPskKeyExchange
+        : TlsKeyExchange
+    {
+        protected TlsClientContext context;
+        protected KeyExchangeAlgorithm keyExchange;
+        protected TlsPskIdentity pskIdentity;
 
-		protected byte[] psk_identity_hint = null;
+        protected byte[] psk_identity_hint = null;
 
-		protected DHPublicKeyParameters dhAgreeServerPublicKey = null;
-		protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null;
+        protected DHPublicKeyParameters dhAgreeServerPublicKey = null;
+        protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null;
 
         protected AsymmetricKeyParameter serverPublicKey = null;
         protected RsaKeyParameters rsaServerPublicKey = null;
-		protected byte[] premasterSecret;
-
-		internal TlsPskKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange,
-			TlsPskIdentity pskIdentity)
-		{
-			switch (keyExchange)
-			{
-				case KeyExchangeAlgorithm.PSK:
-				case KeyExchangeAlgorithm.RSA_PSK:
-				case KeyExchangeAlgorithm.DHE_PSK:
-					break;
-				default:
-					throw new ArgumentException("unsupported key exchange algorithm", "keyExchange");
-			}
-
-			this.context = context;
-			this.keyExchange = keyExchange;
-			this.pskIdentity = pskIdentity;
-		}
-
-		public virtual void SkipServerCertificate()
-		{
+        protected byte[] premasterSecret;
+
+        internal TlsPskKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange,
+            TlsPskIdentity pskIdentity)
+        {
+            switch (keyExchange)
+            {
+                case KeyExchangeAlgorithm.PSK:
+                case KeyExchangeAlgorithm.RSA_PSK:
+                case KeyExchangeAlgorithm.DHE_PSK:
+                    break;
+                default:
+                    throw new ArgumentException("unsupported key exchange algorithm", "keyExchange");
+            }
+
+            this.context = context;
+            this.keyExchange = keyExchange;
+            this.pskIdentity = pskIdentity;
+        }
+
+        public virtual void SkipServerCertificate()
+        {
             if (keyExchange == KeyExchangeAlgorithm.RSA_PSK)
             {
                 throw new TlsFatalAlert(AlertDescription.unexpected_message);
@@ -51,13 +51,13 @@ namespace Org.BouncyCastle.Crypto.Tls
         }
 
         public virtual void ProcessServerCertificate(Certificate serverCertificate)
-		{
+        {
             if (keyExchange != KeyExchangeAlgorithm.RSA_PSK)
             {
                 throw new TlsFatalAlert(AlertDescription.unexpected_message);
             }
 
-            X509CertificateStructure x509Cert = serverCertificate.certs[0];
+            X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
             SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
 
             try
@@ -88,107 +88,107 @@ namespace Org.BouncyCastle.Crypto.Tls
             */
         }
 
-		public virtual void SkipServerKeyExchange()
-		{
+        public virtual void SkipServerKeyExchange()
+        {
             if (keyExchange == KeyExchangeAlgorithm.DHE_PSK)
             {
                 throw new TlsFatalAlert(AlertDescription.unexpected_message);
             }
 
-            this.psk_identity_hint = new byte[0];
-		}
-
-		public virtual void ProcessServerKeyExchange(Stream input)
-		{
-			this.psk_identity_hint = TlsUtilities.ReadOpaque16(input);
-
-			if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
-			{
-				byte[] pBytes = TlsUtilities.ReadOpaque16(input);
-				byte[] gBytes = TlsUtilities.ReadOpaque16(input);
-				byte[] YsBytes = TlsUtilities.ReadOpaque16(input);
-
-				BigInteger p = new BigInteger(1, pBytes);
-				BigInteger g = new BigInteger(1, gBytes);
-				BigInteger Ys = new BigInteger(1, YsBytes);
-				
-				this.dhAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey(
-					new DHPublicKeyParameters(Ys, new DHParameters(p, g)));
-			}
-			else if (this.psk_identity_hint.Length == 0)
-			{
-				// TODO Should we enforce that this message should have been skipped if hint is empty?
-				//throw new TlsFatalAlert(AlertDescription.unexpected_message);
-			}
-		}
-
-		public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void SkipClientCredentials()
-		{
-			// OK
-		}
-
-		public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
-		{
-			throw new TlsFatalAlert(AlertDescription.internal_error);
-		}
-
-		public virtual void GenerateClientKeyExchange(Stream output)
-		{
-			if (psk_identity_hint == null || psk_identity_hint.Length == 0)
-			{
-				pskIdentity.SkipIdentityHint();
-			}
-			else
-			{
-				pskIdentity.NotifyIdentityHint(psk_identity_hint);
-			}
-
-			byte[] psk_identity = pskIdentity.GetPskIdentity();
-
-			TlsUtilities.WriteOpaque16(psk_identity, output);
-
-			if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK)
-			{
-				this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(
-					context.SecureRandom, this.rsaServerPublicKey, output);
-			}
-			else if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
-			{
-				this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(
-					context.SecureRandom, this.dhAgreeServerPublicKey.Parameters, output);
-			}
-		}
-
-		public virtual byte[] GeneratePremasterSecret()
-		{
-			byte[] psk = pskIdentity.GetPsk();
-			byte[] other_secret = GenerateOtherSecret(psk.Length);
-
-			MemoryStream buf = new MemoryStream(4 + other_secret.Length + psk.Length);
-			TlsUtilities.WriteOpaque16(other_secret, buf);
-			TlsUtilities.WriteOpaque16(psk, buf);
-			return buf.ToArray();
-		}
-
-		protected virtual byte[] GenerateOtherSecret(int pskLength)
-		{
-			if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
-			{
-				return TlsDHUtilities.CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey);
-			}
-
-			if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK)
-			{
-				return this.premasterSecret;
-			}
-
-			return new byte[pskLength];
-		}
+            this.psk_identity_hint = TlsUtilities.EmptyBytes;
+        }
+
+        public virtual void ProcessServerKeyExchange(Stream input)
+        {
+            this.psk_identity_hint = TlsUtilities.ReadOpaque16(input);
+
+            if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
+            {
+                byte[] pBytes = TlsUtilities.ReadOpaque16(input);
+                byte[] gBytes = TlsUtilities.ReadOpaque16(input);
+                byte[] YsBytes = TlsUtilities.ReadOpaque16(input);
+
+                BigInteger p = new BigInteger(1, pBytes);
+                BigInteger g = new BigInteger(1, gBytes);
+                BigInteger Ys = new BigInteger(1, YsBytes);
+                
+                this.dhAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey(
+                    new DHPublicKeyParameters(Ys, new DHParameters(p, g)));
+            }
+            else if (this.psk_identity_hint.Length == 0)
+            {
+                // TODO Should we enforce that this message should have been skipped if hint is empty?
+                //throw new TlsFatalAlert(AlertDescription.unexpected_message);
+            }
+        }
+
+        public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
+        {
+            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public virtual void SkipClientCredentials()
+        {
+            // OK
+        }
+
+        public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
+        {
+            throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public virtual void GenerateClientKeyExchange(Stream output)
+        {
+            if (psk_identity_hint == null || psk_identity_hint.Length == 0)
+            {
+                pskIdentity.SkipIdentityHint();
+            }
+            else
+            {
+                pskIdentity.NotifyIdentityHint(psk_identity_hint);
+            }
+
+            byte[] psk_identity = pskIdentity.GetPskIdentity();
+
+            TlsUtilities.WriteOpaque16(psk_identity, output);
+
+            if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK)
+            {
+                this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(
+                    context.SecureRandom, this.rsaServerPublicKey, output);
+            }
+            else if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
+            {
+                this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(
+                    context.SecureRandom, this.dhAgreeServerPublicKey.Parameters, output);
+            }
+        }
+
+        public virtual byte[] GeneratePremasterSecret()
+        {
+            byte[] psk = pskIdentity.GetPsk();
+            byte[] other_secret = GenerateOtherSecret(psk.Length);
+
+            MemoryStream buf = new MemoryStream(4 + other_secret.Length + psk.Length);
+            TlsUtilities.WriteOpaque16(other_secret, buf);
+            TlsUtilities.WriteOpaque16(psk, buf);
+            return buf.ToArray();
+        }
+
+        protected virtual byte[] GenerateOtherSecret(int pskLength)
+        {
+            if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
+            {
+                return TlsDHUtilities.CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey);
+            }
+
+            if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK)
+            {
+                return this.premasterSecret;
+            }
+
+            return new byte[pskLength];
+        }
 
         protected virtual RsaKeyParameters ValidateRsaPublicKey(RsaKeyParameters key)
         {
diff --git a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
index ad61f08de..aad482316 100644
--- a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
@@ -11,117 +11,117 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// TLS 1.0 RSA key exchange.
-	/// </summary>
-	internal class TlsRsaKeyExchange
-		: TlsKeyExchange
-	{
-		protected TlsClientContext context;
+    /// <summary>
+    /// TLS 1.0 RSA key exchange.
+    /// </summary>
+    internal class TlsRsaKeyExchange
+        : TlsKeyExchange
+    {
+        protected TlsClientContext context;
 
-		protected AsymmetricKeyParameter serverPublicKey = null;
+        protected AsymmetricKeyParameter serverPublicKey = null;
 
         protected RsaKeyParameters rsaServerPublicKey = null;
 
         protected byte[] premasterSecret;
 
-		internal TlsRsaKeyExchange(TlsClientContext context)
-		{
-			this.context = context;
-		}
-
-		public virtual void SkipServerCertificate()
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void ProcessServerCertificate(Certificate serverCertificate)
-		{
-			X509CertificateStructure x509Cert = serverCertificate.certs[0];
-			SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
-
-			try
-			{
-				this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
-			}
+        internal TlsRsaKeyExchange(TlsClientContext context)
+        {
+            this.context = context;
+        }
+
+        public virtual void SkipServerCertificate()
+        {
+            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public virtual void ProcessServerCertificate(Certificate serverCertificate)
+        {
+            X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
+            SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+
+            try
+            {
+                this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+            }
 //			catch (RuntimeException)
-			catch (Exception)
-			{
-				throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
-			}
-
-			// Sanity check the PublicKeyFactory
-			if (this.serverPublicKey.IsPrivate)
-			{
-				throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-
-			this.rsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.serverPublicKey);
-
-			TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment);
-
-			// TODO
-			/*
-			* Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
-			* signing algorithm for the certificate must be the same as the algorithm for the
-			* certificate key."
-			*/
-		}
-
-		public virtual void SkipServerKeyExchange()
-		{
-			// OK
-		}
-
-		public virtual void ProcessServerKeyExchange(Stream input)
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
-		{
-			ClientCertificateType[] types = certificateRequest.CertificateTypes;
-			foreach (ClientCertificateType type in types)
-			{
-				switch (type)
-				{
-					case ClientCertificateType.rsa_sign:
-					case ClientCertificateType.dss_sign:
-					case ClientCertificateType.ecdsa_sign:
-						break;
-					default:
-						throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-				}
-			}
-		}
-
-		public virtual void SkipClientCredentials()
-		{
-			// OK
-		}
-
-		public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
-		{
-			if (!(clientCredentials is TlsSignerCredentials))
-			{
-				throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-		
+            catch (Exception)
+            {
+                throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+            }
+
+            // Sanity check the PublicKeyFactory
+            if (this.serverPublicKey.IsPrivate)
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+
+            this.rsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.serverPublicKey);
+
+            TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment);
+
+            // TODO
+            /*
+            * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
+            * signing algorithm for the certificate must be the same as the algorithm for the
+            * certificate key."
+            */
+        }
+
+        public virtual void SkipServerKeyExchange()
+        {
+            // OK
+        }
+
+        public virtual void ProcessServerKeyExchange(Stream input)
+        {
+            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
+        {
+            byte[] types = certificateRequest.CertificateTypes;
+            foreach (byte type in types)
+            {
+                switch (type)
+                {
+                    case ClientCertificateType.rsa_sign:
+                    case ClientCertificateType.dss_sign:
+                    case ClientCertificateType.ecdsa_sign:
+                        break;
+                    default:
+                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+            }
+        }
+
+        public virtual void SkipClientCredentials()
+        {
+            // OK
+        }
+
+        public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
+        {
+            if (!(clientCredentials is TlsSignerCredentials))
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+        
         public virtual void GenerateClientKeyExchange(Stream output)
-		{
-			this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(
-				context.SecureRandom, this.rsaServerPublicKey, output);
-		}
-
-		public virtual byte[] GeneratePremasterSecret()
-		{
-			byte[] tmp = this.premasterSecret;
-			this.premasterSecret = null;
-			return tmp;
-		}
-
-    	// Would be needed to process RSA_EXPORT server key exchange
+        {
+            this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(
+                context.SecureRandom, this.rsaServerPublicKey, output);
+        }
+
+        public virtual byte[] GeneratePremasterSecret()
+        {
+            byte[] tmp = this.premasterSecret;
+            this.premasterSecret = null;
+            return tmp;
+        }
+
+        // Would be needed to process RSA_EXPORT server key exchange
 //	    protected virtual void ProcessRsaServerKeyExchange(Stream input, ISigner signer)
 //	    {
 //	        Stream sigIn = input;
@@ -150,16 +150,16 @@ namespace Org.BouncyCastle.Crypto.Tls
 //	    }
 
         protected virtual RsaKeyParameters ValidateRsaPublicKey(RsaKeyParameters key)
-		{
-			// TODO What is the minimum bit length required?
+        {
+            // TODO What is the minimum bit length required?
 //			key.Modulus.BitLength;
 
-			if (!key.Exponent.IsProbablePrime(2))
-			{
-				throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-			}
+            if (!key.Exponent.IsProbablePrime(2))
+            {
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
 
-			return key;
-		}
-	}
+            return key;
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
index cb4e26e58..8040f8e6c 100644
--- a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
@@ -72,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                 throw new TlsFatalAlert(AlertDescription.unexpected_message);
             }
 
-            X509CertificateStructure x509Cert = serverCertificate.certs[0];
+            X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
             SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
 
             try
diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index dca842a80..5ed659ce7 100644
--- a/crypto/src/crypto/tls/TlsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections;
 using System.IO;
 using System.Text;
 
@@ -16,6 +17,41 @@ namespace Org.BouncyCastle.Crypto.Tls
     /// <remarks>Some helper functions for MicroTLS.</remarks>
     public class TlsUtilities
     {
+        public static readonly byte[] EmptyBytes = new byte[0];
+
+        public static void CheckUint8(int i)
+        {
+            if (!IsValidUint8(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static void CheckUint16(int i)
+        {
+            if (!IsValidUint16(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static void CheckUint24(int i)
+        {
+            if (!IsValidUint24(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static bool IsValidUint8(int i)
+        {
+            return (i & 0xFF) == i;
+        }
+
+        public static bool IsValidUint16(int i)
+        {
+            return (i & 0xFFFF) == i;
+        }
+
+        public static bool IsValidUint24(int i)
+        {
+            return (i & 0xFFFFFF) == i;
+        }
+
         internal static void WriteUint8(byte i, Stream os)
         {
             os.WriteByte(i);
@@ -99,6 +135,13 @@ namespace Org.BouncyCastle.Crypto.Tls
             os.Write(uints, 0, uints.Length);
         }
 
+        public static void WriteUint8ArrayWithUint8Length(byte[] uints, Stream output)
+        {
+            CheckUint8(uints.Length);
+            WriteUint8((byte)uints.Length, output);
+            WriteUint8Array(uints, output);
+        }
+
         internal static void WriteUint16Array(int[] uints, Stream os)
         {
             for (int i = 0; i < uints.Length; ++i)
@@ -140,6 +183,16 @@ namespace Org.BouncyCastle.Crypto.Tls
             return (i1 << 16) | (i2 << 8) | i3;
         }
 
+        public static byte[] ReadFully(int length, Stream input)
+        {
+            if (length < 1)
+                return EmptyBytes;
+            byte[] buf = new byte[length];
+            if (length != Streams.ReadFully(input, buf))
+                throw new EndOfStreamException();
+            return buf;
+        }
+
         internal static void ReadFully(byte[] buf, Stream inStr)
         {
             if (Streams.ReadFully(inStr, buf, 0, buf.Length) < buf.Length)
@@ -162,6 +215,12 @@ namespace Org.BouncyCastle.Crypto.Tls
             return bytes;
         }
 
+        public static byte[] ReadOpaque24(Stream input)
+        {
+            int length = ReadUint24(input);
+            return ReadFully(length, input);
+        }
+
         internal static void CheckVersion(byte[] readVersion)
         {
             if ((readVersion[0] != 3) || (readVersion[1] != 1))
@@ -180,6 +239,30 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
         }
 
+        public static Asn1Object ReadAsn1Object(byte[] encoding)
+        {
+            Asn1InputStream asn1 = new Asn1InputStream(encoding);
+            Asn1Object result = asn1.ReadObject();
+            if (null == result)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            if (null != asn1.ReadObject())
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            return result;
+        }
+
+        public static Asn1Object ReadDerObject(byte[] encoding)
+        {
+            /*
+             * NOTE: The current ASN.1 parsing code can't enforce DER-only parsing, but since DER is
+             * canonical, we can check it by re-encoding the result and comparing to the original.
+             */
+            Asn1Object result = ReadAsn1Object(encoding);
+            byte[] check = result.GetEncoded(Asn1Encodable.Der);
+            if (!Arrays.AreEqual(check, encoding))
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            return result;
+        }
+
         internal static void WriteGmtUnixTime(byte[] buf, int offset)
         {
             int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L);
@@ -201,6 +284,35 @@ namespace Org.BouncyCastle.Crypto.Tls
             buf[offset + 1] = 1;
         }
 
+        public static void EncodeSupportedSignatureAlgorithms(IList supportedSignatureAlgorithms, bool allowAnonymous,
+            Stream output)
+        {
+            if (supportedSignatureAlgorithms == null || supportedSignatureAlgorithms.Count < 1
+                || supportedSignatureAlgorithms.Count >= (1 << 15))
+            {
+                throw new ArgumentException("must have length from 1 to (2^15 - 1)", "supportedSignatureAlgorithms");
+            }
+
+            // supported_signature_algorithms
+            int length = 2 * supportedSignatureAlgorithms.Count;
+            TlsUtilities.CheckUint16(length);
+            TlsUtilities.WriteUint16(length, output);
+
+            foreach (SignatureAndHashAlgorithm entry in supportedSignatureAlgorithms)
+            {
+                if (!allowAnonymous && entry.Signature == SignatureAlgorithm.anonymous)
+                {
+                    /*
+                     * RFC 5246 7.4.1.4.1 The "anonymous" value is meaningless in this context but used
+                     * in Section 7.4.3. It MUST NOT appear in this extension.
+                     */
+                    throw new ArgumentException(
+                        "SignatureAlgorithm.anonymous MUST NOT appear in the signature_algorithms extension");
+                }
+                entry.Encode(output);
+            }
+        }
+
         private static void hmac_hash(IDigest digest, byte[] secret, byte[] seed, byte[] output)
         {
             HMac mac = new HMac(digest);