summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/crypto/tls/AbstractTlsClient.cs10
-rw-r--r--crypto/src/crypto/tls/AbstractTlsServer.cs12
-rw-r--r--crypto/src/crypto/tls/AlertDescription.cs13
-rw-r--r--crypto/src/crypto/tls/CipherSuite.cs17
-rw-r--r--crypto/src/crypto/tls/TlsClient.cs2
-rw-r--r--crypto/src/crypto/tls/TlsClientProtocol.cs19
-rw-r--r--crypto/src/crypto/tls/TlsServer.cs3
-rw-r--r--crypto/src/crypto/tls/TlsServerProtocol.cs5
8 files changed, 77 insertions, 4 deletions
diff --git a/crypto/src/crypto/tls/AbstractTlsClient.cs b/crypto/src/crypto/tls/AbstractTlsClient.cs
index 9484afa7d..9944b0b18 100644
--- a/crypto/src/crypto/tls/AbstractTlsClient.cs
+++ b/crypto/src/crypto/tls/AbstractTlsClient.cs
@@ -67,6 +67,16 @@ namespace Org.BouncyCastle.Crypto.Tls
             get { return ProtocolVersion.TLSv12; }
         }
 
+        public virtual bool IsFallback
+        {
+            /*
+             * draft-bmoeller-tls-downgrade-scsv-02 4. [..] is meant for use by clients that repeat a
+             * connection attempt with a downgraded protocol in order to avoid interoperability problems
+             * with legacy servers.
+             */
+            get { return false; }
+        }
+
         public virtual IDictionary GetClientExtensions()
         {
             IDictionary clientExtensions = null;
diff --git a/crypto/src/crypto/tls/AbstractTlsServer.cs b/crypto/src/crypto/tls/AbstractTlsServer.cs
index c2c6fd57c..6cd9a881e 100644
--- a/crypto/src/crypto/tls/AbstractTlsServer.cs
+++ b/crypto/src/crypto/tls/AbstractTlsServer.cs
@@ -110,6 +110,18 @@ namespace Org.BouncyCastle.Crypto.Tls
             this.mClientVersion = clientVersion;
         }
 
+        public virtual void NotifyFallback(bool isFallback)
+        {
+            /*
+             * draft-bmoeller-tls-downgrade-scsv-02 3. If TLS_FALLBACK_SCSV appears in
+             * ClientHello.cipher_suites and the highest protocol version supported by the server is
+             * higher than the version indicated in ClientHello.client_version, the server MUST respond
+             * with an inappropriate_fallback alert.
+             */
+            if (isFallback && MaximumVersion.IsLaterVersionOf(mClientVersion))
+                throw new TlsFatalAlert(AlertDescription.inappropriate_fallback);
+        }
+
         public virtual void NotifyOfferedCipherSuites(int[] offeredCipherSuites)
         {
             this.mOfferedCipherSuites = offeredCipherSuites;
diff --git a/crypto/src/crypto/tls/AlertDescription.cs b/crypto/src/crypto/tls/AlertDescription.cs
index 5b6e88bf7..ab6924567 100644
--- a/crypto/src/crypto/tls/AlertDescription.cs
+++ b/crypto/src/crypto/tls/AlertDescription.cs
@@ -214,6 +214,17 @@ namespace Org.BouncyCastle.Crypto.Tls
          */
         public const byte unknown_psk_identity = 115;
 
+        /*
+         * draft-bmoeller-tls-downgrade-scsv-02
+         */
+
+        /**
+         * If TLS_FALLBACK_SCSV appears in ClientHello.cipher_suites and the highest protocol version
+         * supported by the server is higher than the version indicated in ClientHello.client_version,
+         * the server MUST respond with an inappropriate_fallback alert.
+         */
+        public const byte inappropriate_fallback = 86;
+
         public static string GetName(byte alertDescription)
         {
             switch (alertDescription)
@@ -278,6 +289,8 @@ namespace Org.BouncyCastle.Crypto.Tls
                 return "bad_certificate_hash_value";
             case unknown_psk_identity:
                 return "unknown_psk_identity";
+            case inappropriate_fallback:
+                return "inappropriate_fallback";
             default:
                 return "UNKNOWN";
             }
diff --git a/crypto/src/crypto/tls/CipherSuite.cs b/crypto/src/crypto/tls/CipherSuite.cs
index f034ab802..540b5d18d 100644
--- a/crypto/src/crypto/tls/CipherSuite.cs
+++ b/crypto/src/crypto/tls/CipherSuite.cs
@@ -348,5 +348,22 @@ namespace Org.BouncyCastle.Crypto.Tls
         public const int TLS_DHE_PSK_WITH_SALSA20_SHA1 = 0xE41D;
         public const int TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE41E;
         public const int TLS_DHE_RSA_WITH_SALSA20_SHA1 = 0xE41F;
+
+        /*
+         * draft-bmoeller-tls-downgrade-scsv-02
+         */
+        public const int TLS_FALLBACK_SCSV = 0x5600;
+
+        public static bool IsScsv(int cipherSuite)
+        {
+            switch (cipherSuite)
+            {
+            case TLS_EMPTY_RENEGOTIATION_INFO_SCSV:
+            case TLS_FALLBACK_SCSV:
+                return true;
+            default:
+                return false;
+            }
+        }
     }
 }
