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; }
+ }
+ }
+}
|