class TTTLS13::Message::Record
rubocop: disable Metrics/ClassLength
Attributes
Public Class Methods
NOTE: If previous Record
has surplus_binary
, surplus_binary
should is given to Record.deserialize
as buffered.
@param binary [String] @param cipher [TTTLS13::Cryptograph::$Object] @param buffered [String] surplus_binary
@param record_size_limit [Integer]
@raise [TTTLS13::Error::ErrorAlerts]
@return [TTTLS13::Message::Record] rubocop: disable Metrics/AbcSize rubocop: disable Metrics/CyclomaticComplexity rubocop: disable Metrics/PerceivedComplexity
# File lib/tttls1.3/message/record.rb, line 72 def self.deserialize(binary, cipher, buffered = '', record_size_limit = DEFAULT_RECORD_SIZE_LIMIT) raise Error::ErrorAlerts, :internal_error if binary.nil? raise Error::ErrorAlerts, :decode_error if binary.length < 5 type = binary[0] legacy_record_version = binary.slice(1, 2) fragment_len = Convert.bin2i(binary.slice(3, 2)) raise Error::ErrorAlerts, :record_overflow \ if (cipher.is_a?(Cryptograph::Passer) && fragment_len > 2**14) || (cipher.is_a?(Cryptograph::Aead) && fragment_len > 2**14 + 256) fragment = binary.slice(5, fragment_len) raise Error::ErrorAlerts, :decode_error \ unless binary.length == 5 + fragment_len if type == ContentType::APPLICATION_DATA if fragment.length - cipher.auth_tag_len > record_size_limit raise Error::ErrorAlerts, :record_overflow end fragment, inner_type = cipher.decrypt(fragment, binary.slice(0, 5)) end messages, surplus_binary = deserialize_fragment(buffered + fragment, inner_type || type) Record.new(type: type, legacy_record_version: legacy_record_version, messages: messages, surplus_binary: surplus_binary, cipher: cipher) end
@param type [TTTLS13::Message::ContentType] @param legacy_record_version
[TTTLS13::Message::ProtocolVersion] @param messages [Array of TTTLS13::Message::$Object] @param surplus_binary
[String] @param cipher [TTTLS13::Cryptograph::$Object]
# File lib/tttls1.3/message/record.rb, line 22 def initialize(type:, legacy_record_version: ProtocolVersion::TLS_1_2, messages:, surplus_binary: '', cipher:) @type = type @legacy_record_version = legacy_record_version @messages = messages @surplus_binary = surplus_binary @cipher = cipher end
Private Class Methods
@param binary [String] @param type [TTTLS13::Message::ContentType]
@raise [TTTLS13::Error::ErrorAlerts]
@return [Array of TTTLS13::Message::$Object] @return [String]
# File lib/tttls1.3/message/record.rb, line 151 def deserialize_fragment(binary, type) raise Error::ErrorAlerts, :internal_error if binary.nil? surplus_binary = '' case type when ContentType::HANDSHAKE messages, surplus_binary = deserialize_handshake(binary) when ContentType::CCS messages = [ChangeCipherSpec.deserialize(binary)] when ContentType::APPLICATION_DATA messages = [ApplicationData.deserialize(binary)] when ContentType::ALERT messages = [Alert.deserialize(binary)] else raise Error::ErrorAlerts, :unexpected_message end [messages, surplus_binary] end
@param binary [String]
@raise [TTTLS13::Error::ErrorAlerts]
@return [Array of TTTLS13::Message::$Object] @return [String]
# File lib/tttls1.3/message/record.rb, line 177 def deserialize_handshake(binary) raise Error::ErrorAlerts, :internal_error if binary.nil? handshakes = [] i = 0 while i < binary.length # Handshake.length is kind of uint24 and Record.length is kind of # uint16, so Handshake can be longer than Record capacity. if binary.length < 4 + i || binary.length < 4 + i + Convert.bin2i(binary.slice(i + 1, 3)) surplus_binary = binary[i..] return [handshakes, surplus_binary] end msg_len = Convert.bin2i(binary.slice(i + 1, 3)) msg_bin = binary.slice(i, msg_len + 4) message = do_deserialize_handshake(msg_bin) i += msg_len + 4 handshakes << message end surplus_binary = binary[i..] [handshakes, surplus_binary] end
@param binary [String]
@raise [TTTLS13::Error::ErrorAlerts]
@return [Array of TTTLS13::Message::$Object] rubocop: disable Metrics/CyclomaticComplexity
# File lib/tttls1.3/message/record.rb, line 208 def do_deserialize_handshake(binary) raise Error::ErrorAlerts, :internal_error if binary.nil? raise Error::ErrorAlerts, :decode_error if binary.empty? case binary[0] when HandshakeType::CLIENT_HELLO ClientHello.deserialize(binary) when HandshakeType::SERVER_HELLO ServerHello.deserialize(binary) when HandshakeType::ENCRYPTED_EXTENSIONS EncryptedExtensions.deserialize(binary) when HandshakeType::CERTIFICATE Certificate.deserialize(binary) when HandshakeType::CERTIFICATE_VERIFY CertificateVerify.deserialize(binary) when HandshakeType::FINISHED Finished.deserialize(binary) when HandshakeType::NEW_SESSION_TICKET NewSessionTicket.deserialize(binary) when HandshakeType::END_OF_EARLY_DATA EndOfEarlyData.deserialize(binary) else raise Error::ErrorAlerts, :unexpected_message end end
Public Instance Methods
NOTE: serialize joins messages. If serialize is received Server
Parameters(EE, CT, CV), it returns one binary.
@param record_size_limit [Integer]
@return [String]
# File lib/tttls1.3/message/record.rb, line 42 def serialize(record_size_limit = DEFAULT_RECORD_SIZE_LIMIT) tlsplaintext = @messages.map(&:serialize).join + @surplus_binary if @cipher.is_a?(Cryptograph::Aead) max = @cipher.tlsplaintext_length_limit(record_size_limit) fragments = tlsplaintext.scan(/.{1,#{max}}/m) else fragments = [tlsplaintext] end fragments.map do |s| @type + @legacy_record_version \ + @cipher.encrypt(s, messages_type).prefix_uint16_length end.join end
Private Instance Methods
@raise [TTTLS13::Error::ErrorAlerts]
@return [TTTLS13::Message::ContentType]
# File lib/tttls1.3/message/record.rb, line 113 def messages_type types = @messages.map do |m| if [Message::ClientHello, Message::ServerHello, Message::EncryptedExtensions, Message::Certificate, Message::CertificateVerify, Message::Finished, Message::EndOfEarlyData, Message::NewSessionTicket].include?(m.class) ContentType::HANDSHAKE elsif m.class == ChangeCipherSpec ContentType::CCS elsif m.class == Message::ApplicationData ContentType::APPLICATION_DATA elsif m.class == Message::Alert ContentType::ALERT else raise Error::ErrorAlerts, :internal_error end end types.uniq! raise Error::ErrorAlerts, :internal_error unless types.length == 1 types.first end