diff --git a/crypto/src/tls/DtlsRecordLayer.cs b/crypto/src/tls/DtlsRecordLayer.cs
index 860c2dc31..e68470adb 100644
--- a/crypto/src/tls/DtlsRecordLayer.cs
+++ b/crypto/src/tls/DtlsRecordLayer.cs
@@ -681,6 +681,11 @@ namespace Org.BouncyCastle.Tls
if (!Arrays.FixedTimeEquals(connectionID.Length, connectionID, 0, record, 11))
return -1;
}
+ else
+ {
+ if (ContentType.tls12_cid == recordType)
+ return -1;
+ }
int length = TlsUtilities.ReadUint16(record, recordHeaderLength - 2);
if (received != (length + recordHeaderLength))
diff --git a/crypto/src/tls/crypto/impl/TlsAeadCipher.cs b/crypto/src/tls/crypto/impl/TlsAeadCipher.cs
index f5ebd7eba..f8f01f380 100644
--- a/crypto/src/tls/crypto/impl/TlsAeadCipher.cs
+++ b/crypto/src/tls/crypto/impl/TlsAeadCipher.cs
@@ -154,14 +154,9 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl
public override int GetCiphertextEncodeLimit(int plaintextLength, int plaintextLimit)
{
- int innerPlaintextLimit = plaintextLength;
- if (m_encryptUseInnerPlaintext)
- {
- // TODO[tls13] Add support for padding
- int maxPadding = 0;
+ plaintextLimit = System.Math.Min(plaintextLength, plaintextLimit);
- innerPlaintextLimit = 1 + System.Math.Min(plaintextLimit, plaintextLength + maxPadding);
- }
+ int innerPlaintextLimit = plaintextLimit + (m_encryptUseInnerPlaintext ? 1 : 0);
return innerPlaintextLimit + m_macSize + m_record_iv_length;
}
diff --git a/crypto/src/tls/crypto/impl/TlsBlockCipher.cs b/crypto/src/tls/crypto/impl/TlsBlockCipher.cs
index 63d4826b3..bc04caee1 100644
--- a/crypto/src/tls/crypto/impl/TlsBlockCipher.cs
+++ b/crypto/src/tls/crypto/impl/TlsBlockCipher.cs
@@ -159,29 +159,22 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl
{
int blockSize = m_decryptCipher.GetBlockSize();
int macSize = m_readMac.Size;
- int maxExtraPadding = 256;
-
+ int maxPadding = 256;
int innerPlaintextLimit = plaintextLimit + (m_decryptUseInnerPlaintext ? 1 : 0);
- return GetCiphertextLength(blockSize, macSize, maxExtraPadding, innerPlaintextLimit);
+ return GetCiphertextLength(blockSize, macSize, maxPadding, innerPlaintextLimit);
}
public override int GetCiphertextEncodeLimit(int plaintextLength, int plaintextLimit)
{
+ plaintextLimit = System.Math.Min(plaintextLength, plaintextLimit);
+
int blockSize = m_encryptCipher.GetBlockSize();
int macSize = m_writeMac.Size;
- int maxExtraPadding = m_useExtraPadding ? 256 : blockSize;
-
- int innerPlaintextLimit = plaintextLength;
- if (m_encryptUseInnerPlaintext)
- {
- // TODO[cid] Add support for padding
- int maxPadding = 0;
-
- innerPlaintextLimit = 1 + System.Math.Min(plaintextLimit, plaintextLength + maxPadding);
- }
+ int maxPadding = m_useExtraPadding ? 256 : blockSize;
+ int innerPlaintextLimit = plaintextLimit + (m_encryptUseInnerPlaintext ? 1 : 0);
- return GetCiphertextLength(blockSize, macSize, maxExtraPadding, innerPlaintextLimit);
+ return GetCiphertextLength(blockSize, macSize, maxPadding, innerPlaintextLimit);
}
public override int GetPlaintextDecodeLimit(int ciphertextLimit)
diff --git a/crypto/src/tls/crypto/impl/TlsNullCipher.cs b/crypto/src/tls/crypto/impl/TlsNullCipher.cs
index 2008fd1d6..8e52f6374 100644
--- a/crypto/src/tls/crypto/impl/TlsNullCipher.cs
+++ b/crypto/src/tls/crypto/impl/TlsNullCipher.cs
@@ -1,6 +1,8 @@
using System;
using System.IO;
+using Org.BouncyCastle.Utilities;
+
namespace Org.BouncyCastle.Tls.Crypto.Impl
{
/// <summary>The NULL cipher.</summary>
@@ -9,13 +11,24 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl
{
protected readonly TlsCryptoParameters m_cryptoParams;
protected readonly TlsSuiteHmac m_readMac, m_writeMac;
+ protected readonly byte[] m_decryptConnectionID, m_encryptConnectionID;
+ protected readonly bool m_decryptUseInnerPlaintext, m_encryptUseInnerPlaintext;
/// <exception cref="IOException"/>
public TlsNullCipher(TlsCryptoParameters cryptoParams, TlsHmac clientMac, TlsHmac serverMac)
{
- if (TlsImplUtilities.IsTlsV13(cryptoParams))
+ SecurityParameters securityParameters = cryptoParams.SecurityParameters;
+ ProtocolVersion negotiatedVersion = securityParameters.NegotiatedVersion;
+
+ if (TlsImplUtilities.IsTlsV13(negotiatedVersion))
throw new TlsFatalAlert(AlertDescription.internal_error);
+ m_decryptConnectionID = securityParameters.ConnectionIDPeer;
+ m_encryptConnectionID = securityParameters.ConnectionIDLocal;
+
+ m_decryptUseInnerPlaintext = !Arrays.IsNullOrEmpty(m_decryptConnectionID);
+ m_encryptUseInnerPlaintext = !Arrays.IsNullOrEmpty(m_encryptConnectionID);
+
m_cryptoParams = cryptoParams;
int keyBlockSize = clientMac.MacLength + serverMac.MacLength;
@@ -58,38 +71,87 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl
public override int GetCiphertextDecodeLimit(int plaintextLimit)
{
- return plaintextLimit + m_writeMac.Size;
+ int innerPlaintextLimit = plaintextLimit + (m_decryptUseInnerPlaintext ? 1 : 0);
+
+ return innerPlaintextLimit + m_readMac.Size;
}
public override int GetCiphertextEncodeLimit(int plaintextLength, int plaintextLimit)
{
- return plaintextLength + m_writeMac.Size;
+ plaintextLimit = System.Math.Min(plaintextLength, plaintextLimit);
+
+ int innerPlaintextLimit = plaintextLimit + (m_encryptUseInnerPlaintext ? 1 : 0);
+
+ return innerPlaintextLimit + m_writeMac.Size;
+ }
+
+ public override int GetPlaintextDecodeLimit(int ciphertextLimit)
+ {
+ int innerPlaintextLimit = ciphertextLimit - m_readMac.Size;
+
+ return innerPlaintextLimit - (m_decryptUseInnerPlaintext ? 1 : 0);
}
- public override int GetPlaintextLimit(int ciphertextLimit)
+ public override int GetPlaintextEncodeLimit(int ciphertextLimit)
{
- return ciphertextLimit - m_writeMac.Size;
+ int innerPlaintextLimit = ciphertextLimit - m_writeMac.Size;
+
+ return innerPlaintextLimit - (m_encryptUseInnerPlaintext ? 1 : 0);
}
public override TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion,
int headerAllocation, byte[] plaintext, int offset, int len)
{
- byte[] mac = m_writeMac.CalculateMac(seqNo, contentType, plaintext, offset, len);
- byte[] ciphertext = new byte[headerAllocation + len + mac.Length];
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return EncodePlaintext(seqNo, contentType, recordVersion, headerAllocation, plaintext.AsSpan(offset, len));
+#else
+ int macSize = m_writeMac.Size;
+
+ // TODO[cid] If we support adding padding to DTLSInnerPlaintext, this will need review
+ int innerPlaintextLength = len + (m_encryptUseInnerPlaintext ? 1 : 0);
+
+ byte[] ciphertext = new byte[headerAllocation + innerPlaintextLength + macSize];
Array.Copy(plaintext, offset, ciphertext, headerAllocation, len);
- Array.Copy(mac, 0, ciphertext, headerAllocation + len, mac.Length);
- return new TlsEncodeResult(ciphertext, 0, ciphertext.Length, contentType);
+
+ short recordType = contentType;
+ if (m_encryptUseInnerPlaintext)
+ {
+ ciphertext[headerAllocation + len] = (byte)contentType;
+ recordType = ContentType.tls12_cid;
+ }
+
+ byte[] mac = m_writeMac.CalculateMac(seqNo, recordType, m_encryptConnectionID, ciphertext, headerAllocation,
+ innerPlaintextLength);
+ Array.Copy(mac, 0, ciphertext, headerAllocation + innerPlaintextLength, mac.Length);
+
+ return new TlsEncodeResult(ciphertext, 0, ciphertext.Length, recordType);
+#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public override TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion,
int headerAllocation, ReadOnlySpan<byte> plaintext)
{
- byte[] mac = m_writeMac.CalculateMac(seqNo, contentType, plaintext);
- byte[] ciphertext = new byte[headerAllocation + plaintext.Length + mac.Length];
+ int macSize = m_writeMac.Size;
+
+ // TODO[cid] If we support adding padding to DTLSInnerPlaintext, this will need review
+ int innerPlaintextLength = plaintext.Length + (m_encryptUseInnerPlaintext ? 1 : 0);
+
+ byte[] ciphertext = new byte[headerAllocation + innerPlaintextLength + macSize];
plaintext.CopyTo(ciphertext.AsSpan(headerAllocation));
- mac.CopyTo(ciphertext.AsSpan(headerAllocation + plaintext.Length));
- return new TlsEncodeResult(ciphertext, 0, ciphertext.Length, contentType);
+
+ short recordType = contentType;
+ if (m_encryptUseInnerPlaintext)
+ {
+ ciphertext[headerAllocation + plaintext.Length] = (byte)contentType;
+ recordType = ContentType.tls12_cid;
+ }
+
+ byte[] mac = m_writeMac.CalculateMac(seqNo, recordType, m_encryptConnectionID,
+ ciphertext.AsSpan(headerAllocation, innerPlaintextLength));
+ mac.CopyTo(ciphertext.AsSpan(headerAllocation + innerPlaintextLength));
+
+ return new TlsEncodeResult(ciphertext, 0, ciphertext.Length, recordType);
}
#endif
@@ -97,18 +159,41 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl
byte[] ciphertext, int offset, int len)
{
int macSize = m_readMac.Size;
- if (len < macSize)
- throw new TlsFatalAlert(AlertDescription.decode_error);
- int macInputLen = len - macSize;
+ int innerPlaintextLength = len - macSize;
+
+ if (innerPlaintextLength < (m_decryptUseInnerPlaintext ? 1 : 0))
+ throw new TlsFatalAlert(AlertDescription.decode_error);
- byte[] expectedMac = m_readMac.CalculateMac(seqNo, recordType, ciphertext, offset, macInputLen);
+ byte[] expectedMac = m_readMac.CalculateMac(seqNo, recordType, m_decryptConnectionID, ciphertext, offset,
+ innerPlaintextLength);
- bool badMac = !TlsUtilities.ConstantTimeAreEqual(macSize, expectedMac, 0, ciphertext, offset + macInputLen);
+ bool badMac = !TlsUtilities.ConstantTimeAreEqual(macSize, expectedMac, 0, ciphertext,
+ offset + innerPlaintextLength);
if (badMac)
throw new TlsFatalAlert(AlertDescription.bad_record_mac);
- return new TlsDecodeResult(ciphertext, offset, macInputLen, recordType);
+ short contentType = recordType;
+ int plaintextLength = innerPlaintextLength;
+
+ if (m_decryptUseInnerPlaintext)
+ {
+ // Strip padding and read true content type from DTLSInnerPlaintext
+ for (;;)
+ {
+ if (--plaintextLength < 0)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ byte octet = ciphertext[offset + plaintextLength];
+ if (0 != octet)
+ {
+ contentType = (short)(octet & 0xFF);
+ break;
+ }
+ }
+ }
+
+ return new TlsDecodeResult(ciphertext, offset, plaintextLength, contentType);
}
public override bool UsesOpaqueRecordType
|