summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2014-08-22 18:22:13 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2014-08-22 18:22:13 +0700
commit91443f862f00e62fe69a28e4afee7c00c1c264bd (patch)
treebd81f549a40d72ae82ecaddf6714c9285ca0de87
parentMore TLS porting from Java API (diff)
downloadBouncyCastle.NET-ed25519-91443f862f00e62fe69a28e4afee7c00c1c264bd.tar.xz
More TLS porting from Java API
-rw-r--r--crypto/crypto.csproj30
-rw-r--r--crypto/src/crypto/tls/CombinedHash.cs203
-rw-r--r--crypto/src/crypto/tls/DeferredHash.cs199
-rw-r--r--crypto/src/crypto/tls/DigitallySigned.cs70
-rw-r--r--crypto/src/crypto/tls/LegacyTlsAuthentication.cs9
-rw-r--r--crypto/src/crypto/tls/ServerDHParams.cs60
-rw-r--r--crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs15
-rw-r--r--crypto/src/crypto/tls/TlsDHUtilities.cs46
-rw-r--r--crypto/src/crypto/tls/TlsEccUtilities.cs2
-rw-r--r--crypto/src/crypto/tls/TlsExtensionsUtilities.cs2
-rw-r--r--crypto/src/crypto/tls/TlsSrpUtilities.cs2
-rw-r--r--crypto/src/crypto/tls/TlsSrtpUtilities.cs62
-rw-r--r--crypto/src/crypto/tls/TlsStream.cs120
-rw-r--r--crypto/src/crypto/tls/TlsUtilities.cs2
-rw-r--r--crypto/src/crypto/tls/UseSrtpData.cs56
15 files changed, 721 insertions, 157 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 0e9227970..6a3d80f7d 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -4454,6 +4454,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\DeferredHash.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\tls\DigestAlgorithm.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4464,6 +4469,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\DigitallySigned.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\tls\ECBasisType.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4599,6 +4609,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\ServerDHParams.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\tls\ServerName.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4609,6 +4624,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\ServerOnlyTlsAuthentication.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\tls\SessionParameters.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4889,6 +4909,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\TlsSrtpUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\tls\TlsStream.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4914,6 +4939,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\UseSrtpData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\util\Pack.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/crypto/tls/CombinedHash.cs b/crypto/src/crypto/tls/CombinedHash.cs
index 59ad87a7b..74a52d598 100644
--- a/crypto/src/crypto/tls/CombinedHash.cs
+++ b/crypto/src/crypto/tls/CombinedHash.cs
@@ -1,82 +1,133 @@
 using System;
 
