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);
}
/// <exception cref="IOException"/>
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);
}
/// <exception cref="IOException"/>
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;
}
/// <exception cref="IOException"/>
@@ -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
/// </remarks>
/// <returns>the <see cref="HeartbeatMode"/> value.</returns>
short GetHeartbeatPolicy();
+
+ /// <summary>Indicates whether a DTLS connection should ignore corrupt records (bad_record_mac) instead of
+ /// failing the connection.</summary>
+ /// <remarks>Called only once at the start of a connection and applies throughout.</remarks>
+ /// <returns>The value <c>true</c> to ignore corrupt DTLS records, or <c>false</c> to fail the connection.
+ /// </returns>
+ 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
/// <returns>the amount of data written to output.</returns>
/// <exception cref="IOException">in case of failure.</exception>
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();
+ }
}
}
|