diff --git a/crypto/src/crypto/tls/TlsClient.cs b/crypto/src/crypto/tls/TlsClient.cs
index cd5dfad13..116f6a779 100644
--- a/crypto/src/crypto/tls/TlsClient.cs
+++ b/crypto/src/crypto/tls/TlsClient.cs
@@ -27,6 +27,8 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         ProtocolVersion ClientVersion { get; }
 
+        bool IsFallback { get; }
+
         /// <summary>
         /// Get the list of cipher suites that this client supports.
         /// </summary>
diff --git a/crypto/src/crypto/tls/TlsClientProtocol.cs b/crypto/src/crypto/tls/TlsClientProtocol.cs
index 9fe50add8..ea8a1b2e4 100644
--- a/crypto/src/crypto/tls/TlsClientProtocol.cs
+++ b/crypto/src/crypto/tls/TlsClientProtocol.cs
@@ -607,7 +607,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             int selectedCipherSuite = TlsUtilities.ReadUint16(buf);
             if (!Arrays.Contains(this.mOfferedCipherSuites, selectedCipherSuite)
                 || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
-                || selectedCipherSuite == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+                || CipherSuite.IsScsv(selectedCipherSuite)
                 || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, server_version))
             {
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
@@ -815,6 +815,8 @@ namespace Org.BouncyCastle.Crypto.Tls
                 }
             }
 
+            bool fallback = this.mTlsClient.IsFallback;
+
             this.mOfferedCipherSuites = this.mTlsClient.GetCipherSuites();
 
             this.mOfferedCompressionMethods = this.mTlsClient.GetCompressionMethods();
@@ -850,9 +852,9 @@ namespace Org.BouncyCastle.Crypto.Tls
                 byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
                 bool noRenegExt = (null == renegExtData);
 
-                bool noSCSV = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
+                bool noRenegScsv = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
 
-                if (noRenegExt && noSCSV)
+                if (noRenegExt && noRenegScsv)
                 {
                     // TODO Consider whether to default to a client extension instead
     //                this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mClientExtensions);
@@ -860,6 +862,17 @@ namespace Org.BouncyCastle.Crypto.Tls
                     this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
                 }
 
+                /*
+                 * draft-bmoeller-tls-downgrade-scsv-02 4. If a client sends a
+                 * ClientHello.client_version containing a lower value than the latest (highest-valued)
+                 * version supported by the client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite
+                 * value in ClientHello.cipher_suites.
+                 */
+                if (fallback && !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
+                {
+                    this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
+                }
+
                 TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, message);
             }
 
diff --git a/crypto/src/crypto/tls/TlsServer.cs b/crypto/src/crypto/tls/TlsServer.cs
index 93e62b9ac..e791f93a9 100644
--- a/crypto/src/crypto/tls/TlsServer.cs
+++ b/crypto/src/crypto/tls/TlsServer.cs
@@ -13,6 +13,9 @@ namespace Org.BouncyCastle.Crypto.Tls
         void NotifyClientVersion(ProtocolVersion clientVersion);
 
         /// <exception cref="IOException"></exception>
+        void NotifyFallback(bool isFallback);
+
+        /// <exception cref="IOException"></exception>
         void NotifyOfferedCipherSuites(int[] offeredCipherSuites);
 
         /// <exception cref="IOException"></exception>
diff --git a/crypto/src/crypto/tls/TlsServerProtocol.cs b/crypto/src/crypto/tls/TlsServerProtocol.cs
index 165d6a147..b1fb830b6 100644
--- a/crypto/src/crypto/tls/TlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/TlsServerProtocol.cs
@@ -453,6 +453,8 @@ namespace Org.BouncyCastle.Crypto.Tls
         protected virtual void ReceiveClientHelloMessage(MemoryStream buf)
         {
             ProtocolVersion client_version = TlsUtilities.ReadVersion(buf);
+            mRecordStream.SetWriteVersion(client_version);
+
             if (client_version.IsDtls)
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
 
@@ -499,6 +501,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             ContextAdmin.SetClientVersion(client_version);
 
             mTlsServer.NotifyClientVersion(client_version);
+            mTlsServer.NotifyFallback(Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV));
 
             mSecurityParameters.clientRandom = client_random;
 
@@ -626,7 +629,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             int selectedCipherSuite = mTlsServer.GetSelectedCipherSuite();
             if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite)
                 || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
-                || selectedCipherSuite == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+                || CipherSuite.IsScsv(selectedCipherSuite)
                 || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, server_version))
             {
                 throw new TlsFatalAlert(AlertDescription.internal_error);