Botan 1.10.17
Botan::Record_Reader Class Reference

#include <tls_record.h>

Public Member Functions

void add_input (const byte input[], size_t input_size)
SecureVector< byteget_record (byte &msg_type)
size_t get_record (byte &msg_type, MemoryRegion< byte > &buffer)
 Record_Reader ()
void reset ()
void set_keys (const CipherSuite &suite, const SessionKeys &keys, Connection_Side side)
void set_version (Version_Code version)
 ~Record_Reader ()

Detailed Description

TLS Record Reader

Definition at line 79 of file tls_record.h.

Constructor & Destructor Documentation

◆ Record_Reader()

Botan::Record_Reader::Record_Reader ( )
inline

Definition at line 102 of file tls_record.h.

102{ mac = 0; reset(); }

References reset().

◆ ~Record_Reader()

Botan::Record_Reader::~Record_Reader ( )
inline

Definition at line 104 of file tls_record.h.

104{ delete mac; }

Member Function Documentation

◆ add_input()

void Botan::Record_Reader::add_input ( const byte input[],
size_t input_size )

Definition at line 111 of file rec_read.cpp.

112 {
113 input_queue.write(input, input_size);
114 }

◆ get_record() [1/2]

SecureVector< byte > Botan::Record_Reader::get_record ( byte & msg_type)

References reset(), set_keys(), and set_version().

◆ get_record() [2/2]

size_t Botan::Record_Reader::get_record ( byte & msg_type,
MemoryRegion< byte > & buffer )
Parameters
msg_type(output variable)
buffer(output variable)
Returns
Number of bytes still needed (minimum), or 0 if success

Definition at line 119 of file rec_read.cpp.

