summary refs log tree commit diff
path: root/crypto
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-03-25 14:52:49 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-04-13 17:16:20 +0700
commit88c141ee70aed4f7e6599b467de5b776f8fe9490 (patch)
treeb928d07287cc76ef4840d204e4e8924b22f73fd2 /crypto
parentRFC 9146: DtlsRecordLayer support for connection ID (diff)
downloadBouncyCastle.NET-ed25519-88c141ee70aed4f7e6599b467de5b776f8fe9490.tar.xz
RFC 9146: TlsNullCipher support for connection ID
Diffstat (limited to 'crypto')
-rw-r--r--crypto/src/tls/DtlsRecordLayer.cs5
-rw-r--r--crypto/src/tls/crypto/impl/TlsAeadCipher.cs9
-rw-r--r--crypto/src/tls/crypto/impl/TlsBlockCipher.cs21
-rw-r--r--crypto/src/tls/crypto/impl/TlsNullCipher.cs123
4 files changed, 118 insertions, 40 deletions
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