summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Hook <dgh@cryptoworkshop.com>2022-03-23 13:24:15 +1100
committerDavid Hook <dgh@cryptoworkshop.com>2022-03-23 13:24:15 +1100
commitfbd1138e762589b0b5b754b225660f912aa0d2f2 (patch)
tree780bba5af2f988ac6e8cd59b88160e9768111372
parentfixed case of IV to upper github #353 (diff)
parentRefactoring (diff)
downloadBouncyCastle.NET-ed25519-fbd1138e762589b0b5b754b225660f912aa0d2f2.tar.xz
Merge remote-tracking branch 'refs/remotes/origin/master'
-rw-r--r--crypto/BouncyCastle.Android.csproj1
-rw-r--r--crypto/BouncyCastle.csproj1
-rw-r--r--crypto/BouncyCastle.iOS.csproj1
-rw-r--r--crypto/crypto.csproj5
-rw-r--r--crypto/src/tls/CertificateCompressionAlgorithm.cs47
-rw-r--r--crypto/src/tls/DeferredHash.cs41
-rw-r--r--crypto/src/tls/DigestInputBuffer.cs2
-rw-r--r--crypto/src/tls/DtlsReliableHandshake.cs183
-rw-r--r--crypto/src/tls/DtlsServerProtocol.cs13
-rw-r--r--crypto/src/tls/ExtensionType.cs8
-rw-r--r--crypto/src/tls/HandshakeType.cs8
-rw-r--r--crypto/src/tls/TlsClientProtocol.cs4
-rw-r--r--crypto/src/tls/TlsExtensionsUtilities.cs32
-rw-r--r--crypto/src/tls/TlsHandshakeHash.cs2
-rw-r--r--crypto/src/tls/TlsServerProtocol.cs6
-rw-r--r--crypto/src/tls/TlsUtilities.cs38
-rw-r--r--crypto/src/tls/crypto/TlsCryptoUtilities.cs18
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.cs2
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs20
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsDH.cs4
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsDHDomain.cs28
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsECDomain.cs20
22 files changed, 335 insertions, 149 deletions
diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj
index 875c99cfe..3d84af346 100644
--- a/crypto/BouncyCastle.Android.csproj
+++ b/crypto/BouncyCastle.Android.csproj
@@ -1602,6 +1602,7 @@
     <Compile Include="src\tls\CachedInformationType.cs" />
     <Compile Include="src\tls\CertChainType.cs" />
     <Compile Include="src\tls\Certificate.cs" />
+    <Compile Include="src\tls\CertificateCompressionAlgorithm.cs" />
     <Compile Include="src\tls\CertificateEntry.cs" />
     <Compile Include="src\tls\CertificateRequest.cs" />
     <Compile Include="src\tls\CertificateStatus.cs" />
diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj
index f7083b062..84d7bf6fc 100644
--- a/crypto/BouncyCastle.csproj
+++ b/crypto/BouncyCastle.csproj
@@ -1596,6 +1596,7 @@
     <Compile Include="src\tls\CachedInformationType.cs" />
     <Compile Include="src\tls\CertChainType.cs" />
     <Compile Include="src\tls\Certificate.cs" />
+    <Compile Include="src\tls\CertificateCompressionAlgorithm.cs" />
     <Compile Include="src\tls\CertificateEntry.cs" />
     <Compile Include="src\tls\CertificateRequest.cs" />
     <Compile Include="src\tls\CertificateStatus.cs" />
diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj
index 4490f0f07..d76444e71 100644
--- a/crypto/BouncyCastle.iOS.csproj
+++ b/crypto/BouncyCastle.iOS.csproj
@@ -1597,6 +1597,7 @@
     <Compile Include="src\tls\CachedInformationType.cs" />
     <Compile Include="src\tls\CertChainType.cs" />
     <Compile Include="src\tls\Certificate.cs" />
+    <Compile Include="src\tls\CertificateCompressionAlgorithm.cs" />
     <Compile Include="src\tls\CertificateEntry.cs" />
     <Compile Include="src\tls\CertificateRequest.cs" />
     <Compile Include="src\tls\CertificateStatus.cs" />
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index d3666bfcf..092331032 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -7869,6 +7869,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\tls\CertificateCompressionAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\tls\CertificateEntry.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/tls/CertificateCompressionAlgorithm.cs b/crypto/src/tls/CertificateCompressionAlgorithm.cs
new file mode 100644
index 000000000..4b6ebdadc
--- /dev/null
+++ b/crypto/src/tls/CertificateCompressionAlgorithm.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Tls
+{
+    /**
+     * RFC 8879
+     */
+    public abstract class CertificateCompressionAlgorithm
+    {
+        public const int zlib = 1;
+        public const int brotli = 2;
+        public const int zstd = 3;
+
+        public static string GetName(int certificateCompressionAlgorithm)
+        {
+            switch (certificateCompressionAlgorithm)
+            {
+            case zlib:
+                return "zlib";
+            case brotli:
+                return "brotli";
+            case zstd:
+                return "zstd";
+            default:
+                return "UNKNOWN";
+            }
+        }
+
+        public static string GetText(int certificateCompressionAlgorithm)
+        {
+            return GetName(certificateCompressionAlgorithm) + "(" + certificateCompressionAlgorithm + ")";
+        }
+
+        public static bool IsRecognized(int certificateCompressionAlgorithm)
+        {
+            switch (certificateCompressionAlgorithm)
+            {
+            case zlib:
+            case brotli:
+            case zstd:
+                return true;
+            default:
+                return false;
+            }
+        }
+    }
+}
diff --git a/crypto/src/tls/DeferredHash.cs b/crypto/src/tls/DeferredHash.cs
index bba3019a1..ac66c8f0c 100644
--- a/crypto/src/tls/DeferredHash.cs
+++ b/crypto/src/tls/DeferredHash.cs
@@ -16,7 +16,7 @@ namespace Org.BouncyCastle.Tls
         private readonly TlsContext m_context;
 
         private DigestInputBuffer m_buf;
