diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index f45215de4..fc38358c3 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -4354,6 +4354,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\tls\ExporterLabel.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\tls\ExtensionType.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -4559,6 +4564,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\tls\TlsPeer.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\tls\TlsProtocolHandler.cs"
SubType = "Code"
BuildAction = "Compile"
diff --git a/crypto/src/crypto/tls/DefaultTlsClient.cs b/crypto/src/crypto/tls/DefaultTlsClient.cs
index a5fbe8235..d59fae164 100644
--- a/crypto/src/crypto/tls/DefaultTlsClient.cs
+++ b/crypto/src/crypto/tls/DefaultTlsClient.cs
@@ -36,6 +36,17 @@ namespace Org.BouncyCastle.Crypto.Tls
this.context = context;
}
+ public virtual bool ShouldUseGmtUnixTime()
+ {
+ /*
+ * draft-mathewson-no-gmtunixtime-00 2. For the reasons we discuss above, we recommend that
+ * TLS implementors MUST by default set the entire value the ClientHello.Random and
+ * ServerHello.Random fields, including gmt_unix_time, to a cryptographically random
+ * sequence.
+ */
+ return false;
+ }
+
public virtual int[] GetCipherSuites()
{
return new int[] {
diff --git a/crypto/src/crypto/tls/ExporterLabel.cs b/crypto/src/crypto/tls/ExporterLabel.cs
new file mode 100644
index 000000000..e26f15dc7
--- /dev/null
+++ b/crypto/src/crypto/tls/ExporterLabel.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 5705
+ */
+ public class ExporterLabel
+ {
+ /*
+ * BC-specific
+ */
+ internal const string client_random = "client random";
+ internal const string server_random = "server random";
+
+ /*
+ * RFC 5246
+ */
+ public const string client_finished = "client finished";
+ public const string server_finished = "server finished";
+ public const string master_secret = "master secret";
+ public const string key_expansion = "key expansion";
+
+ /*
+ * RFC 5216
+ */
+ public const string client_EAP_encryption = "client EAP encryption";
+
+ /*
+ * RFC 5281
+ */
+ public const string ttls_keying_material = "ttls keying material";
+ public const string ttls_challenge = "ttls challenge";
+
+ /*
+ * RFC 5764
+ */
+ public const string dtls_srtp = "EXTRACTOR-dtls_srtp";
+ }
+}
diff --git a/crypto/src/crypto/tls/PskTlsClient.cs b/crypto/src/crypto/tls/PskTlsClient.cs
index 6011daada..e60688155 100644
--- a/crypto/src/crypto/tls/PskTlsClient.cs
+++ b/crypto/src/crypto/tls/PskTlsClient.cs
@@ -30,6 +30,17 @@ namespace Org.BouncyCastle.Crypto.Tls
this.context = context;
}
+ public virtual bool ShouldUseGmtUnixTime()
+ {
+ /*
+ * draft-mathewson-no-gmtunixtime-00 2. For the reasons we discuss above, we recommend that
+ * TLS implementors MUST by default set the entire value the ClientHello.Random and
+ * ServerHello.Random fields, including gmt_unix_time, to a cryptographically random
+ * sequence.
+ */
+ return false;
+ }
+
public virtual int[] GetCipherSuites()
{
return new int[] {
diff --git a/crypto/src/crypto/tls/SrpTlsClient.cs b/crypto/src/crypto/tls/SrpTlsClient.cs
index f9c8ccc74..3769fc85d 100644
--- a/crypto/src/crypto/tls/SrpTlsClient.cs
+++ b/crypto/src/crypto/tls/SrpTlsClient.cs
@@ -35,6 +35,17 @@ namespace Org.BouncyCastle.Crypto.Tls
this.context = context;
}
+ public virtual bool ShouldUseGmtUnixTime()
+ {
+ /*
+ * draft-mathewson-no-gmtunixtime-00 2. For the reasons we discuss above, we recommend that
+ * TLS implementors MUST by default set the entire value the ClientHello.Random and
+ * ServerHello.Random fields, including gmt_unix_time, to a cryptographically random
+ * sequence.
+ */
+ return false;
+ }
+
public virtual int[] GetCipherSuites()
{
return new int[] {
diff --git a/crypto/src/crypto/tls/TlsClient.cs b/crypto/src/crypto/tls/TlsClient.cs
index 9e7937c94..a4cdc647d 100644
--- a/crypto/src/crypto/tls/TlsClient.cs
+++ b/crypto/src/crypto/tls/TlsClient.cs
@@ -5,6 +5,7 @@ using System.IO;
namespace Org.BouncyCastle.Crypto.Tls
{
public interface TlsClient
+ : TlsPeer
{
/// <summary>
/// Called at the start of a new TLS session, before any other methods.
diff --git a/crypto/src/crypto/tls/TlsPeer.cs b/crypto/src/crypto/tls/TlsPeer.cs
new file mode 100644
index 000000000..5b5c94a44
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsPeer.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsPeer
+ {
+ /// <summary>
+ /// draft-mathewson-no-gmtunixtime-00 2. "If existing users of a TLS implementation may rely on
+ /// gmt_unix_time containing the current time, we recommend that implementors MAY provide the
+ /// ability to set gmt_unix_time as an option only, off by default."
+ /// </summary>
+ /// <returns>
+ /// <code>true</code> if the current time should be used in the gmt_unix_time field of
+ /// Random, or <code>false</code> if gmt_unix_time should contain a cryptographically
+ /// random value.
+ /// </returns>
+ bool ShouldUseGmtUnixTime();
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsProtocolHandler.cs b/crypto/src/crypto/tls/TlsProtocolHandler.cs
index c538229dc..4707df3b5 100644
--- a/crypto/src/crypto/tls/TlsProtocolHandler.cs
+++ b/crypto/src/crypto/tls/TlsProtocolHandler.cs
@@ -816,9 +816,8 @@ namespace Org.BouncyCastle.Crypto.Tls
* First, generate some random data.
*/
this.securityParameters = new SecurityParameters();
- this.securityParameters.clientRandom = new byte[32];
- random.NextBytes(securityParameters.clientRandom, 4, 28);
- TlsUtilities.WriteGmtUnixTime(securityParameters.clientRandom, 0);
+ this.securityParameters.clientRandom = CreateRandomBlock(tlsClient.ShouldUseGmtUnixTime(), random,
+ ExporterLabel.client_random);
this.tlsClientContext = new TlsClientContextImpl(random, securityParameters);
this.tlsClient = tlsClient;
@@ -1176,6 +1175,29 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
+ protected static byte[] CreateRandomBlock(bool useGMTUnixTime, SecureRandom random, string asciiLabel)
+ {
+ /*
+ * We use the TLS 1.0 PRF on the SecureRandom output, to guard against RNGs where the raw
+ * output could be used to recover the internal state.
+ */
+ byte[] secret = new byte[32];
+ random.NextBytes(secret);
+
+ byte[] seed = new byte[8];
+ // TODO Use high-resolution timer
+ TlsUtilities.WriteUint64(DateTimeUtilities.CurrentUnixMs(), seed, 0);
+
+ byte[] result = TlsUtilities.PRF(secret, asciiLabel, seed, 32);
+
+ if (useGMTUnixTime)
+ {
+ TlsUtilities.WriteGmtUnixTime(result, 0);
+ }
+
+ return result;
+ }
+
internal void Flush()
{
rs.Flush();
|