summary refs log tree commit diff
path: root/crypto/src/tls
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-05-10 12:54:22 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-05-10 12:54:22 +0700
commit217c08cdb0359f95c40f1a09e4e545a4552509fe (patch)
treebb6418fed2a682e42ea77a82cd2da6f3e923d929 /crypto/src/tls
parentAvoid duplicate call (diff)
downloadBouncyCastle.NET-ed25519-217c08cdb0359f95c40f1a09e4e545a4552509fe.tar.xz
Improve TLS handshake hash tracking
Diffstat (limited to 'crypto/src/tls')
-rw-r--r--crypto/src/tls/DtlsClientProtocol.cs110
-rw-r--r--crypto/src/tls/DtlsServerProtocol.cs29
-rw-r--r--crypto/src/tls/SignatureScheme.cs5
-rw-r--r--crypto/src/tls/TlsClientProtocol.cs115
-rw-r--r--crypto/src/tls/TlsServerProtocol.cs31
-rw-r--r--crypto/src/tls/TlsUtilities.cs116
6 files changed, 223 insertions, 183 deletions
diff --git a/crypto/src/tls/DtlsClientProtocol.cs b/crypto/src/tls/DtlsClientProtocol.cs
index 44f574e3a..dd273f3e7 100644
--- a/crypto/src/tls/DtlsClientProtocol.cs
+++ b/crypto/src/tls/DtlsClientProtocol.cs
@@ -137,6 +137,10 @@ namespace Org.BouncyCastle.Tls
             }
 
             handshake.HandshakeHash.NotifyPrfDetermined();
+            if (!ProtocolVersion.DTLSv12.Equals(securityParameters.NegotiatedVersion))
+            {
+                handshake.HandshakeHash.SealHashAlgorithms();
+            }
 
             ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.MaxFragmentLength);
 
@@ -237,12 +241,6 @@ namespace Org.BouncyCastle.Tls
 
                 TlsUtilities.EstablishServerSigAlgs(securityParameters, state.certificateRequest);
 
-                /*
-                 * TODO Give the client a chance to immediately select the CertificateVerify hash
-                 * algorithm here to avoid tracking the other hash algorithms unnecessarily?
-                 */
-                TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash, securityParameters.ServerSigAlgs);
-
                 serverMessage = handshake.ReceiveMessage();
             }
             else
@@ -262,54 +260,71 @@ namespace Org.BouncyCastle.Tls
                 throw new TlsFatalAlert(AlertDescription.unexpected_message);
             }
 
-            IList clientSupplementalData = state.client.GetClientSupplementalData();
-            if (clientSupplementalData != null)
-            {
-                byte[] supplementalDataBody = GenerateSupplementalData(clientSupplementalData);
-                handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody);
-            }
+            TlsCredentials clientAuthCredentials = null;
+            TlsCredentialedSigner clientAuthSigner = null;
+            Certificate clientAuthCertificate = null;
+            SignatureAndHashAlgorithm clientAuthAlgorithm = null;
+            TlsStreamSigner clientAuthStreamSigner = null;
 
-            if (null != state.certificateRequest)
+            if (state.certificateRequest != null)
             {
-                state.clientCredentials = TlsUtilities.EstablishClientCredentials(state.authentication,
+                clientAuthCredentials = TlsUtilities.EstablishClientCredentials(state.authentication,
                     state.certificateRequest);
+                if (clientAuthCredentials != null)
+                {
+                    clientAuthCertificate = clientAuthCredentials.Certificate;
 
-                /*
-                 * RFC 5246 If no suitable certificate is available, the client MUST send a certificate
-                 * message containing no certificates.
-                 * 
-                 * NOTE: In previous RFCs, this was SHOULD instead of MUST.
-                 */
+                    if (clientAuthCredentials is TlsCredentialedSigner)
+                    {
+                        clientAuthSigner = (TlsCredentialedSigner)clientAuthCredentials;
+                        clientAuthAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+                            securityParameters.NegotiatedVersion, clientAuthSigner);
+                        clientAuthStreamSigner = clientAuthSigner.GetStreamSigner();
 
-                Certificate clientCertificate = null;
-                if (null != state.clientCredentials)
-                {
-                    clientCertificate = state.clientCredentials.Certificate;
-                }
+                        if (ProtocolVersion.DTLSv12.Equals(securityParameters.NegotiatedVersion))
+                        {
+                            TlsUtilities.VerifySupportedSignatureAlgorithm(securityParameters.ServerSigAlgs,
+                                clientAuthAlgorithm, AlertDescription.internal_error);
 
-                SendCertificateMessage(state.clientContext, handshake, clientCertificate, null);
-            }
+                            if (clientAuthStreamSigner == null)
+                            {
+                                TlsUtilities.TrackHashAlgorithmClient(handshake.HandshakeHash, clientAuthAlgorithm);
+                            }
+                        }
 
-            TlsCredentialedSigner credentialedSigner = null;
-            TlsStreamSigner streamSigner = null;
+                        if (clientAuthStreamSigner != null)
+                        {
+                            handshake.HandshakeHash.ForceBuffering();
+                        }
+                    }
+                }
+            }
 
-            if (null != state.clientCredentials)
+            if (ProtocolVersion.DTLSv12.Equals(securityParameters.NegotiatedVersion))
             {
-                state.keyExchange.ProcessClientCredentials(state.clientCredentials);
+                handshake.HandshakeHash.SealHashAlgorithms();
+            }
 
-                if (state.clientCredentials is TlsCredentialedSigner)
-                {
-                    credentialedSigner = (TlsCredentialedSigner)state.clientCredentials;
-                    streamSigner = credentialedSigner.GetStreamSigner();
-                }
+            if (clientAuthCredentials == null)
+            {
+                state.keyExchange.SkipClientCredentials();
             }
             else
             {
-                state.keyExchange.SkipClientCredentials();
+                state.keyExchange.ProcessClientCredentials(clientAuthCredentials);                    
             }
 
-            bool forceBuffering = streamSigner != null;
-            TlsUtilities.SealHandshakeHash(state.clientContext, handshake.HandshakeHash, forceBuffering);
+            IList clientSupplementalData = state.client.GetClientSupplementalData();
+            if (clientSupplementalData != null)
+            {
+                byte[] supplementalDataBody = GenerateSupplementalData(clientSupplementalData);
+                handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody);
+            }
+
+            if (null != state.certificateRequest)
+            {
+                SendCertificateMessage(state.clientContext, handshake, clientAuthCertificate, null);
+            }
 
             byte[] clientKeyExchangeBody = GenerateClientKeyExchange(state);
             handshake.SendMessage(HandshakeType.client_key_exchange, clientKeyExchangeBody);
@@ -319,18 +334,16 @@ namespace Org.BouncyCastle.Tls
             TlsProtocol.EstablishMasterSecret(state.clientContext, state.keyExchange);
             recordLayer.InitPendingEpoch(TlsUtilities.InitCipher(state.clientContext));
 
+            if (clientAuthSigner != null)
             {
-                if (credentialedSigner != null)
-                {
-                    DigitallySigned certificateVerify = TlsUtilities.GenerateCertificateVerifyClient(
-                        state.clientContext, credentialedSigner, streamSigner, handshake.HandshakeHash);
-                    byte[] certificateVerifyBody = GenerateCertificateVerify(state, certificateVerify);
-                    handshake.SendMessage(HandshakeType.certificate_verify, certificateVerifyBody);
-                }
-
-                handshake.PrepareToFinish();
+                DigitallySigned certificateVerify = TlsUtilities.GenerateCertificateVerifyClient(state.clientContext,
+                    clientAuthSigner, clientAuthAlgorithm, clientAuthStreamSigner, handshake.HandshakeHash);
+                byte[] certificateVerifyBody = GenerateCertificateVerify(state, certificateVerify);
+                handshake.SendMessage(HandshakeType.certificate_verify, certificateVerifyBody);
             }
 
