mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 00:01:36 +00:00
manually read tls clienthello [wip]
This commit is contained in:
parent
8ce0de8bed
commit
3fa65c48dd
5
libmproxy/contrib/tls/__init__.py
Normal file
5
libmproxy/contrib/tls/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# This file is dual licensed under the terms of the Apache License, Version
|
||||||
|
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||||
|
# for complete details.
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
213
libmproxy/contrib/tls/_constructs.py
Normal file
213
libmproxy/contrib/tls/_constructs.py
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
# This file is dual licensed under the terms of the Apache License, Version
|
||||||
|
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||||
|
# for complete details.
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
from construct import Array, Bytes, Struct, UBInt16, UBInt32, UBInt8, PascalString, Embed, \
|
||||||
|
TunnelAdapter, GreedyRange, Switch
|
||||||
|
|
||||||
|
from .utils import UBInt24
|
||||||
|
|
||||||
|
ProtocolVersion = Struct(
|
||||||
|
"version",
|
||||||
|
UBInt8("major"),
|
||||||
|
UBInt8("minor"),
|
||||||
|
)
|
||||||
|
|
||||||
|
TLSPlaintext = Struct(
|
||||||
|
"TLSPlaintext",
|
||||||
|
UBInt8("type"),
|
||||||
|
ProtocolVersion,
|
||||||
|
UBInt16("length"), # TODO: Reject packets with length > 2 ** 14
|
||||||
|
Bytes("fragment", lambda ctx: ctx.length),
|
||||||
|
)
|
||||||
|
|
||||||
|
TLSCompressed = Struct(
|
||||||
|
"TLSCompressed",
|
||||||
|
UBInt8("type"),
|
||||||
|
ProtocolVersion,
|
||||||
|
UBInt16("length"), # TODO: Reject packets with length > 2 ** 14 + 1024
|
||||||
|
Bytes("fragment", lambda ctx: ctx.length),
|
||||||
|
)
|
||||||
|
|
||||||
|
TLSCiphertext = Struct(
|
||||||
|
"TLSCiphertext",
|
||||||
|
UBInt8("type"),
|
||||||
|
ProtocolVersion,
|
||||||
|
UBInt16("length"), # TODO: Reject packets with length > 2 ** 14 + 2048
|
||||||
|
Bytes("fragment", lambda ctx: ctx.length),
|
||||||
|
)
|
||||||
|
|
||||||
|
Random = Struct(
|
||||||
|
"random",
|
||||||
|
UBInt32("gmt_unix_time"),
|
||||||
|
Bytes("random_bytes", 28),
|
||||||
|
)
|
||||||
|
|
||||||
|
SessionID = Struct(
|
||||||
|
"session_id",
|
||||||
|
UBInt8("length"),
|
||||||
|
Bytes("session_id", lambda ctx: ctx.length),
|
||||||
|
)
|
||||||
|
|
||||||
|
CipherSuites = Struct(
|
||||||
|
"cipher_suites",
|
||||||
|
UBInt16("length"), # TODO: Reject packets of length 0
|
||||||
|
Array(lambda ctx: ctx.length // 2, UBInt16("cipher_suites")),
|
||||||
|
)
|
||||||
|
|
||||||
|
CompressionMethods = Struct(
|
||||||
|
"compression_methods",
|
||||||
|
UBInt8("length"), # TODO: Reject packets of length 0
|
||||||
|
Array(lambda ctx: ctx.length, UBInt8("compression_methods")),
|
||||||
|
)
|
||||||
|
|
||||||
|
ServerName = Struct(
|
||||||
|
"",
|
||||||
|
UBInt8("type"),
|
||||||
|
PascalString("name", length_field=UBInt16("length")),
|
||||||
|
)
|
||||||
|
|
||||||
|
SNIExtension = Struct(
|
||||||
|
"",
|
||||||
|
TunnelAdapter(
|
||||||
|
PascalString("server_names", length_field=UBInt16("length")),
|
||||||
|
TunnelAdapter(
|
||||||
|
PascalString("", length_field=UBInt16("length")),
|
||||||
|
GreedyRange(ServerName)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
ALPNExtension = Struct(
|
||||||
|
"",
|
||||||
|
TunnelAdapter(
|
||||||
|
PascalString("alpn_protocols", length_field=UBInt16("length")),
|
||||||
|
TunnelAdapter(
|
||||||
|
PascalString("", length_field=UBInt16("length")),
|
||||||
|
GreedyRange(PascalString("name"))
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
UnknownExtension = Struct(
|
||||||
|
"",
|
||||||
|
PascalString("bytes", length_field=UBInt16("extensions_length"))
|
||||||
|
)
|
||||||
|
|
||||||
|
Extension = Struct(
|
||||||
|
"Extension",
|
||||||
|
UBInt16("type"),
|
||||||
|
Embed(
|
||||||
|
Switch(
|
||||||
|
"data", lambda ctx: ctx.type,
|
||||||
|
{
|
||||||
|
0x00: SNIExtension,
|
||||||
|
0x10: ALPNExtension
|
||||||
|
},
|
||||||
|
default=UnknownExtension
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
extensions = TunnelAdapter(
|
||||||
|
PascalString("extensions", length_field=UBInt16("extensions_length")),
|
||||||
|
GreedyRange(Extension)
|
||||||
|
)
|
||||||
|
|
||||||
|
ClientHello = Struct(
|
||||||
|
"ClientHello",
|
||||||
|
ProtocolVersion,
|
||||||
|
Random,
|
||||||
|
SessionID,
|
||||||
|
CipherSuites,
|
||||||
|
CompressionMethods,
|
||||||
|
extensions,
|
||||||
|
)
|
||||||
|
|
||||||
|
ServerHello = Struct(
|
||||||
|
"ServerHello",
|
||||||
|
ProtocolVersion,
|
||||||
|
Random,
|
||||||
|
SessionID,
|
||||||
|
Bytes("cipher_suite", 2),
|
||||||
|
UBInt8("compression_method"),
|
||||||
|
extensions,
|
||||||
|
)
|
||||||
|
|
||||||
|
ClientCertificateType = Struct(
|
||||||
|
"certificate_types",
|
||||||
|
UBInt8("length"), # TODO: Reject packets of length 0
|
||||||
|
Array(lambda ctx: ctx.length, UBInt8("certificate_types")),
|
||||||
|
)
|
||||||
|
|
||||||
|
SignatureAndHashAlgorithm = Struct(
|
||||||
|
"algorithms",
|
||||||
|
UBInt8("hash"),
|
||||||
|
UBInt8("signature"),
|
||||||
|
)
|
||||||
|
|
||||||
|
SupportedSignatureAlgorithms = Struct(
|
||||||
|
"supported_signature_algorithms",
|
||||||
|
UBInt16("supported_signature_algorithms_length"),
|
||||||
|
# TODO: Reject packets of length 0
|
||||||
|
Array(
|
||||||
|
lambda ctx: ctx.supported_signature_algorithms_length / 2,
|
||||||
|
SignatureAndHashAlgorithm,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
DistinguishedName = Struct(
|
||||||
|
"certificate_authorities",
|
||||||
|
UBInt16("length"),
|
||||||
|
Bytes("certificate_authorities", lambda ctx: ctx.length),
|
||||||
|
)
|
||||||
|
|
||||||
|
CertificateRequest = Struct(
|
||||||
|
"CertificateRequest",
|
||||||
|
ClientCertificateType,
|
||||||
|
SupportedSignatureAlgorithms,
|
||||||
|
DistinguishedName,
|
||||||
|
)
|
||||||
|
|
||||||
|
ServerDHParams = Struct(
|
||||||
|
"ServerDHParams",
|
||||||
|
UBInt16("dh_p_length"),
|
||||||
|
Bytes("dh_p", lambda ctx: ctx.dh_p_length),
|
||||||
|
UBInt16("dh_g_length"),
|
||||||
|
Bytes("dh_g", lambda ctx: ctx.dh_g_length),
|
||||||
|
UBInt16("dh_Ys_length"),
|
||||||
|
Bytes("dh_Ys", lambda ctx: ctx.dh_Ys_length),
|
||||||
|
)
|
||||||
|
|
||||||
|
PreMasterSecret = Struct(
|
||||||
|
"pre_master_secret",
|
||||||
|
ProtocolVersion,
|
||||||
|
Bytes("random_bytes", 46),
|
||||||
|
)
|
||||||
|
|
||||||
|
ASN1Cert = Struct(
|
||||||
|
"ASN1Cert",
|
||||||
|
UBInt32("length"), # TODO: Reject packets with length not in 1..2^24-1
|
||||||
|
Bytes("asn1_cert", lambda ctx: ctx.length),
|
||||||
|
)
|
||||||
|
|
||||||
|
Certificate = Struct(
|
||||||
|
"Certificate", # TODO: Reject packets with length > 2 ** 24 - 1
|
||||||
|
UBInt32("certificates_length"),
|
||||||
|
Bytes("certificates_bytes", lambda ctx: ctx.certificates_length),
|
||||||
|
)
|
||||||
|
|
||||||
|
Handshake = Struct(
|
||||||
|
"Handshake",
|
||||||
|
UBInt8("msg_type"),
|
||||||
|
UBInt24("length"), # TODO: Reject packets with length > 2 ** 24
|
||||||
|
Bytes("body", lambda ctx: ctx.length),
|
||||||
|
)
|
||||||
|
|
||||||
|
Alert = Struct(
|
||||||
|
"Alert",
|
||||||
|
UBInt8("level"),
|
||||||
|
UBInt8("description"),
|
||||||
|
)
|
64
libmproxy/contrib/tls/alert_message.py
Normal file
64
libmproxy/contrib/tls/alert_message.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# This file is dual licensed under the terms of the Apache License, Version
|
||||||
|
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||||
|
# for complete details.
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from characteristic import attributes
|
||||||
|
|
||||||
|
from . import _constructs
|
||||||
|
|
||||||
|
|
||||||
|
class AlertLevel(Enum):
|
||||||
|
WARNING = 1
|
||||||
|
FATAL = 2
|
||||||
|
|
||||||
|
|
||||||
|
class AlertDescription(Enum):
|
||||||
|
CLOSE_NOTIFY = 0
|
||||||
|
UNEXPECTED_MESSAGE = 10
|
||||||
|
BAD_RECORD_MAC = 20
|
||||||
|
DECRYPTION_FAILED_RESERVED = 21
|
||||||
|
RECORD_OVERFLOW = 22
|
||||||
|
DECOMPRESSION_FAILURE = 30
|
||||||
|
HANDSHAKE_FAILURE = 40
|
||||||
|
NO_CERTIFICATE_RESERVED = 41
|
||||||
|
BAD_CERTIFICATE = 42
|
||||||
|
UNSUPPORTED_CERTIFICATE = 43
|
||||||
|
CERTIFICATE_REVOKED = 44
|
||||||
|
CERTIFICATE_EXPIRED = 45
|
||||||
|
CERTIFICATE_UNKNOWN = 46
|
||||||
|
ILLEGAL_PARAMETER = 47
|
||||||
|
UNKNOWN_CA = 48
|
||||||
|
ACCESS_DENIED = 49
|
||||||
|
DECODE_ERROR = 50
|
||||||
|
DECRYPT_ERROR = 51
|
||||||
|
EXPORT_RESTRICTION_RESERVED = 60
|
||||||
|
PROTOCOL_VERSION = 70
|
||||||
|
INSUFFICIENT_SECURITY = 71
|
||||||
|
INTERNAL_ERROR = 80
|
||||||
|
USER_CANCELED = 90
|
||||||
|
NO_RENEGOTIATION = 100
|
||||||
|
UNSUPPORTED_EXTENSION = 110
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['level', 'description'])
|
||||||
|
class Alert(object):
|
||||||
|
"""
|
||||||
|
An object representing an Alert message.
|
||||||
|
"""
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, bytes):
|
||||||
|
"""
|
||||||
|
Parse an ``Alert`` struct.
|
||||||
|
|
||||||
|
:param bytes: the bytes representing the input.
|
||||||
|
:return: Alert object.
|
||||||
|
"""
|
||||||
|
construct = _constructs.Alert.parse(bytes)
|
||||||
|
return cls(
|
||||||
|
level=AlertLevel(construct.level),
|
||||||
|
description=AlertDescription(construct.description)
|
||||||
|
)
|
343
libmproxy/contrib/tls/ciphersuites.py
Normal file
343
libmproxy/contrib/tls/ciphersuites.py
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
# This file is dual licensed under the terms of the Apache License, Version
|
||||||
|
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||||
|
# for complete details.
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from .exceptions import UnsupportedCipherException
|
||||||
|
|
||||||
|
|
||||||
|
class CipherSuites(Enum):
|
||||||
|
TLS_NULL_WITH_NULL_NULL = 0x0000
|
||||||
|
TLS_RSA_WITH_NULL_MD5 = 0x0001
|
||||||
|
TLS_RSA_WITH_NULL_SHA = 0x0002
|
||||||
|
TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003
|
||||||
|
TLS_RSA_WITH_RC4_128_MD5 = 0x0004
|
||||||
|
TLS_RSA_WITH_RC4_128_SHA = 0x0005
|
||||||
|
TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x0006
|
||||||
|
TLS_RSA_WITH_IDEA_CBC_SHA = 0x0007
|
||||||
|
TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008
|
||||||
|
TLS_RSA_WITH_DES_CBC_SHA = 0x0009
|
||||||
|
TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A
|
||||||
|
TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B
|
||||||
|
TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000C
|
||||||
|
TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D
|
||||||
|
TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000E
|
||||||
|
TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F
|
||||||
|
TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010
|
||||||
|
TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011
|
||||||
|
TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012
|
||||||
|
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013
|
||||||
|
TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014
|
||||||
|
TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x0015
|
||||||
|
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016
|
||||||
|
TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017
|
||||||
|
TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018
|
||||||
|
TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x0019
|
||||||
|
TLS_DH_anon_WITH_DES_CBC_SHA = 0x001A
|
||||||
|
TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x001B
|
||||||
|
TLS_KRB5_WITH_DES_CBC_SHA = 0x001E
|
||||||
|
TLS_KRB5_WITH_3DES_EDE_CBC_SHA = 0x001F
|
||||||
|
TLS_KRB5_WITH_RC4_128_SHA = 0x0020
|
||||||
|
TLS_KRB5_WITH_IDEA_CBC_SHA = 0x0021
|
||||||
|
TLS_KRB5_WITH_DES_CBC_MD5 = 0x0022
|
||||||
|
TLS_KRB5_WITH_3DES_EDE_CBC_MD5 = 0x0023
|
||||||
|
TLS_KRB5_WITH_RC4_128_MD5 = 0x0024
|
||||||
|
TLS_KRB5_WITH_IDEA_CBC_MD5 = 0x0025
|
||||||
|
TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA = 0x0026
|
||||||
|
TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA = 0x0027
|
||||||
|
TLS_KRB5_EXPORT_WITH_RC4_40_SHA = 0x0028
|
||||||
|
TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 = 0x0029
|
||||||
|
TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 = 0x002A
|
||||||
|
TLS_KRB5_EXPORT_WITH_RC4_40_MD5 = 0x002B
|
||||||
|
TLS_PSK_WITH_NULL_SHA = 0x002C
|
||||||
|
TLS_DHE_PSK_WITH_NULL_SHA = 0x002D
|
||||||
|
TLS_RSA_PSK_WITH_NULL_SHA = 0x002E
|
||||||
|
TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F
|
||||||
|
TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030
|
||||||
|
TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031
|
||||||
|
TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032
|
||||||
|
TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033
|
||||||
|
TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x0034
|
||||||
|
TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035
|
||||||
|
TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036
|
||||||
|
TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037
|
||||||
|
TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038
|
||||||
|
TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039
|
||||||
|
TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x003A
|
||||||
|
TLS_RSA_WITH_NULL_SHA256 = 0x003B
|
||||||
|
TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C
|
||||||
|
TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D
|
||||||
|
TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x003E
|
||||||
|
TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x003F
|
||||||
|
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040
|
||||||
|
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0041
|
||||||
|
TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0042
|
||||||
|
TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0043
|
||||||
|
TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044
|
||||||
|
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0045
|
||||||
|
TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = 0x0046
|
||||||
|
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067
|
||||||
|
TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x0068
|
||||||
|
TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x0069
|
||||||
|
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A
|
||||||
|
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B
|
||||||
|
TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x006C
|
||||||
|
TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x006D
|
||||||
|
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0084
|
||||||
|
TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0085
|
||||||
|
TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0086
|
||||||
|
TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0087
|
||||||
|
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088
|
||||||
|
TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089
|
||||||
|
TLS_PSK_WITH_RC4_128_SHA = 0x008A
|
||||||
|
TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B
|
||||||
|
TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C
|
||||||
|
TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D
|
||||||
|
TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008E
|
||||||
|
TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008F
|
||||||
|
TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090
|
||||||
|
TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091
|
||||||
|
TLS_RSA_PSK_WITH_RC4_128_SHA = 0x0092
|
||||||
|
TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = 0x0093
|
||||||
|
TLS_RSA_PSK_WITH_AES_128_CBC_SHA = 0x0094
|
||||||
|
TLS_RSA_PSK_WITH_AES_256_CBC_SHA = 0x0095
|
||||||
|
TLS_RSA_WITH_SEED_CBC_SHA = 0x0096
|
||||||
|
TLS_DH_DSS_WITH_SEED_CBC_SHA = 0x0097
|
||||||
|
TLS_DH_RSA_WITH_SEED_CBC_SHA = 0x0098
|
||||||
|
TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099
|
||||||
|
TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A
|
||||||
|
TLS_DH_anon_WITH_SEED_CBC_SHA = 0x009B
|
||||||
|
TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C
|
||||||
|
TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D
|
||||||
|
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E
|
||||||
|
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F
|
||||||
|
TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = 0x00A0
|
||||||
|
TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = 0x00A1
|
||||||
|
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2
|
||||||
|
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3
|
||||||
|
TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = 0x00A4
|
||||||
|
TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = 0x00A5
|
||||||
|
TLS_DH_anon_WITH_AES_128_GCM_SHA256 = 0x00A6
|
||||||
|
TLS_DH_anon_WITH_AES_256_GCM_SHA384 = 0x00A7
|
||||||
|
TLS_PSK_WITH_AES_128_GCM_SHA256 = 0x00A8
|
||||||
|
TLS_PSK_WITH_AES_256_GCM_SHA384 = 0x00A9
|
||||||
|
TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = 0x00AA
|
||||||
|
TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = 0x00AB
|
||||||
|
TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 = 0x00AC
|
||||||
|
TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 = 0x00AD
|
||||||
|
TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AE
|
||||||
|
TLS_PSK_WITH_AES_256_CBC_SHA384 = 0x00AF
|
||||||
|
TLS_PSK_WITH_NULL_SHA256 = 0x00B0
|
||||||
|
TLS_PSK_WITH_NULL_SHA384 = 0x00B1
|
||||||
|
TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = 0x00B2
|
||||||
|
TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = 0x00B3
|
||||||
|
TLS_DHE_PSK_WITH_NULL_SHA256 = 0x00B4
|
||||||
|
TLS_DHE_PSK_WITH_NULL_SHA384 = 0x00B5
|
||||||
|
TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = 0x00B6
|
||||||
|
TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = 0x00B7
|
||||||
|
TLS_RSA_PSK_WITH_NULL_SHA256 = 0x00B8
|
||||||
|
TLS_RSA_PSK_WITH_NULL_SHA384 = 0x00B9
|
||||||
|
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BA
|
||||||
|
TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BB
|
||||||
|
TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BC
|
||||||
|
TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BD
|
||||||
|
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BE
|
||||||
|
TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BF
|
||||||
|
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C0
|
||||||
|
TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C1
|
||||||
|
TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C2
|
||||||
|
TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C3
|
||||||
|
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C4
|
||||||
|
TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C5
|
||||||
|
TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF
|
||||||
|
TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001
|
||||||
|
TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002
|
||||||
|
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003
|
||||||
|
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = 0xC004
|
||||||
|
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0xC005
|
||||||
|
TLS_ECDHE_ECDSA_WITH_NULL_SHA = 0xC006
|
||||||
|
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007
|
||||||
|
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008
|
||||||
|
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009
|
||||||
|
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A
|
||||||
|
TLS_ECDH_RSA_WITH_NULL_SHA = 0xC00B
|
||||||
|
TLS_ECDH_RSA_WITH_RC4_128_SHA = 0xC00C
|
||||||
|
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = 0xC00D
|
||||||
|
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = 0xC00E
|
||||||
|
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = 0xC00F
|
||||||
|
TLS_ECDHE_RSA_WITH_NULL_SHA = 0xC010
|
||||||
|
TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011
|
||||||
|
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012
|
||||||
|
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013
|
||||||
|
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014
|
||||||
|
TLS_ECDH_anon_WITH_NULL_SHA = 0xC015
|
||||||
|
TLS_ECDH_anon_WITH_RC4_128_SHA = 0xC016
|
||||||
|
TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = 0xC017
|
||||||
|
TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018
|
||||||
|
TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019
|
||||||
|
TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01A
|
||||||
|
TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0xC01B
|
||||||
|
TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = 0xC01C
|
||||||
|
TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01D
|
||||||
|
TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0xC01E
|
||||||
|
TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = 0xC01F
|
||||||
|
TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0xC020
|
||||||
|
TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0xC021
|
||||||
|
TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = 0xC022
|
||||||
|
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023
|
||||||
|
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024
|
||||||
|
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC025
|
||||||
|
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC026
|
||||||
|
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027
|
||||||
|
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028
|
||||||
|
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = 0xC029
|
||||||
|
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = 0xC02A
|
||||||
|
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B
|
||||||
|
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C
|
||||||
|
TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02D
|
||||||
|
TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02E
|
||||||
|
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F
|
||||||
|
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030
|
||||||
|
TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031
|
||||||
|
TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032
|
||||||
|
TLS_ECDHE_PSK_WITH_RC4_128_SHA = 0xC033
|
||||||
|
TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = 0xC034
|
||||||
|
TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = 0xC035
|
||||||
|
TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = 0xC036
|
||||||
|
TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = 0xC037
|
||||||
|
TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = 0xC038
|
||||||
|
TLS_ECDHE_PSK_WITH_NULL_SHA = 0xC039
|
||||||
|
TLS_ECDHE_PSK_WITH_NULL_SHA256 = 0xC03A
|
||||||
|
TLS_ECDHE_PSK_WITH_NULL_SHA384 = 0xC03B
|
||||||
|
TLS_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC03C
|
||||||
|
TLS_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC03D
|
||||||
|
TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 = 0xC03E
|
||||||
|
TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 = 0xC03F
|
||||||
|
TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC040
|
||||||
|
TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC041
|
||||||
|
TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 = 0xC042
|
||||||
|
TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 = 0xC043
|
||||||
|
TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC044
|
||||||
|
TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC045
|
||||||
|
TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 = 0xC046
|
||||||
|
TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 = 0xC047
|
||||||
|
TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 = 0xC048
|
||||||
|
TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 = 0xC049
|
||||||
|
TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 = 0xC04A
|
||||||
|
TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 = 0xC04B
|
||||||
|
TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC04C
|
||||||
|
TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC04D
|
||||||
|
TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC04E
|
||||||
|
TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC04F
|
||||||
|
TLS_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC050
|
||||||
|
TLS_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC051
|
||||||
|
TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC052
|
||||||
|
TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC053
|
||||||
|
TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC054
|
||||||
|
TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC055
|
||||||
|
TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 = 0xC056
|
||||||
|
TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 = 0xC057
|
||||||
|
TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 = 0xC058
|
||||||
|
TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 = 0xC059
|
||||||
|
TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 = 0xC05A
|
||||||
|
TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 = 0xC05B
|
||||||
|
TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 = 0xC05C
|
||||||
|
TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 = 0xC05D
|
||||||
|
TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 = 0xC05E
|
||||||
|
TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 = 0xC05F
|
||||||
|
TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC060
|
||||||
|
TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC061
|
||||||
|
TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC062
|
||||||
|
TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC063
|
||||||
|
TLS_PSK_WITH_ARIA_128_CBC_SHA256 = 0xC064
|
||||||
|
TLS_PSK_WITH_ARIA_256_CBC_SHA384 = 0xC065
|
||||||
|
TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 = 0xC066
|
||||||
|
TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 = 0xC067
|
||||||
|
TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 = 0xC068
|
||||||
|
TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 = 0xC069
|
||||||
|
TLS_PSK_WITH_ARIA_128_GCM_SHA256 = 0xC06A
|
||||||
|
TLS_PSK_WITH_ARIA_256_GCM_SHA384 = 0xC06B
|
||||||
|
TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 = 0xC06C
|
||||||
|
TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 = 0xC06D
|
||||||
|
TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 = 0xC06E
|
||||||
|
TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 = 0xC06F
|
||||||
|
TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 = 0xC070
|
||||||
|
TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 = 0xC071
|
||||||
|
TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC072
|
||||||
|
TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC073
|
||||||
|
TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC074
|
||||||
|
TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC075
|
||||||
|
TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC076
|
||||||
|
TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC077
|
||||||
|
TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC078
|
||||||
|
TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC079
|
||||||
|
TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07A
|
||||||
|
TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07B
|
||||||
|
TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07C
|
||||||
|
TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07D
|
||||||
|
TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07E
|
||||||
|
TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07F
|
||||||
|
TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC080
|
||||||
|
TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC081
|
||||||
|
TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC082
|
||||||
|
TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC083
|
||||||
|
TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 = 0xC084
|
||||||
|
TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 = 0xC085
|
||||||
|
TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC086
|
||||||
|
TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC087
|
||||||
|
TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC088
|
||||||
|
TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC089
|
||||||
|
TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08A
|
||||||
|
TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08B
|
||||||
|
TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08C
|
||||||
|
TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08D
|
||||||
|
TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08E
|
||||||
|
TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08F
|
||||||
|
TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC090
|
||||||
|
TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC091
|
||||||
|
TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC092
|
||||||
|
TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC093
|
||||||
|
TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC094
|
||||||
|
TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC095
|
||||||
|
TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC096
|
||||||
|
TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC097
|
||||||
|
TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC098
|
||||||
|
TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC099
|
||||||
|
TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC09A
|
||||||
|
TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC09B
|
||||||
|
TLS_RSA_WITH_AES_128_CCM = 0xC09C
|
||||||
|
TLS_RSA_WITH_AES_256_CCM = 0xC09D
|
||||||
|
TLS_DHE_RSA_WITH_AES_128_CCM = 0xC09E
|
||||||
|
TLS_DHE_RSA_WITH_AES_256_CCM = 0xC09F
|
||||||
|
TLS_RSA_WITH_AES_128_CCM_8 = 0xC0A0
|
||||||
|
TLS_RSA_WITH_AES_256_CCM_8 = 0xC0A1
|
||||||
|
TLS_DHE_RSA_WITH_AES_128_CCM_8 = 0xC0A2
|
||||||
|
TLS_DHE_RSA_WITH_AES_256_CCM_8 = 0xC0A3
|
||||||
|
TLS_PSK_WITH_AES_128_CCM = 0xC0A4
|
||||||
|
TLS_PSK_WITH_AES_256_CCM = 0xC0A5
|
||||||
|
TLS_DHE_PSK_WITH_AES_128_CCM = 0xC0A6
|
||||||
|
TLS_DHE_PSK_WITH_AES_256_CCM = 0xC0A7
|
||||||
|
TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8
|
||||||
|
TLS_PSK_WITH_AES_256_CCM_8 = 0xC0A9
|
||||||
|
TLS_PSK_DHE_WITH_AES_128_CCM_8 = 0xC0AA
|
||||||
|
TLS_PSK_DHE_WITH_AES_256_CCM_8 = 0xC0AB
|
||||||
|
TLS_ECDHE_ECDSA_WITH_AES_128_CCM = 0xC0AC
|
||||||
|
TLS_ECDHE_ECDSA_WITH_AES_256_CCM = 0xC0AD
|
||||||
|
TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE
|
||||||
|
TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 = 0xC0AF
|
||||||
|
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC14
|
||||||
|
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC13
|
||||||
|
|
||||||
|
|
||||||
|
def select_preferred_ciphersuite(client_supported, server_supported):
|
||||||
|
for i in server_supported:
|
||||||
|
assert isinstance(i, CipherSuites)
|
||||||
|
if i in client_supported:
|
||||||
|
return i
|
||||||
|
|
||||||
|
raise UnsupportedCipherException(
|
||||||
|
"Client supported ciphersuites are not supported on the server."
|
||||||
|
)
|
2
libmproxy/contrib/tls/exceptions.py
Normal file
2
libmproxy/contrib/tls/exceptions.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
class UnsupportedCipherException(Exception):
|
||||||
|
pass
|
178
libmproxy/contrib/tls/hello_message.py
Normal file
178
libmproxy/contrib/tls/hello_message.py
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
# This file is dual licensed under the terms of the Apache License, Version
|
||||||
|
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||||
|
# for complete details.
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from characteristic import attributes
|
||||||
|
|
||||||
|
from construct import Container
|
||||||
|
|
||||||
|
from six import BytesIO
|
||||||
|
|
||||||
|
from . import _constructs
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['major', 'minor'])
|
||||||
|
class ProtocolVersion(object):
|
||||||
|
"""
|
||||||
|
An object representing a ProtocolVersion struct.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['gmt_unix_time', 'random_bytes'])
|
||||||
|
class Random(object):
|
||||||
|
"""
|
||||||
|
An object representing a Random struct.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['type', 'data'])
|
||||||
|
class Extension(object):
|
||||||
|
"""
|
||||||
|
An object representing an Extension struct.
|
||||||
|
"""
|
||||||
|
def as_bytes(self):
|
||||||
|
return _constructs.Extension.build(Container(
|
||||||
|
type=self.type.value, length=len(self.data), data=self.data))
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['client_version', 'random', 'session_id', 'cipher_suites',
|
||||||
|
'compression_methods', 'extensions'])
|
||||||
|
class ClientHello(object):
|
||||||
|
"""
|
||||||
|
An object representing a ClientHello message.
|
||||||
|
"""
|
||||||
|
def as_bytes(self):
|
||||||
|
return _constructs.ClientHello.build(
|
||||||
|
Container(
|
||||||
|
version=Container(major=self.client_version.major,
|
||||||
|
minor=self.client_version.minor),
|
||||||
|
random=Container(
|
||||||
|
gmt_unix_time=self.random.gmt_unix_time,
|
||||||
|
random_bytes=self.random.random_bytes
|
||||||
|
),
|
||||||
|
session_id=Container(length=len(self.session_id),
|
||||||
|
session_id=self.session_id),
|
||||||
|
cipher_suites=Container(length=len(self.cipher_suites) * 2,
|
||||||
|
cipher_suites=self.cipher_suites),
|
||||||
|
compression_methods=Container(
|
||||||
|
length=len(self.compression_methods),
|
||||||
|
compression_methods=self.compression_methods
|
||||||
|
),
|
||||||
|
extensions_length=sum([2 + 2 + len(ext.data)
|
||||||
|
for ext in self.extensions]),
|
||||||
|
extensions_bytes=b''.join(
|
||||||
|
[ext.as_bytes() for ext in self.extensions]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, bytes):
|
||||||
|
"""
|
||||||
|
Parse a ``ClientHello`` struct.
|
||||||
|
|
||||||
|
:param bytes: the bytes representing the input.
|
||||||
|
:return: ClientHello object.
|
||||||
|
"""
|
||||||
|
construct = _constructs.ClientHello.parse(bytes)
|
||||||
|
# XXX Is there a better way in Construct to parse an array of
|
||||||
|
# variable-length structs?
|
||||||
|
extensions = []
|
||||||
|
extensions_io = BytesIO(construct.extensions_bytes)
|
||||||
|
while extensions_io.tell() < construct.extensions_length:
|
||||||
|
extension_construct = _constructs.Extension.parse_stream(
|
||||||
|
extensions_io)
|
||||||
|
extensions.append(
|
||||||
|
Extension(type=ExtensionType(extension_construct.type),
|
||||||
|
data=extension_construct.data))
|
||||||
|
return ClientHello(
|
||||||
|
client_version=ProtocolVersion(
|
||||||
|
major=construct.version.major,
|
||||||
|
minor=construct.version.minor,
|
||||||
|
),
|
||||||
|
random=Random(
|
||||||
|
gmt_unix_time=construct.random.gmt_unix_time,
|
||||||
|
random_bytes=construct.random.random_bytes,
|
||||||
|
),
|
||||||
|
session_id=construct.session_id.session_id,
|
||||||
|
# TODO: cipher suites should be enums
|
||||||
|
cipher_suites=construct.cipher_suites.cipher_suites,
|
||||||
|
compression_methods=(
|
||||||
|
construct.compression_methods.compression_methods
|
||||||
|
),
|
||||||
|
extensions=extensions,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ExtensionType(Enum):
|
||||||
|
SIGNATURE_ALGORITHMS = 13
|
||||||
|
# XXX: See http://tools.ietf.org/html/rfc5246#ref-TLSEXT
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['server_version', 'random', 'session_id', 'cipher_suite',
|
||||||
|
'compression_method', 'extensions'])
|
||||||
|
class ServerHello(object):
|
||||||
|
"""
|
||||||
|
An object representing a ServerHello message.
|
||||||
|
"""
|
||||||
|
def as_bytes(self):
|
||||||
|
return _constructs.ServerHello.build(
|
||||||
|
Container(
|
||||||
|
version=Container(major=self.server_version.major,
|
||||||
|
minor=self.server_version.minor),
|
||||||
|
random=Container(
|
||||||
|
gmt_unix_time=self.random.gmt_unix_time,
|
||||||
|
random_bytes=self.random.random_bytes
|
||||||
|
),
|
||||||
|
session_id=Container(length=len(self.session_id),
|
||||||
|
session_id=self.session_id),
|
||||||
|
cipher_suite=self.cipher_suite,
|
||||||
|
compression_method=self.compression_method.value,
|
||||||
|
extensions_length=sum([2 + 2 + len(ext.data)
|
||||||
|
for ext in self.extensions]),
|
||||||
|
extensions_bytes=b''.join(
|
||||||
|
[ext.as_bytes() for ext in self.extensions]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, bytes):
|
||||||
|
"""
|
||||||
|
Parse a ``ServerHello`` struct.
|
||||||
|
|
||||||
|
:param bytes: the bytes representing the input.
|
||||||
|
:return: ServerHello object.
|
||||||
|
"""
|
||||||
|
construct = _constructs.ServerHello.parse(bytes)
|
||||||
|
# XXX: Find a better way to parse extensions
|
||||||
|
extensions = []
|
||||||
|
extensions_io = BytesIO(construct.extensions_bytes)
|
||||||
|
while extensions_io.tell() < construct.extensions_length:
|
||||||
|
extension_construct = _constructs.Extension.parse_stream(
|
||||||
|
extensions_io)
|
||||||
|
extensions.append(
|
||||||
|
Extension(type=ExtensionType(extension_construct.type),
|
||||||
|
data=extension_construct.data))
|
||||||
|
return ServerHello(
|
||||||
|
server_version=ProtocolVersion(
|
||||||
|
major=construct.version.major,
|
||||||
|
minor=construct.version.minor,
|
||||||
|
),
|
||||||
|
random=Random(
|
||||||
|
gmt_unix_time=construct.random.gmt_unix_time,
|
||||||
|
random_bytes=construct.random.random_bytes,
|
||||||
|
),
|
||||||
|
session_id=construct.session_id.session_id,
|
||||||
|
cipher_suite=construct.cipher_suite,
|
||||||
|
compression_method=CompressionMethod(construct.compression_method),
|
||||||
|
extensions=extensions,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CompressionMethod(Enum):
|
||||||
|
NULL = 0
|
313
libmproxy/contrib/tls/message.py
Normal file
313
libmproxy/contrib/tls/message.py
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
# This file is dual licensed under the terms of the Apache License, Version
|
||||||
|
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||||
|
# for complete details.
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from characteristic import attributes
|
||||||
|
|
||||||
|
from construct import Container
|
||||||
|
|
||||||
|
from six import BytesIO
|
||||||
|
|
||||||
|
from . import _constructs
|
||||||
|
|
||||||
|
from .hello_message import (
|
||||||
|
ClientHello, ProtocolVersion, ServerHello
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ClientCertificateType(Enum):
|
||||||
|
RSA_SIGN = 1
|
||||||
|
DSS_SIGN = 2
|
||||||
|
RSA_FIXED_DH = 3
|
||||||
|
DSS_FIXED_DH = 4
|
||||||
|
RSA_EPHEMERAL_DH_RESERVED = 5
|
||||||
|
DSS_EPHEMERAL_DH_RESERVED = 6
|
||||||
|
FORTEZZA_DMS_RESERVED = 20
|
||||||
|
|
||||||
|
|
||||||
|
class HashAlgorithm(Enum):
|
||||||
|
NONE = 0
|
||||||
|
MD5 = 1
|
||||||
|
SHA1 = 2
|
||||||
|
SHA224 = 3
|
||||||
|
SHA256 = 4
|
||||||
|
SHA384 = 5
|
||||||
|
SHA512 = 6
|
||||||
|
|
||||||
|
|
||||||
|
class SignatureAlgorithm(Enum):
|
||||||
|
ANONYMOUS = 0
|
||||||
|
RSA = 1
|
||||||
|
DSA = 2
|
||||||
|
ECDSA = 3
|
||||||
|
|
||||||
|
|
||||||
|
class HandshakeType(Enum):
|
||||||
|
HELLO_REQUEST = 0
|
||||||
|
CLIENT_HELLO = 1
|
||||||
|
SERVER_HELLO = 2
|
||||||
|
CERTIFICATE = 11
|
||||||
|
SERVER_KEY_EXCHANGE = 12
|
||||||
|
CERTIFICATE_REQUEST = 13
|
||||||
|
SERVER_HELLO_DONE = 14
|
||||||
|
CERTIFICATE_VERIFY = 15
|
||||||
|
CLIENT_KEY_EXCHANGE = 16
|
||||||
|
FINISHED = 20
|
||||||
|
|
||||||
|
|
||||||
|
class HelloRequest(object):
|
||||||
|
"""
|
||||||
|
An object representing a HelloRequest struct.
|
||||||
|
"""
|
||||||
|
def as_bytes(self):
|
||||||
|
return b''
|
||||||
|
|
||||||
|
|
||||||
|
class ServerHelloDone(object):
|
||||||
|
"""
|
||||||
|
An object representing a ServerHelloDone struct.
|
||||||
|
"""
|
||||||
|
def as_bytes(self):
|
||||||
|
return b''
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['certificate_types', 'supported_signature_algorithms',
|
||||||
|
'certificate_authorities'])
|
||||||
|
class CertificateRequest(object):
|
||||||
|
"""
|
||||||
|
An object representing a CertificateRequest struct.
|
||||||
|
"""
|
||||||
|
def as_bytes(self):
|
||||||
|
return _constructs.CertificateRequest.build(Container(
|
||||||
|
certificate_types=Container(
|
||||||
|
length=len(self.certificate_types),
|
||||||
|
certificate_types=[cert_type.value
|
||||||
|
for cert_type in self.certificate_types]
|
||||||
|
),
|
||||||
|
supported_signature_algorithms=Container(
|
||||||
|
supported_signature_algorithms_length=2 * len(
|
||||||
|
self.supported_signature_algorithms
|
||||||
|
),
|
||||||
|
algorithms=[Container(
|
||||||
|
hash=algorithm.hash.value,
|
||||||
|
signature=algorithm.signature.value,
|
||||||
|
)
|
||||||
|
for algorithm in self.supported_signature_algorithms
|
||||||
|
]
|
||||||
|
),
|
||||||
|
certificate_authorities=Container(
|
||||||
|
length=len(self.certificate_authorities),
|
||||||
|
certificate_authorities=self.certificate_authorities
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, bytes):
|
||||||
|
"""
|
||||||
|
Parse a ``CertificateRequest`` struct.
|
||||||
|
|
||||||
|
:param bytes: the bytes representing the input.
|
||||||
|
:return: CertificateRequest object.
|
||||||
|
"""
|
||||||
|
construct = _constructs.CertificateRequest.parse(bytes)
|
||||||
|
return cls(
|
||||||
|
certificate_types=[
|
||||||
|
ClientCertificateType(cert_type)
|
||||||
|
for cert_type in construct.certificate_types.certificate_types
|
||||||
|
],
|
||||||
|
supported_signature_algorithms=[
|
||||||
|
SignatureAndHashAlgorithm(
|
||||||
|
hash=HashAlgorithm(algorithm.hash),
|
||||||
|
signature=SignatureAlgorithm(algorithm.signature),
|
||||||
|
)
|
||||||
|
for algorithm in (
|
||||||
|
construct.supported_signature_algorithms.algorithms
|
||||||
|
)
|
||||||
|
],
|
||||||
|
certificate_authorities=(
|
||||||
|
construct.certificate_authorities.certificate_authorities
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['hash', 'signature'])
|
||||||
|
class SignatureAndHashAlgorithm(object):
|
||||||
|
"""
|
||||||
|
An object representing a SignatureAndHashAlgorithm struct.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['dh_p', 'dh_g', 'dh_Ys'])
|
||||||
|
class ServerDHParams(object):
|
||||||
|
"""
|
||||||
|
An object representing a ServerDHParams struct.
|
||||||
|
"""
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, bytes):
|
||||||
|
"""
|
||||||
|
Parse a ``ServerDHParams`` struct.
|
||||||
|
|
||||||
|
:param bytes: the bytes representing the input.
|
||||||
|
:return: ServerDHParams object.
|
||||||
|
"""
|
||||||
|
construct = _constructs.ServerDHParams.parse(bytes)
|
||||||
|
return cls(
|
||||||
|
dh_p=construct.dh_p,
|
||||||
|
dh_g=construct.dh_g,
|
||||||
|
dh_Ys=construct.dh_Ys
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['client_version', 'random'])
|
||||||
|
class PreMasterSecret(object):
|
||||||
|
"""
|
||||||
|
An object representing a PreMasterSecret struct.
|
||||||
|
"""
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, bytes):
|
||||||
|
"""
|
||||||
|
Parse a ``PreMasterSecret`` struct.
|
||||||
|
|
||||||
|
:param bytes: the bytes representing the input.
|
||||||
|
:return: CertificateRequest object.
|
||||||
|
"""
|
||||||
|
construct = _constructs.PreMasterSecret.parse(bytes)
|
||||||
|
return cls(
|
||||||
|
client_version=ProtocolVersion(
|
||||||
|
major=construct.version.major,
|
||||||
|
minor=construct.version.minor,
|
||||||
|
),
|
||||||
|
random=construct.random_bytes,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['asn1_cert'])
|
||||||
|
class ASN1Cert(object):
|
||||||
|
"""
|
||||||
|
An object representing ASN.1 Certificate
|
||||||
|
"""
|
||||||
|
def as_bytes(self):
|
||||||
|
return _constructs.ASN1Cert.build(Container(
|
||||||
|
length=len(self.asn1_cert),
|
||||||
|
asn1_cert=self.asn1_cert
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['certificate_list'])
|
||||||
|
class Certificate(object):
|
||||||
|
"""
|
||||||
|
An object representing a Certificate struct.
|
||||||
|
"""
|
||||||
|
def as_bytes(self):
|
||||||
|
return _constructs.Certificate.build(Container(
|
||||||
|
certificates_length=sum([4 + len(asn1cert.asn1_cert)
|
||||||
|
for asn1cert in self.certificate_list]),
|
||||||
|
certificates_bytes=b''.join(
|
||||||
|
[asn1cert.as_bytes() for asn1cert in self.certificate_list]
|
||||||
|
)
|
||||||
|
|
||||||
|
))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, bytes):
|
||||||
|
"""
|
||||||
|
Parse a ``Certificate`` struct.
|
||||||
|
|
||||||
|
:param bytes: the bytes representing the input.
|
||||||
|
:return: Certificate object.
|
||||||
|
"""
|
||||||
|
construct = _constructs.Certificate.parse(bytes)
|
||||||
|
# XXX: Find a better way to parse an array of variable-length objects
|
||||||
|
certificates = []
|
||||||
|
certificates_io = BytesIO(construct.certificates_bytes)
|
||||||
|
|
||||||
|
while certificates_io.tell() < construct.certificates_length:
|
||||||
|
certificate_construct = _constructs.ASN1Cert.parse_stream(
|
||||||
|
certificates_io
|
||||||
|
)
|
||||||
|
certificates.append(
|
||||||
|
ASN1Cert(asn1_cert=certificate_construct.asn1_cert)
|
||||||
|
)
|
||||||
|
return cls(
|
||||||
|
certificate_list=certificates
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['verify_data'])
|
||||||
|
class Finished(object):
|
||||||
|
def as_bytes(self):
|
||||||
|
return self.verify_data
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['msg_type', 'length', 'body'])
|
||||||
|
class Handshake(object):
|
||||||
|
"""
|
||||||
|
An object representing a Handshake struct.
|
||||||
|
"""
|
||||||
|
def as_bytes(self):
|
||||||
|
if self.msg_type in [
|
||||||
|
HandshakeType.SERVER_HELLO, HandshakeType.CLIENT_HELLO,
|
||||||
|
HandshakeType.CERTIFICATE, HandshakeType.CERTIFICATE_REQUEST,
|
||||||
|
HandshakeType.HELLO_REQUEST, HandshakeType.SERVER_HELLO_DONE,
|
||||||
|
HandshakeType.FINISHED
|
||||||
|
]:
|
||||||
|
_body_as_bytes = self.body.as_bytes()
|
||||||
|
else:
|
||||||
|
_body_as_bytes = b''
|
||||||
|
return _constructs.Handshake.build(
|
||||||
|
Container(
|
||||||
|
msg_type=self.msg_type.value,
|
||||||
|
length=self.length,
|
||||||
|
body=_body_as_bytes
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, bytes):
|
||||||
|
"""
|
||||||
|
Parse a ``Handshake`` struct.
|
||||||
|
|
||||||
|
:param bytes: the bytes representing the input.
|
||||||
|
:return: Handshake object.
|
||||||
|
"""
|
||||||
|
construct = _constructs.Handshake.parse(bytes)
|
||||||
|
return cls(
|
||||||
|
msg_type=HandshakeType(construct.msg_type),
|
||||||
|
length=construct.length,
|
||||||
|
body=cls._get_handshake_message(
|
||||||
|
HandshakeType(construct.msg_type), construct.body
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_handshake_message(msg_type, body):
|
||||||
|
_handshake_message_parser = {
|
||||||
|
HandshakeType.CLIENT_HELLO: ClientHello.from_bytes,
|
||||||
|
HandshakeType.SERVER_HELLO: ServerHello.from_bytes,
|
||||||
|
HandshakeType.CERTIFICATE: Certificate.from_bytes,
|
||||||
|
# 12: parse_server_key_exchange,
|
||||||
|
HandshakeType.CERTIFICATE_REQUEST: CertificateRequest.from_bytes,
|
||||||
|
# 15: parse_certificate_verify,
|
||||||
|
# 16: parse_client_key_exchange,
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
if msg_type == HandshakeType.HELLO_REQUEST:
|
||||||
|
return HelloRequest()
|
||||||
|
elif msg_type == HandshakeType.SERVER_HELLO_DONE:
|
||||||
|
return ServerHelloDone()
|
||||||
|
elif msg_type == HandshakeType.FINISHED:
|
||||||
|
return Finished(verify_data=body)
|
||||||
|
elif msg_type in [HandshakeType.SERVER_KEY_EXCHANGE,
|
||||||
|
HandshakeType.CERTIFICATE_VERIFY,
|
||||||
|
HandshakeType.CLIENT_KEY_EXCHANGE,
|
||||||
|
]:
|
||||||
|
raise NotImplementedError
|
||||||
|
else:
|
||||||
|
return _handshake_message_parser[msg_type](body)
|
||||||
|
except NotImplementedError:
|
||||||
|
return None # TODO
|
110
libmproxy/contrib/tls/record.py
Normal file
110
libmproxy/contrib/tls/record.py
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
# This file is dual licensed under the terms of the Apache License, Version
|
||||||
|
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||||
|
# for complete details.
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from characteristic import attributes
|
||||||
|
|
||||||
|
from construct import Container
|
||||||
|
|
||||||
|
from . import _constructs
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['major', 'minor'])
|
||||||
|
class ProtocolVersion(object):
|
||||||
|
"""
|
||||||
|
An object representing a ProtocolVersion struct.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['type', 'version', 'fragment'])
|
||||||
|
class TLSPlaintext(object):
|
||||||
|
"""
|
||||||
|
An object representing a TLSPlaintext struct.
|
||||||
|
"""
|
||||||
|
def as_bytes(self):
|
||||||
|
return _constructs.TLSPlaintext.build(
|
||||||
|
Container(
|
||||||
|
type=self.type.value,
|
||||||
|
version=Container(major=self.version.major,
|
||||||
|
minor=self.version.minor),
|
||||||
|
length=len(self.fragment),
|
||||||
|
fragment=self.fragment
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, bytes):
|
||||||
|
"""
|
||||||
|
Parse a ``TLSPlaintext`` struct.
|
||||||
|
|
||||||
|
:param bytes: the bytes representing the input.
|
||||||
|
:return: TLSPlaintext object.
|
||||||
|
"""
|
||||||
|
construct = _constructs.TLSPlaintext.parse(bytes)
|
||||||
|
return cls(
|
||||||
|
type=ContentType(construct.type),
|
||||||
|
version=ProtocolVersion(
|
||||||
|
major=construct.version.major,
|
||||||
|
minor=construct.version.minor
|
||||||
|
),
|
||||||
|
fragment=construct.fragment
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['type', 'version', 'fragment'])
|
||||||
|
class TLSCompressed(object):
|
||||||
|
"""
|
||||||
|
An object representing a TLSCompressed struct.
|
||||||
|
"""
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, bytes):
|
||||||
|
"""
|
||||||
|
Parse a ``TLSCompressed`` struct.
|
||||||
|
|
||||||
|
:param bytes: the bytes representing the input.
|
||||||
|
:return: TLSCompressed object.
|
||||||
|
"""
|
||||||
|
construct = _constructs.TLSCompressed.parse(bytes)
|
||||||
|
return cls(
|
||||||
|
type=ContentType(construct.type),
|
||||||
|
version=ProtocolVersion(
|
||||||
|
major=construct.version.major,
|
||||||
|
minor=construct.version.minor
|
||||||
|
),
|
||||||
|
fragment=construct.fragment
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@attributes(['type', 'version', 'fragment'])
|
||||||
|
class TLSCiphertext(object):
|
||||||
|
"""
|
||||||
|
An object representing a TLSCiphertext struct.
|
||||||
|
"""
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, bytes):
|
||||||
|
"""
|
||||||
|
Parse a ``TLSCiphertext`` struct.
|
||||||
|
|
||||||
|
:param bytes: the bytes representing the input.
|
||||||
|
:return: TLSCiphertext object.
|
||||||
|
"""
|
||||||
|
construct = _constructs.TLSCiphertext.parse(bytes)
|
||||||
|
return cls(
|
||||||
|
type=ContentType(construct.type),
|
||||||
|
version=ProtocolVersion(
|
||||||
|
major=construct.version.major,
|
||||||
|
minor=construct.version.minor
|
||||||
|
),
|
||||||
|
fragment=construct.fragment
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ContentType(Enum):
|
||||||
|
CHANGE_CIPHER_SPEC = 20
|
||||||
|
ALERT = 21
|
||||||
|
HANDSHAKE = 22
|
||||||
|
APPLICATION_DATA = 23
|
52
libmproxy/contrib/tls/utils.py
Normal file
52
libmproxy/contrib/tls/utils.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# This file is dual licensed under the terms of the Apache License, Version
|
||||||
|
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||||
|
# for complete details.
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
import construct
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
|
||||||
|
class _UBInt24(construct.Adapter):
|
||||||
|
def _encode(self, obj, context):
|
||||||
|
return (
|
||||||
|
six.int2byte((obj & 0xFF0000) >> 16) +
|
||||||
|
six.int2byte((obj & 0x00FF00) >> 8) +
|
||||||
|
six.int2byte(obj & 0x0000FF)
|
||||||
|
)
|
||||||
|
|
||||||
|
def _decode(self, obj, context):
|
||||||
|
obj = bytearray(obj)
|
||||||
|
return (obj[0] << 16 | obj[1] << 8 | obj[2])
|
||||||
|
|
||||||
|
|
||||||
|
def UBInt24(name): # noqa
|
||||||
|
return _UBInt24(construct.Bytes(name, 3))
|
||||||
|
|
||||||
|
|
||||||
|
def LengthPrefixedArray(subcon, length_field=construct.UBInt8("length")):
|
||||||
|
"""
|
||||||
|
An array prefixed by a byte length field.
|
||||||
|
|
||||||
|
In contrast to construct.macros.PrefixedArray,
|
||||||
|
the length field signifies the number of bytes, not the number of elements.
|
||||||
|
"""
|
||||||
|
subcon_with_pos = construct.Struct(
|
||||||
|
subcon.name,
|
||||||
|
construct.Embed(subcon),
|
||||||
|
construct.Anchor("__current_pos")
|
||||||
|
)
|
||||||
|
|
||||||
|
return construct.Embed(
|
||||||
|
construct.Struct(
|
||||||
|
"",
|
||||||
|
length_field,
|
||||||
|
construct.Anchor("__start_pos"),
|
||||||
|
construct.RepeatUntil(
|
||||||
|
lambda obj, ctx: obj.__current_pos == ctx.__start_pos + getattr(ctx, length_field.name),
|
||||||
|
subcon_with_pos
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
@ -1,6 +1,6 @@
|
|||||||
from __future__ import (absolute_import, print_function, division)
|
from __future__ import (absolute_import, print_function, division)
|
||||||
|
|
||||||
import traceback
|
from ..contrib.tls._constructs import ClientHello
|
||||||
|
|
||||||
from netlib import tcp
|
from netlib import tcp
|
||||||
import netlib.http.http2
|
import netlib.http.http2
|
||||||
@ -11,15 +11,15 @@ from .layer import Layer
|
|||||||
|
|
||||||
class TlsLayer(Layer):
|
class TlsLayer(Layer):
|
||||||
def __init__(self, ctx, client_tls, server_tls):
|
def __init__(self, ctx, client_tls, server_tls):
|
||||||
|
self.client_sni = None
|
||||||
|
self.client_alpn_protos = None
|
||||||
|
|
||||||
super(TlsLayer, self).__init__(ctx)
|
super(TlsLayer, self).__init__(ctx)
|
||||||
self._client_tls = client_tls
|
self._client_tls = client_tls
|
||||||
self._server_tls = server_tls
|
self._server_tls = server_tls
|
||||||
self.client_sni = None
|
|
||||||
self._sni_from_server_change = None
|
|
||||||
self.client_alpn_protos = None
|
|
||||||
self.__server_tls_exception = None
|
|
||||||
|
|
||||||
# foo alpn protos = [netlib.http.http1.HTTP1Protocol.ALPN_PROTO_HTTP1, netlib.http.http2.HTTP2Protocol.ALPN_PROTO_H2], # TODO: read this from client_conn first
|
self._sni_from_server_change = None
|
||||||
|
self.__server_tls_exception = None
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
"""
|
"""
|
||||||
@ -45,6 +45,28 @@ class TlsLayer(Layer):
|
|||||||
https://www.openssl.org/docs/ssl/SSL_CTX_set_cert_cb.html
|
https://www.openssl.org/docs/ssl/SSL_CTX_set_cert_cb.html
|
||||||
- The original mitmproxy issue is https://github.com/mitmproxy/mitmproxy/issues/427
|
- The original mitmproxy issue is https://github.com/mitmproxy/mitmproxy/issues/427
|
||||||
"""
|
"""
|
||||||
|
import struct
|
||||||
|
|
||||||
|
# Read all records that contain the initial Client Hello message.
|
||||||
|
client_hello = ""
|
||||||
|
client_hello_size = 1
|
||||||
|
offset = 0
|
||||||
|
while len(client_hello) < client_hello_size:
|
||||||
|
record_header = self.client_conn.rfile.peek(offset+5)[offset:]
|
||||||
|
record_size = struct.unpack("!H", record_header[3:])[0] + 5
|
||||||
|
record_body = self.client_conn.rfile.peek(offset+record_size)[offset+5:]
|
||||||
|
client_hello += record_body
|
||||||
|
offset += record_size
|
||||||
|
client_hello_size = struct.unpack("!I", '\x00' + client_hello[1:4])[0] + 4
|
||||||
|
|
||||||
|
client_hello = ClientHello.parse(client_hello[4:])
|
||||||
|
|
||||||
|
for extension in client_hello.extensions:
|
||||||
|
if extension.type == 0x00:
|
||||||
|
host = extension.server_names[0].name
|
||||||
|
if extension.type == 0x10:
|
||||||
|
alpn = extension.alpn_protocols
|
||||||
|
|
||||||
client_tls_requires_server_cert = (
|
client_tls_requires_server_cert = (
|
||||||
self._client_tls and self._server_tls and not self.config.no_upstream_cert
|
self._client_tls and self._server_tls and not self.config.no_upstream_cert
|
||||||
)
|
)
|
||||||
@ -60,12 +82,12 @@ class TlsLayer(Layer):
|
|||||||
def connect(self):
|
def connect(self):
|
||||||
if not self.server_conn:
|
if not self.server_conn:
|
||||||
self.ctx.connect()
|
self.ctx.connect()
|
||||||
if self._server_tls and not self._server_tls_established:
|
if self._server_tls and not self.server_conn.tls_established:
|
||||||
self._establish_tls_with_server()
|
self._establish_tls_with_server()
|
||||||
|
|
||||||
def reconnect(self):
|
def reconnect(self):
|
||||||
self.ctx.reconnect()
|
self.ctx.reconnect()
|
||||||
if self._server_tls and not self._server_tls_established:
|
if self._server_tls and not self.server_conn.tls_established:
|
||||||
self._establish_tls_with_server()
|
self._establish_tls_with_server()
|
||||||
|
|
||||||
def set_server(self, address, server_tls, sni, depth=1):
|
def set_server(self, address, server_tls, sni, depth=1):
|
||||||
@ -74,10 +96,6 @@ class TlsLayer(Layer):
|
|||||||
self._sni_from_server_change = sni
|
self._sni_from_server_change = sni
|
||||||
self._server_tls = server_tls
|
self._server_tls = server_tls
|
||||||
|
|
||||||
@property
|
|
||||||
def _server_tls_established(self):
|
|
||||||
return self.server_conn and self.server_conn.tls_established
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sni_for_upstream_connection(self):
|
def sni_for_upstream_connection(self):
|
||||||
if self._sni_from_server_change is False:
|
if self._sni_from_server_change is False:
|
||||||
@ -138,6 +156,10 @@ class TlsLayer(Layer):
|
|||||||
connection.set_context(new_context)
|
connection.set_context(new_context)
|
||||||
|
|
||||||
def __handle_alpn_select(self, conn_, options):
|
def __handle_alpn_select(self, conn_, options):
|
||||||
|
"""
|
||||||
|
Once the client signals the alternate protocols it supports,
|
||||||
|
we reconnect upstream with the same list and pass the server's choice down to the client.
|
||||||
|
"""
|
||||||
# TODO: change to something meaningful?
|
# TODO: change to something meaningful?
|
||||||
# alpn_preference = netlib.http.http1.HTTP1Protocol.ALPN_PROTO_HTTP1
|
# alpn_preference = netlib.http.http1.HTTP1Protocol.ALPN_PROTO_HTTP1
|
||||||
alpn_preference = netlib.http.http2.HTTP2Protocol.ALPN_PROTO_H2
|
alpn_preference = netlib.http.http2.HTTP2Protocol.ALPN_PROTO_H2
|
||||||
|
4
setup.py
4
setup.py
@ -20,7 +20,9 @@ deps = {
|
|||||||
"pyperclip>=1.5.8",
|
"pyperclip>=1.5.8",
|
||||||
"blinker>=1.3",
|
"blinker>=1.3",
|
||||||
"pyparsing>=1.5.2",
|
"pyparsing>=1.5.2",
|
||||||
"html2text>=2015.4.14"
|
"html2text>=2015.4.14",
|
||||||
|
"construct>=2.5.2",
|
||||||
|
"six>=1.9.0",
|
||||||
}
|
}
|
||||||
# A script -> additional dependencies dict.
|
# A script -> additional dependencies dict.
|
||||||
scripts = {
|
scripts = {
|
||||||
|
Loading…
Reference in New Issue
Block a user