summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crypto/BouncyCastle.Android.csproj1
-rw-r--r--crypto/BouncyCastle.csproj1
-rw-r--r--crypto/BouncyCastle.iOS.csproj1
-rw-r--r--crypto/crypto.csproj5
-rw-r--r--crypto/src/tls/CertificateCompressionAlgorithm.cs47
-rw-r--r--crypto/src/tls/ExtensionType.cs8
-rw-r--r--crypto/src/tls/HandshakeType.cs8
-rw-r--r--crypto/src/tls/TlsClientProtocol.cs2
-rw-r--r--crypto/src/tls/TlsExtensionsUtilities.cs32
-rw-r--r--crypto/src/tls/TlsServerProtocol.cs2
-rw-r--r--crypto/src/tls/TlsUtilities.cs36
11 files changed, 143 insertions, 0 deletions
diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj
index 875c99cfe..3d84af346 100644
--- a/crypto/BouncyCastle.Android.csproj
+++ b/crypto/BouncyCastle.Android.csproj
@@ -1602,6 +1602,7 @@
     <Compile Include="src\tls\CachedInformationType.cs" />
     <Compile Include="src\tls\CertChainType.cs" />
     <Compile Include="src\tls\Certificate.cs" />
+    <Compile Include="src\tls\CertificateCompressionAlgorithm.cs" />
     <Compile Include="src\tls\CertificateEntry.cs" />
     <Compile Include="src\tls\CertificateRequest.cs" />
     <Compile Include="src\tls\CertificateStatus.cs" />
diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj
index f7083b062..84d7bf6fc 100644
--- a/crypto/BouncyCastle.csproj
+++ b/crypto/BouncyCastle.csproj
@@ -1596,6 +1596,7 @@
     <Compile Include="src\tls\CachedInformationType.cs" />
     <Compile Include="src\tls\CertChainType.cs" />
     <Compile Include="src\tls\Certificate.cs" />
+    <Compile Include="src\tls\CertificateCompressionAlgorithm.cs" />
     <Compile Include="src\tls\CertificateEntry.cs" />
     <Compile Include="src\tls\CertificateRequest.cs" />
     <Compile Include="src\tls\CertificateStatus.cs" />
diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj
index 4490f0f07..d76444e71 100644
--- a/crypto/BouncyCastle.iOS.csproj
+++ b/crypto/BouncyCastle.iOS.csproj
@@ -1597,6 +1597,7 @@
     <Compile Include="src\tls\CachedInformationType.cs" />
     <Compile Include="src\tls\CertChainType.cs" />
     <Compile Include="src\tls\Certificate.cs" />
+    <Compile Include="src\tls\CertificateCompressionAlgorithm.cs" />
     <Compile Include="src\tls\CertificateEntry.cs" />
     <Compile Include="src\tls\CertificateRequest.cs" />
     <Compile Include="src\tls\CertificateStatus.cs" />
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index d3666bfcf..092331032 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -7869,6 +7869,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\tls\CertificateCompressionAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\tls\CertificateEntry.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/tls/CertificateCompressionAlgorithm.cs b/crypto/src/tls/CertificateCompressionAlgorithm.cs
new file mode 100644
index 000000000..4b6ebdadc
--- /dev/null
+++ b/crypto/src/tls/CertificateCompressionAlgorithm.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Tls
+{
+    /**
+     * RFC 8879
+     */
+    public abstract class CertificateCompressionAlgorithm
+    {
+        public const int zlib = 1;
+        public const int brotli = 2;
+        public const int zstd = 3;
+
+        public static string GetName(int certificateCompressionAlgorithm)
+        {
+            switch (certificateCompressionAlgorithm)
+            {
+            case zlib:
+                return "zlib";
+            case brotli:
+                return "brotli";
+            case zstd:
+                return "zstd";
+            default:
+                return "UNKNOWN";
+            }
+        }
+
+        public static string GetText(int certificateCompressionAlgorithm)
+        {
+            return GetName(certificateCompressionAlgorithm) + "(" + certificateCompressionAlgorithm + ")";
+        }
+
+        public static bool IsRecognized(int certificateCompressionAlgorithm)
+        {
+            switch (certificateCompressionAlgorithm)
+            {
+            case zlib:
+            case brotli:
+            case zstd:
+                return true;
+            default:
+                return false;
+            }
+        }
+    }
+}
diff --git a/crypto/src/tls/ExtensionType.cs b/crypto/src/tls/ExtensionType.cs
index 87f6a7574..a1f1fa7e8 100644
--- a/crypto/src/tls/ExtensionType.cs
+++ b/crypto/src/tls/ExtensionType.cs
@@ -107,6 +107,11 @@ namespace Org.BouncyCastle.Tls
         public const int cached_info = 25;
 
         /*
+         * RFC 8879
+         */
+        public const int compress_certificate = 27;
+
+        /*
          * RFC 8449
          */
         public const int record_size_limit = 28;