+            handshake.PrepareToFinish();
+
             securityParameters.m_localVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext,
                 handshake.HandshakeHash, false);
             handshake.SendMessage(HandshakeType.finished, securityParameters.LocalVerifyData);
@@ -973,7 +986,6 @@ namespace Org.BouncyCastle.Tls
             internal TlsAuthentication authentication = null;
             internal CertificateStatus certificateStatus = null;
             internal CertificateRequest certificateRequest = null;
-            internal TlsCredentials clientCredentials = null;
             internal TlsHeartbeat heartbeat = null;
             internal short heartbeatPolicy = HeartbeatMode.peer_not_allowed_to_send;
         }
diff --git a/crypto/src/tls/DtlsServerProtocol.cs b/crypto/src/tls/DtlsServerProtocol.cs
index b49122423..2c6ddf31f 100644
--- a/crypto/src/tls/DtlsServerProtocol.cs
+++ b/crypto/src/tls/DtlsServerProtocol.cs
@@ -146,6 +146,10 @@ namespace Org.BouncyCastle.Tls
             }
 
             handshake.HandshakeHash.NotifyPrfDetermined();
+            if (!ProtocolVersion.DTLSv12.Equals(securityParameters.NegotiatedVersion))
+            {
+                handshake.HandshakeHash.SealHashAlgorithms();
+            }
 
             IList serverSupplementalData = state.server.GetServerSupplementalData();
             if (serverSupplementalData != null)
@@ -225,17 +229,30 @@ namespace Org.BouncyCastle.Tls
 
                     TlsUtilities.EstablishServerSigAlgs(securityParameters, state.certificateRequest);
 
-                    TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash, securityParameters.ServerSigAlgs);
+                    if (ProtocolVersion.DTLSv12.Equals(securityParameters.NegotiatedVersion))
+                    {
+                        TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash, securityParameters.ServerSigAlgs);
 
-                    byte[] certificateRequestBody = GenerateCertificateRequest(state, state.certificateRequest);
-                    handshake.SendMessage(HandshakeType.certificate_request, certificateRequestBody);
+                        if (!state.serverContext.Crypto.HasAllRawSignatureAlgorithms())
+                        {
+                            handshake.HandshakeHash.ForceBuffering();
+                        }
+                    }
                 }
             }
 
-            handshake.SendMessage(HandshakeType.server_hello_done, TlsUtilities.EmptyBytes);
+            if (ProtocolVersion.DTLSv12.Equals(securityParameters.NegotiatedVersion))
+            {
+                handshake.HandshakeHash.SealHashAlgorithms();
+            }
+
+            if (null != state.certificateRequest)
+            {
+                byte[] certificateRequestBody = GenerateCertificateRequest(state, state.certificateRequest);
+                handshake.SendMessage(HandshakeType.certificate_request, certificateRequestBody);
+            }
 
-            bool forceBuffering = false;
-            TlsUtilities.SealHandshakeHash(state.serverContext, handshake.HandshakeHash, forceBuffering);
+            handshake.SendMessage(HandshakeType.server_hello_done, TlsUtilities.EmptyBytes);
 
             clientMessage = handshake.ReceiveMessage();
 
diff --git a/crypto/src/tls/SignatureScheme.cs b/crypto/src/tls/SignatureScheme.cs
index 03a8ce30f..ed8e3c21b 100644
--- a/crypto/src/tls/SignatureScheme.cs
+++ b/crypto/src/tls/SignatureScheme.cs
@@ -97,6 +97,11 @@ namespace Org.BouncyCastle.Tls
             }
         }
 
