Botan  1.10.9
Public Member Functions | List of all members
Botan::Record_Reader Class Reference

#include <tls_record.h>

Public Member Functions

void add_input (const byte input[], size_t input_size)
 
size_t get_record (byte &msg_type, MemoryRegion< byte > &buffer)
 
SecureVector< byteget_record (byte &msg_type)
 
 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

Botan::Record_Reader::Record_Reader ( )
inline

Definition at line 102 of file tls_record.h.

References mac.

102 { mac = 0; reset(); }
Botan::Record_Reader::~Record_Reader ( )
inline

Definition at line 104 of file tls_record.h.

References mac.

104 { delete mac; }

Member Function Documentation

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

Definition at line 111 of file rec_read.cpp.

References Botan::SecureQueue::write().

112  {
113  input_queue.write(input, input_size);
114  }
void write(const byte[], size_t)
Definition: secqueue.cpp:117
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.

References Botan::ALERT, Botan::APPLICATION_DATA, Botan::BAD_RECORD_MAC, Botan::CHANGE_CIPHER_SPEC, Botan::CLIENT_HELLO_SSLV2, Botan::copy_mem(), Botan::Buffered_Computation::final(), Botan::get_byte(), Botan::HANDSHAKE, Botan::Pipe::LAST_MESSAGE, Botan::make_u16bit(), Botan::SecureQueue::peek(), Botan::Pipe::process_msg(), Botan::PROTOCOL_VERSION, Botan::SecureQueue::read(), Botan::Pipe::read_all(), Botan::MemoryRegion< T >::resize(), Botan::MemoryRegion< T >::size(), Botan::SecureQueue::size(), Botan::SSL_V3, Botan::UNEXPECTED_MESSAGE, Botan::Buffered_Computation::update(), and Botan::Buffered_Computation::update_be().

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  {
159  throw TLS_Exception(UNEXPECTED_MESSAGE,
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))
167  throw TLS_Exception(PROTOCOL_VERSION,
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  }
size_t read(byte[], size_t)
Definition: secqueue.cpp:137
byte get_byte(size_t byte_num, T input)
Definition: get_byte.h:21
size_t peek(byte[], size_t, size_t=0) const
Definition: secqueue.cpp:159
unsigned char byte
Definition: types.h:22
SecureVector< byte > read_all(message_id msg=DEFAULT_MESSAGE)
Definition: pipe_rw.cpp:105
static const message_id LAST_MESSAGE
Definition: pipe.h:52
void update(const byte in[], size_t length)
Definition: buf_comp.h:33
unsigned short u16bit
Definition: types.h:27
size_t size() const
Definition: secmem.h:29
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:22
void final(byte out[])
Definition: buf_comp.h:80
size_t size() const
Definition: secqueue.cpp:190
u16bit make_u16bit(byte i0, byte i1)
Definition: loadstor.h:47
void update_be(const T in)
Definition: buf_comp.h:48
void process_msg(const byte in[], size_t length)
Definition: pipe.cpp:116
SecureVector<byte> Botan::Record_Reader::get_record ( byte msg_type)
void Botan::Record_Reader::reset ( )

Definition at line 17 of file rec_read.cpp.

References Botan::Pipe::reset().

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  }
void reset()
Definition: pipe.cpp:76
void Botan::Record_Reader::set_keys ( const CipherSuite suite,
const SessionKeys keys,
Connection_Side  side 
)

Definition at line 46 of file rec_read.cpp.

References Botan::Library_State::algorithm_factory(), Botan::Pipe::append(), 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_Management::global_state(), Botan::have_block_cipher(), Botan::have_hash(), Botan::have_stream_cipher(), Botan::CipherSuite::mac_algo(), Botan::Algorithm_Factory::make_mac(), Botan::Buffered_Computation::output_length(), Botan::Pipe::reset(), Botan::SessionKeys::server_cipher_key(), Botan::SessionKeys::server_iv(), Botan::SessionKeys::server_mac_key(), and Botan::SymmetricAlgorithm::set_key().

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  }
void append(Filter *filt)
Definition: pipe.cpp:215
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20
void reset()
Definition: pipe.cpp:76
Algorithm_Factory & algorithm_factory() const
Definition: libstate.cpp:173
OctetString SymmetricKey
Definition: symkey.h:147
void set_key(const SymmetricKey &key)
Definition: sym_algo.h:60
Library_State & global_state()
size_t block_size_of(const std::string &name)
Definition: lookup.cpp:35
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
bool have_block_cipher(const std::string &algo_spec)
Definition: lookup.h:235
Keyed_Filter * get_cipher(const std::string &algo_spec, Cipher_Dir direction)
Definition: lookup.cpp:124
virtual size_t output_length() const =0
OctetString InitializationVector
Definition: symkey.h:152
void Botan::Record_Reader::set_version ( Version_Code  version)

Definition at line 34 of file rec_read.cpp.

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

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  }
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20

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