Botan 1.10.17

rec_read.cpp
Go to the documentation of this file.
1 /*
2 * TLS Record Reading
3 * (C) 2004-2010 Jack Lloyd
4 *
5 * Released under the terms of the Botan license
6 */
7
8 #include <botan/tls_record.h>
9 #include <botan/lookup.h>
10 #include <botan/loadstor.h>
11
12 namespace Botan {
13
14 /*
15 * Reset the state
16 */
17 void Record_Reader::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 }
30
31 /*
32 * Set the version to use
33 */
34 void Record_Reader::set_version(Version_Code version)
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 }
42
43 /*
44 * Set the keys for reading
45 */
46 void Record_Reader::set_keys(const CipherSuite& suite, const SessionKeys& keys,
47 Connection_Side side)
48 {
49 cipher.reset();
50 delete mac;
51 mac = 0;
52 seq_no = 0;
53
54 SymmetricKey mac_key, cipher_key;
55 InitializationVector iv;
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 }
110
111 void Record_Reader::add_input(const byte input[], size_t input_size)
112 {
113 input_queue.write(input, input_size);
114 }
115
116 /*
117 * Retrieve the next record
118 */
119 size_t Record_Reader::get_record(byte& msg_type,
120 MemoryRegion<byte>& output)
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 }
260
261 }
Botan::SessionKeys::server_mac_key
SymmetricKey server_mac_key() const
Definition: tls_session_key.cpp:42
Botan::MemoryRegion::resize
void resize(size_t n)
Definition: secmem.h:217
Botan::Record_Reader::get_record
size_t get_record(byte &msg_type, MemoryRegion< byte > &buffer)
Definition: rec_read.cpp:119
Botan::Pipe::append
void append(Filter *filt)
Definition: pipe.cpp:215
Botan::SessionKeys::client_mac_key
SymmetricKey client_mac_key() const
Definition: tls_session_key.cpp:34
Botan::Algorithm_Factory
Definition: algo_factory.h:34
Botan::SecureQueue::size
size_t size() const
Definition: secqueue.cpp:190
Botan::ALERT
Definition: tls_magic.h:35
Botan::OctetString
Definition: symkey.h:19
Botan::SecureQueue::read
size_t read(byte[], size_t)
Definition: secqueue.cpp:137
Botan::Library_State::algorithm_factory
Algorithm_Factory & algorithm_factory() const
Definition: libstate.cpp:173
Botan::Record_Reader::add_input
void add_input(const byte input[], size_t input_size)
Definition: rec_read.cpp:111
Botan::UNEXPECTED_MESSAGE
Definition: tls_magic.h:64
Botan::CipherSuite::mac_algo
std::string mac_algo() const
Definition: tls_suites.h:26
Botan::Invalid_Argument
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20
Botan::HANDSHAKE
Definition: tls_magic.h:36
Botan::TLS_Exception
Definition: tls_exceptn.h:19
Botan::get_byte
byte get_byte(size_t byte_num, T input)
Definition: get_byte.h:21
Botan::TLS_V10
Definition: tls_magic.h:25
Botan::Pipe::reset
void reset()
Definition: pipe.cpp:76
Botan::CLIENT_HELLO_SSLV2
Definition: tls_magic.h:43
Botan::Record_Reader::set_version
void set_version(Version_Code version)
Definition: rec_read.cpp:34
Botan::Algorithm_Factory::make_mac
MessageAuthenticationCode * make_mac(const std::string &algo_spec, const std::string &provider="")
Definition: algo_factory.cpp:286
Botan::DECRYPTION
Definition: sym_algo.h:87
Botan::SessionKeys::client_iv
InitializationVector client_iv() const
Definition: tls_session_key.cpp:50
Botan::SessionKeys::server_cipher_key
SymmetricKey server_cipher_key() const
Definition: tls_session_key.cpp:26
Botan::byte
unsigned char byte
Definition: types.h:22
Botan::Connection_Side
Connection_Side
Definition: tls_magic.h:29
Botan::BAD_RECORD_MAC
Definition: tls_magic.h:65
Botan::SessionKeys::client_cipher_key
SymmetricKey client_cipher_key() const
Definition: tls_session_key.cpp:18
Botan::Pipe::read_all
SecureVector< byte > read_all(message_id msg=DEFAULT_MESSAGE)
Definition: pipe_rw.cpp:105
Botan::SymmetricAlgorithm::set_key
void set_key(const SymmetricKey &key)
Definition: sym_algo.h:60
Botan::Pipe::LAST_MESSAGE
static const message_id LAST_MESSAGE
Definition: pipe.h:52
Botan::Global_State_Management::global_state
Library_State & global_state()
Definition: global_state.cpp:32
Botan::Buffered_Computation::update
void update(const byte in[], size_t length)
Definition: buf_comp.h:33
Botan::Record_Reader::reset
void reset()
Definition: rec_read.cpp:17
Botan::u16bit
unsigned short u16bit
Definition: types.h:27
Botan::PROTOCOL_VERSION
Definition: tls_magic.h:81
Botan::block_size_of
size_t block_size_of(const std::string &name)
Definition: lookup.cpp:35
Botan::SessionKeys
Definition: tls_session_key.h:20
Botan::Decoding_Error
Definition: exceptn.h:138
Botan::Version_Code
Version_Code
Definition: tls_magic.h:22
Botan::Record_Reader::set_keys
void set_keys(const CipherSuite &suite, const SessionKeys &keys, Connection_Side side)
Definition: rec_read.cpp:46
Botan::MemoryRegion< byte >
Botan::copy_mem
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:22
Botan
Definition: algo_base.h:14
Botan::SSL_V3
Definition: tls_magic.h:24
Botan::Buffered_Computation::final
void final(byte out[])
Definition: buf_comp.h:80
Botan::SecureQueue::write
void write(const byte[], size_t)
Definition: secqueue.cpp:117
Botan::have_stream_cipher
bool have_stream_cipher(const std::string &algo_spec)
Definition: lookup.h:248
Botan::MemoryRegion::size
size_t size() const
Definition: secmem.h:29
Botan::SessionKeys::server_iv
InitializationVector server_iv() const
Definition: tls_session_key.cpp:58
Botan::have_hash
bool have_hash(const std::string &algo_spec)
Definition: lookup.h:261
Botan::make_u16bit
u16bit make_u16bit(byte i0, byte i1)
Definition: loadstor.h:47
Botan::SecureQueue::peek
size_t peek(byte[], size_t, size_t=0) const
Definition: secqueue.cpp:159
Botan::APPLICATION_DATA
Definition: tls_magic.h:37
Botan::CipherSuite::cipher_algo
std::string cipher_algo() const
Definition: tls_suites.h:25
Botan::have_block_cipher
bool have_block_cipher(const std::string &algo_spec)
Definition: lookup.h:235
Botan::CipherSuite
Definition: tls_suites.h:20
Botan::TLS_V11
Definition: tls_magic.h:26
Botan::SecureVector< byte >
Botan::Buffered_Computation::update_be
void update_be(const T in)
Definition: buf_comp.h:48
Botan::get_cipher
Keyed_Filter * get_cipher(const std::string &algo_spec, Cipher_Dir direction)
Definition: lookup.cpp:124
Botan::CHANGE_CIPHER_SPEC
Definition: tls_magic.h:34
Botan::Buffered_Computation::output_length
virtual size_t output_length() const =0
Botan::Pipe::process_msg
void process_msg(const byte in[], size_t length)
Definition: pipe.cpp:116
Botan::CLIENT
Definition: tls_magic.h:29