diff options
-rw-r--r-- | crypto/BouncyCastle.Android.csproj | 1 | ||||
-rw-r--r-- | crypto/BouncyCastle.csproj | 1 | ||||
-rw-r--r-- | crypto/BouncyCastle.iOS.csproj | 1 | ||||
-rw-r--r-- | crypto/crypto.csproj | 5 | ||||
-rw-r--r-- | crypto/src/tls/CertificateCompressionAlgorithm.cs | 47 | ||||
-rw-r--r-- | crypto/src/tls/ExtensionType.cs | 8 | ||||
-rw-r--r-- | crypto/src/tls/HandshakeType.cs | 8 | ||||
-rw-r--r-- | crypto/src/tls/TlsClientProtocol.cs | 2 | ||||
-rw-r--r-- | crypto/src/tls/TlsExtensionsUtilities.cs | 32 | ||||
-rw-r--r-- | crypto/src/tls/TlsServerProtocol.cs | 2 | ||||
-rw-r--r-- | crypto/src/tls/TlsUtilities.cs | 36 |
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: { |