Check rng return value when generating secrets and IVs in libtls
[strongswan.git] / src / libtls / tls_protection.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "tls_protection.h"
17
18 #include <debug.h>
19
20 typedef struct private_tls_protection_t private_tls_protection_t;
21
22 /**
23 * Private data of an tls_protection_t object.
24 */
25 struct private_tls_protection_t {
26
27 /**
28 * Public tls_protection_t interface.
29 */
30 tls_protection_t public;
31
32 /**
33 * negotiated TLS version
34 */
35 tls_version_t version;
36
37 /**
38 * Upper layer, TLS record compression
39 */
40 tls_compression_t *compression;
41
42 /**
43 * TLS alert handler
44 */
45 tls_alert_t *alert;
46
47 /**
48 * RNG if we generate IVs ourself
49 */
50 rng_t *rng;
51
52 /**
53 * Sequence number of incoming records
54 */
55 u_int32_t seq_in;
56
57 /**
58 * Sequence number for outgoing records
59 */
60 u_int32_t seq_out;
61
62 /**
63 * Signer instance for inbound traffic
64 */
65 signer_t *signer_in;
66
67 /**
68 * Signer instance for outbound traffic
69 */
70 signer_t *signer_out;
71
72 /**
73 * Crypter instance for inbound traffic
74 */
75 crypter_t *crypter_in;
76
77 /**
78 * Crypter instance for outbound traffic
79 */
80 crypter_t *crypter_out;
81
82 /**
83 * Current IV for input decryption
84 */
85 chunk_t iv_in;
86
87 /**
88 * Current IV for output decryption
89 */
90 chunk_t iv_out;
91 };
92
93 /**
94 * Create the header and feed it into a signer for MAC verification
95 */
96 static bool sigheader(signer_t *signer, u_int32_t seq, u_int8_t type,
97 u_int16_t version, u_int16_t length)
98 {
99 /* we only support 32 bit sequence numbers, but TLS uses 64 bit */
100 struct __attribute__((__packed__)) {
101 u_int32_t seq_high;
102 u_int32_t seq_low;
103 u_int8_t type;
104 u_int16_t version;
105 u_int16_t length;
106 } header = {
107 .type = type,
108 };
109 htoun32(&header.seq_low, seq);
110 htoun16(&header.version, version);
111 htoun16(&header.length, length);
112
113 return signer->get_signature(signer, chunk_from_thing(header), NULL);
114 }
115
116 METHOD(tls_protection_t, process, status_t,
117 private_tls_protection_t *this, tls_content_type_t type, chunk_t data)
118 {
119 if (this->alert->fatal(this->alert))
120 { /* don't accept more input, fatal error occurred */
121 return NEED_MORE;
122 }
123
124 if (this->crypter_in)
125 {
126 chunk_t iv, next_iv = chunk_empty;
127 u_int8_t bs, padding_length;
128
129 bs = this->crypter_in->get_block_size(this->crypter_in);
130 if (this->iv_in.len)
131 { /* < TLSv1.1 uses IV from key derivation/last block */
132 if (data.len < bs || data.len % bs)
133 {
134 DBG1(DBG_TLS, "encrypted TLS record length invalid");
135 this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
136 return NEED_MORE;
137 }
138 iv = this->iv_in;
139 next_iv = chunk_clone(chunk_create(data.ptr + data.len - bs, bs));
140 }
141 else
142 { /* TLSv1.1 uses random IVs, prepended to record */
143 iv.len = this->crypter_in->get_iv_size(this->crypter_in);
144 iv = chunk_create(data.ptr, iv.len);
145 data = chunk_skip(data, iv.len);
146 if (data.len < bs || data.len % bs)
147 {
148 DBG1(DBG_TLS, "encrypted TLS record length invalid");
149 this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
150 return NEED_MORE;
151 }
152 }
153 this->crypter_in->decrypt(this->crypter_in, data, iv, NULL);
154
155 if (next_iv.len)
156 { /* next record IV is last ciphertext block of this record */
157 memcpy(this->iv_in.ptr, next_iv.ptr, next_iv.len);
158 free(next_iv.ptr);
159 }
160
161 padding_length = data.ptr[data.len - 1];
162 if (padding_length < data.len)
163 { /* remove padding if it looks valid. Continue with no padding, try
164 * to prevent timing attacks. */
165 data.len -= padding_length + 1;
166 }
167 }
168 if (this->signer_in)
169 {
170 chunk_t mac;
171 u_int8_t bs;
172
173 bs = this->signer_in->get_block_size(this->signer_in);
174 if (data.len < bs)
175 {
176 DBG1(DBG_TLS, "TLS record too short to verify MAC");
177 this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
178 return NEED_MORE;
179 }
180 mac = chunk_skip(data, data.len - bs);
181 data.len -= bs;
182
183 if (!sigheader(this->signer_in, this->seq_in, type,
184 this->version, data.len) ||
185 !this->signer_in->verify_signature(this->signer_in, data, mac))
186 {
187 DBG1(DBG_TLS, "TLS record MAC verification failed");
188 this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
189 return NEED_MORE;
190 }
191 }
192
193 if (type == TLS_CHANGE_CIPHER_SPEC)
194 {
195 this->seq_in = 0;
196 }
197 else
198 {
199 this->seq_in++;
200 }
201 return this->compression->process(this->compression, type, data);
202 }
203
204 METHOD(tls_protection_t, build, status_t,
205 private_tls_protection_t *this, tls_content_type_t *type, chunk_t *data)
206 {
207 status_t status;
208
209 status = this->compression->build(this->compression, type, data);
210 if (*type == TLS_CHANGE_CIPHER_SPEC)
211 {
212 this->seq_out = 0;
213 return status;
214 }
215
216 if (status == NEED_MORE)
217 {
218 if (this->signer_out)
219 {
220 chunk_t mac;
221
222 if (!sigheader(this->signer_out, this->seq_out, *type,
223 this->version, data->len) ||
224 !this->signer_out->allocate_signature(this->signer_out,
225 *data, &mac))
226 {
227 return FAILED;
228 }
229 if (this->crypter_out)
230 {
231 chunk_t padding, iv;
232 u_int8_t bs, padding_length;
233
234 bs = this->crypter_out->get_block_size(this->crypter_out);
235 padding_length = bs - ((data->len + mac.len + 1) % bs);
236
237 padding = chunk_alloca(padding_length);
238 memset(padding.ptr, padding_length, padding.len);
239
240 if (this->iv_out.len)
241 { /* < TLSv1.1 uses IV from key derivation/last block */
242 iv = this->iv_out;
243 }
244 else
245 { /* TLSv1.1 uses random IVs, prepended to record */
246 iv.len = this->crypter_out->get_iv_size(this->crypter_out);
247 if (!this->rng ||
248 !this->rng->allocate_bytes(this->rng, iv.len, &iv))
249 {
250 DBG1(DBG_TLS, "failed to generate TLS IV");
251 free(data->ptr);
252 return FAILED;
253 }
254 }
255
256 *data = chunk_cat("mmcc", *data, mac, padding,
257 chunk_from_thing(padding_length));
258 /* encrypt inline */
259 this->crypter_out->encrypt(this->crypter_out, *data, iv, NULL);
260
261 if (this->iv_out.len)
262 { /* next record IV is last ciphertext block of this record */
263 memcpy(this->iv_out.ptr, data->ptr + data->len -
264 this->iv_out.len, this->iv_out.len);
265 }
266 else
267 { /* prepend IV */
268 *data = chunk_cat("mm", iv, *data);
269 }
270 }
271 else
272 { /* NULL encryption */
273 *data = chunk_cat("mm", *data, mac);
274 }
275 }
276 this->seq_out++;
277 }
278 return status;
279 }
280
281 METHOD(tls_protection_t, set_cipher, void,
282 private_tls_protection_t *this, bool inbound, signer_t *signer,
283 crypter_t *crypter, chunk_t iv)
284 {
285 if (inbound)
286 {
287 this->signer_in = signer;
288 this->crypter_in = crypter;
289 this->iv_in = iv;
290 }
291 else
292 {
293 this->signer_out = signer;
294 this->crypter_out = crypter;
295 this->iv_out = iv;
296 if (!iv.len)
297 { /* generate IVs if none given */
298 this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
299 }
300 }
301 }
302
303 METHOD(tls_protection_t, set_version, void,
304 private_tls_protection_t *this, tls_version_t version)
305 {
306 this->version = version;
307 }
308
309 METHOD(tls_protection_t, destroy, void,
310 private_tls_protection_t *this)
311 {
312 DESTROY_IF(this->rng);
313 free(this);
314 }
315
316 /**
317 * See header
318 */
319 tls_protection_t *tls_protection_create(tls_compression_t *compression,
320 tls_alert_t *alert)
321 {
322 private_tls_protection_t *this;
323
324 INIT(this,
325 .public = {
326 .process = _process,
327 .build = _build,
328 .set_cipher = _set_cipher,
329 .set_version = _set_version,
330 .destroy = _destroy,
331 },
332 .alert = alert,
333 .compression = compression,
334 );
335
336 return &this->public;
337 }