-        private readonly IDictionary m_hashes;
+        private IDictionary m_hashes;
         private bool m_forceBuffering;
         private bool m_sealed;
 
@@ -29,25 +29,16 @@ namespace Org.BouncyCastle.Tls
             this.m_sealed = false;
         }
 
-        private DeferredHash(TlsContext context, IDictionary hashes)
-        {
-            this.m_context = context;
-            this.m_buf = null;
-            this.m_hashes = hashes;
-            this.m_forceBuffering = false;
-            this.m_sealed = true;
-        }
-
         /// <exception cref="IOException"/>
         public void CopyBufferTo(Stream output)
         {
             if (m_buf == null)
             {
-                // If you see this, you need to call forceBuffering() before SealHashAlgorithms()
+                // If you see this, you need to call ForceBuffering() before SealHashAlgorithms()
                 throw new InvalidOperationException("Not buffering");
             }
 
-            m_buf.CopyTo(output);
+            m_buf.CopyInputTo(output);
         }
 
         public void ForceBuffering()
@@ -96,7 +87,7 @@ namespace Org.BouncyCastle.Tls
             CheckStopBuffering();
         }
 
-        public TlsHandshakeHash StopTracking()
+        public void StopTracking()
         {
             SecurityParameters securityParameters = m_context.SecurityParameters;
 
@@ -106,8 +97,8 @@ namespace Org.BouncyCastle.Tls
             case PrfAlgorithm.ssl_prf_legacy:
             case PrfAlgorithm.tls_prf_legacy:
             {
-                CloneHash(newHashes, HashAlgorithm.md5);
-                CloneHash(newHashes, HashAlgorithm.sha1);
+                CloneHash(newHashes, CryptoHashAlgorithm.md5);
+                CloneHash(newHashes, CryptoHashAlgorithm.sha1);
                 break;
             }
             default:
@@ -116,7 +107,11 @@ namespace Org.BouncyCastle.Tls
                 break;
             }
             }
-            return new DeferredHash(m_context, newHashes);
+
+            this.m_buf = null;
+            this.m_hashes = newHashes;
+            this.m_forceBuffering = false;
+            this.m_sealed = true;
         }
 
         public TlsHash ForkPrfHash()
@@ -131,7 +126,9 @@ namespace Org.BouncyCastle.Tls
             case PrfAlgorithm.ssl_prf_legacy:
             case PrfAlgorithm.tls_prf_legacy:
             {
-                prfHash = new CombinedHash(m_context, CloneHash(HashAlgorithm.md5), CloneHash(HashAlgorithm.sha1));
+                TlsHash md5Hash = CloneHash(CryptoHashAlgorithm.md5);
+                TlsHash sha1Hash = CloneHash(CryptoHashAlgorithm.sha1);
+                prfHash = new CombinedHash(m_context, md5Hash, sha1Hash);
                 break;
             }
             default:
@@ -151,20 +148,20 @@ namespace Org.BouncyCastle.Tls
 
         public byte[] GetFinalHash(int cryptoHashAlgorithm)
         {
-            TlsHash d = (TlsHash)m_hashes[cryptoHashAlgorithm];
-            if (d == null)
+            TlsHash hash = (TlsHash)m_hashes[cryptoHashAlgorithm];
+            if (hash == null)
                 throw new InvalidOperationException("CryptoHashAlgorithm." + cryptoHashAlgorithm
                     + " is not being tracked");
 
             CheckStopBuffering();
 
-            d = d.CloneHash();
+            hash = hash.CloneHash();
             if (m_buf != null)
             {
-                m_buf.UpdateDigest(d);
+                m_buf.UpdateDigest(hash);
             }
 
-            return d.CalculateHash();
+            return hash.CalculateHash();
         }
 
         public void Update(byte[] input, int inOff, int len)
diff --git a/crypto/src/tls/DigestInputBuffer.cs b/crypto/src/tls/DigestInputBuffer.cs
index 7dd525f88..9b4ea4b06 100644
--- a/crypto/src/tls/DigestInputBuffer.cs
+++ b/crypto/src/tls/DigestInputBuffer.cs
@@ -15,7 +15,7 @@ namespace Org.BouncyCastle.Tls
         }
 
         /// <exception cref="IOException"/>
-        internal void CopyTo(Stream output)
+        internal void CopyInputTo(Stream output)
         {
             // TODO[tls-port]
             // NOTE: Copy data since the output here may be under control of external code.
diff --git a/crypto/src/tls/DtlsReliableHandshake.cs b/crypto/src/tls/DtlsReliableHandshake.cs
index e27d72762..7581e4766 100644
--- a/crypto/src/tls/DtlsReliableHandshake.cs
+++ b/crypto/src/tls/DtlsReliableHandshake.cs
@@ -142,11 +142,9 @@ namespace Org.BouncyCastle.Tls
             get { return m_handshakeHash; }
         }
 
