diff options
Diffstat (limited to 'crypto/src/tls/TlsExtensionsUtilities.cs')
-rw-r--r-- | crypto/src/tls/TlsExtensionsUtilities.cs | 1377 |
1 files changed, 1377 insertions, 0 deletions
diff --git a/crypto/src/tls/TlsExtensionsUtilities.cs b/crypto/src/tls/TlsExtensionsUtilities.cs new file mode 100644 index 000000000..688fee3c7 --- /dev/null +++ b/crypto/src/tls/TlsExtensionsUtilities.cs @@ -0,0 +1,1377 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Tls +{ + public abstract class TlsExtensionsUtilities + { + public static IDictionary EnsureExtensionsInitialised(IDictionary extensions) + { + return extensions == null ? Platform.CreateHashtable() : extensions; + } + + /// <param name="extensions">(Int32 -> byte[])</param> + /// <param name="protocolNameList">an <see cref="IList"/> of <see cref="ProtocolName"/>.</param> + /// <exception cref="IOException"/> + public static void AddAlpnExtensionClient(IDictionary extensions, IList protocolNameList) + { + extensions[ExtensionType.application_layer_protocol_negotiation] = CreateAlpnExtensionClient(protocolNameList); + } + + /// <exception cref="IOException"/> + public static void AddAlpnExtensionServer(IDictionary extensions, ProtocolName protocolName) + { + extensions[ExtensionType.application_layer_protocol_negotiation] = CreateAlpnExtensionServer(protocolName); + } + + /// <exception cref="IOException"/> + public static void AddCertificateAuthoritiesExtension(IDictionary extensions, IList authorities) + { + extensions[ExtensionType.certificate_authorities] = CreateCertificateAuthoritiesExtension(authorities); + } + + /// <exception cref="IOException"/> + public static void AddClientCertificateTypeExtensionClient(IDictionary extensions, short[] certificateTypes) + { + extensions[ExtensionType.client_certificate_type] = CreateCertificateTypeExtensionClient(certificateTypes); + } + + /// <exception cref="IOException"/> + public static void AddClientCertificateTypeExtensionServer(IDictionary extensions, short certificateType) + { + extensions[ExtensionType.client_certificate_type] = CreateCertificateTypeExtensionServer(certificateType); + } + + public static void AddClientCertificateUrlExtension(IDictionary extensions) + { + extensions[ExtensionType.client_certificate_url] = CreateClientCertificateUrlExtension(); + } + + /// <exception cref="IOException"/> + public static void AddCookieExtension(IDictionary extensions, byte[] cookie) + { + extensions[ExtensionType.cookie] = CreateCookieExtension(cookie); + } + + public static void AddEarlyDataIndication(IDictionary extensions) + { + extensions[ExtensionType.early_data] = CreateEarlyDataIndication(); + } + + /// <exception cref="IOException"/> + public static void AddEarlyDataMaxSize(IDictionary extensions, long maxSize) + { + extensions[ExtensionType.early_data] = CreateEarlyDataMaxSize(maxSize); + } + + public static void AddEmptyExtensionData(IDictionary extensions, Int32 extType) + { + extensions[extType] = CreateEmptyExtensionData(); + } + + public static void AddEncryptThenMacExtension(IDictionary extensions) + { + extensions[ExtensionType.encrypt_then_mac] = CreateEncryptThenMacExtension(); + } + + public static void AddExtendedMasterSecretExtension(IDictionary extensions) + { + extensions[ExtensionType.extended_master_secret] = CreateExtendedMasterSecretExtension(); + } + + /// <exception cref="IOException"/> + public static void AddHeartbeatExtension(IDictionary extensions, HeartbeatExtension heartbeatExtension) + { + extensions[ExtensionType.heartbeat] = CreateHeartbeatExtension(heartbeatExtension); + } + + /// <exception cref="IOException"/> + public static void AddKeyShareClientHello(IDictionary extensions, IList clientShares) + { + extensions[ExtensionType.key_share] = CreateKeyShareClientHello(clientShares); + } + + /// <exception cref="IOException"/> + public static void AddKeyShareHelloRetryRequest(IDictionary extensions, int namedGroup) + { + extensions[ExtensionType.key_share] = CreateKeyShareHelloRetryRequest(namedGroup); + } + + /// <exception cref="IOException"/> + public static void AddKeyShareServerHello(IDictionary extensions, KeyShareEntry serverShare) + { + extensions[ExtensionType.key_share] = CreateKeyShareServerHello(serverShare); + } + + /// <exception cref="IOException"/> + public static void AddMaxFragmentLengthExtension(IDictionary extensions, short maxFragmentLength) + { + extensions[ExtensionType.max_fragment_length] = CreateMaxFragmentLengthExtension(maxFragmentLength); + } + + /// <exception cref="IOException"/> + public static void AddOidFiltersExtension(IDictionary extensions, IDictionary filters) + { + extensions[ExtensionType.oid_filters] = CreateOidFiltersExtension(filters); + } + + /// <exception cref="IOException"/> + public static void AddPaddingExtension(IDictionary extensions, int dataLength) + { + extensions[ExtensionType.padding] = CreatePaddingExtension(dataLength); + } + + public static void AddPostHandshakeAuthExtension(IDictionary extensions) + { + extensions[ExtensionType.post_handshake_auth] = CreatePostHandshakeAuthExtension(); + } + + /// <exception cref="IOException"/> + public static void AddPreSharedKeyClientHello(IDictionary extensions, OfferedPsks offeredPsks) + { + extensions[ExtensionType.pre_shared_key] = CreatePreSharedKeyClientHello(offeredPsks); + } + + /// <exception cref="IOException"/> + public static void AddPreSharedKeyServerHello(IDictionary extensions, int selectedIdentity) + { + extensions[ExtensionType.pre_shared_key] = CreatePreSharedKeyServerHello(selectedIdentity); + } + + /// <exception cref="IOException"/> + public static void AddPskKeyExchangeModesExtension(IDictionary extensions, short[] modes) + { + extensions[ExtensionType.psk_key_exchange_modes] = CreatePskKeyExchangeModesExtension(modes); + } + + /// <exception cref="IOException"/> + public static void AddRecordSizeLimitExtension(IDictionary extensions, int recordSizeLimit) + { + extensions[ExtensionType.record_size_limit] = CreateRecordSizeLimitExtension(recordSizeLimit); + } + + /// <exception cref="IOException"/> + public static void AddServerCertificateTypeExtensionClient(IDictionary extensions, short[] certificateTypes) + { + extensions[ExtensionType.server_certificate_type] = CreateCertificateTypeExtensionClient(certificateTypes); + } + + /// <exception cref="IOException"/> + public static void AddServerCertificateTypeExtensionServer(IDictionary extensions, short certificateType) + { + extensions[ExtensionType.server_certificate_type] = CreateCertificateTypeExtensionServer(certificateType); + } + + /// <exception cref="IOException"/> + public static void AddServerNameExtensionClient(IDictionary extensions, IList serverNameList) + { + extensions[ExtensionType.server_name] = CreateServerNameExtensionClient(serverNameList); + } + + /// <exception cref="IOException"/> + public static void AddServerNameExtensionServer(IDictionary extensions) + { + extensions[ExtensionType.server_name] = CreateServerNameExtensionServer(); + } + + /// <exception cref="IOException"/> + public static void AddSignatureAlgorithmsExtension(IDictionary extensions, IList supportedSignatureAlgorithms) + { + extensions[ExtensionType.signature_algorithms] = CreateSignatureAlgorithmsExtension(supportedSignatureAlgorithms); + } + + /// <exception cref="IOException"/> + public static void AddSignatureAlgorithmsCertExtension(IDictionary extensions, IList supportedSignatureAlgorithms) + { + extensions[ExtensionType.signature_algorithms_cert] = CreateSignatureAlgorithmsCertExtension(supportedSignatureAlgorithms); + } + + /// <exception cref="IOException"/> + public static void AddStatusRequestExtension(IDictionary extensions, CertificateStatusRequest statusRequest) + { + extensions[ExtensionType.status_request] = CreateStatusRequestExtension(statusRequest); + } + + /// <exception cref="IOException"/> + public static void AddStatusRequestV2Extension(IDictionary extensions, IList statusRequestV2) + { + extensions[ExtensionType.status_request_v2] = CreateStatusRequestV2Extension(statusRequestV2); + } + + /// <exception cref="IOException"/> + public static void AddSupportedGroupsExtension(IDictionary extensions, IList namedGroups) + { + extensions[ExtensionType.supported_groups] = CreateSupportedGroupsExtension(namedGroups); + } + + /// <exception cref="IOException"/> + public static void AddSupportedPointFormatsExtension(IDictionary extensions, short[] ecPointFormats) + { + extensions[ExtensionType.ec_point_formats] = CreateSupportedPointFormatsExtension(ecPointFormats); + } + + /// <exception cref="IOException"/> + public static void AddSupportedVersionsExtensionClient(IDictionary extensions, ProtocolVersion[] versions) + { + extensions[ExtensionType.supported_versions] = CreateSupportedVersionsExtensionClient(versions); + } + + /// <exception cref="IOException"/> + public static void AddSupportedVersionsExtensionServer(IDictionary extensions, ProtocolVersion selectedVersion) + { + extensions[ExtensionType.supported_versions] = CreateSupportedVersionsExtensionServer(selectedVersion); + } + + public static void AddTruncatedHmacExtension(IDictionary extensions) + { + extensions[ExtensionType.truncated_hmac] = CreateTruncatedHmacExtension(); + } + + /// <exception cref="IOException"/> + public static void AddTrustedCAKeysExtensionClient(IDictionary extensions, IList trustedAuthoritiesList) + { + extensions[ExtensionType.trusted_ca_keys] = CreateTrustedCAKeysExtensionClient(trustedAuthoritiesList); + } + + public static void AddTrustedCAKeysExtensionServer(IDictionary extensions) + { + extensions[ExtensionType.trusted_ca_keys] = CreateTrustedCAKeysExtensionServer(); + } + + /// <returns>an <see cref="IList"/> of <see cref="ProtocolName"/>.</returns> + /// <exception cref="IOException"/> + public static IList GetAlpnExtensionClient(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.application_layer_protocol_negotiation); + return extensionData == null ? null : ReadAlpnExtensionClient(extensionData); + } + + /// <exception cref="IOException"/> + public static ProtocolName GetAlpnExtensionServer(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.application_layer_protocol_negotiation); + return extensionData == null ? null : ReadAlpnExtensionServer(extensionData); + } + + /// <exception cref="IOException"/> + public static IList GetCertificateAuthoritiesExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.certificate_authorities); + return extensionData == null ? null : ReadCertificateAuthoritiesExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static short[] GetClientCertificateTypeExtensionClient(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.client_certificate_type); + return extensionData == null ? null : ReadCertificateTypeExtensionClient(extensionData); + } + + /// <exception cref="IOException"/> + public static short GetClientCertificateTypeExtensionServer(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.client_certificate_type); + return extensionData == null ? (short)-1 : ReadCertificateTypeExtensionServer(extensionData); + } + + /// <exception cref="IOException"/> + public static byte[] GetCookieExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.cookie); + return extensionData == null ? null : ReadCookieExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static long GetEarlyDataMaxSize(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.early_data); + return extensionData == null ? -1L : ReadEarlyDataMaxSize(extensionData); + } + + /// <exception cref="IOException"/> + public static HeartbeatExtension GetHeartbeatExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.heartbeat); + return extensionData == null ? null : ReadHeartbeatExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static IList GetKeyShareClientHello(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.key_share); + return extensionData == null ? null : ReadKeyShareClientHello(extensionData); + } + + /// <exception cref="IOException"/> + public static int GetKeyShareHelloRetryRequest(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.key_share); + return extensionData == null ? -1 : ReadKeyShareHelloRetryRequest(extensionData); + } + + /// <exception cref="IOException"/> + public static KeyShareEntry GetKeyShareServerHello(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.key_share); + return extensionData == null ? null : ReadKeyShareServerHello(extensionData); + } + + /// <exception cref="IOException"/> + public static short GetMaxFragmentLengthExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.max_fragment_length); + return extensionData == null ? (short)-1 : ReadMaxFragmentLengthExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static IDictionary GetOidFiltersExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.oid_filters); + return extensionData == null ? null : ReadOidFiltersExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static int GetPaddingExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.padding); + return extensionData == null ? -1 : ReadPaddingExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static OfferedPsks GetPreSharedKeyClientHello(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.pre_shared_key); + return extensionData == null ? null : ReadPreSharedKeyClientHello(extensionData); + } + + /// <exception cref="IOException"/> + public static int GetPreSharedKeyServerHello(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.pre_shared_key); + return extensionData == null ? -1 : ReadPreSharedKeyServerHello(extensionData); + } + + /// <exception cref="IOException"/> + public static short[] GetPskKeyExchangeModesExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.psk_key_exchange_modes); + return extensionData == null ? null : ReadPskKeyExchangeModesExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static int GetRecordSizeLimitExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.record_size_limit); + return extensionData == null ? -1 : ReadRecordSizeLimitExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static short[] GetServerCertificateTypeExtensionClient(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_certificate_type); + return extensionData == null ? null : ReadCertificateTypeExtensionClient(extensionData); + } + + /// <exception cref="IOException"/> + public static short GetServerCertificateTypeExtensionServer(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_certificate_type); + return extensionData == null ? (short)-1 : ReadCertificateTypeExtensionServer(extensionData); + } + + /// <exception cref="IOException"/> + public static IList GetServerNameExtensionClient(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_name); + return extensionData == null ? null : ReadServerNameExtensionClient(extensionData); + } + + /// <exception cref="IOException"/> + public static IList GetSignatureAlgorithmsExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.signature_algorithms); + return extensionData == null ? null : ReadSignatureAlgorithmsExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static IList GetSignatureAlgorithmsCertExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.signature_algorithms_cert); + return extensionData == null ? null : ReadSignatureAlgorithmsCertExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static CertificateStatusRequest GetStatusRequestExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.status_request); + return extensionData == null ? null : ReadStatusRequestExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static IList GetStatusRequestV2Extension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.status_request_v2); + return extensionData == null ? null : ReadStatusRequestV2Extension(extensionData); + } + + /// <exception cref="IOException"/> + public static int[] GetSupportedGroupsExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.supported_groups); + return extensionData == null ? null : ReadSupportedGroupsExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static short[] GetSupportedPointFormatsExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.ec_point_formats); + return extensionData == null ? null : ReadSupportedPointFormatsExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static ProtocolVersion[] GetSupportedVersionsExtensionClient(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.supported_versions); + return extensionData == null ? null : ReadSupportedVersionsExtensionClient(extensionData); + } + + /// <exception cref="IOException"/> + public static ProtocolVersion GetSupportedVersionsExtensionServer(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.supported_versions); + return extensionData == null ? null : ReadSupportedVersionsExtensionServer(extensionData); + } + + /// <exception cref="IOException"/> + public static IList GetTrustedCAKeysExtensionClient(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.trusted_ca_keys); + return extensionData == null ? null : ReadTrustedCAKeysExtensionClient(extensionData); + } + + /// <exception cref="IOException"/> + public static bool HasClientCertificateUrlExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.client_certificate_url); + return extensionData == null ? false : ReadClientCertificateUrlExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static bool HasEarlyDataIndication(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.early_data); + return extensionData == null ? false : ReadEarlyDataIndication(extensionData); + } + + /// <exception cref="IOException"/> + public static bool HasEncryptThenMacExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.encrypt_then_mac); + return extensionData == null ? false : ReadEncryptThenMacExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static bool HasExtendedMasterSecretExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.extended_master_secret); + return extensionData == null ? false : ReadExtendedMasterSecretExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static bool HasServerNameExtensionServer(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_name); + return extensionData == null ? false : ReadServerNameExtensionServer(extensionData); + } + + /// <exception cref="IOException"/> + public static bool HasPostHandshakeAuthExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.post_handshake_auth); + return extensionData == null ? false : ReadPostHandshakeAuthExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static bool HasTruncatedHmacExtension(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.truncated_hmac); + return extensionData == null ? false : ReadTruncatedHmacExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static bool HasTrustedCAKeysExtensionServer(IDictionary extensions) + { + byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.trusted_ca_keys); + return extensionData == null ? false : ReadTrustedCAKeysExtensionServer(extensionData); + } + + /// <param name="protocolNameList">an <see cref="IList"/> of <see cref="ProtocolName"/>.</param> + /// <exception cref="IOException"/> + public static byte[] CreateAlpnExtensionClient(IList protocolNameList) + { + if (protocolNameList == null || protocolNameList.Count < 1) + throw new TlsFatalAlert(AlertDescription.internal_error); + + MemoryStream buf = new MemoryStream(); + + // Placeholder for length + TlsUtilities.WriteUint16(0, buf); + + foreach (ProtocolName protocolName in protocolNameList) + { + protocolName.Encode(buf); + } + + return PatchOpaque16(buf); + } + + /// <exception cref="IOException"/> + public static byte[] CreateAlpnExtensionServer(ProtocolName protocolName) + { + IList protocol_name_list = Platform.CreateArrayList(); + protocol_name_list.Add(protocolName); + + return CreateAlpnExtensionClient(protocol_name_list); + } + + /// <exception cref="IOException"/> + public static byte[] CreateCertificateAuthoritiesExtension(IList authorities) + { + if (null == authorities || authorities.Count < 1) + throw new TlsFatalAlert(AlertDescription.internal_error); + + MemoryStream buf = new MemoryStream(); + + // Placeholder for length + TlsUtilities.WriteUint16(0, buf); + + foreach (X509Name authority in authorities) + { + byte[] derEncoding = authority.GetEncoded(Asn1Encodable.Der); + TlsUtilities.WriteOpaque16(derEncoding, buf); + } + + return PatchOpaque16(buf); + } + + /// <exception cref="IOException"/> + public static byte[] CreateCertificateTypeExtensionClient(short[] certificateTypes) + { + if (TlsUtilities.IsNullOrEmpty(certificateTypes) || certificateTypes.Length > 255) + throw new TlsFatalAlert(AlertDescription.internal_error); + + return TlsUtilities.EncodeUint8ArrayWithUint8Length(certificateTypes); + } + + /// <exception cref="IOException"/> + public static byte[] CreateCertificateTypeExtensionServer(short certificateType) + { + return TlsUtilities.EncodeUint8(certificateType); + } + + public static byte[] CreateClientCertificateUrlExtension() + { + return CreateEmptyExtensionData(); + } + + /// <exception cref="IOException"/> + public static byte[] CreateCookieExtension(byte[] cookie) + { + if (TlsUtilities.IsNullOrEmpty(cookie) || cookie.Length >= (1 << 16)) + throw new TlsFatalAlert(AlertDescription.internal_error); + + return TlsUtilities.EncodeOpaque16(cookie); + } + + public static byte[] CreateEarlyDataIndication() + { + return CreateEmptyExtensionData(); + } + + /// <exception cref="IOException"/> + public static byte[] CreateEarlyDataMaxSize(long maxSize) + { + return TlsUtilities.EncodeUint32(maxSize); + } + + public static byte[] CreateEmptyExtensionData() + { + return TlsUtilities.EmptyBytes; + } + + public static byte[] CreateEncryptThenMacExtension() + { + return CreateEmptyExtensionData(); + } + + public static byte[] CreateExtendedMasterSecretExtension() + { + return CreateEmptyExtensionData(); + } + + /// <exception cref="IOException"/> + public static byte[] CreateHeartbeatExtension(HeartbeatExtension heartbeatExtension) + { + if (heartbeatExtension == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + MemoryStream buf = new MemoryStream(); + + heartbeatExtension.Encode(buf); + + return buf.ToArray(); + } + + /// <exception cref="IOException"/> + public static byte[] CreateKeyShareClientHello(IList clientShares) + { + if (clientShares == null || clientShares.Count < 1) + return TlsUtilities.EncodeUint16(0); + + MemoryStream buf = new MemoryStream(); + + // Placeholder for length + TlsUtilities.WriteUint16(0, buf); + + foreach (KeyShareEntry clientShare in clientShares) + { + clientShare.Encode(buf); + } + + return PatchOpaque16(buf); + } + + /// <exception cref="IOException"/> + public static byte[] CreateKeyShareHelloRetryRequest(int namedGroup) + { + return TlsUtilities.EncodeUint16(namedGroup); + } + + /// <exception cref="IOException"/> + public static byte[] CreateKeyShareServerHello(KeyShareEntry serverShare) + { + if (serverShare == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + MemoryStream buf = new MemoryStream(); + + serverShare.Encode(buf); + + return buf.ToArray(); + } + + /// <exception cref="IOException"/> + public static byte[] CreateMaxFragmentLengthExtension(short maxFragmentLength) + { + return TlsUtilities.EncodeUint8(maxFragmentLength); + } + + /// <exception cref="IOException"/> + public static byte[] CreateOidFiltersExtension(IDictionary filters) + { + MemoryStream buf = new MemoryStream(); + + // Placeholder for length + TlsUtilities.WriteUint16(0, buf); + + if (null != filters) + { + foreach (DerObjectIdentifier certificateExtensionOid in filters.Keys) + { + byte[] certificateExtensionValues = (byte[])filters[certificateExtensionOid]; + + if (null == certificateExtensionOid || null == certificateExtensionValues) + throw new TlsFatalAlert(AlertDescription.internal_error); + + byte[] derEncoding = certificateExtensionOid.GetEncoded(Asn1Encodable.Der); + TlsUtilities.WriteOpaque8(derEncoding, buf); + + TlsUtilities.WriteOpaque16(certificateExtensionValues, buf); + } + } + + return PatchOpaque16(buf); + } + + /// <exception cref="IOException"/> + public static byte[] CreatePaddingExtension(int dataLength) + { + TlsUtilities.CheckUint16(dataLength); + return new byte[dataLength]; + } + + public static byte[] CreatePostHandshakeAuthExtension() + { + return CreateEmptyExtensionData(); + } + + /// <exception cref="IOException"/> + public static byte[] CreatePreSharedKeyClientHello(OfferedPsks offeredPsks) + { + if (offeredPsks == null) + throw new TlsFatalAlert(AlertDescription.internal_error); + + MemoryStream buf = new MemoryStream(); + + offeredPsks.Encode(buf); + + return buf.ToArray(); + } + + /// <exception cref="IOException"/> + public static byte[] CreatePreSharedKeyServerHello(int selectedIdentity) + { + return TlsUtilities.EncodeUint16(selectedIdentity); + } + + /// <exception cref="IOException"/> + public static byte[] CreatePskKeyExchangeModesExtension(short[] modes) + { + if (TlsUtilities.IsNullOrEmpty(modes) || modes.Length > 255) + throw new TlsFatalAlert(AlertDescription.internal_error); + + return TlsUtilities.EncodeUint8ArrayWithUint8Length(modes); + } + + /// <exception cref="IOException"/> + public static byte[] CreateRecordSizeLimitExtension(int recordSizeLimit) + { + if (recordSizeLimit < 64) + throw new TlsFatalAlert(AlertDescription.internal_error); + + return TlsUtilities.EncodeUint16(recordSizeLimit); + } + + /// <exception cref="IOException"/> + public static byte[] CreateServerNameExtensionClient(IList serverNameList) + { + if (serverNameList == null) + throw new TlsFatalAlert(AlertDescription.internal_error); + + MemoryStream buf = new MemoryStream(); + + new ServerNameList(serverNameList).Encode(buf); + + return buf.ToArray(); + } + + public static byte[] CreateServerNameExtensionServer() + { + return CreateEmptyExtensionData(); + } + + /// <exception cref="IOException"/> + public static byte[] CreateSignatureAlgorithmsExtension(IList supportedSignatureAlgorithms) + { + MemoryStream buf = new MemoryStream(); + + TlsUtilities.EncodeSupportedSignatureAlgorithms(supportedSignatureAlgorithms, buf); + + return buf.ToArray(); + } + + /// <exception cref="IOException"/> + public static byte[] CreateSignatureAlgorithmsCertExtension(IList supportedSignatureAlgorithms) + { + return CreateSignatureAlgorithmsExtension(supportedSignatureAlgorithms); + } + + /// <exception cref="IOException"/> + public static byte[] CreateStatusRequestExtension(CertificateStatusRequest statusRequest) + { + if (statusRequest == null) + throw new TlsFatalAlert(AlertDescription.internal_error); + + MemoryStream buf = new MemoryStream(); + + statusRequest.Encode(buf); + + return buf.ToArray(); + } + + /// <exception cref="IOException"/> + public static byte[] CreateStatusRequestV2Extension(IList statusRequestV2) + { + if (statusRequestV2 == null || statusRequestV2.Count < 1) + throw new TlsFatalAlert(AlertDescription.internal_error); + + MemoryStream buf = new MemoryStream(); + + // Placeholder for length + TlsUtilities.WriteUint16(0, buf); + + foreach (CertificateStatusRequestItemV2 entry in statusRequestV2) + { + entry.Encode(buf); + } + + return PatchOpaque16(buf); + } + + /// <exception cref="IOException"/> + public static byte[] CreateSupportedGroupsExtension(IList namedGroups) + { + if (namedGroups == null || namedGroups.Count < 1) + throw new TlsFatalAlert(AlertDescription.internal_error); + + int count = namedGroups.Count; + int[] values = new int[count]; + for (int i = 0; i < count; ++i) + { + values[i] = (Int32)namedGroups[i]; + } + + return TlsUtilities.EncodeUint16ArrayWithUint16Length(values); + } + + /// <exception cref="IOException"/> + public static byte[] CreateSupportedPointFormatsExtension(short[] ecPointFormats) + { + if (ecPointFormats == null || !Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed)) + { + /* + * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST + * contain the value 0 (uncompressed) as one of the items in the list of point formats. + */ + + // NOTE: We add it at the start (highest preference) + ecPointFormats = Arrays.Prepend(ecPointFormats, ECPointFormat.uncompressed); + } + + return TlsUtilities.EncodeUint8ArrayWithUint8Length(ecPointFormats); + } + + /// <exception cref="IOException"/> + public static byte[] CreateSupportedVersionsExtensionClient(ProtocolVersion[] versions) + { + if (TlsUtilities.IsNullOrEmpty(versions) || versions.Length > 127) + throw new TlsFatalAlert(AlertDescription.internal_error); + + int count = versions.Length; + byte[] data = new byte[1 + count * 2]; + TlsUtilities.WriteUint8(count * 2, data, 0); + for (int i = 0; i < count; ++i) + { + TlsUtilities.WriteVersion((ProtocolVersion)versions[i], data, 1 + i * 2); + } + return data; + } + + /// <exception cref="IOException"/> + public static byte[] CreateSupportedVersionsExtensionServer(ProtocolVersion selectedVersion) + { + return TlsUtilities.EncodeVersion(selectedVersion); + } + + public static byte[] CreateTruncatedHmacExtension() + { + return CreateEmptyExtensionData(); + } + + /// <exception cref="IOException"/> + public static byte[] CreateTrustedCAKeysExtensionClient(IList trustedAuthoritiesList) + { + MemoryStream buf = new MemoryStream(); + + // Placeholder for length + TlsUtilities.WriteUint16(0, buf); + + if (trustedAuthoritiesList != null) + { + foreach (TrustedAuthority entry in trustedAuthoritiesList) + { + entry.Encode(buf); + } + } + + return PatchOpaque16(buf); + } + + public static byte[] CreateTrustedCAKeysExtensionServer() + { + return CreateEmptyExtensionData(); + } + + /// <exception cref="IOException"/> + private static bool ReadEmptyExtensionData(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + if (extensionData.Length != 0) + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + + return true; + } + + /// <returns>an <see cref="IList"/> of <see cref="ProtocolName"/>.</returns> + /// <exception cref="IOException"/> + public static IList ReadAlpnExtensionClient(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + MemoryStream buf = new MemoryStream(extensionData); + + int length = TlsUtilities.ReadUint16(buf); + if (length != (extensionData.Length - 2)) + throw new TlsFatalAlert(AlertDescription.decode_error); + + IList protocol_name_list = Platform.CreateArrayList(); + while (buf.Position < buf.Length) + { + ProtocolName protocolName = ProtocolName.Parse(buf); + + protocol_name_list.Add(protocolName); + } + return protocol_name_list; + } + + /// <exception cref="IOException"/> + public static ProtocolName ReadAlpnExtensionServer(byte[] extensionData) + { + IList protocol_name_list = ReadAlpnExtensionClient(extensionData); + if (protocol_name_list.Count != 1) + throw new TlsFatalAlert(AlertDescription.decode_error); + + return (ProtocolName)protocol_name_list[0]; + } + + /// <exception cref="IOException"/> + public static IList ReadCertificateAuthoritiesExtension(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + if (extensionData.Length < 5) + throw new TlsFatalAlert(AlertDescription.decode_error); + + MemoryStream buf = new MemoryStream(extensionData); + + int length = TlsUtilities.ReadUint16(buf); + if (length != (extensionData.Length - 2)) + throw new TlsFatalAlert(AlertDescription.decode_error); + + IList authorities = Platform.CreateArrayList(); + while (buf.Position < buf.Length) + { + byte[] derEncoding = TlsUtilities.ReadOpaque16(buf, 1); + Asn1Object asn1 = TlsUtilities.ReadDerObject(derEncoding); + authorities.Add(X509Name.GetInstance(asn1)); + } + return authorities; + } + + /// <exception cref="IOException"/> + public static short[] ReadCertificateTypeExtensionClient(byte[] extensionData) + { + short[] certificateTypes = TlsUtilities.DecodeUint8ArrayWithUint8Length(extensionData); + if (certificateTypes.Length < 1) + throw new TlsFatalAlert(AlertDescription.decode_error); + + return certificateTypes; + } + + /// <exception cref="IOException"/> + public static short ReadCertificateTypeExtensionServer(byte[] extensionData) + { + return TlsUtilities.DecodeUint8(extensionData); + } + + /// <exception cref="IOException"/> + public static bool ReadClientCertificateUrlExtension(byte[] extensionData) + { + return ReadEmptyExtensionData(extensionData); + } + + /// <exception cref="IOException"/> + public static byte[] ReadCookieExtension(byte[] extensionData) + { + return TlsUtilities.DecodeOpaque16(extensionData, 1); + } + + /// <exception cref="IOException"/> + public static bool ReadEarlyDataIndication(byte[] extensionData) + { + return ReadEmptyExtensionData(extensionData); + } + + /// <exception cref="IOException"/> + public static long ReadEarlyDataMaxSize(byte[] extensionData) + { + return TlsUtilities.DecodeUint32(extensionData); + } + + /// <exception cref="IOException"/> + public static bool ReadEncryptThenMacExtension(byte[] extensionData) + { + return ReadEmptyExtensionData(extensionData); + } + + /// <exception cref="IOException"/> + public static bool ReadExtendedMasterSecretExtension(byte[] extensionData) + { + return ReadEmptyExtensionData(extensionData); + } + + /// <exception cref="IOException"/> + public static HeartbeatExtension ReadHeartbeatExtension(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + MemoryStream buf = new MemoryStream(extensionData, false); + + HeartbeatExtension heartbeatExtension = HeartbeatExtension.Parse(buf); + + TlsProtocol.AssertEmpty(buf); + + return heartbeatExtension; + } + + /// <exception cref="IOException"/> + public static IList ReadKeyShareClientHello(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + /* + * TODO[tls13] Clients MUST NOT offer multiple KeyShareEntry values for the same group. + * Clients MUST NOT offer any KeyShareEntry values for groups not listed in the client's + * "supported_groups" extension. Servers MAY check for violations of these rules and abort + * the handshake with an "illegal_parameter" alert if one is violated. + */ + + MemoryStream buf = new MemoryStream(extensionData, false); + + int length = TlsUtilities.ReadUint16(buf); + if (length != (extensionData.Length - 2)) + throw new TlsFatalAlert(AlertDescription.decode_error); + + IList clientShares = Platform.CreateArrayList(); + while (buf.Position < buf.Length) + { + KeyShareEntry clientShare = KeyShareEntry.Parse(buf); + + clientShares.Add(clientShare); + } + return clientShares; + } + + /// <exception cref="IOException"/> + public static int ReadKeyShareHelloRetryRequest(byte[] extensionData) + { + return TlsUtilities.DecodeUint16(extensionData); + } + + /// <exception cref="IOException"/> + public static KeyShareEntry ReadKeyShareServerHello(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + MemoryStream buf = new MemoryStream(extensionData, false); + + KeyShareEntry serverShare = KeyShareEntry.Parse(buf); + + TlsProtocol.AssertEmpty(buf); + + return serverShare; + } + + /// <exception cref="IOException"/> + public static short ReadMaxFragmentLengthExtension(byte[] extensionData) + { + return TlsUtilities.DecodeUint8(extensionData); + } + + /// <exception cref="IOException"/> + public static IDictionary ReadOidFiltersExtension(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + if (extensionData.Length < 2) + throw new TlsFatalAlert(AlertDescription.decode_error); + + MemoryStream buf = new MemoryStream(extensionData, false); + + int length = TlsUtilities.ReadUint16(buf); + if (length != (extensionData.Length - 2)) + throw new TlsFatalAlert(AlertDescription.decode_error); + + IDictionary filters = Platform.CreateHashtable(); + while (buf.Position < buf.Length) + { + byte[] derEncoding = TlsUtilities.ReadOpaque8(buf, 1); + Asn1Object asn1 = TlsUtilities.ReadDerObject(derEncoding); + DerObjectIdentifier certificateExtensionOid = DerObjectIdentifier.GetInstance(asn1); + + if (filters.Contains(certificateExtensionOid)) + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + + byte[] certificateExtensionValues = TlsUtilities.ReadOpaque16(buf); + + filters[certificateExtensionOid] = certificateExtensionValues; + } + return filters; + } + + /// <exception cref="IOException"/> + public static int ReadPaddingExtension(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + if (!Arrays.AreAllZeroes(extensionData, 0, extensionData.Length)) + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + + return extensionData.Length; + } + + /// <exception cref="IOException"/> + public static bool ReadPostHandshakeAuthExtension(byte[] extensionData) + { + return ReadEmptyExtensionData(extensionData); + } + + /// <exception cref="IOException"/> + public static OfferedPsks ReadPreSharedKeyClientHello(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + MemoryStream buf = new MemoryStream(extensionData, false); + + OfferedPsks offeredPsks = OfferedPsks.Parse(buf); + + TlsProtocol.AssertEmpty(buf); + + return offeredPsks; + } + + /// <exception cref="IOException"/> + public static int ReadPreSharedKeyServerHello(byte[] extensionData) + { + return TlsUtilities.DecodeUint16(extensionData); + } + + /// <exception cref="IOException"/> + public static short[] ReadPskKeyExchangeModesExtension(byte[] extensionData) + { + short[] modes = TlsUtilities.DecodeUint8ArrayWithUint8Length(extensionData); + if (modes.Length < 1) + throw new TlsFatalAlert(AlertDescription.decode_error); + + return modes; + } + + /// <exception cref="IOException"/> + public static int ReadRecordSizeLimitExtension(byte[] extensionData) + { + int recordSizeLimit = TlsUtilities.DecodeUint16(extensionData); + if (recordSizeLimit < 64) + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + + return recordSizeLimit; + } + + /// <exception cref="IOException"/> + public static IList ReadServerNameExtensionClient(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + MemoryStream buf = new MemoryStream(extensionData, false); + + ServerNameList serverNameList = ServerNameList.Parse(buf); + + TlsProtocol.AssertEmpty(buf); + + return serverNameList.ServerNames; + } + + /// <exception cref="IOException"/> + public static bool ReadServerNameExtensionServer(byte[] extensionData) + { + return ReadEmptyExtensionData(extensionData); + } + + /// <exception cref="IOException"/> + public static IList ReadSignatureAlgorithmsExtension(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + MemoryStream buf = new MemoryStream(extensionData, false); + + IList supported_signature_algorithms = TlsUtilities.ParseSupportedSignatureAlgorithms(buf); + + TlsProtocol.AssertEmpty(buf); + + return supported_signature_algorithms; + } + + /// <exception cref="IOException"/> + public static IList ReadSignatureAlgorithmsCertExtension(byte[] extensionData) + { + return ReadSignatureAlgorithmsExtension(extensionData); + } + + /// <exception cref="IOException"/> + public static CertificateStatusRequest ReadStatusRequestExtension(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + MemoryStream buf = new MemoryStream(extensionData, false); + + CertificateStatusRequest statusRequest = CertificateStatusRequest.Parse(buf); + + TlsProtocol.AssertEmpty(buf); + + return statusRequest; + } + + /// <exception cref="IOException"/> + public static IList ReadStatusRequestV2Extension(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + if (extensionData.Length < 3) + throw new TlsFatalAlert(AlertDescription.decode_error); + + MemoryStream buf = new MemoryStream(extensionData, false); + + int length = TlsUtilities.ReadUint16(buf); + if (length != (extensionData.Length - 2)) + throw new TlsFatalAlert(AlertDescription.decode_error); + + IList statusRequestV2 = Platform.CreateArrayList(); + while (buf.Position < buf.Length) + { + CertificateStatusRequestItemV2 entry = CertificateStatusRequestItemV2.Parse(buf); + statusRequestV2.Add(entry); + } + return statusRequestV2; + } + + /// <exception cref="IOException"/> + public static int[] ReadSupportedGroupsExtension(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + + MemoryStream buf = new MemoryStream(extensionData, false); + + int length = TlsUtilities.ReadUint16(buf); + if (length < 2 || (length & 1) != 0) + throw new TlsFatalAlert(AlertDescription.decode_error); + + int[] namedGroups = TlsUtilities.ReadUint16Array(length / 2, buf); + + TlsProtocol.AssertEmpty(buf); + + return namedGroups; + } + + /// <exception cref="IOException"/> + public static short[] ReadSupportedPointFormatsExtension(byte[] extensionData) + { + short[] ecPointFormats = TlsUtilities.DecodeUint8ArrayWithUint8Length(extensionData); + if (!Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed)) + { + /* + * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST + * contain the value 0 (uncompressed) as one of the items in the list of point formats. + */ + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + return ecPointFormats; + } + + /// <exception cref="IOException"/> + public static ProtocolVersion[] ReadSupportedVersionsExtensionClient(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + if (extensionData.Length < 3 || extensionData.Length > 255 || (extensionData.Length & 1) == 0) + throw new TlsFatalAlert(AlertDescription.decode_error); + + int length = TlsUtilities.ReadUint8(extensionData, 0); + if (length != (extensionData.Length - 1)) + throw new TlsFatalAlert(AlertDescription.decode_error); + + int count = length / 2; + ProtocolVersion[] versions = new ProtocolVersion[count]; + for (int i = 0; i < count; ++i) + { + versions[i] = TlsUtilities.ReadVersion(extensionData, 1 + i * 2); + } + return versions; + } + + /// <exception cref="IOException"/> + public static ProtocolVersion ReadSupportedVersionsExtensionServer(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + if (extensionData.Length != 2) + throw new TlsFatalAlert(AlertDescription.decode_error); + + return TlsUtilities.ReadVersion(extensionData, 0); + } + + /// <exception cref="IOException"/> + public static bool ReadTruncatedHmacExtension(byte[] extensionData) + { + return ReadEmptyExtensionData(extensionData); + } + + /// <exception cref="IOException"/> + public static IList ReadTrustedCAKeysExtensionClient(byte[] extensionData) + { + if (extensionData == null) + throw new ArgumentNullException("extensionData"); + if (extensionData.Length < 2) + throw new TlsFatalAlert(AlertDescription.decode_error); + + MemoryStream buf = new MemoryStream(extensionData, false); + + int length = TlsUtilities.ReadUint16(buf); + if (length != (extensionData.Length - 2)) + throw new TlsFatalAlert(AlertDescription.decode_error); + + IList trusted_authorities_list = Platform.CreateArrayList(); + while (buf.Position < buf.Length) + { + TrustedAuthority entry = TrustedAuthority.Parse(buf); + trusted_authorities_list.Add(entry); + } + return trusted_authorities_list; + } + + /// <exception cref="IOException"/> + public static bool ReadTrustedCAKeysExtensionServer(byte[] extensionData) + { + return ReadEmptyExtensionData(extensionData); + } + + /// <exception cref="IOException"/> + private static byte[] PatchOpaque16(MemoryStream buf) + { + int length = (int)buf.Length - 2; + TlsUtilities.CheckUint16(length); + byte[] extensionData = buf.ToArray(); + TlsUtilities.WriteUint16(length, extensionData, 0); + return extensionData; + } + } +} |