#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) #pragma warning disable using System; using System.Collections.Generic; using System.IO; using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1; using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509; using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities; namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Tls { public static class TlsExtensionsUtilities { public static IDictionary<int, byte[]> EnsureExtensionsInitialised(IDictionary<int, byte[]> extensions) { return extensions == null ? new Dictionary<int, byte[]>() : extensions; } /// <param name="extensions">(Int32 -> byte[])</param> /// <param name="protocolNameList">an <see cref="IList{T}"/> of <see cref="ProtocolName"/>.</param> /// <exception cref="IOException"/> public static void AddAlpnExtensionClient(IDictionary<int, byte[]> extensions, IList<ProtocolName> protocolNameList) { extensions[ExtensionType.application_layer_protocol_negotiation] = CreateAlpnExtensionClient(protocolNameList); } /// <exception cref="IOException"/> public static void AddAlpnExtensionServer(IDictionary<int, byte[]> extensions, ProtocolName protocolName) { extensions[ExtensionType.application_layer_protocol_negotiation] = CreateAlpnExtensionServer(protocolName); } /// <exception cref="IOException"/> public static void AddCertificateAuthoritiesExtension(IDictionary<int, byte[]> extensions, IList<X509Name> authorities) { extensions[ExtensionType.certificate_authorities] = CreateCertificateAuthoritiesExtension(authorities); } /// <exception cref="IOException"/> public static void AddClientCertificateTypeExtensionClient(IDictionary<int, byte[]> extensions, short[] certificateTypes) { extensions[ExtensionType.client_certificate_type] = CreateCertificateTypeExtensionClient(certificateTypes); } /// <exception cref="IOException"/> public static void AddClientCertificateTypeExtensionServer(IDictionary<int, byte[]> extensions, short certificateType) { extensions[ExtensionType.client_certificate_type] = CreateCertificateTypeExtensionServer(certificateType); } public static void AddClientCertificateUrlExtension(IDictionary<int, byte[]> extensions) { extensions[ExtensionType.client_certificate_url] = CreateClientCertificateUrlExtension(); } /// <exception cref="IOException"/> public static void AddCompressCertificateExtension(IDictionary<int, byte[]> extensions, int[] algorithms) { extensions[ExtensionType.compress_certificate] = CreateCompressCertificateExtension(algorithms); } /// <exception cref="IOException"/> public static void AddCookieExtension(IDictionary<int, byte[]> extensions, byte[] cookie) { extensions[ExtensionType.cookie] = CreateCookieExtension(cookie); } public static void AddEarlyDataIndication(IDictionary<int, byte[]> extensions) { extensions[ExtensionType.early_data] = CreateEarlyDataIndication(); } /// <exception cref="IOException"/> public static void AddEarlyDataMaxSize(IDictionary<int, byte[]> extensions, long maxSize) { extensions[ExtensionType.early_data] = CreateEarlyDataMaxSize(maxSize); } public static void AddEmptyExtensionData(IDictionary<int, byte[]> extensions, int extType) { extensions[extType] = CreateEmptyExtensionData(); } public static void AddEncryptThenMacExtension(IDictionary<int, byte[]> extensions) { extensions[ExtensionType.encrypt_then_mac] = CreateEncryptThenMacExtension(); } public static void AddExtendedMasterSecretExtension(IDictionary<int, byte[]> extensions) { extensions[ExtensionType.extended_master_secret] = CreateExtendedMasterSecretExtension(); } /// <exception cref="IOException"/> public static void AddHeartbeatExtension(IDictionary<int, byte[]> extensions, HeartbeatExtension heartbeatExtension) { extensions[ExtensionType.heartbeat] = CreateHeartbeatExtension(heartbeatExtension); } /// <exception cref="IOException"/> public static void AddKeyShareClientHello(IDictionary<int, byte[]> extensions, IList<KeyShareEntry> clientShares) { extensions[ExtensionType.key_share] = CreateKeyShareClientHello(clientShares); } /// <exception cref="IOException"/> public static void AddKeyShareHelloRetryRequest(IDictionary<int, byte[]> extensions, int namedGroup) { extensions[ExtensionType.key_share] = CreateKeyShareHelloRetryRequest(namedGroup); } /// <exception cref="IOException"/> public static void AddKeyShareServerHello(IDictionary<int, byte[]> extensions, KeyShareEntry serverShare) { extensions[ExtensionType.key_share] = CreateKeyShareServerHello(serverShare); } /// <exception cref="IOException"/> public static void AddMaxFragmentLengthExtension(IDictionary<int, byte[]> extensions, short maxFragmentLength) { extensions[ExtensionType.max_fragment_length] = CreateMaxFragmentLengthExtension(maxFragmentLength); } /// <exception cref="IOException"/> public static void AddOidFiltersExtension(IDictionary<int, byte[]> extensions, IDictionary<DerObjectIdentifier, byte[]> filters) { extensions[ExtensionType.oid_filters] = CreateOidFiltersExtension(filters); } /// <exception cref="IOException"/> public static void AddPaddingExtension(IDictionary<int, byte[]> extensions, int dataLength) { extensions[ExtensionType.padding] = CreatePaddingExtension(dataLength); } public static void AddPostHandshakeAuthExtension(IDictionary<int, byte[]> extensions) { extensions[ExtensionType.post_handshake_auth] = CreatePostHandshakeAuthExtension(); } /// <exception cref="IOException"/> public static void AddPreSharedKeyClientHello(IDictionary<int, byte[]> extensions, OfferedPsks offeredPsks) { extensions[ExtensionType.pre_shared_key] = CreatePreSharedKeyClientHello(offeredPsks); } /// <exception cref="IOException"/> public static void AddPreSharedKeyServerHello(IDictionary<int, byte[]> extensions, int selectedIdentity) { extensions[ExtensionType.pre_shared_key] = CreatePreSharedKeyServerHello(selectedIdentity); } /// <exception cref="IOException"/> public static void AddPskKeyExchangeModesExtension(IDictionary<int, byte[]> extensions, short[] modes) { extensions[ExtensionType.psk_key_exchange_modes] = CreatePskKeyExchangeModesExtension(modes); } /// <exception cref="IOException"/> public static void AddRecordSizeLimitExtension(IDictionary<int, byte[]> extensions, int recordSizeLimit) { extensions[ExtensionType.record_size_limit] = CreateRecordSizeLimitExtension(recordSizeLimit); } /// <exception cref="IOException"/> public static void AddServerCertificateTypeExtensionClient(IDictionary<int, byte[]> extensions, short[] certificateTypes) { extensions[ExtensionType.server_certificate_type] = CreateCertificateTypeExtensionClient(certificateTypes); } /// <exception cref="IOException"/> public static void AddServerCertificateTypeExtensionServer(IDictionary<int, byte[]> extensions, short certificateType) { extensions[ExtensionType.server_certificate_type] = CreateCertificateTypeExtensionServer(certificateType); } /// <exception cref="IOException"/> public static void AddServerNameExtensionClient(IDictionary<int, byte[]> extensions, IList<ServerName> serverNameList) { extensions[ExtensionType.server_name] = CreateServerNameExtensionClient(serverNameList); } /// <exception cref="IOException"/> public static void AddServerNameExtensionServer(IDictionary<int, byte[]> extensions) { extensions[ExtensionType.server_name] = CreateServerNameExtensionServer(); } /// <exception cref="IOException"/> public static void AddSignatureAlgorithmsExtension(IDictionary<int, byte[]> extensions, IList<SignatureAndHashAlgorithm> supportedSignatureAlgorithms) { extensions[ExtensionType.signature_algorithms] = CreateSignatureAlgorithmsExtension(supportedSignatureAlgorithms); } /// <exception cref="IOException"/> public static void AddSignatureAlgorithmsCertExtension(IDictionary<int, byte[]> extensions, IList<SignatureAndHashAlgorithm> supportedSignatureAlgorithms) { extensions[ExtensionType.signature_algorithms_cert] = CreateSignatureAlgorithmsCertExtension(supportedSignatureAlgorithms); } /// <exception cref="IOException"/> public static void AddStatusRequestExtension(IDictionary<int, byte[]> extensions, CertificateStatusRequest statusRequest) { extensions[ExtensionType.status_request] = CreateStatusRequestExtension(statusRequest); } /// <exception cref="IOException"/> public static void AddStatusRequestV2Extension(IDictionary<int, byte[]> extensions, IList<CertificateStatusRequestItemV2> statusRequestV2) { extensions[ExtensionType.status_request_v2] = CreateStatusRequestV2Extension(statusRequestV2); } /// <exception cref="IOException"/> public static void AddSupportedGroupsExtension(IDictionary<int, byte[]> extensions, IList<int> namedGroups) { extensions[ExtensionType.supported_groups] = CreateSupportedGroupsExtension(namedGroups); } /// <exception cref="IOException"/> public static void AddSupportedPointFormatsExtension(IDictionary<int, byte[]> extensions, short[] ecPointFormats) { extensions[ExtensionType.ec_point_formats] = CreateSupportedPointFormatsExtension(ecPointFormats); } /// <exception cref="IOException"/> public static void AddSupportedVersionsExtensionClient(IDictionary<int, byte[]> extensions, ProtocolVersion[] versions) { extensions[ExtensionType.supported_versions] = CreateSupportedVersionsExtensionClient(versions); } /// <exception cref="IOException"/> public static void AddSupportedVersionsExtensionServer(IDictionary<int, byte[]> extensions, ProtocolVersion selectedVersion) { extensions[ExtensionType.supported_versions] = CreateSupportedVersionsExtensionServer(selectedVersion); } public static void AddTruncatedHmacExtension(IDictionary<int, byte[]> extensions) { extensions[ExtensionType.truncated_hmac] = CreateTruncatedHmacExtension(); } /// <exception cref="IOException"/> public static void AddTrustedCAKeysExtensionClient(IDictionary<int, byte[]> extensions, IList<TrustedAuthority> trustedAuthoritiesList) { extensions[ExtensionType.trusted_ca_keys] = CreateTrustedCAKeysExtensionClient(trustedAuthoritiesList); } public static void AddTrustedCAKeysExtensionServer(IDictionary<int, byte[]> extensions) { extensions[ExtensionType.trusted_ca_keys] = CreateTrustedCAKeysExtensionServer(); } /// <returns>an <see cref="IList{T}"/> of <see cref="ProtocolName"/>.</returns> /// <exception cref="IOException"/> public static IList<ProtocolName> GetAlpnExtensionClient(IDictionary<int, byte[]> 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<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.application_layer_protocol_negotiation); return extensionData == null ? null : ReadAlpnExtensionServer(extensionData); } /// <exception cref="IOException"/> public static IList<X509Name> GetCertificateAuthoritiesExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.certificate_authorities); return extensionData == null ? null : ReadCertificateAuthoritiesExtension(extensionData); } /// <exception cref="IOException"/> public static short[] GetClientCertificateTypeExtensionClient(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.client_certificate_type); return extensionData == null ? null : ReadCertificateTypeExtensionClient(extensionData); } /// <exception cref="IOException"/> public static short GetClientCertificateTypeExtensionServer(IDictionary<int, byte[]> extensions, short defaultValue) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.client_certificate_type); return extensionData == null ? defaultValue : ReadCertificateTypeExtensionServer(extensionData); } /// <exception cref="IOException"/> public static int[] GetCompressCertificateExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.compress_certificate); return extensionData == null ? null : ReadCompressCertificateExtension(extensionData); } /// <exception cref="IOException"/> public static byte[] GetCookieExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.cookie); return extensionData == null ? null : ReadCookieExtension(extensionData); } /// <exception cref="IOException"/> public static long GetEarlyDataMaxSize(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.early_data); return extensionData == null ? -1L : ReadEarlyDataMaxSize(extensionData); } /// <exception cref="IOException"/> public static HeartbeatExtension GetHeartbeatExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.heartbeat); return extensionData == null ? null : ReadHeartbeatExtension(extensionData); } /// <exception cref="IOException"/> public static IList<KeyShareEntry> GetKeyShareClientHello(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.key_share); return extensionData == null ? null : ReadKeyShareClientHello(extensionData); } /// <exception cref="IOException"/> public static int GetKeyShareHelloRetryRequest(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.key_share); return extensionData == null ? -1 : ReadKeyShareHelloRetryRequest(extensionData); } /// <exception cref="IOException"/> public static KeyShareEntry GetKeyShareServerHello(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.key_share); return extensionData == null ? null : ReadKeyShareServerHello(extensionData); } /// <exception cref="IOException"/> public static short GetMaxFragmentLengthExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.max_fragment_length); return extensionData == null ? (short)-1 : ReadMaxFragmentLengthExtension(extensionData); } /// <exception cref="IOException"/> public static IDictionary<DerObjectIdentifier, byte[]> GetOidFiltersExtension( IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.oid_filters); return extensionData == null ? null : ReadOidFiltersExtension(extensionData); } /// <exception cref="IOException"/> public static int GetPaddingExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.padding); return extensionData == null ? -1 : ReadPaddingExtension(extensionData); } /// <exception cref="IOException"/> public static OfferedPsks GetPreSharedKeyClientHello(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.pre_shared_key); return extensionData == null ? null : ReadPreSharedKeyClientHello(extensionData); } /// <exception cref="IOException"/> public static int GetPreSharedKeyServerHello(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.pre_shared_key); return extensionData == null ? -1 : ReadPreSharedKeyServerHello(extensionData); } /// <exception cref="IOException"/> public static short[] GetPskKeyExchangeModesExtension(IDictionary<int, byte[]> 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<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.record_size_limit); return extensionData == null ? -1 : ReadRecordSizeLimitExtension(extensionData); } /// <exception cref="IOException"/> public static short[] GetServerCertificateTypeExtensionClient(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_certificate_type); return extensionData == null ? null : ReadCertificateTypeExtensionClient(extensionData); } /// <exception cref="IOException"/> public static short GetServerCertificateTypeExtensionServer(IDictionary<int, byte[]> extensions, short defaultValue) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_certificate_type); return extensionData == null ? defaultValue : ReadCertificateTypeExtensionServer(extensionData); } /// <exception cref="IOException"/> public static IList<ServerName> GetServerNameExtensionClient(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_name); return extensionData == null ? null : ReadServerNameExtensionClient(extensionData); } /// <exception cref="IOException"/> public static IList<SignatureAndHashAlgorithm> GetSignatureAlgorithmsExtension( IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.signature_algorithms); return extensionData == null ? null : ReadSignatureAlgorithmsExtension(extensionData); } /// <exception cref="IOException"/> public static IList<SignatureAndHashAlgorithm> GetSignatureAlgorithmsCertExtension( IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.signature_algorithms_cert); return extensionData == null ? null : ReadSignatureAlgorithmsCertExtension(extensionData); } /// <exception cref="IOException"/> public static CertificateStatusRequest GetStatusRequestExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.status_request); return extensionData == null ? null : ReadStatusRequestExtension(extensionData); } /// <exception cref="IOException"/> public static IList<CertificateStatusRequestItemV2> GetStatusRequestV2Extension( IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.status_request_v2); return extensionData == null ? null : ReadStatusRequestV2Extension(extensionData); } /// <exception cref="IOException"/> public static int[] GetSupportedGroupsExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.supported_groups); return extensionData == null ? null : ReadSupportedGroupsExtension(extensionData); } /// <exception cref="IOException"/> public static short[] GetSupportedPointFormatsExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.ec_point_formats); return extensionData == null ? null : ReadSupportedPointFormatsExtension(extensionData); } /// <exception cref="IOException"/> public static ProtocolVersion[] GetSupportedVersionsExtensionClient(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.supported_versions); return extensionData == null ? null : ReadSupportedVersionsExtensionClient(extensionData); } /// <exception cref="IOException"/> public static ProtocolVersion GetSupportedVersionsExtensionServer(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.supported_versions); return extensionData == null ? null : ReadSupportedVersionsExtensionServer(extensionData); } /// <exception cref="IOException"/> public static IList<TrustedAuthority> GetTrustedCAKeysExtensionClient(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.trusted_ca_keys); return extensionData == null ? null : ReadTrustedCAKeysExtensionClient(extensionData); } /// <exception cref="IOException"/> public static bool HasClientCertificateUrlExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.client_certificate_url); return extensionData == null ? false : ReadClientCertificateUrlExtension(extensionData); } /// <exception cref="IOException"/> public static bool HasEarlyDataIndication(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.early_data); return extensionData == null ? false : ReadEarlyDataIndication(extensionData); } /// <exception cref="IOException"/> public static bool HasEncryptThenMacExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.encrypt_then_mac); return extensionData == null ? false : ReadEncryptThenMacExtension(extensionData); } /// <exception cref="IOException"/> public static bool HasExtendedMasterSecretExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.extended_master_secret); return extensionData == null ? false : ReadExtendedMasterSecretExtension(extensionData); } /// <exception cref="IOException"/> public static bool HasServerNameExtensionServer(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_name); return extensionData == null ? false : ReadServerNameExtensionServer(extensionData); } /// <exception cref="IOException"/> public static bool HasPostHandshakeAuthExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.post_handshake_auth); return extensionData == null ? false : ReadPostHandshakeAuthExtension(extensionData); } /// <exception cref="IOException"/> public static bool HasTruncatedHmacExtension(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.truncated_hmac); return extensionData == null ? false : ReadTruncatedHmacExtension(extensionData); } /// <exception cref="IOException"/> public static bool HasTrustedCAKeysExtensionServer(IDictionary<int, byte[]> extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.trusted_ca_keys); return extensionData == null ? false : ReadTrustedCAKeysExtensionServer(extensionData); } /// <param name="protocolNameList">an <see cref="IList{T}"/> of <see cref="ProtocolName"/>.</param> /// <exception cref="IOException"/> public static byte[] CreateAlpnExtensionClient(IList<ProtocolName> 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) { var protocol_name_list = new List<ProtocolName>(); protocol_name_list.Add(protocolName); return CreateAlpnExtensionClient(protocol_name_list); } /// <exception cref="IOException"/> public static byte[] CreateCertificateAuthoritiesExtension(IList<X509Name> 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[] 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)) 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<KeyShareEntry> 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<DerObjectIdentifier, byte[]> filters) { MemoryStream buf = new MemoryStream(); // Placeholder for length TlsUtilities.WriteUint16(0, buf); if (null != filters) { //foreach (DerObjectIdentifier certificateExtensionOid in filters.Keys) foreach (var filter in filters) { var certificateExtensionOid = filter.Key; var certificateExtensionValues = filter.Value; 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<ServerName> 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<SignatureAndHashAlgorithm> supportedSignatureAlgorithms) { MemoryStream buf = new MemoryStream(); TlsUtilities.EncodeSupportedSignatureAlgorithms(supportedSignatureAlgorithms, buf); return buf.ToArray(); } /// <exception cref="IOException"/> public static byte[] CreateSignatureAlgorithmsCertExtension( IList<SignatureAndHashAlgorithm> 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<CertificateStatusRequestItemV2> 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<int> 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] = 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(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<TrustedAuthority> 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{T}"/> of <see cref="ProtocolName"/>.</returns> /// <exception cref="IOException"/> public static IList<ProtocolName> 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); var protocol_name_list = new List<ProtocolName>(); 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) { var protocol_name_list = ReadAlpnExtensionClient(extensionData); if (protocol_name_list.Count != 1) throw new TlsFatalAlert(AlertDescription.decode_error); return protocol_name_list[0]; } /// <exception cref="IOException"/> public static IList<X509Name> 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); var authorities = new List<X509Name>(); while (buf.Position < buf.Length) { byte[] derEncoding = TlsUtilities.ReadOpaque16(buf, 1); Asn1Object asn1 = TlsUtilities.ReadAsn1Object(derEncoding); X509Name ca = X509Name.GetInstance(asn1); TlsUtilities.RequireDerEncoding(ca, derEncoding); authorities.Add(ca); } 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 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); } /// <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<KeyShareEntry> 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); var clientShares = new List<KeyShareEntry>(); 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<DerObjectIdentifier, byte[]> 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); var filters = new Dictionary<DerObjectIdentifier, byte[]>(); while (buf.Position < buf.Length) { byte[] derEncoding = TlsUtilities.ReadOpaque8(buf, 1); Asn1Object asn1 = TlsUtilities.ReadAsn1Object(derEncoding); DerObjectIdentifier certificateExtensionOid = DerObjectIdentifier.GetInstance(asn1); TlsUtilities.RequireDerEncoding(certificateExtensionOid, derEncoding); if (filters.ContainsKey(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<ServerName> 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<SignatureAndHashAlgorithm> ReadSignatureAlgorithmsExtension(byte[] extensionData) { if (extensionData == null) throw new ArgumentNullException("extensionData"); MemoryStream buf = new MemoryStream(extensionData, false); var supported_signature_algorithms = TlsUtilities.ParseSupportedSignatureAlgorithms(buf); TlsProtocol.AssertEmpty(buf); return supported_signature_algorithms; } /// <exception cref="IOException"/> public static IList<SignatureAndHashAlgorithm> 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<CertificateStatusRequestItemV2> 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); var statusRequestV2 = new List<CertificateStatusRequestItemV2>(); 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<TrustedAuthority> 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); var trusted_authorities_list = new List<TrustedAuthority>(); 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 = Convert.ToInt32(buf.Length) - 2; TlsUtilities.CheckUint16(length); byte[] extensionData = buf.ToArray(); TlsUtilities.WriteUint16(length, extensionData, 0); return extensionData; } } } #pragma warning restore #endif