clean up clienthello parsing

This commit is contained in:
Maximilian Hils 2015-08-26 22:00:50 +02:00
parent 2cfc1b1b40
commit 9c6b3eb58a
10 changed files with 19 additions and 1041 deletions

View File

@ -8,3 +8,7 @@ jsbeautifier, git checkout 25/03/12, MIT license
wbxml
- https://github.com/davidpshaw/PyWBXMLDecoder
tls, BSD license
- https://github.com/mhils/tls/tree/extension-parsing
- limited to required files.

View File

@ -4,8 +4,8 @@
from __future__ import absolute_import, division, print_function
from construct import Array, Bytes, Struct, UBInt16, UBInt32, UBInt8, PascalString, Embed, \
TunnelAdapter, GreedyRange, Switch
from construct import (Array, Bytes, Struct, UBInt16, UBInt32, UBInt8, PascalString, Embed, TunnelAdapter, GreedyRange,
Switch, OptionalGreedyRange)
from .utils import UBInt24
@ -113,7 +113,7 @@ Extension = Struct(
extensions = TunnelAdapter(
PascalString("extensions", length_field=UBInt16("extensions_length")),
GreedyRange(Extension)
OptionalGreedyRange(Extension)
)
ClientHello = Struct(

View File

@ -1,64 +0,0 @@
# 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)
)

View File

@ -1,343 +0,0 @@
# 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."
)

View File

@ -1,2 +0,0 @@
class UnsupportedCipherException(Exception):
pass

View File

@ -1,178 +0,0 @@
# 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

View File

@ -1,313 +0,0 @@
# 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

View File

@ -1,110 +0,0 @@
# 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

View File

@ -24,29 +24,3 @@ class _UBInt24(construct.Adapter):
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
),
)
)

View File

@ -61,7 +61,12 @@ class TlsLayer(Layer):
layer()
def _get_client_hello(self):
# Read all records that contain the initial Client Hello message.
"""
Peek into the socket and read all records that contain the initial client hello message.
Returns:
The raw handshake packet bytes, without TLS record header(s).
"""
client_hello = ""
client_hello_size = 1
offset = 0
@ -75,10 +80,15 @@ class TlsLayer(Layer):
return client_hello
def _parse_client_hello(self):
"""
Peek into the connection, read the initial client hello and parse it to obtain ALPN values.
"""
raw_client_hello = self._get_client_hello()[4:] # exclude handshake header.
try:
client_hello = ClientHello.parse(self._get_client_hello()[4:])
client_hello = ClientHello.parse(raw_client_hello)
except ConstructError as e:
self.log("Cannot parse Client Hello: %s" % repr(e), "error")
self.log("Raw Client Hello:\r\n:%s" % raw_client_hello.encode("hex"), "debug")
return
for extension in client_hello.extensions: