From 0db55f1b5e2dbed6bc774432be7172abe3daa1e4 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Wed, 2 Mar 2022 16:36:48 +0700 Subject: RFC 8879 preliminaries --- crypto/src/tls/CertificateCompressionAlgorithm.cs | 47 +++++++++++++++++++++++ crypto/src/tls/ExtensionType.cs | 8 ++++ crypto/src/tls/HandshakeType.cs | 8 ++++ crypto/src/tls/TlsClientProtocol.cs | 2 + crypto/src/tls/TlsExtensionsUtilities.cs | 32 +++++++++++++++ crypto/src/tls/TlsServerProtocol.cs | 2 + crypto/src/tls/TlsUtilities.cs | 36 +++++++++++++++++ 7 files changed, 135 insertions(+) create mode 100644 crypto/src/tls/CertificateCompressionAlgorithm.cs (limited to 'crypto/src/tls') 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 @@ -106,6 +106,11 @@ namespace Org.BouncyCastle.Tls */ public const int cached_info = 25; + /* + * RFC 8879 + */ + public const int compress_certificate = 27; + /* * RFC 8449 */ @@ -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 @@ -52,6 +52,12 @@ namespace Org.BouncyCastle.Tls extensions[ExtensionType.client_certificate_url] = CreateClientCertificateUrlExtension(); } + /// + public static void AddCompressCertificateExtension(IDictionary extensions, int[] algorithms) + { + extensions[ExtensionType.compress_certificate] = CreateCompressCertificateExtension(algorithms); + } + /// public static void AddCookieExtension(IDictionary extensions, byte[] cookie) { @@ -279,6 +285,13 @@ namespace Org.BouncyCastle.Tls return extensionData == null ? (short)-1 : ReadCertificateTypeExtensionServer(extensionData); } + /// + public static int[] GetCompressCertificateExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.compress_certificate); + return extensionData == null ? null : ReadCompressCertificateExtension(extensionData); + } + /// public static byte[] GetCookieExtension(IDictionary extensions) { @@ -579,6 +592,15 @@ namespace Org.BouncyCastle.Tls return CreateEmptyExtensionData(); } + /// + public static byte[] CreateCompressCertificateExtension(int[] algorithms) + { + if (TlsUtilities.IsNullOrEmpty(algorithms) || algorithms.Length > 127) + throw new TlsFatalAlert(AlertDescription.internal_error); + + return TlsUtilities.EncodeUint16ArrayWithUint8Length(algorithms); + } + /// public static byte[] CreateCookieExtension(byte[] cookie) { @@ -994,6 +1016,16 @@ namespace Org.BouncyCastle.Tls return ReadEmptyExtensionData(extensionData); } + /// + public static int[] ReadCompressCertificateExtension(byte[] extensionData) + { + int[] algorithms = TlsUtilities.DecodeUint16ArrayWithUint8Length(extensionData); + if (algorithms.Length < 1) + throw new TlsFatalAlert(AlertDescription.decode_error); + + return algorithms; + } + /// public static byte[] ReadCookieExtension(byte[] extensionData) { 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: { -- cgit 1.5.1