+        public static int GetCryptoHashAlgorithm(SignatureAndHashAlgorithm signatureAndHashAlgorithm)
+        {
+            return GetCryptoHashAlgorithm(From(signatureAndHashAlgorithm));
+        }
+
         public static string GetName(int signatureScheme)
         {
             switch (signatureScheme)
diff --git a/crypto/src/tls/TlsClientProtocol.cs b/crypto/src/tls/TlsClientProtocol.cs
index 89e7c4ba9..930294eae 100644
--- a/crypto/src/tls/TlsClientProtocol.cs
+++ b/crypto/src/tls/TlsClientProtocol.cs
@@ -450,24 +450,27 @@ namespace Org.BouncyCastle.Tls
                     {
                         Process13HelloRetryRequest(serverHello);
                         m_handshakeHash.NotifyPrfDetermined();
+                        m_handshakeHash.SealHashAlgorithms();
                         TlsUtilities.AdjustTranscriptForRetry(m_handshakeHash);
                         buf.UpdateHash(m_handshakeHash);
                         this.m_connectionState = CS_SERVER_HELLO_RETRY_REQUEST;
 
                         Send13ClientHelloRetry();
-                        m_handshakeHash.SealHashAlgorithms();
                         this.m_connectionState = CS_CLIENT_HELLO_RETRY;
                     }
                     else
                     {
                         ProcessServerHello(serverHello);
                         m_handshakeHash.NotifyPrfDetermined();
+                        if (!ProtocolVersion.TLSv12.Equals(securityParameters.NegotiatedVersion))
+                        {
+                            m_handshakeHash.SealHashAlgorithms();
+                        }
                         buf.UpdateHash(m_handshakeHash);
                         this.m_connectionState = CS_SERVER_HELLO;
 
                         if (TlsUtilities.IsTlsV13(securityParameters.NegotiatedVersion))
                         {
-                            m_handshakeHash.SealHashAlgorithms();
                             Process13ServerHelloCoda(serverHello, false);
                         }
                     }
@@ -526,61 +529,73 @@ namespace Org.BouncyCastle.Tls
 
                     this.m_connectionState = CS_SERVER_HELLO_DONE;
 
-                    IList clientSupplementalData = m_tlsClient.GetClientSupplementalData();
-                    if (clientSupplementalData != null)
+                    TlsCredentials clientAuthCredentials = null;
+                    TlsCredentialedSigner clientAuthSigner = null;
+                    Certificate clientAuthCertificate = null;
+                    SignatureAndHashAlgorithm clientAuthAlgorithm = null;
+                    TlsStreamSigner clientAuthStreamSigner = null;
+
+                    if (m_certificateRequest != null)
                     {
-                        SendSupplementalDataMessage(clientSupplementalData);
-                        this.m_connectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
+                        clientAuthCredentials = TlsUtilities.EstablishClientCredentials(m_authentication,
+                            m_certificateRequest);
+                        if (clientAuthCredentials != null)
+                        {
+                            clientAuthCertificate = clientAuthCredentials.Certificate;
+
+                            if (clientAuthCredentials is TlsCredentialedSigner)
+                            {
+                                clientAuthSigner = (TlsCredentialedSigner)clientAuthCredentials;
+                                clientAuthAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+                                    securityParameters.NegotiatedVersion, clientAuthSigner);
+                                clientAuthStreamSigner = clientAuthSigner.GetStreamSigner();
+
+                                if (ProtocolVersion.TLSv12.Equals(securityParameters.NegotiatedVersion))
+                                {
+                                    TlsUtilities.VerifySupportedSignatureAlgorithm(securityParameters.ServerSigAlgs,
+                                        clientAuthAlgorithm, AlertDescription.internal_error);
+
+                                    if (clientAuthStreamSigner == null)
+                                    {
+                                        TlsUtilities.TrackHashAlgorithmClient(m_handshakeHash, clientAuthAlgorithm);
+                                    }
+                                }
+
+                                if (clientAuthStreamSigner != null)
+                                {
+                                    m_handshakeHash.ForceBuffering();
+                                }
+                            }
+                        }
                     }
 
-                    TlsCredentialedSigner credentialedSigner = null;
-                    TlsStreamSigner streamSigner = null;
+                    if (ProtocolVersion.TLSv12.Equals(securityParameters.NegotiatedVersion))
+                    {
+                        m_handshakeHash.SealHashAlgorithms();
+                    }
 
-                    if (m_certificateRequest == null)
+                    if (clientAuthCredentials == null)
                     {
                         m_keyExchange.SkipClientCredentials();
                     }
                     else
                     {
-                        Certificate clientCertificate = null;
-
-                        TlsCredentials clientCredentials = TlsUtilities.EstablishClientCredentials(m_authentication,
-                            m_certificateRequest);
-                        if (null == clientCredentials)
-                        {
-                            m_keyExchange.SkipClientCredentials();
-
-                            /*
-                             * RFC 5246 If no suitable certificate is available, the client MUST send a
-                             * certificate message containing no certificates.
-                             * 
-                             * NOTE: In previous RFCs, this was SHOULD instead of MUST.
-                             */
-                        }
-                        else
-                        {
-                            m_keyExchange.ProcessClientCredentials(clientCredentials);
-
-                            clientCertificate = clientCredentials.Certificate;
-
-                            if (clientCredentials is TlsCredentialedSigner)
-                            {
-                                credentialedSigner = (TlsCredentialedSigner)clientCredentials;
-                                streamSigner = credentialedSigner.GetStreamSigner();
-                            }
-                        }
+                        m_keyExchange.ProcessClientCredentials(clientAuthCredentials);                    
+                    }
 
-                        SendCertificateMessage(clientCertificate, null);
-                        this.m_connectionState = CS_CLIENT_CERTIFICATE;
+                    IList clientSupplementalData = m_tlsClient.GetClientSupplementalData();
+                    if (clientSupplementalData != null)
+                    {
+                        SendSupplementalDataMessage(clientSupplementalData);
+                        this.m_connectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
                     }
 
-                    bool forceBuffering = streamSigner != null;
-                    TlsUtilities.SealHandshakeHash(m_tlsClientContext, m_handshakeHash, forceBuffering);
+                    if (m_certificateRequest != null)
+                    {
+                        SendCertificateMessage(clientAuthCertificate, null);
+                        this.m_connectionState = CS_CLIENT_CERTIFICATE;                    
+                    }
 
-                    /*
-                     * Send the client key exchange message, depending on the key exchange we are using
-                     * in our CipherSuite.
-                     */
                     SendClientKeyExchange();
                     this.m_connectionState = CS_CLIENT_KEY_EXCHANGE;
 
@@ -601,10 +616,11 @@ namespace Org.BouncyCastle.Tls
 
                     m_recordStream.SetPendingCipher(TlsUtilities.InitCipher(m_tlsClientContext));
 
-                    if (credentialedSigner != null)
+                    if (clientAuthSigner != null)
                     {
                         DigitallySigned certificateVerify = TlsUtilities.GenerateCertificateVerifyClient(
-                            m_tlsClientContext, credentialedSigner, streamSigner, m_handshakeHash);
+                            m_tlsClientContext, clientAuthSigner, clientAuthAlgorithm, clientAuthStreamSigner,
+                            m_handshakeHash);
                         SendCertificateVerifyMessage(certificateVerify);
                         this.m_connectionState = CS_CLIENT_CERTIFICATE_VERIFY;
                     }
@@ -674,13 +690,6 @@ namespace Org.BouncyCastle.Tls
                     ReceiveCertificateRequest(buf);
 
                     TlsUtilities.EstablishServerSigAlgs(securityParameters, m_certificateRequest);
-
-                    /*
-                     * TODO Give the client a chance to immediately select the CertificateVerify hash
-                     * algorithm here to avoid tracking the other hash algorithms unnecessarily?
-                     */
-                    TlsUtilities.TrackHashAlgorithms(m_handshakeHash, securityParameters.ServerSigAlgs);
-
                     break;
                 }
                 default:
diff --git a/crypto/src/tls/TlsServerProtocol.cs b/crypto/src/tls/TlsServerProtocol.cs
index 523fc0030..a21ae69cd 100644
--- a/crypto/src/tls/TlsServerProtocol.cs
+++ b/crypto/src/tls/TlsServerProtocol.cs
@@ -899,11 +899,13 @@ namespace Org.BouncyCastle.Tls
 
                     ServerHello serverHello = GenerateServerHello(clientHello, buf);
                     m_handshakeHash.NotifyPrfDetermined();