-        internal TlsHandshakeHash PrepareToFinish()
+        internal void PrepareToFinish()
         {
-            TlsHandshakeHash result = m_handshakeHash;
-            this.m_handshakeHash = m_handshakeHash.StopTracking();
-            return result;
+            m_handshakeHash.StopTracking();
         }
 
         /// <exception cref="IOException"/>
@@ -173,68 +171,60 @@ namespace Org.BouncyCastle.Tls
         }
 
         /// <exception cref="IOException"/>
+        internal Message ReceiveMessage()
+        {
+            Message message = ImplReceiveMessage();
+            UpdateHandshakeMessagesDigest(message);
+            return message;
+        }
+
+        /// <exception cref="IOException"/>
         internal byte[] ReceiveMessageBody(short msg_type)
         {
-            Message message = ReceiveMessage();
+            Message message = ImplReceiveMessage();
             if (message.Type != msg_type)
                 throw new TlsFatalAlert(AlertDescription.unexpected_message);
 
+            UpdateHandshakeMessagesDigest(message);
             return message.Body;
         }
 
         /// <exception cref="IOException"/>
-        internal Message ReceiveMessage()
+        internal Message ReceiveMessageDelayedDigest(short msg_type)
         {
-            long currentTimeMillis = DateTimeUtilities.CurrentUnixMs();
-
-            if (null == m_resendTimeout)
-            {
-                m_resendMillis = INITIAL_RESEND_MILLIS;
-                m_resendTimeout = new Timeout(m_resendMillis, currentTimeMillis);
-
-                PrepareInboundFlight(Platform.CreateHashtable());
-            }
+            Message message = ImplReceiveMessage();
+            if (message.Type != msg_type)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
 
-            byte[] buf = null;
+            return message;
+        }
 
-            for (;;)
+        /// <exception cref="IOException"/>
+        internal void UpdateHandshakeMessagesDigest(Message message)
+        {
+            short msg_type = message.Type;
+            switch (msg_type)
             {
-                if (m_recordLayer.IsClosed)
-                    throw new TlsFatalAlert(AlertDescription.user_canceled);
-
-                Message pending = GetPendingMessage();
-                if (pending != null)
-                    return pending;
-
-                if (Timeout.HasExpired(m_handshakeTimeout, currentTimeMillis))
-                    throw new TlsTimeoutException("Handshake timed out");
-
-                int waitMillis = Timeout.GetWaitMillis(m_handshakeTimeout, currentTimeMillis);
-                waitMillis = Timeout.ConstrainWaitMillis(waitMillis, m_resendTimeout, currentTimeMillis);
-
-                // NOTE: Ensure a finite wait, of at least 1ms
-                if (waitMillis < 1)
-                {
-                    waitMillis = 1;
-                }
-
-                int receiveLimit = m_recordLayer.GetReceiveLimit();
-                if (buf == null || buf.Length < receiveLimit)
-                {
-                    buf = new byte[receiveLimit];
-                }
-
-                int received = m_recordLayer.Receive(buf, 0, receiveLimit, waitMillis);
-                if (received < 0)
-                {
-                    ResendOutboundFlight();
-                }
-                else
-                {
-                    ProcessRecord(MAX_RECEIVE_AHEAD, m_recordLayer.ReadEpoch, buf, 0, received);
-                }
+            case HandshakeType.hello_request:
+            case HandshakeType.hello_verify_request:
+            case HandshakeType.key_update:
+                break;
 
-                currentTimeMillis = DateTimeUtilities.CurrentUnixMs();
+            // TODO[dtls13] Not included in the transcript for (D)TLS 1.3+
+            case HandshakeType.new_session_ticket:
+            default:
+            {
+                byte[] body = message.Body;
+                byte[] buf = new byte[MESSAGE_HEADER_LENGTH];
+                TlsUtilities.WriteUint8(msg_type, buf, 0);
+                TlsUtilities.WriteUint24(body.Length, buf, 1);
+                TlsUtilities.WriteUint16(message.Seq, buf, 4);
+                TlsUtilities.WriteUint24(0, buf, 6);
+                TlsUtilities.WriteUint24(body.Length, buf, 9);
+                m_handshakeHash.Update(buf, 0, buf.Length);
+                m_handshakeHash.Update(body, 0, body.Length);
+                break;
+            }
             }
         }
 
@@ -297,12 +287,68 @@ namespace Org.BouncyCastle.Tls
                 if (body != null)
                 {
                     m_previousInboundFlight = null;
-                    return UpdateHandshakeMessagesDigest(new Message(m_next_receive_seq++, next.MsgType, body));
+                    return new Message(m_next_receive_seq++, next.MsgType, body);
                 }
             }
             return null;
         }
 
