2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
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>.
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
16 #include "tls_protection.h"
20 typedef struct private_tls_protection_t private_tls_protection_t
;
23 * Private data of an tls_protection_t object.
25 struct private_tls_protection_t
{
28 * Public tls_protection_t interface.
30 tls_protection_t
public;
33 * negotiated TLS version
35 tls_version_t version
;
38 * Upper layer, TLS record compression
40 tls_compression_t
*compression
;
48 * RNG if we generate IVs ourself
53 * Sequence number of incoming records
58 * Sequence number for outgoing records
63 * Signer instance for inbound traffic
68 * Signer instance for outbound traffic
73 * Crypter instance for inbound traffic
75 crypter_t
*crypter_in
;
78 * Crypter instance for outbound traffic
80 crypter_t
*crypter_out
;
83 * Current IV for input decryption
88 * Current IV for output decryption
94 * Create the header and feed it into a signer for MAC verification
96 static bool sigheader(signer_t
*signer
, u_int32_t seq
, u_int8_t type
,
97 u_int16_t version
, u_int16_t length
)
99 /* we only support 32 bit sequence numbers, but TLS uses 64 bit */
100 struct __attribute__((__packed__
)) {
109 htoun32(&header
.seq_low
, seq
);
110 htoun16(&header
.version
, version
);
111 htoun16(&header
.length
, length
);
113 return signer
->get_signature(signer
, chunk_from_thing(header
), NULL
);
116 METHOD(tls_protection_t
, process
, status_t
,
117 private_tls_protection_t
*this, tls_content_type_t type
, chunk_t data
)
119 if (this->alert
->fatal(this->alert
))
120 { /* don't accept more input, fatal error occurred */
124 if (this->crypter_in
)
126 chunk_t iv
, next_iv
= chunk_empty
;
127 u_int8_t bs
, padding_length
;
129 bs
= this->crypter_in
->get_block_size(this->crypter_in
);
131 { /* < TLSv1.1 uses IV from key derivation/last block */
132 if (data
.len
< bs
|| data
.len
% bs
)
134 DBG1(DBG_TLS
, "encrypted TLS record length invalid");
135 this->alert
->add(this->alert
, TLS_FATAL
, TLS_BAD_RECORD_MAC
);
139 next_iv
= chunk_clone(chunk_create(data
.ptr
+ data
.len
- bs
, bs
));
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
)
148 DBG1(DBG_TLS
, "encrypted TLS record length invalid");
149 this->alert
->add(this->alert
, TLS_FATAL
, TLS_BAD_RECORD_MAC
);
153 this->crypter_in
->decrypt(this->crypter_in
, data
, iv
, NULL
);
156 { /* next record IV is last ciphertext block of this record */
157 memcpy(this->iv_in
.ptr
, next_iv
.ptr
, next_iv
.len
);
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;
173 bs
= this->signer_in
->get_block_size(this->signer_in
);
176 DBG1(DBG_TLS
, "TLS record too short to verify MAC");
177 this->alert
->add(this->alert
, TLS_FATAL
, TLS_BAD_RECORD_MAC
);
180 mac
= chunk_skip(data
, data
.len
- bs
);
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
))
187 DBG1(DBG_TLS
, "TLS record MAC verification failed");
188 this->alert
->add(this->alert
, TLS_FATAL
, TLS_BAD_RECORD_MAC
);
193 if (type
== TLS_CHANGE_CIPHER_SPEC
)
201 return this->compression
->process(this->compression
, type
, data
);
204 METHOD(tls_protection_t
, build
, status_t
,
205 private_tls_protection_t
*this, tls_content_type_t
*type
, chunk_t
*data
)
209 status
= this->compression
->build(this->compression
, type
, data
);
210 if (*type
== TLS_CHANGE_CIPHER_SPEC
)
216 if (status
== NEED_MORE
)
218 if (this->signer_out
)
222 if (!sigheader(this->signer_out
, this->seq_out
, *type
,
223 this->version
, data
->len
) ||
224 !this->signer_out
->allocate_signature(this->signer_out
,
229 if (this->crypter_out
)
232 u_int8_t bs
, padding_length
;
234 bs
= this->crypter_out
->get_block_size(this->crypter_out
);
235 padding_length
= bs
- ((data
->len
+ mac
.len
+ 1) % bs
);
237 padding
= chunk_alloca(padding_length
);
238 memset(padding
.ptr
, padding_length
, padding
.len
);
240 if (this->iv_out
.len
)
241 { /* < TLSv1.1 uses IV from key derivation/last block */
245 { /* TLSv1.1 uses random IVs, prepended to record */
246 iv
.len
= this->crypter_out
->get_iv_size(this->crypter_out
);
248 !this->rng
->allocate_bytes(this->rng
, iv
.len
, &iv
))
250 DBG1(DBG_TLS
, "failed to generate TLS IV");
256 *data
= chunk_cat("mmcc", *data
, mac
, padding
,
257 chunk_from_thing(padding_length
));
259 this->crypter_out
->encrypt(this->crypter_out
, *data
, iv
, NULL
);
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
);
268 *data
= chunk_cat("mm", iv
, *data
);
272 { /* NULL encryption */
273 *data
= chunk_cat("mm", *data
, mac
);
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
)
287 this->signer_in
= signer
;
288 this->crypter_in
= crypter
;
293 this->signer_out
= signer
;
294 this->crypter_out
= crypter
;
297 { /* generate IVs if none given */
298 this->rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
303 METHOD(tls_protection_t
, set_version
, void,
304 private_tls_protection_t
*this, tls_version_t version
)
306 this->version
= version
;
309 METHOD(tls_protection_t
, destroy
, void,
310 private_tls_protection_t
*this)
312 DESTROY_IF(this->rng
);
319 tls_protection_t
*tls_protection_create(tls_compression_t
*compression
,
322 private_tls_protection_t
*this;
328 .set_cipher
= _set_cipher
,
329 .set_version
= _set_version
,
333 .compression
= compression
,
336 return &this->public;