Botan  1.10.9
rec_wri.cpp
Go to the documentation of this file.
1 /*
2 * TLS Record Writing
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/internal/tls_handshake_hash.h>
10 #include <botan/lookup.h>
11 #include <botan/loadstor.h>
12 #include <botan/libstate.h>
13 
14 namespace Botan {
15 
16 /**
17 * Record_Writer Constructor
18 */
19 Record_Writer::Record_Writer(std::tr1::function<void (const byte[], size_t)> out) :
20  output_fn(out),
21  buffer(DEFAULT_BUFFERSIZE)
22  {
23  mac = 0;
24  reset();
25  }
26 
27 /**
28 * Reset the state
29 */
31  {
32  cipher.reset();
33 
34  delete mac;
35  mac = 0;
36 
37  zeroise(buffer);
38  buf_pos = 0;
39 
40  major = minor = buf_type = 0;
41  block_size = 0;
42  mac_size = 0;
43  iv_size = 0;
44 
45  seq_no = 0;
46  }
47 
48 /**
49 * Set the version to use
50 */
52  {
53  if(version != SSL_V3 && version != TLS_V10 && version != TLS_V11)
54  throw Invalid_Argument("Record_Writer: Invalid protocol version");
55 
56  major = (version >> 8) & 0xFF;
57  minor = (version & 0xFF);
58  }
59 
60 /**
61 * Set the keys for writing
62 */
63 void Record_Writer::set_keys(const CipherSuite& suite, const SessionKeys& keys,
64  Connection_Side side)
65  {
66  cipher.reset();
67  delete mac;
68  mac = 0;
69  seq_no = 0;
70 
71  SymmetricKey mac_key, cipher_key;
73 
74  if(side == CLIENT)
75  {
76  cipher_key = keys.client_cipher_key();
77  iv = keys.client_iv();
78  mac_key = keys.client_mac_key();
79  }
80  else
81  {
82  cipher_key = keys.server_cipher_key();
83  iv = keys.server_iv();
84  mac_key = keys.server_mac_key();
85  }
86 
87  const std::string cipher_algo = suite.cipher_algo();
88  const std::string mac_algo = suite.mac_algo();
89 
90  if(have_block_cipher(cipher_algo))
91  {
92  cipher.append(get_cipher(
93  cipher_algo + "/CBC/NoPadding",
94  cipher_key, iv, ENCRYPTION)
95  );
96  block_size = block_size_of(cipher_algo);
97 
98  if(major > 3 || (major == 3 && minor >= 2))
99  iv_size = block_size;
100  else
101  iv_size = 0;
102  }
103  else if(have_stream_cipher(cipher_algo))
104  {
105  cipher.append(get_cipher(cipher_algo, cipher_key, ENCRYPTION));
106  block_size = 0;
107  iv_size = 0;
108  }
109  else
110  throw Invalid_Argument("Record_Writer: Unknown cipher " + cipher_algo);
111 
112  if(have_hash(mac_algo))
113  {
115 
116  if(major == 3 && minor == 0)
117  mac = af.make_mac("SSL3-MAC(" + mac_algo + ")");
118  else
119  mac = af.make_mac("HMAC(" + mac_algo + ")");
120 
121  mac->set_key(mac_key);
122  mac_size = mac->output_length();
123  }
124  else
125  throw Invalid_Argument("Record_Writer: Unknown hash " + mac_algo);
126  }
127 
128 /**
129 * Send one or more records to the other side
130 */
131 void Record_Writer::send(byte type, const byte input[], size_t length)
132  {
133  if(type != buf_type)
134  flush();
135 
136  const size_t BUFFER_SIZE = buffer.size();
137  buf_type = type;
138 
139  // FIXME: compression right here
140 
141  buffer.copy(buf_pos, input, length);
142  if(buf_pos + length >= BUFFER_SIZE)
143  {
144  send_record(buf_type, &buffer[0], length);
145  input += (BUFFER_SIZE - buf_pos);
146  length -= (BUFFER_SIZE - buf_pos);
147  while(length >= BUFFER_SIZE)
148  {
149  send_record(buf_type, input, BUFFER_SIZE);
150  input += BUFFER_SIZE;
151  length -= BUFFER_SIZE;
152  }
153  buffer.copy(input, length);
154  buf_pos = 0;
155  }
156  buf_pos += length;
157  }
158 
159 /**
160 * Split buffer into records, and send them all
161 */
163  {
164  const byte* buf_ptr = &buffer[0];
165  size_t offset = 0;
166 
167  while(offset != buf_pos)
168  {
169  size_t record_size = buf_pos - offset;
170  if(record_size > MAX_PLAINTEXT_SIZE)
171  record_size = MAX_PLAINTEXT_SIZE;
172 
173  send_record(buf_type, buf_ptr + offset, record_size);
174  offset += record_size;
175  }
176  buf_type = 0;
177  buf_pos = 0;
178  }
179 
180 /**
181 * Encrypt and send the record
182 */
183 void Record_Writer::send_record(byte type, const byte buf[], size_t length)
184  {
185  if(length >= MAX_COMPRESSED_SIZE)
187  "Record_Writer: Compressed packet is too big");
188 
189  if(mac_size == 0)
190  send_record(type, major, minor, buf, length);
191  else
192  {
193  mac->update_be(seq_no);
194  mac->update(type);
195 
196  if(major > 3 || (major == 3 && minor != 0))
197  {
198  mac->update(major);
199  mac->update(minor);
200  }
201 
202  mac->update(get_byte<u16bit>(0, length));
203  mac->update(get_byte<u16bit>(1, length));
204  mac->update(buf, length);
205 
206  SecureVector<byte> buf_mac = mac->final();
207 
208  // TODO: This could all use a single buffer
209  cipher.start_msg();
210 
211  if(iv_size)
212  {
213  RandomNumberGenerator& rng = global_state().global_rng();
214 
215  SecureVector<byte> random_iv(iv_size);
216 
217  rng.randomize(&random_iv[0], random_iv.size());
218 
219  cipher.write(random_iv);
220  }
221 
222  cipher.write(buf, length);
223  cipher.write(buf_mac);
224 
225  if(block_size)
226  {
227  size_t pad_val =
228  (block_size - (1 + length + buf_mac.size())) % block_size;
229 
230  for(size_t i = 0; i != pad_val + 1; ++i)
231  cipher.write(pad_val);
232  }
233  cipher.end_msg();
234 
235  SecureVector<byte> output = cipher.read_all(Pipe::LAST_MESSAGE);
236 
237  send_record(type, major, minor, &output[0], output.size());
238 
239  seq_no++;
240  }
241  }
242 
243 /**
244 * Send a final record packet
245 */
246 void Record_Writer::send_record(byte type, byte major, byte minor,
247  const byte out[], size_t length)
248  {
249  if(length >= MAX_CIPHERTEXT_SIZE)
250  throw TLS_Exception(INTERNAL_ERROR,
251  "Record_Writer: Record is too big");
252 
253  byte header[5] = { type, major, minor, 0 };
254  for(size_t i = 0; i != 2; ++i)
255  header[i+3] = get_byte<u16bit>(i, length);
256 
257  output_fn(header, 5);
258  output_fn(out, length);
259  }
260 
261 /**
262 * Send an alert
263 */
265  {
266  byte alert[2] = { level, type };
267  send(ALERT, alert, sizeof(alert));
268  flush();
269  }
270 
271 }
void start_msg()
Definition: pipe.cpp:152
Record_Writer(std::tr1::function< void(const byte[], size_t)> output_fn)
Definition: rec_wri.cpp:19
void append(Filter *filt)
Definition: pipe.cpp:215
RandomNumberGenerator & global_rng()
Definition: libstate.cpp:183
void write(const byte in[], size_t length)
Definition: pipe_rw.cpp:34
SymmetricKey server_mac_key() const
SymmetricKey client_cipher_key() const
SymmetricKey client_mac_key() const
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20
void set_version(Version_Code)
Definition: rec_wri.cpp:51
void set_keys(const CipherSuite &, const SessionKeys &, Connection_Side)
Definition: rec_wri.cpp:63
void reset()
Definition: pipe.cpp:76
void copy(const T in[], size_t n)
Definition: secmem.h:120
InitializationVector server_iv() const
MessageAuthenticationCode * make_mac(const std::string &algo_spec, const std::string &provider="")
std::string cipher_algo() const
Definition: tls_suites.h:25
Algorithm_Factory & algorithm_factory() const
Definition: libstate.cpp:173
unsigned char byte
Definition: types.h:22
Alert_Level
Definition: tls_magic.h:57
SymmetricKey server_cipher_key() const
Connection_Side
Definition: tls_magic.h:29
void end_msg()
Definition: pipe.cpp:166
SecureVector< byte > read_all(message_id msg=DEFAULT_MESSAGE)
Definition: pipe_rw.cpp:105
RandomNumberGenerator * rng
Definition: global_rng.cpp:165
void set_key(const SymmetricKey &key)
Definition: sym_algo.h:60
static const message_id LAST_MESSAGE
Definition: pipe.h:52
Library_State & global_state()
void update(const byte in[], size_t length)
Definition: buf_comp.h:33
size_t block_size_of(const std::string &name)
Definition: lookup.cpp:35
Version_Code
Definition: tls_magic.h:22
size_t size() const
Definition: secmem.h:29
void final(byte out[])
Definition: buf_comp.h:80
Alert_Type
Definition: tls_magic.h:62
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
std::string mac_algo() const
Definition: tls_suites.h:26
bool have_block_cipher(const std::string &algo_spec)
Definition: lookup.h:235
void alert(Alert_Level, Alert_Type)
Definition: rec_wri.cpp:264
void update_be(const T in)
Definition: buf_comp.h:48
Keyed_Filter * get_cipher(const std::string &algo_spec, Cipher_Dir direction)
Definition: lookup.cpp:124
InitializationVector client_iv() const
void zeroise(MemoryRegion< T > &vec)
Definition: secmem.h:415
virtual size_t output_length() const =0
void send(byte type, const byte input[], size_t length)
Definition: rec_wri.cpp:131