+        /// <exception cref="IOException"/>
+        private Message ImplReceiveMessage()
+        {
+            long currentTimeMillis = DateTimeUtilities.CurrentUnixMs();
+
+            if (null == m_resendTimeout)
+            {
+                m_resendMillis = INITIAL_RESEND_MILLIS;
+                m_resendTimeout = new Timeout(m_resendMillis, currentTimeMillis);
+
+                PrepareInboundFlight(Platform.CreateHashtable());
+            }
+
+            byte[] buf = null;
+
+            for (;;)
+            {
+                if (m_recordLayer.IsClosed)
+                    throw new TlsFatalAlert(AlertDescription.user_canceled);
+
+                Message pending = GetPendingMessage();
+                if (pending != null)
+                    return pending;
+
+                if (Timeout.HasExpired(m_handshakeTimeout, currentTimeMillis))
+                    throw new TlsTimeoutException("Handshake timed out");
+
+                int waitMillis = Timeout.GetWaitMillis(m_handshakeTimeout, currentTimeMillis);
+                waitMillis = Timeout.ConstrainWaitMillis(waitMillis, m_resendTimeout, currentTimeMillis);
+
+                // NOTE: Ensure a finite wait, of at least 1ms
+                if (waitMillis < 1)
+                {
+                    waitMillis = 1;
+                }
+
+                int receiveLimit = m_recordLayer.GetReceiveLimit();
+                if (buf == null || buf.Length < receiveLimit)
+                {
+                    buf = new byte[receiveLimit];
+                }
+
+                int received = m_recordLayer.Receive(buf, 0, receiveLimit, waitMillis);
+                if (received < 0)
+                {
+                    ResendOutboundFlight();
+                }
+                else
+                {
+                    ProcessRecord(MAX_RECEIVE_AHEAD, m_recordLayer.ReadEpoch, buf, 0, received);
+                }
+
+                currentTimeMillis = DateTimeUtilities.CurrentUnixMs();
+            }
+        }
+
         private void PrepareInboundFlight(IDictionary nextFlight)
         {
             ResetAll(m_currentInboundFlight);
@@ -400,37 +446,6 @@ namespace Org.BouncyCastle.Tls
         }
 
         /// <exception cref="IOException"/>
-        private Message UpdateHandshakeMessagesDigest(Message message)
-        {
-            short msg_type = message.Type;
-            switch (msg_type)
-            {
-            case HandshakeType.hello_request:
-            case HandshakeType.hello_verify_request:
-            case HandshakeType.key_update:
-                break;
-
-            // TODO[dtls13] Not included in the transcript for (D)TLS 1.3+
-            case HandshakeType.new_session_ticket:
-            default:
-            {
-                byte[] body = message.Body;
-                byte[] buf = new byte[MESSAGE_HEADER_LENGTH];
-                TlsUtilities.WriteUint8(msg_type, buf, 0);
-                TlsUtilities.WriteUint24(body.Length, buf, 1);
-                TlsUtilities.WriteUint16(message.Seq, buf, 4);
-                TlsUtilities.WriteUint24(0, buf, 6);
-                TlsUtilities.WriteUint24(body.Length, buf, 9);
-                m_handshakeHash.Update(buf, 0, buf.Length);
-                m_handshakeHash.Update(body, 0, body.Length);
-                break;
-            }
-            }
-
-            return message;
-        }
-
-        /// <exception cref="IOException"/>
         private void WriteMessage(Message message)
         {
             int sendLimit = m_recordLayer.GetSendLimit();
diff --git a/crypto/src/tls/DtlsServerProtocol.cs b/crypto/src/tls/DtlsServerProtocol.cs
index 99c47ba1b..b49122423 100644
--- a/crypto/src/tls/DtlsServerProtocol.cs
+++ b/crypto/src/tls/DtlsServerProtocol.cs
@@ -297,12 +297,17 @@ namespace Org.BouncyCastle.Tls
              * parameters).
              */
             {
-                TlsHandshakeHash certificateVerifyHash = handshake.PrepareToFinish();
-
                 if (ExpectCertificateVerifyMessage(state))
                 {
-                    byte[] certificateVerifyBody = handshake.ReceiveMessageBody(HandshakeType.certificate_verify);
-                    ProcessCertificateVerify(state, certificateVerifyBody, certificateVerifyHash);
+                    clientMessage = handshake.ReceiveMessageDelayedDigest(HandshakeType.certificate_verify);
+                    byte[] certificateVerifyBody = clientMessage.Body;
+                    ProcessCertificateVerify(state, certificateVerifyBody, handshake.HandshakeHash);
+                    handshake.PrepareToFinish();
+                    handshake.UpdateHandshakeMessagesDigest(clientMessage);
+                }
+                else
+                {
+                    handshake.PrepareToFinish();
                 }
             }
 
diff --git a/crypto/src/tls/ExtensionType.cs b/crypto/src/tls/ExtensionType.cs
index 87f6a7574..a1f1fa7e8 100644
--- a/crypto/src/tls/ExtensionType.cs
+++ b/crypto/src/tls/ExtensionType.cs
@@ -107,6 +107,11 @@ namespace Org.BouncyCastle.Tls
         public const int cached_info = 25;
 
         /*
+         * RFC 8879
+         */
+        public const int compress_certificate = 27;
+
+        /*
          * RFC 8449
          */
         public const int record_size_limit = 28;
@@ -191,6 +196,8 @@ namespace Org.BouncyCastle.Tls
                 return "token_binding";
             case cached_info:
                 return "cached_info";
+            case compress_certificate:
+                return "compress_certificate";
             case record_size_limit:
                 return "record_size_limit";
             case session_ticket:
@@ -257,6 +264,7 @@ namespace Org.BouncyCastle.Tls
             case extended_master_secret:
             case token_binding:
             case cached_info:
+            case compress_certificate:
             case record_size_limit:
             case session_ticket:
             case pre_shared_key:
