Rebuild library.lo after changing ./configure options
[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 * TLS context
34 */
35 tls_t *tls;
36
37 /**
38 * Upper layer, TLS record compression
39 */
40 tls_compression_t *compression;
41
42 /**
43 * RNG if we generate IVs ourself
44 */
45 rng_t *rng;
46
47 /**
48 * Sequence number of incoming records
49 */
50 u_int32_t seq_in;
51
52 /**
53 * Sequence number for outgoing records
54 */
55 u_int32_t seq_out;
56
57 /**
58 * Signer instance for inbound traffic
59 */
60 signer_t *signer_in;
61
62 /**
63 * Signer instance for outbound traffic
64 */
65 signer_t *signer_out;
66
67 /**
68 * Crypter instance for inbound traffic
69 */
70 crypter_t *crypter_in;
71
72 /**
73 * Crypter instance for outbound traffic
74 */
75 crypter_t *crypter_out;
76
77 /**
78 * Current IV for input decryption
79 */
80 chunk_t iv_in;
81
82 /**
83 * Current IV for output decryption
84 */
85 chunk_t iv_out;
86 };
87
88 /**
89 * Create the header to append to the record data to create the MAC
90 */
91 static chunk_t sigheader(u_int32_t seq, u_int8_t type,
92 u_int16_t version, u_int16_t length)
93 {
94 /* we only support 32 bit sequence numbers, but TLS uses 64 bit */
95 u_int32_t seq_high = 0;
96
97 seq = htonl(seq);
98 version = htons(version);
99 length = htons(length);
100
101 return chunk_cat("ccccc", chunk_from_thing(seq_high),
102 chunk_from_thing(seq), chunk_from_thing(type),
103 chunk_from_thing(version), chunk_from_thing(length));
104 }
105
106 METHOD(tls_protection_t, process, status_t,
107 private_tls_protection_t *this, tls_content_type_t type, chunk_t data)
108 {
109 if (this->crypter_in)
110 {
111 chunk_t iv, next_iv = chunk_empty;
112 u_int8_t bs, padding_length;
113
114 bs = this->crypter_in->get_block_size(this->crypter_in);
115 if (this->iv_in.len)
116 { /* < TLSv1.1 uses IV from key derivation/last block */
117 if (data.len < bs || data.len % bs)
118 {
119 DBG1(DBG_TLS, "encrypted TLS record length invalid");
120 return FAILED;
121 }
122 iv = this->iv_in;
123 next_iv = chunk_clone(chunk_create(data.ptr + data.len - bs, bs));
124 }
125 else
126 { /* TLSv1.1 uses random IVs, prepended to record */
127 iv.len = this->crypter_in->get_iv_size(this->crypter_in);
128 iv = chunk_create(data.ptr, iv.len);
129 data = chunk_skip(data, iv.len);
130 if (data.len < bs || data.len % bs)
131 {
132 DBG1(DBG_TLS, "encrypted TLS record length invalid");
133 return FAILED;
134 }
135 }
136 this->crypter_in->decrypt(this->crypter_in, data, iv, NULL);
137
138 if (next_iv.len)
139 { /* next record IV is last ciphertext block of this record */
140 memcpy(this->iv_in.ptr, next_iv.ptr, next_iv.len);
141 free(next_iv.ptr);
142 }
143
144 padding_length = data.ptr[data.len - 1];
145 if (padding_length >= data.len)
146 {
147 DBG1(DBG_TLS, "invalid TLS record padding");
148 return FAILED;
149 }
150 data.len -= padding_length + 1;
151 }
152 if (this->signer_in)
153 {
154 chunk_t mac, macdata, header;
155 u_int8_t bs;
156
157 bs = this->signer_in->get_block_size(this->signer_in);
158 if (data.len <= bs)
159 {
160 DBG1(DBG_TLS, "TLS record too short to verify MAC");
161 return FAILED;
162 }
163 mac = chunk_skip(data, data.len - bs);
164 data.len -= bs;
165
166 header = sigheader(this->seq_in, type,
167 this->tls->get_version(this->tls), data.len);
168 macdata = chunk_cat("mc", header, data);
169 if (!this->signer_in->verify_signature(this->signer_in, macdata, mac))
170 {
171 DBG1(DBG_TLS, "TLS record MAC verification failed");
172 free(macdata.ptr);
173 return FAILED;
174 }
175 free(macdata.ptr);
176 }
177
178 if (type == TLS_CHANGE_CIPHER_SPEC)
179 {
180 this->seq_in = 0;
181 }
182 else
183 {
184 this->seq_in++;
185 }
186 return this->compression->process(this->compression, type, data);
187 }
188
189 METHOD(tls_protection_t, build, status_t,
190 private_tls_protection_t *this, tls_content_type_t *type, chunk_t *data)
191 {
192 status_t status;
193
194 status = this->compression->build(this->compression, type, data);
195 if (*type == TLS_CHANGE_CIPHER_SPEC)
196 {
197 this->seq_out = 0;
198 return status;
199 }
200
201 if (status == NEED_MORE)
202 {
203 if (this->signer_out)
204 {
205 chunk_t mac, header;
206
207 header = sigheader(this->seq_out, *type,
208 this->tls->get_version(this->tls), data->len);
209 this->signer_out->get_signature(this->signer_out, header, NULL);
210 free(header.ptr);
211 this->signer_out->allocate_signature(this->signer_out, *data, &mac);
212 if (this->crypter_out)
213 {
214 chunk_t padding, iv;
215 u_int8_t bs, padding_length;
216
217 bs = this->crypter_out->get_block_size(this->crypter_out);
218 padding_length = bs - ((data->len + mac.len + 1) % bs);
219
220 padding = chunk_alloca(padding_length);
221 memset(padding.ptr, padding_length, padding.len);
222
223 if (this->iv_out.len)
224 { /* < TLSv1.1 uses IV from key derivation/last block */
225 iv = this->iv_out;
226 }
227 else
228 { /* TLSv1.1 uses random IVs, prepended to record */
229 if (!this->rng)
230 {
231 DBG1(DBG_TLS, "no RNG supported to generate TLS IV");
232 free(data->ptr);
233 return FAILED;
234 }
235 iv.len = this->crypter_out->get_iv_size(this->crypter_out);
236 this->rng->allocate_bytes(this->rng, iv.len, &iv);
237 }
238
239 *data = chunk_cat("mmcc", *data, mac, padding,
240 chunk_from_thing(padding_length));
241 /* encrypt inline */
242 this->crypter_out->encrypt(this->crypter_out, *data, iv, NULL);
243
244 if (this->iv_out.len)
245 { /* next record IV is last ciphertext block of this record */
246 memcpy(this->iv_out.ptr, data->ptr + data->len -
247 this->iv_out.len, this->iv_out.len);
248 }
249 else
250 { /* prepend IV */
251 *data = chunk_cat("mm", iv, *data);
252 }
253 }
254 else
255 { /* NULL encryption */
256 *data = chunk_cat("mm", *data, mac);
257 }
258 }
259 this->seq_out++;
260 }
261 return status;
262 }
263
264 METHOD(tls_protection_t, set_cipher, void,
265 private_tls_protection_t *this, bool inbound, signer_t *signer,
266 crypter_t *crypter, chunk_t iv)
267 {
268 if (inbound)
269 {
270 this->signer_in = signer;
271 this->crypter_in = crypter;
272 this->iv_in = iv;
273 }
274 else
275 {
276 this->signer_out = signer;
277 this->crypter_out = crypter;
278 this->iv_out = iv;
279 if (!iv.len)
280 { /* generate IVs if none given */
281 this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
282 }
283 }
284 }
285
286 METHOD(tls_protection_t, destroy, void,
287 private_tls_protection_t *this)
288 {
289 DESTROY_IF(this->rng);
290 free(this);
291 }
292
293 /**
294 * See header
295 */
296 tls_protection_t *tls_protection_create(tls_t *tls,
297 tls_compression_t *compression)
298 {
299 private_tls_protection_t *this;
300
301 INIT(this,
302 .public = {
303 .process = _process,
304 .build = _build,
305 .set_cipher = _set_cipher,
306 .destroy = _destroy,
307 },
308 .tls = tls,
309 .compression = compression,
310 );
311
312 return &this->public;
313 }