tls_client_handler module¶
- class tls_client_handler.Certificate(conf=None, content={}, sender=None)¶
Bases:
TLSMsgCertificate Message handler for teh TLS client
- get_public_key()¶
Returning the corresponding public key
- Returns:
the public key object
- Return type:
public_key
- init_from_conf(certificate_request_context=b'')¶
- class tls_client_handler.CertificateVerify(conf=None, content={}, sender=None)¶
Bases:
TLSMsg- check_signature(tls_handshake, public_key)¶
- get_cert_from_handshake_msg_list(handshake_msg_list)¶
parse handshake message list and extract certificates
- get_last_exchange(c_register_tickets, is_post_hand_auth_proposed) bool¶
returns the last_message tag
last_exchange is set to False in the following cases:
post handshake: post_hand_auth_proposed (post handshake)
session resumption: method is ‘cs_generated’ or PSK in use in CS
this corresponds to the value c_register_tickets
- handle_c_client_finished(lurk_client, ks, handshake_msg_list, c_register_tickets)¶
generates certificate_verify and updates ks
- handle_c_init_client_finished(lurk_client, ks, handshake_msg_list, c_register_tickets)¶
generates certificate_verify and updates ks
- init_content_from_lurk_resp(lurk_resp)¶
- class tls_client_handler.ClientHello(conf=None, content={})¶
Bases:
TLSMsg- from_record_layer_bytes(byte_string)¶
initiates TLSMsg from TLS record layer bytes
- init(lurk_client=None, tls_handshake=None, ks=None, engine_ticket_db=None)¶
- init_from_test_vector(lurk_client=None, tls_handshake=None, ks=None)¶
init from vector has mostly been done to work with the illustarted TLS 1.3
This function has not done intensive testing. Initially, we expected to test the library against welknown test vectors, but instead we are testing the tls client against with different OpenSSL flavors of TLS.
We leave this part as an initial step for a more extensivve use of test vectors.
Illustrated TLS only works for unauthenticated TLS client. The CS works with freshness set to null.
There is more work to do to integrate the test_vector functionality into the more generic way to handle the client hello.
- set_lurk_session_state(has_proposed_psk_in_cs)¶
determine if a c_init_client_hello is performed
The current policy is to trigger a c_init_client_hello only when an interaction with the CS is needed. The reason is that we want to limit the interactions with the CS. Other policies may be implemented.
- to_record_layer_bytes(content_type=None, content=None)¶
return a byte format TLS Reccord
The inner packet ( self.content ) is wrapped into the TLS Reccord.
- class tls_client_handler.EngineTicketDB¶
Bases:
TicketDBStoring tickets received by the server
Unlike TicketDB, the engine may not be aware of the psk. In addition, the Engine selects tickets that apply to a given TLS server while the CS requires ticket information associated to a specific ticket. Such differences requires different structurre of teh database.
- get_ticket_info_list(clt_conf)¶
- key(clt_conf)¶
- register(conf, new_session_ticket, ks, tls_handshake)¶
- class tls_client_handler.ExtClientProtocolVersions¶
Bases:
object
- class tls_client_handler.ExtClientSignatureAlgorithms(sig_list)¶
Bases:
object
Bases:
object
- class tls_client_handler.ExtPostHandshakeAuthentication¶
Bases:
object
Bases:
objectgenerates the pre_shared_key extention
- class tls_client_handler.ExtPskKeyExchangeMode(ke_modes)¶
Bases:
object
- class tls_client_handler.ExtSupportedGroups(supported_groups)¶
Bases:
object
- class tls_client_handler.Finished(conf=None, content={}, sender=None)¶
Bases:
ClientHello- check_verify_data(tls_handshake, ks)¶
- class tls_client_handler.NewSessionTicket(conf=None, content={}, sender=None)¶
Bases:
TLSMsg- handle_c_register_ticket(lurk_client)¶
generates certificate_verify and updates ks
- class tls_client_handler.ServerHello(conf=None, content=None)¶
Bases:
ClientHello- handle_c_server_hello(lurk_client, tls_handshake, ks, client_hello)¶
performs the c_server_hello and update tls_handshake and ks
- handle_server_hello(lurk_client, client_hello, tls_handshake, ks, tls_msg)¶
- set_lurk_session_state(client_hello, tls_handshake)¶
set the c_server_hello and c_register_tickets staus
Determine if the TLS client needs to perform a c_server_hello or a c_register_tickets LURK exchange.
There different ways to implement it. Our implementation considers these exchanges are only performed when it actually make sense to benefit from the additional security provided by the CS. .
- There is a need to interact with the CS if:
the exchange includes ECDHE either with the TLS ECDHE mode or
TLS PSK-ECDHE mode and the mode is ‘cs_generated’
the TLS mode is psk based and the PSK is in the CS
the client will be authenticated. However, we cannot determine
it as long as we have not received a certificate request.
In any of these case, the key scheduler cannot be used to generate secrets and these MUST be generated by the CS. In any other case, there is no need to interact with the CS.
It could happen that a c_init_client_hello has initiated a session with the CS, and no more messages are sent. For example, the client may request ECDHE key share being generated by the CS while the CS does not pick that mode. Another case may consider the user using a set of PSKs that are shared between the CS and the Engine. The c_init_client_hello is necessary to generate the binders. However, if the TLS server choses a PSK that is known to the engine and if the Engine has generated the ECDHE key_share - or there are not ECDHE key_share involved, then the Engine may build its own key scheduler. Such example are a bit of a corner case and the CS MUST be able to remove session after some time out.
In the worst case, c_init_client_hello may be sent, c_server_hello is not needed but later on the server request an authentication of the client in which case a c_finished client is needed. Such scenario corresponds to the branch (a) in the LURK specification. This branch is optional and an implementation may chose to consider the ability to skip the c_server_hello or not. In the latter case, a c_init_client_hello will always be followed by a c_server_hello. This would result in the simplified version of this function: ## self.c_server_hello = client_hello.c_init_client_hello ## self.c_register_tickets = self.c_server_hello
The current version of the function considers that a c_server_hello exchange may or may not be performed - considering the various corner cases. When a c_server_hello exchange is expected, the varaible self.c_server_hello is set to True. Note that self.c_server_hello is set to False when there is a c_init_client_hello exchange bu no c_server_hello exchange as well as when no c_init_client_hello has been initated.
Similarly, when a c_register_ticket exchange is expected upon receiving a NewSession Ticket, this function sets the self.c_register_tickets to True. Note that tickets are registered only when these can only be handled by the Engine E and necessarily be handled by the CS.
- set_tls_mode(tls_handshake) str¶
returns the tls_mode ‘ecdhe’, ‘psk_ecdhe’ or ‘psk’
- class tls_client_handler.TLSByteStreamParser(socket, debug=None, sender='server')¶
Bases:
objectParse received bytes and convert them into TLS messages
collect received bytes, reassemble plaintext fragments
- socket¶
the socket the parser is listening to
- cipher¶
the cipher to decrypt the incoming TLS fragments. By default the cipher is set to None for example to handle non encrypted ServerHello.
- byte_stream¶
the received bytes. Anytime there is a read on the socket the raw bytes are aggregated into this variable. By default, it is set to th empty byte stream b’’.
- fragment¶
the bytes associated to fragments that have been received. These fragments are considered as intermediary steps to output a message. Sufficnet bytes my be receievd to get a fragment but not enough to get a TLS message. When sufficient fragments are received, the TLS message is output and the fragment bytes emptied.
- debug¶
indicates if debug message are output (for debuging purpose)
- sender¶
indicates who is sending the received message. In the case of a TLS client, the sender is set to ‘server’
- __init__(socket, debug=None, sender='server')¶
converts received bytes into TLS messages
collect received bytes, reassemble plaintext fragments
- Parameters:
sender (str) – the entity from whihc the tls messages are received ‘client’ or ‘server’
- fragment_reassembly(plain_text: TLSMsg = None) TLSMsg¶
returns the first TLS message
returns the first tls (handshake) message from a TLS plaintext fragment or a TLSMsg with its content set to None.
Returning such message MAY require reassembling fragments. Note that the fragment MAY also contain other TLS messages when multiple handshake messages are pipelined.
- Parameters:
plain_text –
The plain text message which contains:
plain_text_fragment_type corresponds to the TLSPlaintext
’type’. It is extracted from the TLS reccord or the InnerPlaintext. It can be ‘change_cipher’, ‘alert’, ‘handshake’ or ‘application_data’ but in our case, it MUST be set to ‘handshake’ as fragmentation only happens for handshake messages.
plain_text_fragment (bytes): the actual bytes of the fragment.
current_fragment corresponds to the ongoing fragments being reassembled.
The TLS record is a plain text structure as defined below. For ‘change_cipher_text’ and ‘alert’ message, the plaintext contains a full tls message and a single one. In other words, there is no fragmentation. For ‘application_data’ this is transparent to TLS as fragmentation is handled by the application. The case that is of interest to use is the case of handshake message that can be fragmented.
TLSPlaintext = Struct( 'type' / ContentType, 'legacy_record_version' / Const( b'' ), 'fragment' / Prefixed( BytesInteger(2), Switch( this.type, { 'change_cipher_spec' : ChangeCipherSpec, 'alert' : Alert, 'handshake' : GreedyBytes, 'application_data' : GreedyBytes } ) ) )
The function only takes the bytes associated to the fragment as these fragment may be carried inside a TLSPlaintext message as weel as in a InnerPlaintext structure.
fragment MAY be a full handshake message in which case the fragment is returned as the message. The TLSPlaintext structure considers that a full message is sent but does not consider a fragment is set. Fragmentation does not concerns alert messages, nor application data, but only handshake messages.
A fragment will not make possible the parsing. Fragments can be : 1. a starting initial fragment:
a non starting initial fragment:
a non initial fragment
With the current structure, 1) and 3) will generate an error upon parsing as the fragment will not be recognized as handshake message., while 2) will parse the first handshake message and ignore the bytes associatefd to the first fragment.
To do so we need to manually check length.
- next_clear_text_fragment() TLSMsg¶
returns the next clear text fragment
- Return type:
tls_msg
The next clear text message corresponds to the fragment (in clear) carried by the next reccord layer. The reccord layer is read from self.byte_stream buffer, this results in a plain text. When self.byte_stream does not have sufficient bytes, complementary bytes are read from the socket. Once we have sufficient reccord layer, the resulting tls message is built. When the plain text is of type ‘application_data’, it contains an inner message that contains the clear text fragment.
- parse_record_layer_length() int¶
returns the record layer length from bytes
note that the len is the len of the plain text which may contain a full message or a fragment.
- parse_single_msg() dict¶
- read_bytes(bufsize=4096) int¶
reads and appends bytes to the byte_stream
returns:
- class tls_client_handler.TLSMsg(conf=None, content_type=None, content={}, sender=None)¶
Bases:
object- __init__(conf=None, content_type=None, content={}, sender=None)¶
basic structure for a TLS message
TLS uses multiple representation for a TLS message. It can be for example a InnerPlaintext or an Plaintext. TLSMsg enables to associate a content_type to a content and provides more abstraction.
- Parameters:
conf – the configuration of the TLS client
content_type – ‘application_data’, ‘handshake’, ‘alert’,…
content – the content of the message, it can be a fragment in which case it is commonly a byte or a structure.
sender – th eentity sending the message.
- add_ext(ext_list)¶
- decrypt_inner_msg(cipher, debug=None)¶
decyrpt the inner plaintext of the encrypted fragment returns a TLSMsg object
- descriptor(sender=None, label='')¶
return a TLSMsg descriptor (aiming) at uniquely mapping a message
This is mostly useful for test_vector and is currenlty in mapping (sender, content_type, handshake.msg_type). Fragmented messages are not considered.
- encrypt_and_send(cipher, socket, sender, debug=None)¶
encrypt and send the provided innet_tls_msg
The current tls msg is considered as the inner clear text message
- from_inner_msg_struct(inner_msg: dict)¶
- from_record_layer_bytes(byte_string)¶
initiates TLSMsg from TLS record layer bytes
- from_record_layer_struct(tls_plain_text)¶
initiates TLSMsg from a tls_plaintext structure
- from_test_vector(test_vector_file, key)¶
- to_inner_msg_bytes()¶
- to_inner_msg_struct()¶
- to_record_layer_bytes(content_type=None, content=None)¶
return a byte format TLS Reccord
The inner packet ( self.content ) is wrapped into the TLS Reccord.
- to_record_layer_struct(content_type=None, content=None) dict¶
return a plaintext structure representing the record layer