diff --git a/crypto/src/tls/HandshakeType.cs b/crypto/src/tls/HandshakeType.cs
index 563cd1150..ad2c29c07 100644
--- a/crypto/src/tls/HandshakeType.cs
+++ b/crypto/src/tls/HandshakeType.cs
@@ -44,6 +44,11 @@ namespace Org.BouncyCastle.Tls
         public const short key_update = 24;
         public const short message_hash = 254;
 
+        /*
+         * RFC 8879
+         */
+        public const short compressed_certificate = 25;
+
         public static string GetName(short handshakeType)
         {
             switch (handshakeType)
@@ -88,6 +93,8 @@ namespace Org.BouncyCastle.Tls
                 return "key_update";
             case message_hash:
                 return "message_hash";
+            case compressed_certificate:
+                return "compressed_certificate";
             default:
                 return "UNKNOWN";
             }
@@ -122,6 +129,7 @@ namespace Org.BouncyCastle.Tls
             case encrypted_extensions:
             case key_update:
             case message_hash:
+            case compressed_certificate:
                 return true;
             default:
                 return false;
diff --git a/crypto/src/tls/TlsClientProtocol.cs b/crypto/src/tls/TlsClientProtocol.cs
index c132b257b..cb59289ae 100644
--- a/crypto/src/tls/TlsClientProtocol.cs
+++ b/crypto/src/tls/TlsClientProtocol.cs
@@ -315,6 +315,7 @@ namespace Org.BouncyCastle.Tls
             case HandshakeType.certificate_url:
             case HandshakeType.client_hello:
             case HandshakeType.client_key_exchange:
+            case HandshakeType.compressed_certificate:
             case HandshakeType.end_of_early_data:
             case HandshakeType.hello_request:
             case HandshakeType.hello_verify_request:
@@ -608,7 +609,7 @@ namespace Org.BouncyCastle.Tls
                         this.m_connectionState = CS_CLIENT_CERTIFICATE_VERIFY;
                     }
 
-                    this.m_handshakeHash = m_handshakeHash.StopTracking();
+                    m_handshakeHash.StopTracking();
 
                     SendChangeCipherSpec();
                     SendFinishedMessage();
@@ -743,6 +744,7 @@ namespace Org.BouncyCastle.Tls
             case HandshakeType.certificate_verify:
             case HandshakeType.client_hello:
             case HandshakeType.client_key_exchange:
+            case HandshakeType.compressed_certificate:
             case HandshakeType.encrypted_extensions:
             case HandshakeType.end_of_early_data:
             case HandshakeType.hello_verify_request:
diff --git a/crypto/src/tls/TlsExtensionsUtilities.cs b/crypto/src/tls/TlsExtensionsUtilities.cs
index 5a13d8d2e..e1db93016 100644
--- a/crypto/src/tls/TlsExtensionsUtilities.cs
+++ b/crypto/src/tls/TlsExtensionsUtilities.cs
@@ -53,6 +53,12 @@ namespace Org.BouncyCastle.Tls
         }
 
         /// <exception cref="IOException"/>
+        public static void AddCompressCertificateExtension(IDictionary extensions, int[] algorithms)
+        {
+            extensions[ExtensionType.compress_certificate] = CreateCompressCertificateExtension(algorithms);
+        }
+
+        /// <exception cref="IOException"/>
         public static void AddCookieExtension(IDictionary extensions, byte[] cookie)
         {
             extensions[ExtensionType.cookie] = CreateCookieExtension(cookie);
@@ -280,6 +286,13 @@ namespace Org.BouncyCastle.Tls
         }
 
         /// <exception cref="IOException"/>
+        public static int[] GetCompressCertificateExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.compress_certificate);
+            return extensionData == null ? null : ReadCompressCertificateExtension(extensionData);
+        }
+
+        /// <exception cref="IOException"/>
         public static byte[] GetCookieExtension(IDictionary extensions)
         {
             byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.cookie);
@@ -580,6 +593,15 @@ namespace Org.BouncyCastle.Tls
         }
 
         /// <exception cref="IOException"/>
+        public static byte[] CreateCompressCertificateExtension(int[] algorithms)
+        {
+            if (TlsUtilities.IsNullOrEmpty(algorithms) || algorithms.Length > 127)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            return TlsUtilities.EncodeUint16ArrayWithUint8Length(algorithms);
+        }
+
+        /// <exception cref="IOException"/>
         public static byte[] CreateCookieExtension(byte[] cookie)
         {
             if (TlsUtilities.IsNullOrEmpty(cookie) || cookie.Length >= (1 << 16))
@@ -995,6 +1017,16 @@ namespace Org.BouncyCastle.Tls
         }
 
         /// <exception cref="IOException"/>