@@ -191,6 +196,8 @@ namespace Org.BouncyCastle.Tls
                 return "token_binding";
             case cached_info:
                 return "cached_info";
+            case compress_certificate:
+                return "compress_certificate";
             case record_size_limit:
                 return "record_size_limit";
             case session_ticket:
@@ -257,6 +264,7 @@ namespace Org.BouncyCastle.Tls
             case extended_master_secret:
             case token_binding:
             case cached_info:
+            case compress_certificate:
             case record_size_limit:
             case session_ticket:
             case pre_shared_key:
diff --git a/crypto/src/tls/HandshakeType.cs b/crypto/src/tls/HandshakeType.cs
index 563cd1150..ad2c29c07 100644
--- a/crypto/src/tls/HandshakeType.cs
+++ b/crypto/src/tls/HandshakeType.cs
@@ -44,6 +44,11 @@ namespace Org.BouncyCastle.Tls
         public const short key_update = 24;
         public const short message_hash = 254;
 
+        /*
+         * RFC 8879
+         */
+        public const short compressed_certificate = 25;
+
         public static string GetName(short handshakeType)
         {
             switch (handshakeType)
@@ -88,6 +93,8 @@ namespace Org.BouncyCastle.Tls
                 return "key_update";
             case message_hash:
                 return "message_hash";
+            case compressed_certificate:
+                return "compressed_certificate";
             default:
                 return "UNKNOWN";
             }
@@ -122,6 +129,7 @@ namespace Org.BouncyCastle.Tls
             case encrypted_extensions:
             case key_update:
             case message_hash:
+            case compressed_certificate:
                 return true;
             default:
                 return false;
diff --git a/crypto/src/tls/TlsClientProtocol.cs b/crypto/src/tls/TlsClientProtocol.cs
index c132b257b..19e2eda3d 100644
--- a/crypto/src/tls/TlsClientProtocol.cs
+++ b/crypto/src/tls/TlsClientProtocol.cs
@@ -315,6 +315,7 @@ namespace Org.BouncyCastle.Tls
             case HandshakeType.certificate_url:
             case HandshakeType.client_hello:
             case HandshakeType.client_key_exchange:
+            case HandshakeType.compressed_certificate:
             case HandshakeType.end_of_early_data:
             case HandshakeType.hello_request:
             case HandshakeType.hello_verify_request:
@@ -743,6 +744,7 @@ namespace Org.BouncyCastle.Tls
             case HandshakeType.certificate_verify:
             case HandshakeType.client_hello:
             case HandshakeType.client_key_exchange:
+            case HandshakeType.compressed_certificate:
             case HandshakeType.encrypted_extensions:
             case HandshakeType.end_of_early_data:
             case HandshakeType.hello_verify_request:
diff --git a/crypto/src/tls/TlsExtensionsUtilities.cs b/crypto/src/tls/TlsExtensionsUtilities.cs
index 5a13d8d2e..e1db93016 100644
--- a/crypto/src/tls/TlsExtensionsUtilities.cs
+++ b/crypto/src/tls/TlsExtensionsUtilities.cs
@@ -53,6 +53,12 @@ namespace Org.BouncyCastle.Tls
         }
 
         /// <exception cref="IOException"/>
+        public static void AddCompressCertificateExtension(IDictionary extensions, int[] algorithms)
+        {
+            extensions[ExtensionType.compress_certificate] = CreateCompressCertificateExtension(algorithms);
+        }
+
+        /// <exception cref="IOException"/>
         public static void AddCookieExtension(IDictionary extensions, byte[] cookie)
         {
             extensions[ExtensionType.cookie] = CreateCookieExtension(cookie);
@@ -280,6 +286,13 @@ namespace Org.BouncyCastle.Tls
         }
 
         /// <exception cref="IOException"/>
+        public static int[] GetCompressCertificateExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.compress_certificate);
+            return extensionData == null ? null : ReadCompressCertificateExtension(extensionData);
+        }
+
+        /// <exception cref="IOException"/>
         public static byte[] GetCookieExtension(IDictionary extensions)
         {
             byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.cookie);
@@ -580,6 +593,15 @@ namespace Org.BouncyCastle.Tls
         }
 
         /// <exception cref="IOException"/>
