From 51628afb7a6a9979bcd736af04fd0e01656ef26d Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 5 Nov 2022 21:43:59 +0700 Subject: Add TlsPeer.IgnoreCorruptDtlsRecords - property controls behaviour when bad_record_mac thrown for DTLS record. - defaults to 'false' (don't ignore i.e. fail the connection) - see https://github.com/bcgit/bc-csharp/pull/279 --- crypto/src/tls/AbstractTlsPeer.cs | 2 ++ crypto/src/tls/DtlsClientProtocol.cs | 4 ++-- crypto/src/tls/DtlsServerProtocol.cs | 2 +- crypto/src/tls/DtlsTransport.cs | 9 +++++++-- crypto/src/tls/TlsPeer.cs | 7 +++++++ crypto/src/tls/crypto/impl/TlsAeadCipher.cs | 9 +++++++++ crypto/src/tls/crypto/impl/TlsAeadCipherImpl.cs | 2 ++ crypto/src/tls/crypto/impl/bc/BcChaCha20Poly1305.cs | 6 ++++++ crypto/src/tls/crypto/impl/bc/BcTlsAeadCipherImpl.cs | 5 +++++ 9 files changed, 41 insertions(+), 5 deletions(-) (limited to 'crypto') diff --git a/crypto/src/tls/AbstractTlsPeer.cs b/crypto/src/tls/AbstractTlsPeer.cs index 4e1b28e58..6d7c88f1b 100644 --- a/crypto/src/tls/AbstractTlsPeer.cs +++ b/crypto/src/tls/AbstractTlsPeer.cs @@ -157,5 +157,7 @@ namespace Org.BouncyCastle.Tls { return HeartbeatMode.peer_not_allowed_to_send; } + + public virtual bool IgnoreCorruptDtlsRecords => false; } } diff --git a/crypto/src/tls/DtlsClientProtocol.cs b/crypto/src/tls/DtlsClientProtocol.cs index b8c09617a..0a4a711ae 100644 --- a/crypto/src/tls/DtlsClientProtocol.cs +++ b/crypto/src/tls/DtlsClientProtocol.cs @@ -173,7 +173,7 @@ namespace Org.BouncyCastle.Tls recordLayer.InitHeartbeat(state.heartbeat, HeartbeatMode.peer_allowed_to_send == state.heartbeatPolicy); - return new DtlsTransport(recordLayer); + return new DtlsTransport(recordLayer, state.client.IgnoreCorruptDtlsRecords); } InvalidateSession(state); @@ -392,7 +392,7 @@ namespace Org.BouncyCastle.Tls recordLayer.InitHeartbeat(state.heartbeat, HeartbeatMode.peer_allowed_to_send == state.heartbeatPolicy); - return new DtlsTransport(recordLayer); + return new DtlsTransport(recordLayer, state.client.IgnoreCorruptDtlsRecords); } /// diff --git a/crypto/src/tls/DtlsServerProtocol.cs b/crypto/src/tls/DtlsServerProtocol.cs index b42f97b64..5edd5595e 100644 --- a/crypto/src/tls/DtlsServerProtocol.cs +++ b/crypto/src/tls/DtlsServerProtocol.cs @@ -381,7 +381,7 @@ namespace Org.BouncyCastle.Tls recordLayer.InitHeartbeat(state.heartbeat, HeartbeatMode.peer_allowed_to_send == state.heartbeatPolicy); - return new DtlsTransport(recordLayer); + return new DtlsTransport(recordLayer, state.server.IgnoreCorruptDtlsRecords); } /// diff --git a/crypto/src/tls/DtlsTransport.cs b/crypto/src/tls/DtlsTransport.cs index 1a6ec131f..6d481702f 100644 --- a/crypto/src/tls/DtlsTransport.cs +++ b/crypto/src/tls/DtlsTransport.cs @@ -8,10 +8,12 @@ namespace Org.BouncyCastle.Tls : DatagramTransport { private readonly DtlsRecordLayer m_recordLayer; + private readonly bool m_ignoreCorruptRecords; - internal DtlsTransport(DtlsRecordLayer recordLayer) + internal DtlsTransport(DtlsRecordLayer recordLayer, bool ignoreCorruptRecords) { - this.m_recordLayer = recordLayer; + m_recordLayer = recordLayer; + m_ignoreCorruptRecords = ignoreCorruptRecords; } /// @@ -44,6 +46,9 @@ namespace Org.BouncyCastle.Tls } catch (TlsFatalAlert fatalAlert) { + if (m_ignoreCorruptRecords && AlertDescription.bad_record_mac == fatalAlert.AlertDescription) + return -1; + m_recordLayer.Fail(fatalAlert.AlertDescription); throw fatalAlert; } diff --git a/crypto/src/tls/TlsPeer.cs b/crypto/src/tls/TlsPeer.cs index ef2837135..04d66d38f 100644 --- a/crypto/src/tls/TlsPeer.cs +++ b/crypto/src/tls/TlsPeer.cs @@ -119,5 +119,12 @@ namespace Org.BouncyCastle.Tls /// /// the value. short GetHeartbeatPolicy(); + + /// Indicates whether a DTLS connection should ignore corrupt records (bad_record_mac) instead of + /// failing the connection. + /// Called only once at the start of a connection and applies throughout. + /// The value true to ignore corrupt DTLS records, or false to fail the connection. + /// + bool IgnoreCorruptDtlsRecords { get; } } } diff --git a/crypto/src/tls/crypto/impl/TlsAeadCipher.cs b/crypto/src/tls/crypto/impl/TlsAeadCipher.cs index a53e1e835..594981210 100644 --- a/crypto/src/tls/crypto/impl/TlsAeadCipher.cs +++ b/crypto/src/tls/crypto/impl/TlsAeadCipher.cs @@ -351,12 +351,21 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl outputPos = m_decryptCipher.DoFinal(ciphertext, encryptionOffset, encryptionLength, ciphertext, encryptionOffset); } + catch (TlsFatalAlert fatalAlert) + { + if (AlertDescription.bad_record_mac == fatalAlert.AlertDescription) + { + m_decryptCipher.Reset(); + } + throw fatalAlert; + } catch (IOException e) { throw e; } catch (Exception e) { + m_decryptCipher.Reset(); throw new TlsFatalAlert(AlertDescription.bad_record_mac, e); } diff --git a/crypto/src/tls/crypto/impl/TlsAeadCipherImpl.cs b/crypto/src/tls/crypto/impl/TlsAeadCipherImpl.cs index 4c69c0b72..0cd2923c2 100644 --- a/crypto/src/tls/crypto/impl/TlsAeadCipherImpl.cs +++ b/crypto/src/tls/crypto/impl/TlsAeadCipherImpl.cs @@ -41,5 +41,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl /// the amount of data written to output. /// in case of failure. int DoFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset); + + void Reset(); } } diff --git a/crypto/src/tls/crypto/impl/bc/BcChaCha20Poly1305.cs b/crypto/src/tls/crypto/impl/bc/BcChaCha20Poly1305.cs index f8e36a245..06a09bbb1 100644 --- a/crypto/src/tls/crypto/impl/bc/BcChaCha20Poly1305.cs +++ b/crypto/src/tls/crypto/impl/bc/BcChaCha20Poly1305.cs @@ -96,6 +96,12 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC } } + public void Reset() + { + m_cipher.Reset(); + m_mac.Reset(); + } + public void SetKey(byte[] key, int keyOff, int keyLen) { KeyParameter cipherKey = new KeyParameter(key, keyOff, keyLen); diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsAeadCipherImpl.cs b/crypto/src/tls/crypto/impl/bc/BcTlsAeadCipherImpl.cs index 0b2781326..4965c92bd 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsAeadCipherImpl.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsAeadCipherImpl.cs @@ -57,5 +57,10 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC return len; } + + public void Reset() + { + m_cipher.Reset(); + } } } -- cgit 1.4.1