+        public static int[] ReadCompressCertificateExtension(byte[] extensionData)
+        {
+            int[] algorithms = TlsUtilities.DecodeUint16ArrayWithUint8Length(extensionData);
+            if (algorithms.Length < 1)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            return algorithms;
+        }
+
+        /// <exception cref="IOException"/>
         public static byte[] ReadCookieExtension(byte[] extensionData)
         {
             return TlsUtilities.DecodeOpaque16(extensionData, 1);
diff --git a/crypto/src/tls/TlsHandshakeHash.cs b/crypto/src/tls/TlsHandshakeHash.cs
index aa33c680d..88aeaaa32 100644
--- a/crypto/src/tls/TlsHandshakeHash.cs
+++ b/crypto/src/tls/TlsHandshakeHash.cs
@@ -20,7 +20,7 @@ namespace Org.BouncyCastle.Tls
 
         void SealHashAlgorithms();
 
-        TlsHandshakeHash StopTracking();
+        void StopTracking();
 
         TlsHash ForkPrfHash();
 
diff --git a/crypto/src/tls/TlsServerProtocol.cs b/crypto/src/tls/TlsServerProtocol.cs
index 40218a2fb..0ab8a7a98 100644
--- a/crypto/src/tls/TlsServerProtocol.cs
+++ b/crypto/src/tls/TlsServerProtocol.cs
@@ -834,6 +834,7 @@ namespace Org.BouncyCastle.Tls
             case HandshakeType.certificate_status:
             case HandshakeType.certificate_url:
             case HandshakeType.client_key_exchange:
+            case HandshakeType.compressed_certificate:
             case HandshakeType.encrypted_extensions:
             case HandshakeType.end_of_early_data:
             case HandshakeType.hello_request:
@@ -1201,6 +1202,7 @@ namespace Org.BouncyCastle.Tls
             case HandshakeType.certificate_request:
             case HandshakeType.certificate_status:
             case HandshakeType.certificate_url:
+            case HandshakeType.compressed_certificate:
             case HandshakeType.encrypted_extensions:
             case HandshakeType.end_of_early_data:
             case HandshakeType.hello_request:
@@ -1320,7 +1322,7 @@ namespace Org.BouncyCastle.Tls
             TlsUtilities.VerifyCertificateVerifyClient(m_tlsServerContext, m_certificateRequest, certificateVerify,
                 m_handshakeHash);
 
-            this.m_handshakeHash = m_handshakeHash.StopTracking();
+            m_handshakeHash.StopTracking();
         }
 
         /// <exception cref="IOException"/>
@@ -1355,7 +1357,7 @@ namespace Org.BouncyCastle.Tls
 
             if (!ExpectCertificateVerifyMessage())
             {
-                this.m_handshakeHash = m_handshakeHash.StopTracking();
+                m_handshakeHash.StopTracking();
             }
         }
 
diff --git a/crypto/src/tls/TlsUtilities.cs b/crypto/src/tls/TlsUtilities.cs
index 8733fd68f..1d9759bca 100644
--- a/crypto/src/tls/TlsUtilities.cs
+++ b/crypto/src/tls/TlsUtilities.cs
@@ -486,6 +486,14 @@ namespace Org.BouncyCastle.Tls
             }
         }
 
+        public static void WriteUint16ArrayWithUint8Length(int[] u16s, byte[] buf, int offset)
+        {
+            int length = 2 * u16s.Length;
+            CheckUint8(length);
+            WriteUint8(length, buf, offset);
+            WriteUint16Array(u16s, buf, offset + 1);
+        }
+
         public static void WriteUint16ArrayWithUint16Length(int[] u16s, Stream output)
         {
             int length = 2 * u16s.Length;
@@ -577,6 +585,25 @@ namespace Org.BouncyCastle.Tls
             return ReadUint16(buf, 0);
         }
 
+        public static int[] DecodeUint16ArrayWithUint8Length(byte[] buf)
+        {
+            if (buf == null)
+                throw new ArgumentNullException("buf");
+
+            int length = ReadUint8(buf, 0);
+            if (buf.Length != (length + 1) || (length & 1) != 0)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            int count = length / 2, pos = 1;
+            int[] u16s = new int[count];
+            for (int i = 0; i < count; ++i)
+            {
+                u16s[i] = ReadUint16(buf, pos);
+                pos += 2;
+            }
+            return u16s;
+        }
+
         public static long DecodeUint32(byte[] buf)
         {
             if (buf == null)
@@ -636,6 +663,14 @@ namespace Org.BouncyCastle.Tls
             return encoding;
         }
 
+        public static byte[] EncodeUint16ArrayWithUint8Length(int[] u16s)
+        {
+            int length = 2 * u16s.Length;
+            byte[] result = new byte[1 + length];
+            WriteUint16ArrayWithUint8Length(u16s, result, 0);
+            return result;
+        }
+
         public static byte[] EncodeUint16ArrayWithUint16Length(int[] u16s)
         {
             int length = 2 * u16s.Length;
@@ -2083,7 +2118,7 @@ namespace Org.BouncyCastle.Tls
                 output.Write(extraSignatureInput, 0, extraSignatureInput.Length);
             }
 
-            buf.CopyTo(output);
+            buf.CopyInputTo(output);
 
             Platform.Dispose(output);
         }
@@ -5348,6 +5383,7 @@ namespace Org.BouncyCastle.Tls
                 }
             }
             case ExtensionType.signature_algorithms:
+            case ExtensionType.compress_certificate:
             case ExtensionType.certificate_authorities:
             case ExtensionType.signature_algorithms_cert:
             {
diff --git a/crypto/src/tls/crypto/TlsCryptoUtilities.cs b/crypto/src/tls/crypto/TlsCryptoUtilities.cs
index a22049e5d..757eda1be 100644
--- a/crypto/src/tls/crypto/TlsCryptoUtilities.cs
+++ b/crypto/src/tls/crypto/TlsCryptoUtilities.cs
@@ -68,6 +68,24 @@ namespace Org.BouncyCastle.Tls.Crypto
             }
         }
 