-using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <remarks>A combined hash, which implements md5(m) || sha1(m).</remarks>
-	internal class CombinedHash
-		: IDigest
-	{
-		private readonly MD5Digest md5;
-		private readonly Sha1Digest sha1;
-
-		internal CombinedHash()
-		{
-			this.md5 = new MD5Digest();
-			this.sha1 = new Sha1Digest();
-		}
-
-		internal CombinedHash(CombinedHash t)
-		{
-			this.md5 = new MD5Digest(t.md5);
-			this.sha1 = new Sha1Digest(t.sha1);
-		}
-
-		/// <seealso cref="IDigest.AlgorithmName"/>
-		public string AlgorithmName
-		{
-			get
-			{
-				return md5.AlgorithmName + " and " + sha1.AlgorithmName + " for TLS 1.0";
-			}
-		}
-
-		/// <seealso cref="IDigest.GetByteLength"/>
-		public int GetByteLength()
-		{
-			return System.Math.Max(md5.GetByteLength(), sha1.GetByteLength());
-		}
-
-		/// <seealso cref="IDigest.GetDigestSize"/>
-		public int GetDigestSize()
-		{
-			return md5.GetDigestSize() + sha1.GetDigestSize();
-		}
-
-		/// <seealso cref="IDigest.Update"/>
-		public void Update(
-			byte input)
-		{
-			md5.Update(input);
-			sha1.Update(input);
-		}
-
-		/// <seealso cref="IDigest.BlockUpdate"/>
-		public void BlockUpdate(
-			byte[]	input,
-			int		inOff,
-			int		len)
-		{
-			md5.BlockUpdate(input, inOff, len);
-			sha1.BlockUpdate(input, inOff, len);
-		}
-
-		/// <seealso cref="IDigest.DoFinal"/>
-		public int DoFinal(
-			byte[]	output,
-			int		outOff)
-		{
-			int i1 = md5.DoFinal(output, outOff);
-			int i2 = sha1.DoFinal(output, outOff + i1);
-			return i1 + i2;
-		}
-
-		/// <seealso cref="IDigest.Reset"/>
-		public void Reset()
-		{
-			md5.Reset();
-			sha1.Reset();
-		}
-	}
+    /**
+     * A combined hash, which implements md5(m) || sha1(m).
+     */
+    internal class CombinedHash
+        :   TlsHandshakeHash
+    {
+        protected TlsContext mContext;
+        protected IDigest mMd5;
+        protected IDigest mSha1;
+
+        internal CombinedHash()
+        {
+            this.mMd5 = TlsUtilities.CreateHash(HashAlgorithm.md5);
+            this.mSha1 = TlsUtilities.CreateHash(HashAlgorithm.sha1);
+        }
+
+        internal CombinedHash(CombinedHash t)
+        {
+            this.mContext = t.mContext;
+            this.mMd5 = TlsUtilities.CloneHash(HashAlgorithm.md5, t.mMd5);
+            this.mSha1 = TlsUtilities.CloneHash(HashAlgorithm.sha1, t.mSha1);
+        }
+
+        public virtual void Init(TlsContext context)
+        {
+            this.mContext = context;
+        }
+
+        public virtual TlsHandshakeHash NotifyPrfDetermined()
+        {
+            return this;
+        }
+
+        public virtual void TrackHashAlgorithm(byte hashAlgorithm)
+        {
+            throw new InvalidOperationException("CombinedHash only supports calculating the legacy PRF for handshake hash");
+        }
+
+        public virtual void SealHashAlgorithms()
+        {
+        }
+
+        public virtual TlsHandshakeHash StopTracking()
+        {
+            return new CombinedHash(this);
+        }
+
+        public virtual IDigest ForkPrfHash()
+        {
+            return new CombinedHash(this);
+        }
+
+        public virtual byte[] GetFinalHash(byte hashAlgorithm)
+        {
+            throw new InvalidOperationException("CombinedHash doesn't support multiple hashes");
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return mMd5.AlgorithmName + " and " + mSha1.AlgorithmName; }
+        }
+
+        public virtual int GetByteLength()
+        {
+            return System.Math.Max(mMd5.GetByteLength(), mSha1.GetByteLength());
+        }
+
+        public virtual int GetDigestSize()
+        {
+            return mMd5.GetDigestSize() + mSha1.GetDigestSize();
+        }
+
+        public virtual void Update(byte input)
+        {
+            mMd5.Update(input);
+            mSha1.Update(input);
+        }
+
+        /**
+         * @see org.bouncycastle.crypto.Digest#update(byte[], int, int)
+         */
+        public virtual void BlockUpdate(byte[] input, int inOff, int len)
+        {
+            mMd5.BlockUpdate(input, inOff, len);
+            mSha1.BlockUpdate(input, inOff, len);
+        }
+
+        /**
+         * @see org.bouncycastle.crypto.Digest#doFinal(byte[], int)
+         */
+        public virtual int DoFinal(byte[] output, int outOff)
+        {
+            if (mContext != null && TlsUtilities.IsSsl(mContext))
+            {
+                Ssl3Complete(mMd5, Ssl3Mac.IPAD, Ssl3Mac.OPAD, 48);
+                Ssl3Complete(mSha1, Ssl3Mac.IPAD, Ssl3Mac.OPAD, 40);
+            }
+
+            int i1 = mMd5.DoFinal(output, outOff);
+            int i2 = mSha1.DoFinal(output, outOff + i1);
+            return i1 + i2;
+        }
+
+        /**
+         * @see org.bouncycastle.crypto.Digest#reset()
+         */
+        public virtual void Reset()
+        {
+            mMd5.Reset();
+            mSha1.Reset();
+        }
+
+        protected virtual void Ssl3Complete(IDigest d, byte[] ipad, byte[] opad, int padLength)
+        {
+            byte[] master_secret = mContext.SecurityParameters.masterSecret;
+
+            d.BlockUpdate(master_secret, 0, master_secret.Length);
+            d.BlockUpdate(ipad, 0, padLength);
+
+            byte[] tmp = DigestUtilities.DoFinal(d);
+
+            d.BlockUpdate(master_secret, 0, master_secret.Length);
+            d.BlockUpdate(opad, 0, padLength);
+            d.BlockUpdate(tmp, 0, tmp.Length);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/DeferredHash.cs b/crypto/src/crypto/tls/DeferredHash.cs
new file mode 100644
index 000000000..c2d5ab5b6
--- /dev/null
+++ b/crypto/src/crypto/tls/DeferredHash.cs
@@ -0,0 +1,199 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * Buffers input until the hash algorithm is determined.
+     */
+    internal class DeferredHash
+        :   TlsHandshakeHash
+    {
+        protected const int BUFFERING_HASH_LIMIT = 4;
+
+        protected TlsContext mContext;
+
+        private DigestInputBuffer mBuf;
+        private IDictionary mHashes;
+        private int mPrfHashAlgorithm;
+
+        internal DeferredHash()
+        {
+            this.mBuf = new DigestInputBuffer();
+            this.mHashes = Platform.CreateHashtable();
+            this.mPrfHashAlgorithm = -1;
+        }
+
+        private DeferredHash(byte prfHashAlgorithm, IDigest prfHash)
+        {
+            this.mBuf = null;
+            this.mHashes = Platform.CreateHashtable();
+            this.mPrfHashAlgorithm = prfHashAlgorithm;
+            mHashes[prfHashAlgorithm] = prfHash;
+        }
+
+        public virtual void Init(TlsContext context)
+        {
+            this.mContext = context;
+        }
+
+        public virtual TlsHandshakeHash NotifyPrfDetermined()
+        {
+            int prfAlgorithm = mContext.SecurityParameters.PrfAlgorithm;
+            if (prfAlgorithm == PrfAlgorithm.tls_prf_legacy)
+            {
+                CombinedHash legacyHash = new CombinedHash();
+                legacyHash.Init(mContext);
+                mBuf.UpdateDigest(legacyHash);
+                return legacyHash.NotifyPrfDetermined();
+            }
+
+            this.mPrfHashAlgorithm = TlsUtilities.GetHashAlgorithmForPrfAlgorithm(prfAlgorithm);
+
+            CheckTrackingHash((byte)mPrfHashAlgorithm);
+
+            return this;
+        }
+
+        public virtual void TrackHashAlgorithm(byte hashAlgorithm)
+        {
+            if (mBuf == null)
+                throw new InvalidOperationException("Too late to track more hash algorithms");
+
+            CheckTrackingHash(hashAlgorithm);
+        }
+
+        public virtual void SealHashAlgorithms()
+        {
+            CheckStopBuffering();
+        }
+
+        public virtual TlsHandshakeHash StopTracking()
+        {
+            IDigest prfHash = TlsUtilities.CloneHash((byte)mPrfHashAlgorithm, (IDigest)mHashes[mPrfHashAlgorithm]);
+            if (mBuf != null)
+            {
+                mBuf.UpdateDigest(prfHash);
+            }
+            DeferredHash result = new DeferredHash((byte)mPrfHashAlgorithm, prfHash);
+            result.Init(mContext);
+            return result;
+        }
+
+        public virtual IDigest ForkPrfHash()
+        {
+            CheckStopBuffering();
+
+            if (mBuf != null)
+            {
+                IDigest prfHash = TlsUtilities.CreateHash((byte)mPrfHashAlgorithm);
+                mBuf.UpdateDigest(prfHash);
+                return prfHash;
+            }
+
+            return TlsUtilities.CloneHash((byte)mPrfHashAlgorithm, (IDigest)mHashes[mPrfHashAlgorithm]);
+        }
+
+        public virtual byte[] GetFinalHash(byte hashAlgorithm)
+        {
+            IDigest d = (IDigest)mHashes[hashAlgorithm];
+            if (d == null)
+                throw new InvalidOperationException("HashAlgorithm " + hashAlgorithm + " is not being tracked");
+
+            d = TlsUtilities.CloneHash(hashAlgorithm, d);
+            if (mBuf != null)
+            {
+                mBuf.UpdateDigest(d);
+            }
+
+            return DigestUtilities.DoFinal(d);
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { throw new InvalidOperationException("Use Fork() to get a definite IDigest"); }
+        }
+
+        public virtual int GetByteLength()
+        {
+            throw new InvalidOperationException("Use Fork() to get a definite IDigest");
+        }
+
+        public virtual int GetDigestSize()
+        {
+            throw new InvalidOperationException("Use Fork() to get a definite IDigest");
+        }
+
+        public virtual void Update(byte input)
+        {
+            if (mBuf != null)
+            {
+                mBuf.WriteByte(input);
+                return;
+            }
+
+            foreach (IDigest hash in mHashes.Values)
+            {
+                hash.Update(input);
+            }
+        }
+
+        public virtual void BlockUpdate(byte[] input, int inOff, int len)
+        {
+            if (mBuf != null)
+            {
+                mBuf.Write(input, inOff, len);
+                return;
+            }
+
+            foreach (IDigest hash in mHashes.Values)
+            {
+                hash.BlockUpdate(input, inOff, len);
+            }
+        }
+
+        public virtual int DoFinal(byte[] output, int outOff)
+        {
+            throw new InvalidOperationException("Use Fork() to get a definite IDigest");
+        }
+
+        public virtual void Reset()
+        {
+            if (mBuf != null)
+            {
+                mBuf.SetLength(0);
+                return;
+            }
+
+            foreach (IDigest hash in mHashes.Values)
+            {
+                hash.Reset();
+            }
+        }
+
+        protected virtual void CheckStopBuffering()
+        {
+            if (mBuf != null && mHashes.Count <= BUFFERING_HASH_LIMIT)
+            {
+                foreach (IDigest hash in mHashes.Values)
+                {
+                    mBuf.UpdateDigest(hash);
+                }
+
+                this.mBuf = null;
+            }
+        }
+
+        protected virtual void CheckTrackingHash(byte hashAlgorithm)
+        {
+            if (!mHashes.Contains(hashAlgorithm))
+            {
+                IDigest hash = TlsUtilities.CreateHash(hashAlgorithm);
+                mHashes[hashAlgorithm] = hash;
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/DigitallySigned.cs b/crypto/src/crypto/tls/DigitallySigned.cs
new file mode 100644
index 000000000..8b7344fd9
--- /dev/null
+++ b/crypto/src/crypto/tls/DigitallySigned.cs
@@ -0,0 +1,70 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class DigitallySigned
+    {
+        protected readonly SignatureAndHashAlgorithm mAlgorithm;
+        protected readonly byte[] mSignature;
+
+        public DigitallySigned(SignatureAndHashAlgorithm algorithm, byte[] signature)
+        {
+            if (signature == null)
+                throw new ArgumentNullException("signature");
+
+            this.mAlgorithm = algorithm;
+            this.mSignature = signature;
+        }
+
+        /**
+         * @return a {@link SignatureAndHashAlgorithm} (or null before TLS 1.2).
+         */
+        public virtual SignatureAndHashAlgorithm Algorithm
+        {
+            get { return mAlgorithm; }
+        }
+
+        public virtual byte[] Signature
+        {
+            get { return mSignature; }
+        }
+
+        /**
+         * Encode this {@link DigitallySigned} to a {@link Stream}.
+         * 
+         * @param output
+         *            the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            if (mAlgorithm != null)
+            {
+                mAlgorithm.Encode(output);
+            }
+            TlsUtilities.WriteOpaque16(mSignature, output);
+        }
+
+        /**
+         * Parse a {@link DigitallySigned} from a {@link Stream}.
+         * 
+         * @param context
+         *            the {@link TlsContext} of the current connection.
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link DigitallySigned} object.
+         * @throws IOException
+         */
+        public static DigitallySigned Parse(TlsContext context, Stream input)
+        {
+            SignatureAndHashAlgorithm algorithm = null;
+            if (TlsUtilities.IsTlsV12(context))
+            {
+                algorithm = SignatureAndHashAlgorithm.Parse(input);
+            }
+            byte[] signature = TlsUtilities.ReadOpaque16(input);
+            return new DigitallySigned(algorithm, signature);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/LegacyTlsAuthentication.cs b/crypto/src/crypto/tls/LegacyTlsAuthentication.cs
index bce31c0b0..0c0362c4b 100644
--- a/crypto/src/crypto/tls/LegacyTlsAuthentication.cs
+++ b/crypto/src/crypto/tls/LegacyTlsAuthentication.cs
@@ -7,7 +7,7 @@ namespace Org.BouncyCastle.Crypto.Tls
     /// </summary>
     [Obsolete]
     public class LegacyTlsAuthentication
-        : TlsAuthentication
+        :   ServerOnlyTlsAuthentication
     {
         protected ICertificateVerifyer verifyer;
 
@@ -16,15 +16,10 @@ namespace Org.BouncyCastle.Crypto.Tls
             this.verifyer = verifyer;
         }
 
-        public virtual void NotifyServerCertificate(Certificate serverCertificate)
+        public override void NotifyServerCertificate(Certificate serverCertificate)
         {
             if (!this.verifyer.IsValid(serverCertificate.GetCertificateList()))
                 throw new TlsFatalAlert(AlertDescription.user_canceled);
         }
-
-        public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
-        {
-            return null;
-        }
     }
 }
diff --git a/crypto/src/crypto/tls/ServerDHParams.cs b/crypto/src/crypto/tls/ServerDHParams.cs
new file mode 100644
index 000000000..381858854
--- /dev/null
+++ b/crypto/src/crypto/tls/ServerDHParams.cs
@@ -0,0 +1,60 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class ServerDHParams
+    {
+        protected readonly DHPublicKeyParameters mPublicKey;
+
+        public ServerDHParams(DHPublicKeyParameters publicKey)
+        {
+            if (publicKey == null)
+                throw new ArgumentNullException("publicKey");
+
+            this.mPublicKey = publicKey;
+        }
+
+        public virtual DHPublicKeyParameters PublicKey
+        {
+            get { return mPublicKey; }
+        }
+
+        /**
+         * Encode this {@link ServerDHParams} to a {@link Stream}.
+         * 
+         * @param output
+         *            the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            DHParameters dhParameters = mPublicKey.Parameters;
+            BigInteger Ys = mPublicKey.Y;
+
+            TlsDHUtilities.WriteDHParameter(dhParameters.P, output);
+            TlsDHUtilities.WriteDHParameter(dhParameters.G, output);
+            TlsDHUtilities.WriteDHParameter(Ys, output);
+        }
+
+        /**
+         * Parse a {@link ServerDHParams} from a {@link Stream}.
+         * 
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link ServerDHParams} object.
+         * @throws IOException
+         */
+        public static ServerDHParams Parse(Stream input)
+        {
+            BigInteger p = TlsDHUtilities.ReadDHParameter(input);
+            BigInteger g = TlsDHUtilities.ReadDHParameter(input);
+            BigInteger Ys = TlsDHUtilities.ReadDHParameter(input);
+
+            return new ServerDHParams(new DHPublicKeyParameters(Ys, new DHParameters(p, g)));
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs b/crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs
new file mode 100644
index 000000000..485889709
--- /dev/null
+++ b/crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class ServerOnlyTlsAuthentication
+        :   TlsAuthentication
+    {
+        public abstract void NotifyServerCertificate(Certificate serverCertificate);
+
+        public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
+        {
+            return null;
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsDHUtilities.cs b/crypto/src/crypto/tls/TlsDHUtilities.cs
index b5deb8b84..477c3ebac 100644
--- a/crypto/src/crypto/tls/TlsDHUtilities.cs
+++ b/crypto/src/crypto/tls/TlsDHUtilities.cs
@@ -12,6 +12,14 @@ namespace Org.BouncyCastle.Crypto.Tls
 {
     public abstract class TlsDHUtilities
     {
+        internal static readonly BigInteger One = BigInteger.One;
+        internal static readonly BigInteger Two = BigInteger.Two;
+
+        public static bool AreCompatibleParameters(DHParameters a, DHParameters b)
+        {
+            return a.P.Equals(b.P) && a.G.Equals(b.G);
+        }
+
         public static byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey,
             DHPrivateKeyParameters privateKey)
         {
@@ -36,15 +44,23 @@ namespace Org.BouncyCastle.Crypto.Tls
         public static DHPrivateKeyParameters GenerateEphemeralClientKeyExchange(SecureRandom random,
             DHParameters dhParams, Stream output)
         {
-            AsymmetricCipherKeyPair dhAgreeClientKeyPair = GenerateDHKeyPair(random, dhParams);
-            DHPrivateKeyParameters dhAgreeClientPrivateKey =
-                (DHPrivateKeyParameters)dhAgreeClientKeyPair.Private;
+            AsymmetricCipherKeyPair kp = GenerateDHKeyPair(random, dhParams);
+
+            DHPublicKeyParameters dhPublic = (DHPublicKeyParameters)kp.Public;
+            WriteDHParameter(dhPublic.Y, output);
+
+            return (DHPrivateKeyParameters)kp.Private;
+        }
+
+        public static DHPrivateKeyParameters GenerateEphemeralServerKeyExchange(SecureRandom random,
+            DHParameters dhParams, Stream output)
+        {
+            AsymmetricCipherKeyPair kp = GenerateDHKeyPair(random, dhParams);
 
-            BigInteger Yc = ((DHPublicKeyParameters)dhAgreeClientKeyPair.Public).Y;
-            byte[] keData = BigIntegers.AsUnsignedByteArray(Yc);
-            TlsUtilities.WriteOpaque16(keData, output);
+            DHPublicKeyParameters dhPublic = (DHPublicKeyParameters)kp.Public;
+            new ServerDHParams(dhPublic).Encode(output);
 
-            return dhAgreeClientPrivateKey;
+            return (DHPrivateKeyParameters)kp.Private;
         }
         
         public static DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key)
@@ -58,11 +74,11 @@ namespace Org.BouncyCastle.Crypto.Tls
             {
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
             }
-            if (g.CompareTo(BigInteger.Two) < 0 || g.CompareTo(p.Subtract(BigInteger.Two)) > 0)
+            if (g.CompareTo(Two) < 0 || g.CompareTo(p.Subtract(Two)) > 0)
             {
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
             }
-            if (Y.CompareTo(BigInteger.Two) < 0 || Y.CompareTo(p.Subtract(BigInteger.One)) > 0)
+            if (Y.CompareTo(Two) < 0 || Y.CompareTo(p.Subtract(One)) > 0)
             {
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
             }
@@ -71,5 +87,15 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             return key;
         }
+
+        public static BigInteger ReadDHParameter(Stream input)
+        {
+            return new BigInteger(1, TlsUtilities.ReadOpaque16(input));
+        }
+
+        public static void WriteDHParameter(BigInteger x, Stream output)
+        {
+            TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(x), output);
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/crypto/tls/TlsEccUtilities.cs b/crypto/src/crypto/tls/TlsEccUtilities.cs
index 399438879..889c6932b 100644
--- a/crypto/src/crypto/tls/TlsEccUtilities.cs
+++ b/crypto/src/crypto/tls/TlsEccUtilities.cs
@@ -16,7 +16,7 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-    public class TlsEccUtilities
+    public abstract class TlsEccUtilities
     {
         private static readonly string[] CurveNames = new string[] { "sect163k1", "sect163r1", "sect163r2", "sect193r1",
             "sect193r2", "sect233k1", "sect233r1", "sect239k1", "sect283k1", "sect283r1", "sect409k1", "sect409r1",
diff --git a/crypto/src/crypto/tls/TlsExtensionsUtilities.cs b/crypto/src/crypto/tls/TlsExtensionsUtilities.cs
index ca1d4183b..8876911e6 100644
--- a/crypto/src/crypto/tls/TlsExtensionsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsExtensionsUtilities.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-    public class TlsExtensionsUtilities
+    public abstract class TlsExtensionsUtilities
     {
         public static IDictionary EnsureExtensionsInitialised(IDictionary extensions)
         {
diff --git a/crypto/src/crypto/tls/TlsSrpUtilities.cs b/crypto/src/crypto/tls/TlsSrpUtilities.cs
index ada08ef9f..bbb6ac280 100644
--- a/crypto/src/crypto/tls/TlsSrpUtilities.cs
+++ b/crypto/src/crypto/tls/TlsSrpUtilities.cs
@@ -4,7 +4,7 @@ using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-    public class TlsSrpUtilities
+    public abstract class TlsSrpUtilities
     {
         public static void AddSrpExtension(IDictionary extensions, byte[] identity)
         {
diff --git a/crypto/src/crypto/tls/TlsSrtpUtilities.cs b/crypto/src/crypto/tls/TlsSrtpUtilities.cs
new file mode 100644
index 000000000..626c0e3a4
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsSrtpUtilities.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * RFC 5764 DTLS Extension to Establish Keys for SRTP.
+     */
+    public abstract class TlsSRTPUtils
+    {
+        public static void AddUseSrtpExtension(IDictionary extensions, UseSrtpData useSRTPData)
+        {
+            extensions[ExtensionType.use_srtp] = CreateUseSrtpExtension(useSRTPData);
+        }
+
+        public static UseSrtpData GetUseSrtpExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.use_srtp);
+            return extensionData == null ? null : ReadUseSrtpExtension(extensionData);
+        }
+
+        public static byte[] CreateUseSrtpExtension(UseSrtpData useSrtpData)
+        {
+            if (useSrtpData == null)
+                throw new ArgumentNullException("useSrtpData");
+
+            MemoryStream buf = new MemoryStream();
+
+            // SRTPProtectionProfiles
+            TlsUtilities.WriteUint16ArrayWithUint16Length(useSrtpData.ProtectionProfiles, buf);
+
+            // srtp_mki
+            TlsUtilities.WriteOpaque8(useSrtpData.Mki, buf);
+
+            return buf.ToArray();
+        }
+
+        public static UseSrtpData ReadUseSrtpExtension(byte[] extensionData)
+        {
+            if (extensionData == null)
+                throw new ArgumentNullException("extensionData");
+
+            MemoryStream buf = new MemoryStream(extensionData, true);
+
+            // SRTPProtectionProfiles
+            int length = TlsUtilities.ReadUint16(buf);
+            if (length < 2 || (length & 1) != 0)
+            {
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            }
+            int[] protectionProfiles = TlsUtilities.ReadUint16Array(length / 2, buf);
+
+            // srtp_mki
+            byte[] mki = TlsUtilities.ReadOpaque8(buf);
+
+            TlsProtocol.AssertEmpty(buf);
+
+            return new UseSrtpData(protectionProfiles, mki);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsStream.cs b/crypto/src/crypto/tls/TlsStream.cs
index fe24ad3ed..84b901d6e 100644
--- a/crypto/src/crypto/tls/TlsStream.cs
+++ b/crypto/src/crypto/tls/TlsStream.cs
@@ -3,84 +3,84 @@ using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	internal class TlsStream
-		: Stream
-	{
-		private readonly TlsProtocolHandler handler;
+    internal class TlsStream
+        : Stream
+    {
+        private readonly TlsProtocolHandler handler;
 
-		internal TlsStream(
-			TlsProtocolHandler handler)
-		{
-			this.handler = handler;
-		}
+        internal TlsStream(
+            TlsProtocolHandler handler)
+        {
+            this.handler = handler;
+        }
 
-		public override bool CanRead
-		{
-			get { return !handler.IsClosed; }
-		}
+        public override bool CanRead
+        {
+            get { return !handler.IsClosed; }
+        }
 
-		public override bool CanSeek
-		{
-			get { return false; }
-		}
+        public override bool CanSeek
+        {
+            get { return false; }
+        }
 
-		public override bool CanWrite
-		{
-			get { return !handler.IsClosed; }
-		}
+        public override bool CanWrite
+        {
+            get { return !handler.IsClosed; }
+        }
 
-		public override void Close()
-		{
-			handler.Close();
-		}
+        public override void Close()
+        {
+            handler.Close();
+        }
 
-		public override void Flush()
-		{
-			handler.Flush();
-		}
+        public override void Flush()
+        {
+            handler.Flush();
+        }
 
         public override long Length
-		{
-			get { throw new NotSupportedException(); }
-		}
+        {
+            get { throw new NotSupportedException(); }
+        }
 
-		public override long Position
+        public override long Position
         {
             get { throw new NotSupportedException(); }
             set { throw new NotSupportedException(); }
         }
 
-		public override int Read(byte[]	buf, int off, int len)
-		{
-			return this.handler.ReadApplicationData(buf, off, len);
-		}
+        public override int Read(byte[]	buf, int off, int len)
+        {
+            return this.handler.ReadApplicationData(buf, off, len);
+        }
 
-		public override int ReadByte()
-		{
-			byte[] buf = new byte[1];
-			if (this.Read(buf, 0, 1) <= 0)
-				return -1;
-			return buf[0];
-		}
+        public override int ReadByte()
+        {
+            byte[] buf = new byte[1];
+            if (this.Read(buf, 0, 1) <= 0)
+                return -1;
+            return buf[0];
+        }
 
-		public override long Seek(long offset, SeekOrigin origin)
-		{
-			throw new NotSupportedException();
-		}
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
 
         public override void SetLength(long value)
-		{
-			throw new NotSupportedException();
-		}
+        {
+            throw new NotSupportedException();
+        }
 
-		public override void Write(byte[] buf, int off, int len)
-		{
-			this.handler.WriteData(buf, off, len);
-		}
+        public override void Write(byte[] buf, int off, int len)
+        {
+            this.handler.WriteData(buf, off, len);
+        }
 
-		public override void WriteByte(byte b)
-		{
-			this.handler.WriteData(new byte[] { b }, 0, 1);
-		}
-	}
+        public override void WriteByte(byte b)
+        {
+            this.handler.WriteData(new byte[] { b }, 0, 1);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index 3fc6c7df1..f530b01a6 100644
--- a/crypto/src/crypto/tls/TlsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -18,7 +18,7 @@ using Org.BouncyCastle.Utilities.IO;
 namespace Org.BouncyCastle.Crypto.Tls
 {
     /// <remarks>Some helper functions for MicroTLS.</remarks>
-    public class TlsUtilities
+    public abstract class TlsUtilities
     {
         public static readonly byte[] EmptyBytes = new byte[0];
 
diff --git a/crypto/src/crypto/tls/UseSrtpData.cs b/crypto/src/crypto/tls/UseSrtpData.cs
new file mode 100644
index 000000000..fe8f8accb
--- /dev/null
+++ b/crypto/src/crypto/tls/UseSrtpData.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * RFC 5764 4.1.1
+     */
+    public class UseSrtpData
+    {
+        protected readonly int[] mProtectionProfiles;
+        protected readonly byte[] mMki;
+
+        /**
+         * @param protectionProfiles see {@link SrtpProtectionProfile} for valid constants.
+         * @param mki                valid lengths from 0 to 255.
+         */
+        public UseSrtpData(int[] protectionProfiles, byte[] mki)
+        {
+            if (protectionProfiles == null || protectionProfiles.Length < 1
+                || protectionProfiles.Length >= (1 << 15))
+            {
+                throw new ArgumentException("must have length from 1 to (2^15 - 1)", "protectionProfiles");
+            }
+
+            if (mki == null)
+            {
+                mki = TlsUtilities.EmptyBytes;
+            }
+            else if (mki.Length > 255)
+            {
+                throw new ArgumentException("cannot be longer than 255 bytes", "mki");
+            }
+
+            this.mProtectionProfiles = protectionProfiles;
+            this.mMki = mki;
+        }
+
+        /**
+         * @return see {@link SrtpProtectionProfile} for valid constants.
+         */
+        public virtual int[] ProtectionProfiles
+        {
+            get { return mProtectionProfiles; }
+        }
+
+        /**
+         * @return valid lengths from 0 to 255.
+         */
+        public virtual byte[] Mki
+        {
+            get { return mMki; }
+        }
+    }
+}