upgrade to construct 2.8 and new API

This commit is contained in:
Thomas Kriechbaumer 2016-12-04 12:06:22 +01:00
parent 741c2b7b66
commit 33689c6b2d
4 changed files with 119 additions and 150 deletions

View File

@ -3,120 +3,122 @@
# for complete details. # for complete details.
from construct import (Array, Bytes, Struct, UBInt16, UBInt32, UBInt8, PascalString, Embed, TunnelAdapter, GreedyRange, from construct import (
Switch, OptionalGreedyRange, Optional) Array,
Bytes,
from .utils import UBInt24 Struct,
VarInt,
ProtocolVersion = Struct( Int8ub,
"version", Int16ub,
UBInt8("major"), Int24ub,
UBInt8("minor"), Int32ub,
PascalString,
Embedded,
Prefixed,
Range,
GreedyRange,
Switch,
Optional,
) )
TLSPlaintext = Struct( ProtocolVersion = "version" / Struct(
"TLSPlaintext", "major" / Int8ub,
UBInt8("type"), "minor" / Int8ub,
)
TLSPlaintext = "TLSPlaintext" / Struct(
"type" / Int8ub,
ProtocolVersion, ProtocolVersion,
UBInt16("length"), # TODO: Reject packets with length > 2 ** 14 "length" / Int16ub, # TODO: Reject packets with length > 2 ** 14
Bytes("fragment", lambda ctx: ctx.length), "fragment" / Bytes(lambda ctx: ctx.length),
) )
TLSCompressed = Struct( TLSCompressed = "TLSCompressed" / Struct(
"TLSCompressed", "type" / Int8ub,
UBInt8("type"),
ProtocolVersion, ProtocolVersion,
UBInt16("length"), # TODO: Reject packets with length > 2 ** 14 + 1024 "length" / Int16ub, # TODO: Reject packets with length > 2 ** 14 + 1024
Bytes("fragment", lambda ctx: ctx.length), "fragment" / Bytes(lambda ctx: ctx.length),
) )
TLSCiphertext = Struct( TLSCiphertext = "TLSCiphertext" / Struct(
"TLSCiphertext", "type" / Int8ub,
UBInt8("type"),
ProtocolVersion, ProtocolVersion,
UBInt16("length"), # TODO: Reject packets with length > 2 ** 14 + 2048 "length" / Int16ub, # TODO: Reject packets with length > 2 ** 14 + 2048
Bytes("fragment", lambda ctx: ctx.length), "fragment" / Bytes(lambda ctx: ctx.length),
) )
Random = Struct( Random = "random" / Struct(
"random", "gmt_unix_time" / Int32ub,
UBInt32("gmt_unix_time"), "random_bytes" / Bytes(28),
Bytes("random_bytes", 28),
) )
SessionID = Struct( SessionID = "session_id" / Struct(
"session_id", "length" / Int8ub,
UBInt8("length"), "session_id" / Bytes(lambda ctx: ctx.length),
Bytes("session_id", lambda ctx: ctx.length),
) )
CipherSuites = Struct( CipherSuites = "cipher_suites" / Struct(
"cipher_suites", "length" / Int16ub, # TODO: Reject packets of length 0
UBInt16("length"), # TODO: Reject packets of length 0 Array(lambda ctx: ctx.length // 2, "cipher_suites" / Int16ub),
Array(lambda ctx: ctx.length // 2, UBInt16("cipher_suites")),
) )
CompressionMethods = Struct( CompressionMethods = "compression_methods" / Struct(
"compression_methods", "length" / Int8ub, # TODO: Reject packets of length 0
UBInt8("length"), # TODO: Reject packets of length 0 Array(lambda ctx: ctx.length, "compression_methods" / Int8ub),
Array(lambda ctx: ctx.length, UBInt8("compression_methods")),
) )
ServerName = Struct( ServerName = Struct(
"", "type" / Int8ub,
UBInt8("type"), "name" / PascalString("length" / Int16ub),
PascalString("name", length_field=UBInt16("length")),
) )
SNIExtension = Struct( SNIExtension = Prefixed(
"", Int16ub,
TunnelAdapter( Struct(
PascalString("server_names", length_field=UBInt16("length")), Int16ub,
TunnelAdapter( "server_names" / GreedyRange(
PascalString("", length_field=UBInt16("length")), "server_name" / Struct(
GreedyRange(ServerName) "name_type" / Int8ub,
), "host_name" / PascalString("length" / Int16ub),
), )
)
)
) )
ALPNExtension = Struct( ALPNExtension = Prefixed(
"", Int16ub,
TunnelAdapter( Struct(
PascalString("alpn_protocols", length_field=UBInt16("length")), Int16ub,
TunnelAdapter( "alpn_protocols" / GreedyRange(
PascalString("", length_field=UBInt16("length")), "name" / PascalString(Int8ub),
GreedyRange(PascalString("name"))
), ),
), )
) )
UnknownExtension = Struct( UnknownExtension = Struct(
"", "bytes" / PascalString("length" / Int16ub)
PascalString("bytes", length_field=UBInt16("extensions_length"))
) )
Extension = Struct( Extension = "Extension" / Struct(
"Extension", "type" / Int16ub,
UBInt16("type"), Embedded(
Embed(
Switch( Switch(
"", lambda ctx: ctx.type, lambda ctx: ctx.type,
{ {
0x00: SNIExtension, 0x00: SNIExtension,
0x10: ALPNExtension 0x10: ALPNExtension,
}, },
default=UnknownExtension default=UnknownExtension
) )
) )
) )
extensions = TunnelAdapter( extensions = "extensions" / Struct(
Optional(PascalString("extensions", length_field=UBInt16("extensions_length"))), Int16ub,
OptionalGreedyRange(Extension) "extensions" / GreedyRange(Extension)
) )
ClientHello = Struct( ClientHello = "ClientHello" / Struct(
"ClientHello",
ProtocolVersion, ProtocolVersion,
Random, Random,
SessionID, SessionID,
@ -125,31 +127,27 @@ ClientHello = Struct(
extensions, extensions,
) )
ServerHello = Struct( ServerHello = "ServerHello" / Struct(
"ServerHello",
ProtocolVersion, ProtocolVersion,
Random, Random,
SessionID, SessionID,
Bytes("cipher_suite", 2), "cipher_suite" / Bytes(2),
UBInt8("compression_method"), "compression_method" / Int8ub,
extensions, extensions,
) )
ClientCertificateType = Struct( ClientCertificateType = "certificate_types" / Struct(
"certificate_types", "length" / Int8ub, # TODO: Reject packets of length 0
UBInt8("length"), # TODO: Reject packets of length 0 Array(lambda ctx: ctx.length, "certificate_types" / Int8ub),
Array(lambda ctx: ctx.length, UBInt8("certificate_types")),
) )
SignatureAndHashAlgorithm = Struct( SignatureAndHashAlgorithm = "algorithms" / Struct(
"algorithms", "hash" / Int8ub,
UBInt8("hash"), "signature" / Int8ub,
UBInt8("signature"),
) )
SupportedSignatureAlgorithms = Struct( SupportedSignatureAlgorithms = "supported_signature_algorithms" / Struct(
"supported_signature_algorithms", "supported_signature_algorithms_length" / Int16ub,
UBInt16("supported_signature_algorithms_length"),
# TODO: Reject packets of length 0 # TODO: Reject packets of length 0
Array( Array(
lambda ctx: ctx.supported_signature_algorithms_length / 2, lambda ctx: ctx.supported_signature_algorithms_length / 2,
@ -157,56 +155,49 @@ SupportedSignatureAlgorithms = Struct(
), ),
) )
DistinguishedName = Struct( DistinguishedName = "certificate_authorities" / Struct(
"certificate_authorities", "length" / Int16ub,
UBInt16("length"), "certificate_authorities" / Bytes(lambda ctx: ctx.length),
Bytes("certificate_authorities", lambda ctx: ctx.length),
) )
CertificateRequest = Struct( CertificateRequest = "CertificateRequest" / Struct(
"CertificateRequest",
ClientCertificateType, ClientCertificateType,
SupportedSignatureAlgorithms, SupportedSignatureAlgorithms,
DistinguishedName, DistinguishedName,
) )
ServerDHParams = Struct( ServerDHParams = "ServerDHParams" / Struct(
"ServerDHParams", "dh_p_length" / Int16ub,
UBInt16("dh_p_length"), "dh_p" / Bytes(lambda ctx: ctx.dh_p_length),
Bytes("dh_p", lambda ctx: ctx.dh_p_length), "dh_g_length" / Int16ub,
UBInt16("dh_g_length"), "dh_g" / Bytes(lambda ctx: ctx.dh_g_length),
Bytes("dh_g", lambda ctx: ctx.dh_g_length), "dh_Ys_length" / Int16ub,
UBInt16("dh_Ys_length"), "dh_Ys" / Bytes(lambda ctx: ctx.dh_Ys_length),
Bytes("dh_Ys", lambda ctx: ctx.dh_Ys_length),
) )
PreMasterSecret = Struct( PreMasterSecret = "pre_master_secret" / Struct(
"pre_master_secret",
ProtocolVersion, ProtocolVersion,
Bytes("random_bytes", 46), "random_bytes" / Bytes(46),
) )
ASN1Cert = Struct( ASN1Cert = "ASN1Cert" / Struct(
"ASN1Cert", "length" / Int32ub, # TODO: Reject packets with length not in 1..2^24-1
UBInt32("length"), # TODO: Reject packets with length not in 1..2^24-1 "asn1_cert" / Bytes(lambda ctx: ctx.length),
Bytes("asn1_cert", lambda ctx: ctx.length),
) )
Certificate = Struct( Certificate = "Certificate" / Struct(
"Certificate", # TODO: Reject packets with length > 2 ** 24 - 1 # TODO: Reject packets with length > 2 ** 24 - 1
UBInt32("certificates_length"), "certificates_length" / Int32ub,
Bytes("certificates_bytes", lambda ctx: ctx.certificates_length), "certificates_bytes" / Bytes(lambda ctx: ctx.certificates_length),
) )
Handshake = Struct( Handshake = "Handshake" / Struct(
"Handshake", "msg_type" / Int8ub,
UBInt8("msg_type"), "length" / Int24ub,
UBInt24("length"), "body" / Bytes(lambda ctx: ctx.length),
Bytes("body", lambda ctx: ctx.length),
) )
Alert = Struct( Alert = "Alert" / Struct(
"Alert", "level" / Int8ub,
UBInt8("level"), "description" / Int8ub,
UBInt8("description"),
) )

View File

@ -1,22 +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.
import construct
class _UBInt24(construct.Adapter):
def _encode(self, obj, context):
return bytes(
(obj & 0xFF0000) >> 16,
(obj & 0x00FF00) >> 8,
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))

View File

@ -259,19 +259,19 @@ class TlsClientHello:
@property @property
def sni(self): def sni(self):
for extension in self._client_hello.extensions: for extension in self._client_hello.extensions.extensions:
is_valid_sni_extension = ( is_valid_sni_extension = (
extension.type == 0x00 and extension.type == 0x00 and
len(extension.server_names) == 1 and len(extension.server_names) == 1 and
extension.server_names[0].type == 0 and extension.server_names[0].name_type == 0 and
check.is_valid_host(extension.server_names[0].name) check.is_valid_host(extension.server_names[0].host_name)
) )
if is_valid_sni_extension: if is_valid_sni_extension:
return extension.server_names[0].name.decode("idna") return extension.server_names[0].host_name.decode("idna")
@property @property
def alpn_protocols(self): def alpn_protocols(self):
for extension in self._client_hello.extensions: for extension in self._client_hello.extensions.extensions:
if extension.type == 0x10: if extension.type == 0x10:
return list(extension.alpn_protocols) return list(extension.alpn_protocols)

View File

@ -63,7 +63,7 @@ setup(
"click>=6.2, <7.0", "click>=6.2, <7.0",
"certifi>=2015.11.20.1", # no semver here - this should always be on the last release! "certifi>=2015.11.20.1", # no semver here - this should always be on the last release!
"configargparse>=0.10, <0.12", "configargparse>=0.10, <0.12",
"construct>=2.5.2, <2.6", "construct>=2.8, <2.9",
"cryptography>=1.3, <1.7", "cryptography>=1.3, <1.7",
"cssutils>=1.0.1, <1.1", "cssutils>=1.0.1, <1.1",
"Flask>=0.10.1, <0.12", "Flask>=0.10.1, <0.12",