-
-                    if (TlsUtilities.IsTlsV13(securityParameters.NegotiatedVersion))
+                    if (!ProtocolVersion.TLSv12.Equals(securityParameters.NegotiatedVersion))
                     {
                         m_handshakeHash.SealHashAlgorithms();
+                    }
 
+                    if (TlsUtilities.IsTlsV13(securityParameters.NegotiatedVersion))
+                    {
                         if (serverHello.IsHelloRetryRequest())
                         {
                             TlsUtilities.AdjustTranscriptForRetry(m_handshakeHash);
@@ -1026,19 +1028,32 @@ namespace Org.BouncyCastle.Tls
 
                             TlsUtilities.EstablishServerSigAlgs(securityParameters, m_certificateRequest);
 
-                            TlsUtilities.TrackHashAlgorithms(m_handshakeHash, securityParameters.ServerSigAlgs);
+                            if (ProtocolVersion.TLSv12.Equals(securityParameters.NegotiatedVersion))
+                            {
+                                TlsUtilities.TrackHashAlgorithms(m_handshakeHash, securityParameters.ServerSigAlgs);
 
-                            SendCertificateRequestMessage(m_certificateRequest);
-                            this.m_connectionState = CS_SERVER_CERTIFICATE_REQUEST;
+                                if (!m_tlsServerContext.Crypto.HasAllRawSignatureAlgorithms())
+                                {
+                                    m_handshakeHash.ForceBuffering();
+                                }
+                            }
                         }
                     }
 
+                    if (ProtocolVersion.TLSv12.Equals(securityParameters.NegotiatedVersion))
+                    {
+                        m_handshakeHash.SealHashAlgorithms();
+                    }
+
+                    if (null != m_certificateRequest)
+                    {
+                        SendCertificateRequestMessage(m_certificateRequest);
+                        this.m_connectionState = CS_SERVER_CERTIFICATE_REQUEST;
+                    }
+
                     SendServerHelloDoneMessage();
                     this.m_connectionState = CS_SERVER_HELLO_DONE;
 
-                    bool forceBuffering = false;
-                    TlsUtilities.SealHandshakeHash(m_tlsServerContext, m_handshakeHash, forceBuffering);
-
                     break;
                 }
                 default:
diff --git a/crypto/src/tls/TlsUtilities.cs b/crypto/src/tls/TlsUtilities.cs
index 9a6b76e66..076aaf535 100644
--- a/crypto/src/tls/TlsUtilities.cs
+++ b/crypto/src/tls/TlsUtilities.cs
@@ -1086,14 +1086,19 @@ namespace Org.BouncyCastle.Tls
         }
 
         internal static SignatureAndHashAlgorithm GetSignatureAndHashAlgorithm(ProtocolVersion negotiatedVersion,
-            TlsCredentialedSigner signerCredentials)
+            TlsCredentialedSigner credentialedSigner)
         {
             SignatureAndHashAlgorithm signatureAndHashAlgorithm = null;
-            if (IsTlsV12(negotiatedVersion))
+            if (IsSignatureAlgorithmsExtensionAllowed(negotiatedVersion))
             {
-                signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm;
+                signatureAndHashAlgorithm = credentialedSigner.SignatureAndHashAlgorithm;
                 if (signatureAndHashAlgorithm == null)
+                {
+                    /*
+                     * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+                     */
                     throw new TlsFatalAlert(AlertDescription.internal_error);
+                }
             }
             return signatureAndHashAlgorithm;
         }
@@ -1348,6 +1353,14 @@ namespace Org.BouncyCastle.Tls
         public static void VerifySupportedSignatureAlgorithm(IList supportedSignatureAlgorithms,
             SignatureAndHashAlgorithm signatureAlgorithm)
         {
+            VerifySupportedSignatureAlgorithm(supportedSignatureAlgorithms, signatureAlgorithm,
+                AlertDescription.illegal_parameter);
+        }
+
+        /// <exception cref="IOException"/>
+        internal static void VerifySupportedSignatureAlgorithm(IList supportedSignatureAlgorithms,
+            SignatureAndHashAlgorithm signatureAlgorithm, short alertDescription)
+        {
             if (supportedSignatureAlgorithms == null || supportedSignatureAlgorithms.Count < 1
                 || supportedSignatureAlgorithms.Count >= (1 << 15))
             {
@@ -1359,7 +1372,7 @@ namespace Org.BouncyCastle.Tls
             if (signatureAlgorithm.Signature == SignatureAlgorithm.anonymous
                 || !ContainsSignatureAlgorithm(supportedSignatureAlgorithms, signatureAlgorithm))
             {
-                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                throw new TlsFatalAlert(alertDescription);
             }
         }
 
@@ -2125,48 +2138,38 @@ namespace Org.BouncyCastle.Tls
         }
 
         internal static DigitallySigned GenerateCertificateVerifyClient(TlsClientContext clientContext,
-            TlsCredentialedSigner credentialedSigner, TlsStreamSigner streamSigner, TlsHandshakeHash handshakeHash)
+            TlsCredentialedSigner clientAuthSigner, SignatureAndHashAlgorithm clientAuthAlgorithm,
+            TlsStreamSigner clientAuthStreamSigner, TlsHandshakeHash handshakeHash)
         {
             SecurityParameters securityParameters = clientContext.SecurityParameters;
-            ProtocolVersion negotiatedVersion = securityParameters.NegotiatedVersion;
-
-            if (IsTlsV13(negotiatedVersion))
+            if (IsTlsV13(securityParameters.NegotiatedVersion))
             {
                 // Should be using Generate13CertificateVerify instead
                 throw new TlsFatalAlert(AlertDescription.internal_error);
             }
 
-            /*
-             * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
-             */
-            SignatureAndHashAlgorithm signatureAndHashAlgorithm = GetSignatureAndHashAlgorithm(negotiatedVersion,
-                credentialedSigner);
-
             byte[] signature;
-            if (streamSigner != null)
+            if (clientAuthStreamSigner != null)
             {
-                handshakeHash.CopyBufferTo(streamSigner.Stream);
-                signature = streamSigner.GetSignature();
+                handshakeHash.CopyBufferTo(clientAuthStreamSigner.Stream);
+                signature = clientAuthStreamSigner.GetSignature();
             }
             else
             {
                 byte[] hash;
-                if (signatureAndHashAlgorithm == null)
+                if (clientAuthAlgorithm == null)
                 {
                     hash = securityParameters.SessionHash;
                 }
                 else
                 {
-                    int signatureScheme = SignatureScheme.From(signatureAndHashAlgorithm);
-                    int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme);
-
-                    hash = handshakeHash.GetFinalHash(cryptoHashAlgorithm);
+                    hash = handshakeHash.GetFinalHash(SignatureScheme.GetCryptoHashAlgorithm(clientAuthAlgorithm));
                 }
 
-                signature = credentialedSigner.GenerateRawSignature(hash);
+                signature = clientAuthSigner.GenerateRawSignature(hash);
             }
 
-            return new DigitallySigned(signatureAndHashAlgorithm, signature);
+            return new DigitallySigned(clientAuthAlgorithm, signature);
         }
 
         internal static DigitallySigned Generate13CertificateVerify(TlsContext context,
@@ -2202,10 +2205,7 @@ namespace Org.BouncyCastle.Tls
                 return streamSigner.GetSignature();
             }
 
-            int signatureScheme = SignatureScheme.From(signatureAndHashAlgorithm);
-            int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme);
-
-            TlsHash tlsHash = crypto.CreateHash(cryptoHashAlgorithm);
+            TlsHash tlsHash = CreateHash(crypto, signatureAndHashAlgorithm);
             tlsHash.Update(header, 0, header.Length);
             tlsHash.Update(prfHash, 0, prfHash.Length);
             byte[] hash = tlsHash.CalculateHash();