121 {
122 byte header[5] = { 0 };
123
124 const size_t have_in_queue = input_queue.size();
125
126 if(have_in_queue < sizeof(header))
127 return (sizeof(header) - have_in_queue);
128
129 /*
130 * We peek first to make sure we have the full record
131 */
132 input_queue.peek(header, sizeof(header));
133
134 // SSLv2-format client hello?
135 if(header[0] & 0x80 && header[2] == 1 && header[3] == 3)
136 {
137 size_t record_len = make_u16bit(header[0], header[1]) & 0x7FFF;
138
139 if(have_in_queue < record_len + 2)
140 return (record_len + 2 - have_in_queue);
141
142 msg_type = HANDSHAKE;
143 output.resize(record_len + 4);
144
145 input_queue.read(&output[2], record_len + 2);
146 output[0] = CLIENT_HELLO_SSLV2;
147 output[1] = 0;
148 output[2] = header[0] & 0x7F;
149 output[3] = header[1];
150
151 return 0;
152 }
153
154 if(header[0] != CHANGE_CIPHER_SPEC &&
155 header[0] != ALERT &&
156 header[0] != HANDSHAKE &&
157 header[0] != APPLICATION_DATA)
158 {
160 "Record_Reader: Unknown record type");
161 }
162
163 const u16bit version = make_u16bit(header[1], header[2]);
164 const u16bit record_len = make_u16bit(header[3], header[4]);
165
166 if(major && (header[1] != major || header[2] != minor))
168 "Record_Reader: Got unexpected version");
169
170 // If insufficient data, return without doing anything
171 if(have_in_queue < (sizeof(header) + record_len))
172 return (sizeof(header) + record_len - have_in_queue);
173
174 SecureVector<byte> buffer(record_len);
175
176 input_queue.read(header, sizeof(header)); // pull off the header
177 input_queue.read(&buffer[0], buffer.size());
178
179 /*
180 * We are handshaking, no crypto to do so return as-is
181 * TODO: Check msg_type to confirm a handshake?
182 */
183 if(mac_size == 0)
184 {
185 msg_type = header[0];
186 output = buffer;
187 return 0; // got a full record
188 }
189
190 // Otherwise, decrypt, check MAC, return plaintext
191
192 cipher.process_msg(buffer);
193 SecureVector<byte> plaintext = cipher.read_all(Pipe::LAST_MESSAGE);
194
195 size_t pad_size = 0;
196
197 if(block_size)
198 {
199 byte pad_value = plaintext[plaintext.size()-1];
200 pad_size = pad_value + 1;
201
202 /*
203 * Check the padding; if it is wrong, then say we have 0 bytes of
204 * padding, which should ensure that the MAC check below does not
205 * suceed. This hides a timing channel.
206 *
207 * This particular countermeasure is recommended in the TLS 1.2
208 * spec (RFC 5246) in section 6.2.3.2
209 */
210 if(version == SSL_V3)
211 {
212 if(pad_value > block_size)
213 pad_size = 0;
214 }
215 else
216 {
217 bool padding_good = true;
218
219 for(size_t i = 0; i != pad_size; ++i)
220 if(plaintext[plaintext.size()-i-1] != pad_value)
221 padding_good = false;
222
223 if(!padding_good)
224 pad_size = 0;
225 }
226 }
227
228 if(plaintext.size() < mac_size + pad_size + iv_size)
229 throw Decoding_Error("Record_Reader: Record truncated");
230
231 const size_t mac_offset = plaintext.size() - (mac_size + pad_size);
232 SecureVector<byte> received_mac(&plaintext[mac_offset],
233 mac_size);
234
235 const u16bit plain_length = plaintext.size() - (mac_size + pad_size + iv_size);
236
237 mac->update_be(seq_no);
238 mac->update(header[0]); // msg_type
239
240 if(version != SSL_V3)
241 for(size_t i = 0; i != 2; ++i)
242 mac->update(get_byte(i, version));
243
244 mac->update_be(plain_length);
245 mac->update(&plaintext[iv_size], plain_length);
246
247 ++seq_no;
248
249 SecureVector<byte> computed_mac = mac->final();
250
251 if(received_mac != computed_mac)
252 throw TLS_Exception(BAD_RECORD_MAC, "Record_Reader: MAC failure");
253
254 msg_type = header[0];
255
256 output.resize(plain_length);
257 copy_mem(&output[0], &plaintext[iv_size], plain_length);
258 return 0;
259 }
static const message_id LAST_MESSAGE
Definition pipe.h:52
TLS_Exception(Alert_Type type, const std::string &err_msg="Unknown error")
Definition tls_exceptn.h:24
@ PROTOCOL_VERSION
Definition tls_magic.h:81
@ BAD_RECORD_MAC
Definition tls_magic.h:65
@ UNEXPECTED_MESSAGE
Definition tls_magic.h:64
byte get_byte(size_t byte_num, T input)
Definition get_byte.h:21
u16bit make_u16bit(byte i0, byte i1)
Definition loadstor.h:47
void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:22
unsigned short u16bit
Definition types.h:27
@ ALERT
Definition tls_magic.h:35
@ APPLICATION_DATA
Definition tls_magic.h:37
@ HANDSHAKE
Definition tls_magic.h:36
@ CHANGE_CIPHER_SPEC
Definition tls_magic.h:34
@ CLIENT_HELLO_SSLV2
Definition tls_magic.h:43
@ SSL_V3
Definition tls_magic.h:24
Decoding_Error(const std::string &name)
Definition exceptn.h:140

References Botan::ALERT, Botan::APPLICATION_DATA, Botan::BAD_RECORD_MAC, Botan::CHANGE_CIPHER_SPEC, Botan::CLIENT_HELLO_SSLV2, Botan::copy_mem(), Botan::Decoding_Error::Decoding_Error(), Botan::get_byte(), Botan::HANDSHAKE, Botan::Pipe::LAST_MESSAGE, Botan::make_u16bit(), Botan::PROTOCOL_VERSION, Botan::MemoryRegion< T >::resize(), Botan::MemoryRegion< T >::size(), Botan::SSL_V3, Botan::TLS_Exception::TLS_Exception(), and Botan::UNEXPECTED_MESSAGE.

◆ reset()

void Botan::Record_Reader::reset ( )

Definition at line 17 of file rec_read.cpp.

18 {
19 cipher.reset();
20
21 delete mac;
22 mac = 0;
23
24 mac_size = 0;
25 block_size = 0;
26 iv_size = 0;
27 major = minor = 0;
28 seq_no = 0;
29 }

Referenced by get_record(), and Record_Reader().

◆ set_keys()

void Botan::Record_Reader::set_keys ( const CipherSuite & suite,
const SessionKeys & keys,
Connection_Side side )

Definition at line 46 of file rec_read.cpp.

