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
12namespace Botan {
13
14/*
15* Reset the state
16*/
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*/
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*/
46void 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;
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 {
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
111void 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*/
119size_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 {
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 }
260
261}
MessageAuthenticationCode * make_mac(const std::string &algo_spec, const std::string &provider="")
std::string mac_algo() const
Definition tls_suites.h:26
std::string cipher_algo() const
Definition tls_suites.h:25
Algorithm_Factory & algorithm_factory() const
Definition libstate.cpp:173
size_t size() const
Definition secmem.h:29
void resize(size_t n)
Definition secmem.h:217
static const message_id LAST_MESSAGE
Definition pipe.h:52
size_t get_record(byte &msg_type, MemoryRegion< byte > &buffer)
Definition rec_read.cpp:119
void set_version(Version_Code version)
Definition rec_read.cpp:34
void add_input(const byte input[], size_t input_size)
Definition rec_read.cpp:111
void set_keys(const CipherSuite &suite, const SessionKeys &keys, Connection_Side side)
Definition rec_read.cpp:46
InitializationVector client_iv() const
SymmetricKey server_mac_key() const
SymmetricKey server_cipher_key() const
InitializationVector server_iv() const
SymmetricKey client_cipher_key() const
SymmetricKey client_mac_key() const
void set_key(const SymmetricKey &key)
Definition sym_algo.h:60
TLS_Exception(Alert_Type type, const std::string &err_msg="Unknown error")
Definition tls_exceptn.h:24
OctetString SymmetricKey
Definition symkey.h:147
@ PROTOCOL_VERSION
Definition tls_magic.h:81
@ BAD_RECORD_MAC
Definition tls_magic.h:65
@ UNEXPECTED_MESSAGE
Definition tls_magic.h:64
bool have_stream_cipher(const std::string &algo_spec)
Definition lookup.h:248
byte get_byte(size_t byte_num, T input)
Definition get_byte.h:21
bool have_hash(const std::string &algo_spec)
Definition lookup.h:261
Connection_Side
Definition tls_magic.h:29
@ CLIENT
Definition tls_magic.h:29
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
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
unsigned short u16bit
Definition types.h:27
Library_State & global_state()
OctetString InitializationVector
Definition symkey.h:152
@ 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
@ DECRYPTION
Definition sym_algo.h:87
@ CLIENT_HELLO_SSLV2
Definition tls_magic.h:43
Version_Code
Definition tls_magic.h:22
@ SSL_V3
Definition tls_magic.h:24
@ TLS_V10
Definition tls_magic.h:25
@ TLS_V11
Definition tls_magic.h:26
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
Decoding_Error(const std::string &name)
Definition exceptn.h:140