Cast first argument for %.*s to int
[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 <utils/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 if (!this->crypter_in->decrypt(this->crypter_in, data, iv, NULL))
154 {
155 free(next_iv.ptr);
156 this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
157 return NEED_MORE;
158 }
159
160 if (next_iv.len)
161 { /* next record IV is last ciphertext block of this record */
162 memcpy(this->iv_in.ptr, next_iv.ptr, next_iv.len);
163 free(next_iv.ptr);
164 }
165
166 padding_length = data.ptr[data.len - 1];
167 if (padding_length < data.len)
168 { /* remove padding if it looks valid. Continue with no padding, try
169 * to prevent timing attacks. */
170 data.len -= padding_length + 1;
171 }
172 }
173 if (this->signer_in)
174 {
175 chunk_t mac;
176 u_int8_t bs;
177
178 bs = this->signer_in->get_block_size(this->signer_in);
179 if (data.len < bs)
180 {
181 DBG1(DBG_TLS, "TLS record too short to verify MAC");
182 this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
183 return NEED_MORE;
184 }
185 mac = chunk_skip(data, data.len - bs);
186 data.len -= bs;
187
188 if (!sigheader(this->signer_in, this->seq_in, type,
189 this->version, data.len) ||
190 !this->signer_in->verify_signature(this->signer_in, data, mac))
191 {
192 DBG1(DBG_TLS, "TLS record MAC verification failed");
193 this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
194 return NEED_MORE;
195 }
196 }
197
198 if (type == TLS_CHANGE_CIPHER_SPEC)
199 {
200 this->seq_in = 0;
201 }
202 else
203 {
204 this->seq_in++;
205 }
206 return this->compression->process(this->compression, type, data);
207 }
208
209 METHOD(tls_protection_t, build, status_t,
210 private_tls_protection_t *this, tls_content_type_t *type, chunk_t *data)
211 {
212 status_t status;
213
214 status = this->compression->build(this->compression, type, data);
215 if (*type == TLS_CHANGE_CIPHER_SPEC)
216 {
217 this->seq_out = 0;
218 return status;
219 }
220
221 if (status == NEED_MORE)
222 {
223 if (this->signer_out)
224 {
225 chunk_t mac;
226
227 if (!sigheader(this->signer_out, this->seq_out, *type,
228 this->version, data->len) ||
229 !this->signer_out->allocate_signature(this->signer_out,
230 *data, &mac))
231 {
232 return FAILED;
233 }
234 if (this->crypter_out)
235 {
236 chunk_t padding, iv;
237 u_int8_t bs, padding_length;
238
239 bs = this->crypter_out->get_block_size(this->crypter_out);
240 padding_length = bs - ((data->len + mac.len + 1) % bs);
241
242 padding = chunk_alloca(padding_length);
243 memset(padding.ptr, padding_length, padding.len);
244
245 if (this->iv_out.len)
246 { /* < TLSv1.1 uses IV from key derivation/last block */
247 iv = this->iv_out;
248 }
249 else
250 { /* TLSv1.1 uses random IVs, prepended to record */
251 iv.len = this->crypter_out->get_iv_size(this->crypter_out);
252 if (!this->rng ||
253 !this->rng->allocate_bytes(this->rng, iv.len, &iv))
254 {
255 DBG1(DBG_TLS, "failed to generate TLS IV");
256 free(data->ptr);
257 return FAILED;
258 }
259 }
260
261 *data = chunk_cat("mmcc", *data, mac, padding,
262 chunk_from_thing(padding_length));
263 /* encrypt inline */
264 if (!this->crypter_out->encrypt(this->crypter_out, *data,
265 iv, NULL))
266 {
267 if (!this->iv_out.len)
268 {
269 free(iv.ptr);
270 }
271 free(data->ptr);
272 return FAILED;
273 }
274
275 if (this->iv_out.len)
276 { /* next record IV is last ciphertext block of this record */
277 memcpy(this->iv_out.ptr, data->ptr + data->len -
278 this->iv_out.len, this->iv_out.len);
279 }
280 else
281 { /* prepend IV */
282 *data = chunk_cat("mm", iv, *data);
283 }
284 }
285 else
286 { /* NULL encryption */
287 *data = chunk_cat("mm", *data, mac);
288 }
289 }
290 this->seq_out++;
291 }
292 return status;
293 }
294
295 METHOD(tls_protection_t, set_cipher, void,
296 private_tls_protection_t *this, bool inbound, signer_t *signer,
297 crypter_t *crypter, chunk_t iv)
298 {
299 if (inbound)
300 {
301 this->signer_in = signer;
302 this->crypter_in = crypter;
303 this->iv_in = iv;
304 }
305 else
306 {
307 this->signer_out = signer;
308 this->crypter_out = crypter;
309 this->iv_out = iv;
310 if (!iv.len)
311 { /* generate IVs if none given */
312 this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
313 }
314 }
315 }
316
317 METHOD(tls_protection_t, set_version, void,
318 private_tls_protection_t *this, tls_version_t version)
319 {
320 this->version = version;
321 }
322
323 METHOD(tls_protection_t, destroy, void,
324 private_tls_protection_t *this)
325 {
326 DESTROY_IF(this->rng);
327 free(this);
328 }
329
330 /**
331 * See header
332 */
333 tls_protection_t *tls_protection_create(tls_compression_t *compression,
334 tls_alert_t *alert)
335 {
336 private_tls_protection_t *this;
337
338 INIT(this,
339 .public = {
340 .process = _process,
341 .build = _build,
342 .set_cipher = _set_cipher,
343 .set_version = _set_version,
344 .destroy = _destroy,
345 },
346 .alert = alert,
347 .compression = compression,
348 );
349
350 return &this->public;
351 }