@@ -2255,10 +2255,7 @@ namespace Org.BouncyCastle.Tls
                     byte[] hash;
                     if (IsTlsV12(serverContext))
                     {
-                        int signatureScheme = SignatureScheme.From(sigAndHashAlg);
-                        int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme);
-
-                        hash = handshakeHash.GetFinalHash(cryptoHashAlgorithm);
+                        hash = handshakeHash.GetFinalHash(SignatureScheme.GetCryptoHashAlgorithm(sigAndHashAlg));
                     }
                     else
                     {
@@ -2438,28 +2435,28 @@ namespace Org.BouncyCastle.Tls
             }
         }
 
+        internal static void TrackHashAlgorithmClient(TlsHandshakeHash handshakeHash,
+            SignatureAndHashAlgorithm signatureAndHashAlgorithm)
+        {
+            int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureAndHashAlgorithm);
+            if (cryptoHashAlgorithm >= 0)
+            {
+                handshakeHash.TrackHashAlgorithm(cryptoHashAlgorithm);
+            }
+        }
+
         internal static void TrackHashAlgorithms(TlsHandshakeHash handshakeHash, IList supportedSignatureAlgorithms)
         {
-            if (supportedSignatureAlgorithms != null)
+            foreach (SignatureAndHashAlgorithm signatureAndHashAlgorithm in supportedSignatureAlgorithms)
             {
-                foreach (SignatureAndHashAlgorithm signatureAndHashAlgorithm in supportedSignatureAlgorithms)
+                int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureAndHashAlgorithm);
+                if (cryptoHashAlgorithm >= 0)
                 {
-                    /*
-                     * TODO We could validate the signature algorithm part. Currently the impact is
-                     * that we might be tracking extra hashes pointlessly (but there are only a
-                     * limited number of recognized hash algorithms).
-                     */
-                    int signatureScheme = SignatureScheme.From(signatureAndHashAlgorithm);
-                    int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme);
-
-                    if (cryptoHashAlgorithm >= 0)
-                    {
-                        handshakeHash.TrackHashAlgorithm(cryptoHashAlgorithm);
-                    }
-                    else if (HashAlgorithm.Intrinsic == signatureAndHashAlgorithm.Hash)
-                    {
-                        handshakeHash.ForceBuffering();
-                    }
+                    handshakeHash.TrackHashAlgorithm(cryptoHashAlgorithm);
+                }
+                else if (HashAlgorithm.Intrinsic == signatureAndHashAlgorithm.Hash)
+                {
+                    handshakeHash.ForceBuffering();
                 }
             }
         }
@@ -4192,29 +4189,14 @@ namespace Org.BouncyCastle.Tls
             return handshakeHash.ForkPrfHash().CalculateHash();
         }
 
-        internal static void SealHandshakeHash(TlsContext context, TlsHandshakeHash handshakeHash, bool forceBuffering)
-        {
-            if (forceBuffering || !context.Crypto.HasAllRawSignatureAlgorithms())
-            {
-                handshakeHash.ForceBuffering();
-            }
-
-            handshakeHash.SealHashAlgorithms();
-        }
-
         private static TlsHash CreateHash(TlsCrypto crypto, short hashAlgorithm)
         {
-            int cryptoHashAlgorithm = TlsCryptoUtilities.GetHash(hashAlgorithm);
-
-            return crypto.CreateHash(cryptoHashAlgorithm);
+            return crypto.CreateHash(TlsCryptoUtilities.GetHash(hashAlgorithm));
         }
 
         private static TlsHash CreateHash(TlsCrypto crypto, SignatureAndHashAlgorithm signatureAndHashAlgorithm)
         {
-            int signatureScheme = SignatureScheme.From(signatureAndHashAlgorithm);
-            int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme);
-
-            return crypto.CreateHash(cryptoHashAlgorithm);
+            return crypto.CreateHash(SignatureScheme.GetCryptoHashAlgorithm(signatureAndHashAlgorithm));
         }
 
         /// <exception cref="IOException"/>