+        public static int GetHashInternalSize(int cryptoHashAlgorithm)
+        {
+            switch (cryptoHashAlgorithm)
+            {
+            case CryptoHashAlgorithm.md5:
+            case CryptoHashAlgorithm.sha1:
+            case CryptoHashAlgorithm.sha224:
+            case CryptoHashAlgorithm.sha256:
+            case CryptoHashAlgorithm.sm3:
+                return 64;
+            case CryptoHashAlgorithm.sha384:
+            case CryptoHashAlgorithm.sha512:
+                return 128;
+            default:
+                throw new ArgumentException();
+            }
+        }
+
         public static int GetHashOutputSize(int cryptoHashAlgorithm)
         {
             switch (cryptoHashAlgorithm)
diff --git a/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.cs b/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.cs
index 15944cd89..863b96634 100644
--- a/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.cs
@@ -100,7 +100,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             {
                 BcTlsCertificate bcCert = BcTlsCertificate.Convert(m_crypto, peerCertificate);
                 ECPublicKeyParameters peerPublicKey = bcCert.GetPubKeyEC();
-                return BcTlsECDomain.CalculateBasicAgreement(m_crypto, m_privateKey, peerPublicKey);
+                return BcTlsECDomain.CalculateECDHAgreement(m_crypto, m_privateKey, peerPublicKey);
             }
 
             public Certificate Certificate
diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs b/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs
index 69e353bae..e763422ed 100644
--- a/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs
@@ -139,9 +139,10 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
 
         public override TlsNonceGenerator CreateNonceGenerator(byte[] additionalSeedMaterial)
         {
-            IDigest digest = CreateDigest(CryptoHashAlgorithm.sha256);
+            int cryptoHashAlgorithm = CryptoHashAlgorithm.sha256;
+            IDigest digest = CreateDigest(cryptoHashAlgorithm);
 
-            byte[] seed = new byte[digest.GetDigestSize()];
+            byte[] seed = new byte[TlsCryptoUtilities.GetHashOutputSize(cryptoHashAlgorithm)];
             SecureRandom.NextBytes(seed);
 
             DigestRandomGenerator randomGenerator = new DigestRandomGenerator(digest);
@@ -187,7 +188,20 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
 
         public override bool HasCryptoHashAlgorithm(int cryptoHashAlgorithm)
         {
-            return true;
+            switch (cryptoHashAlgorithm)
+            {
+            case CryptoHashAlgorithm.md5:
+            case CryptoHashAlgorithm.sha1:
+            case CryptoHashAlgorithm.sha224:
+            case CryptoHashAlgorithm.sha256:
+            case CryptoHashAlgorithm.sha384:
+            case CryptoHashAlgorithm.sha512:
+            case CryptoHashAlgorithm.sm3:
+                return true;
+
+            default:
+                return false;
+            }
         }
 
         public override bool HasCryptoSignatureAlgorithm(int cryptoSignatureAlgorithm)
diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsDH.cs b/crypto/src/tls/crypto/impl/bc/BcTlsDH.cs
index 8af94f7c6..63fa00ce4 100644
--- a/crypto/src/tls/crypto/impl/bc/BcTlsDH.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcTlsDH.cs
@@ -1,5 +1,4 @@
 using System;
-using System.IO;
 
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
@@ -20,7 +19,6 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             this.m_domain = domain;
         }
 
-        /// <exception cref="IOException"/>
         public virtual byte[] GenerateEphemeral()
         {
             this.m_localKeyPair = m_domain.GenerateKeyPair();
@@ -28,13 +26,11 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             return m_domain.EncodePublicKey((DHPublicKeyParameters)m_localKeyPair.Public);
         }
 
-        /// <exception cref="IOException"/>
         public virtual void ReceivePeerValue(byte[] peerValue)
         {
             this.m_peerPublicKey = m_domain.DecodePublicKey(peerValue);
         }
 
-        /// <exception cref="IOException"/>
         public virtual TlsSecret CalculateSecret()
         {
             return m_domain.CalculateDHAgreement((DHPrivateKeyParameters)m_localKeyPair.Private, m_peerPublicKey);
diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsDHDomain.cs b/crypto/src/tls/crypto/impl/bc/BcTlsDHDomain.cs
index 90b8ce94f..faf6b4576 100644
--- a/crypto/src/tls/crypto/impl/bc/BcTlsDHDomain.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcTlsDHDomain.cs
@@ -37,7 +37,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             return crypto.AdoptLocalSecret(secret);
         }
 
-        public static DHParameters GetParameters(TlsDHConfig dhConfig)
+        public static DHParameters GetDomainParameters(TlsDHConfig dhConfig)
         {
             DHGroup dhGroup = TlsDHUtilities.GetDHGroup(dhConfig);
             if (dhGroup == null)
@@ -46,21 +46,21 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             return new DHParameters(dhGroup.P, dhGroup.G, dhGroup.Q, dhGroup.L);
         }
 
-        protected readonly BcTlsCrypto crypto;
-        protected readonly TlsDHConfig dhConfig;
-        protected readonly DHParameters dhParameters;
+        protected readonly BcTlsCrypto m_crypto;
+        protected readonly TlsDHConfig m_config;
+        protected readonly DHParameters m_domainParameters;
 
         public BcTlsDHDomain(BcTlsCrypto crypto, TlsDHConfig dhConfig)
         {
-            this.crypto = crypto;
-            this.dhConfig = dhConfig;
-            this.dhParameters = GetParameters(dhConfig);
+            this.m_crypto = crypto;
+            this.m_config = dhConfig;
+            this.m_domainParameters = GetDomainParameters(dhConfig);
         }
 
         public virtual BcTlsSecret CalculateDHAgreement(DHPrivateKeyParameters privateKey,
             DHPublicKeyParameters publicKey)
         {
-            return CalculateDHAgreement(crypto, privateKey, publicKey, dhConfig.IsPadded);
+            return CalculateDHAgreement(m_crypto, privateKey, publicKey, m_config.IsPadded);
         }
 
         public virtual TlsAgreement CreateDH()
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
         /// <exception cref="IOException"/>
         public virtual BigInteger DecodeParameter(byte[] encoding)
         {
-            if (dhConfig.IsPadded && GetValueLength(dhParameters) != encoding.Length)
+            if (m_config.IsPadded && GetValueLength(m_domainParameters) != encoding.Length)
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
 
             return new BigInteger(1, encoding);
@@ -89,7 +89,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             {
                 BigInteger y = DecodeParameter(encoding);
 
-                return new DHPublicKeyParameters(y, dhParameters);
+                return new DHPublicKeyParameters(y, m_domainParameters);
             }
             catch (Exception e)
             {
@@ -97,22 +97,20 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             }
         }
 
-        /// <exception cref="IOException"/>
         public virtual byte[] EncodeParameter(BigInteger x)
         {
-            return EncodeValue(dhParameters, dhConfig.IsPadded, x);
+            return EncodeValue(m_domainParameters, m_config.IsPadded, x);
         }
 
-        /// <exception cref="IOException"/>
         public virtual byte[] EncodePublicKey(DHPublicKeyParameters publicKey)
         {
-            return EncodeValue(dhParameters, true, publicKey.Y);
+            return EncodeValue(m_domainParameters, true, publicKey.Y);
         }
 
         public virtual AsymmetricCipherKeyPair GenerateKeyPair()
         {
             DHBasicKeyPairGenerator keyPairGenerator = new DHBasicKeyPairGenerator();
-            keyPairGenerator.Init(new DHKeyGenerationParameters(crypto.SecureRandom, dhParameters));
+            keyPairGenerator.Init(new DHKeyGenerationParameters(m_crypto.SecureRandom, m_domainParameters));
             return keyPairGenerator.GenerateKeyPair();
         }
     }
diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsECDomain.cs b/crypto/src/tls/crypto/impl/bc/BcTlsECDomain.cs
index 61d11fb42..ab3481924 100644
--- a/crypto/src/tls/crypto/impl/bc/BcTlsECDomain.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcTlsECDomain.cs
@@ -4,7 +4,6 @@ using System.IO;
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Agreement;
-using Org.BouncyCastle.Crypto.EC;
 using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
@@ -19,7 +18,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
     public class BcTlsECDomain
         : TlsECDomain
     {
-        public static BcTlsSecret CalculateBasicAgreement(BcTlsCrypto crypto, ECPrivateKeyParameters privateKey,
+        public static BcTlsSecret CalculateECDHAgreement(BcTlsCrypto crypto, ECPrivateKeyParameters privateKey,
             ECPublicKeyParameters publicKey)
         {
             ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement();
@@ -57,20 +56,20 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
         }
 
         protected readonly BcTlsCrypto m_crypto;
-        protected readonly TlsECConfig m_ecConfig;
-        protected readonly ECDomainParameters m_ecDomainParameters;
+        protected readonly TlsECConfig m_config;
+        protected readonly ECDomainParameters m_domainParameters;
 
         public BcTlsECDomain(BcTlsCrypto crypto, TlsECConfig ecConfig)
         {
             this.m_crypto = crypto;
-            this.m_ecConfig = ecConfig;
-            this.m_ecDomainParameters = GetDomainParameters(ecConfig);
+            this.m_config = ecConfig;
+            this.m_domainParameters = GetDomainParameters(ecConfig);
         }
 
         public virtual BcTlsSecret CalculateECDHAgreement(ECPrivateKeyParameters privateKey,
             ECPublicKeyParameters publicKey)
         {
-            return CalculateBasicAgreement(m_crypto, privateKey, publicKey);
+            return CalculateECDHAgreement(m_crypto, privateKey, publicKey);
         }
 
         public virtual TlsAgreement CreateECDH()
@@ -80,16 +79,17 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
 
         public virtual ECPoint DecodePoint(byte[] encoding)
         {
-            return m_ecDomainParameters.Curve.DecodePoint(encoding);
+            return m_domainParameters.Curve.DecodePoint(encoding);
         }
 
+        /// <exception cref="IOException"/>
         public virtual ECPublicKeyParameters DecodePublicKey(byte[] encoding)
         {
             try
             {
                 ECPoint point = DecodePoint(encoding);
 
-                return new ECPublicKeyParameters(point, m_ecDomainParameters);
+                return new ECPublicKeyParameters(point, m_domainParameters);
             }
             catch (IOException e)
             {
@@ -114,7 +114,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
         public virtual AsymmetricCipherKeyPair GenerateKeyPair()
         {
             ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
-            keyPairGenerator.Init(new ECKeyGenerationParameters(m_ecDomainParameters, m_crypto.SecureRandom));
+            keyPairGenerator.Init(new ECKeyGenerationParameters(m_domainParameters, m_crypto.SecureRandom));
             return keyPairGenerator.GenerateKeyPair();
         }
     }