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"
18 #include <utils/debug.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 if (!this->crypter_in
->decrypt(this->crypter_in
, data
, iv
, NULL
))
156 this->alert
->add(this->alert
, TLS_FATAL
, TLS_BAD_RECORD_MAC
);
161 { /* next record IV is last ciphertext block of this record */
162 memcpy(this->iv_in
.ptr
, next_iv
.ptr
, next_iv
.len
);
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;
178 bs
= this->signer_in
->get_block_size(this->signer_in
);
181 DBG1(DBG_TLS
, "TLS record too short to verify MAC");
182 this->alert
->add(this->alert
, TLS_FATAL
, TLS_BAD_RECORD_MAC
);
185 mac
= chunk_skip(data
, data
.len
- bs
);
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
))
192 DBG1(DBG_TLS
, "TLS record MAC verification failed");
193 this->alert
->add(this->alert
, TLS_FATAL
, TLS_BAD_RECORD_MAC
);
198 if (type
== TLS_CHANGE_CIPHER_SPEC
)
206 return this->compression
->process(this->compression
, type
, data
);
209 METHOD(tls_protection_t
, build
, status_t
,
210 private_tls_protection_t
*this, tls_content_type_t
*type
, chunk_t
*data
)
214 status
= this->compression
->build(this->compression
, type
, data
);
215 if (*type
== TLS_CHANGE_CIPHER_SPEC
)
221 if (status
== NEED_MORE
)
223 if (this->signer_out
)
227 if (!sigheader(this->signer_out
, this->seq_out
, *type
,
228 this->version
, data
->len
) ||
229 !this->signer_out
->allocate_signature(this->signer_out
,
234 if (this->crypter_out
)
237 u_int8_t bs
, padding_length
;
239 bs
= this->crypter_out
->get_block_size(this->crypter_out
);
240 padding_length
= bs
- ((data
->len
+ mac
.len
+ 1) % bs
);
242 padding
= chunk_alloca(padding_length
);
243 memset(padding
.ptr
, padding_length
, padding
.len
);
245 if (this->iv_out
.len
)
246 { /* < TLSv1.1 uses IV from key derivation/last block */
250 { /* TLSv1.1 uses random IVs, prepended to record */
251 iv
.len
= this->crypter_out
->get_iv_size(this->crypter_out
);
253 !this->rng
->allocate_bytes(this->rng
, iv
.len
, &iv
))
255 DBG1(DBG_TLS
, "failed to generate TLS IV");
261 *data
= chunk_cat("mmcc", *data
, mac
, padding
,
262 chunk_from_thing(padding_length
));
264 if (!this->crypter_out
->encrypt(this->crypter_out
, *data
,
267 if (!this->iv_out
.len
)
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
);
282 *data
= chunk_cat("mm", iv
, *data
);
286 { /* NULL encryption */
287 *data
= chunk_cat("mm", *data
, mac
);
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
)
301 this->signer_in
= signer
;
302 this->crypter_in
= crypter
;
307 this->signer_out
= signer
;
308 this->crypter_out
= crypter
;
311 { /* generate IVs if none given */
312 this->rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
317 METHOD(tls_protection_t
, set_version
, void,
318 private_tls_protection_t
*this, tls_version_t version
)
320 this->version
= version
;
323 METHOD(tls_protection_t
, destroy
, void,
324 private_tls_protection_t
*this)
326 DESTROY_IF(this->rng
);
333 tls_protection_t
*tls_protection_create(tls_compression_t
*compression
,
336 private_tls_protection_t
*this;
342 .set_cipher
= _set_cipher
,
343 .set_version
= _set_version
,
347 .compression
= compression
,
350 return &this->public;