+        public static byte[] CreateCompressCertificateExtension(int[] algorithms)
+        {
+            if (TlsUtilities.IsNullOrEmpty(algorithms) || algorithms.Length > 127)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            return TlsUtilities.EncodeUint16ArrayWithUint8Length(algorithms);
+        }
+
+        /// <exception cref="IOException"/>
         public static byte[] CreateCookieExtension(byte[] cookie)
         {
             if (TlsUtilities.IsNullOrEmpty(cookie) || cookie.Length >= (1 << 16))
@@ -995,6 +1017,16 @@ namespace Org.BouncyCastle.Tls
         }
 
         /// <exception cref="IOException"/>
+        public static int[] ReadCompressCertificateExtension(byte[] extensionData)
+        {
+            int[] algorithms = TlsUtilities.DecodeUint16ArrayWithUint8Length(extensionData);
+            if (algorithms.Length < 1)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            return algorithms;
+        }
+
+        /// <exception cref="IOException"/>
         public static byte[] ReadCookieExtension(byte[] extensionData)
         {
             return TlsUtilities.DecodeOpaque16(extensionData, 1);
diff --git a/crypto/src/tls/TlsServerProtocol.cs b/crypto/src/tls/TlsServerProtocol.cs
index 40218a2fb..22700a277 100644
--- a/crypto/src/tls/TlsServerProtocol.cs
+++ b/crypto/src/tls/TlsServerProtocol.cs
@@ -834,6 +834,7 @@ namespace Org.BouncyCastle.Tls
             case HandshakeType.certificate_status:
             case HandshakeType.certificate_url:
             case HandshakeType.client_key_exchange:
+            case HandshakeType.compressed_certificate:
             case HandshakeType.encrypted_extensions:
             case HandshakeType.end_of_early_data:
             case HandshakeType.hello_request:
@@ -1201,6 +1202,7 @@ namespace Org.BouncyCastle.Tls
             case HandshakeType.certificate_request:
             case HandshakeType.certificate_status:
             case HandshakeType.certificate_url:
+            case HandshakeType.compressed_certificate:
             case HandshakeType.encrypted_extensions:
             case HandshakeType.end_of_early_data:
             case HandshakeType.hello_request:
diff --git a/crypto/src/tls/TlsUtilities.cs b/crypto/src/tls/TlsUtilities.cs
index 8733fd68f..f48c7e731 100644
--- a/crypto/src/tls/TlsUtilities.cs
+++ b/crypto/src/tls/TlsUtilities.cs
@@ -486,6 +486,14 @@ namespace Org.BouncyCastle.Tls
             }
         }
 
+        public static void WriteUint16ArrayWithUint8Length(int[] u16s, byte[] buf, int offset)
+        {
+            int length = 2 * u16s.Length;
+            CheckUint8(length);
+            WriteUint8(length, buf, offset);
+            WriteUint16Array(u16s, buf, offset + 1);
+        }
+
         public static void WriteUint16ArrayWithUint16Length(int[] u16s, Stream output)
         {
             int length = 2 * u16s.Length;
@@ -577,6 +585,25 @@ namespace Org.BouncyCastle.Tls
             return ReadUint16(buf, 0);
         }
 
+        public static int[] DecodeUint16ArrayWithUint8Length(byte[] buf)
+        {
+            if (buf == null)
+                throw new ArgumentNullException("buf");
+
+            int length = ReadUint8(buf, 0);
+            if (buf.Length != (length + 1) || (length & 1) != 0)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            int count = length / 2, pos = 1;
+            int[] u16s = new int[count];
+            for (int i = 0; i < count; ++i)
+            {
+                u16s[i] = ReadUint16(buf, pos);
+                pos += 2;
+            }
+            return u16s;
+        }
+
         public static long DecodeUint32(byte[] buf)
         {
             if (buf == null)
@@ -636,6 +663,14 @@ namespace Org.BouncyCastle.Tls
             return encoding;
         }
 
+        public static byte[] EncodeUint16ArrayWithUint8Length(int[] u16s)
+        {
+            int length = 2 * u16s.Length;
+            byte[] result = new byte[1 + length];
+            WriteUint16ArrayWithUint8Length(u16s, result, 0);
+            return result;
+        }
+
         public static byte[] EncodeUint16ArrayWithUint16Length(int[] u16s)
         {
             int length = 2 * u16s.Length;
@@ -5348,6 +5383,7 @@ namespace Org.BouncyCastle.Tls
                 }
             }
             case ExtensionType.signature_algorithms:
+            case ExtensionType.compress_certificate:
             case ExtensionType.certificate_authorities:
             case ExtensionType.signature_algorithms_cert:
             {