48 {
49 cipher.reset();
50 delete mac;
51 mac = 0;
52 seq_no = 0;
53
54 SymmetricKey mac_key, cipher_key;
56
57 if(side == CLIENT)
58 {
59 cipher_key = keys.server_cipher_key();
60 iv = keys.server_iv();
61 mac_key = keys.server_mac_key();
62 }
63 else
64 {
65 cipher_key = keys.client_cipher_key();
66 iv = keys.client_iv();
67 mac_key = keys.client_mac_key();
68 }
69
70 const std::string cipher_algo = suite.cipher_algo();
71 const std::string mac_algo = suite.mac_algo();
72
73 if(have_block_cipher(cipher_algo))
74 {
75 cipher.append(get_cipher(
76 cipher_algo + "/CBC/NoPadding",
77 cipher_key, iv, DECRYPTION)
78 );
79 block_size = block_size_of(cipher_algo);
80
81 if(major > 3 || (major == 3 && minor >= 2))
82 iv_size = block_size;
83 else
84 iv_size = 0;
85 }
86 else if(have_stream_cipher(cipher_algo))
87 {
88 cipher.append(get_cipher(cipher_algo, cipher_key, DECRYPTION));
89 block_size = 0;
90 iv_size = 0;
91 }
92 else
93 throw Invalid_Argument("Record_Reader: Unknown cipher " + cipher_algo);
94
95 if(have_hash(mac_algo))
96 {
97 Algorithm_Factory& af = global_state().algorithm_factory();
98
99 if(major == 3 && minor == 0)
100 mac = af.make_mac("SSL3-MAC(" + mac_algo + ")");
101 else
102 mac = af.make_mac("HMAC(" + mac_algo + ")");
103
104 mac->set_key(mac_key);
105 mac_size = mac->output_length();
106 }
107 else
108 throw Invalid_Argument("Record_Reader: Unknown hash " + mac_algo);
109 }
MessageAuthenticationCode * make_mac(const std::string &algo_spec, const std::string &provider="")
Algorithm_Factory & algorithm_factory() const
Definition libstate.cpp:173
void set_key(const SymmetricKey &key)
Definition sym_algo.h:60
OctetString SymmetricKey
Definition symkey.h:147
bool have_stream_cipher(const std::string &algo_spec)
Definition lookup.h:248
bool have_hash(const std::string &algo_spec)
Definition lookup.h:261
@ CLIENT
Definition tls_magic.h:29
Keyed_Filter * get_cipher(const std::string &algo_spec, Cipher_Dir direction)
Definition lookup.cpp:124
std::invalid_argument Invalid_Argument
Definition exceptn.h:20
Library_State & global_state()
OctetString InitializationVector
Definition symkey.h:152
@ DECRYPTION
Definition sym_algo.h:87
size_t block_size_of(const std::string &name)
Definition lookup.cpp:35
bool have_block_cipher(const std::string &algo_spec)
Definition lookup.h:235

References Botan::Library_State::algorithm_factory(), Botan::block_size_of(), Botan::CipherSuite::cipher_algo(), Botan::CLIENT, Botan::SessionKeys::client_cipher_key(), Botan::SessionKeys::client_iv(), Botan::SessionKeys::client_mac_key(), Botan::DECRYPTION, Botan::get_cipher(), Botan::global_state(), Botan::have_block_cipher(), Botan::have_hash(), Botan::have_stream_cipher(), Botan::CipherSuite::mac_algo(), Botan::Algorithm_Factory::make_mac(), Botan::SessionKeys::server_cipher_key(), Botan::SessionKeys::server_iv(), Botan::SessionKeys::server_mac_key(), and Botan::SymmetricAlgorithm::set_key().

Referenced by get_record().

◆ set_version()

void Botan::Record_Reader::set_version ( Version_Code version)

Definition at line 34 of file rec_read.cpp.

35 {
36 if(version != SSL_V3 && version != TLS_V10 && version != TLS_V11)
37 throw Invalid_Argument("Record_Reader: Invalid protocol version");
38
39 major = (version >> 8) & 0xFF;
40 minor = (version & 0xFF);
41 }
@ TLS_V10
Definition tls_magic.h:25
@ TLS_V11
Definition tls_magic.h:26

References Botan::SSL_V3, Botan::TLS_V10, and Botan::TLS_V11.

Referenced by get_record().


The documentation for this class was generated from the following files: