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;
38 * Upper layer, TLS record compression
40 tls_compression_t
*compression
;
43 * RNG if we generate IVs ourself
48 * Sequence number of incoming records
53 * Sequence number for outgoing records
58 * Signer instance for inbound traffic
63 * Signer instance for outbound traffic
68 * Crypter instance for inbound traffic
70 crypter_t
*crypter_in
;
73 * Crypter instance for outbound traffic
75 crypter_t
*crypter_out
;
78 * Current IV for input decryption
83 * Current IV for output decryption
89 * Create the header to append to the record data to create the MAC
91 static chunk_t
sigheader(u_int32_t seq
, u_int8_t type
,
92 u_int16_t version
, u_int16_t length
)
94 /* we only support 32 bit sequence numbers, but TLS uses 64 bit */
95 u_int32_t seq_high
= 0;
98 version
= htons(version
);
99 length
= htons(length
);
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
));
106 METHOD(tls_protection_t
, process
, status_t
,
107 private_tls_protection_t
*this, tls_content_type_t type
, chunk_t data
)
109 if (this->crypter_in
)
111 chunk_t iv
, next_iv
= chunk_empty
;
112 u_int8_t bs
, padding_length
;
114 bs
= this->crypter_in
->get_block_size(this->crypter_in
);
116 { /* < TLSv1.1 uses IV from key derivation/last block */
117 if (data
.len
< bs
|| data
.len
% bs
)
119 DBG1(DBG_IKE
, "encrypted TLS record length invalid");
123 next_iv
= chunk_clone(chunk_create(data
.ptr
+ data
.len
- bs
, bs
));
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
)
132 DBG1(DBG_IKE
, "encrypted TLS record length invalid");
136 this->crypter_in
->decrypt(this->crypter_in
, data
, iv
, NULL
);
139 { /* next record IV is last ciphertext block of this record */
140 memcpy(this->iv_in
.ptr
, next_iv
.ptr
, next_iv
.len
);
144 padding_length
= data
.ptr
[data
.len
- 1];
145 if (padding_length
>= data
.len
)
147 DBG1(DBG_IKE
, "invalid TLS record padding");
150 data
.len
-= padding_length
+ 1;
154 chunk_t mac
, macdata
, header
;
157 bs
= this->signer_in
->get_block_size(this->signer_in
);
160 DBG1(DBG_IKE
, "TLS record too short to verify MAC");
163 mac
= chunk_skip(data
, data
.len
- bs
);
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
))
171 DBG1(DBG_IKE
, "TLS record MAC verification failed");
178 if (type
== TLS_CHANGE_CIPHER_SPEC
)
186 return this->compression
->process(this->compression
, type
, data
);
189 METHOD(tls_protection_t
, build
, status_t
,
190 private_tls_protection_t
*this, tls_content_type_t
*type
, chunk_t
*data
)
194 status
= this->compression
->build(this->compression
, type
, data
);
195 if (*type
== TLS_CHANGE_CIPHER_SPEC
)
201 if (status
== NEED_MORE
)
203 if (this->signer_out
)
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
);
211 this->signer_out
->allocate_signature(this->signer_out
, *data
, &mac
);
212 if (this->crypter_out
)
215 u_int8_t bs
, padding_length
;
217 bs
= this->crypter_out
->get_block_size(this->crypter_out
);
218 padding_length
= bs
- ((data
->len
+ mac
.len
+ 1) % bs
);
220 padding
= chunk_alloca(padding_length
);
221 memset(padding
.ptr
, padding_length
, padding
.len
);
223 if (this->iv_out
.len
)
224 { /* < TLSv1.1 uses IV from key derivation/last block */
228 { /* TLSv1.1 uses random IVs, prepended to record */
231 DBG1(DBG_IKE
, "no RNG supported to generate TLS IV");
235 iv
.len
= this->crypter_out
->get_iv_size(this->crypter_out
);
236 this->rng
->allocate_bytes(this->rng
, iv
.len
, &iv
);
239 *data
= chunk_cat("mmcc", *data
, mac
, padding
,
240 chunk_from_thing(padding_length
));
242 this->crypter_out
->encrypt(this->crypter_out
, *data
, iv
, NULL
);
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
);
251 *data
= chunk_cat("mm", iv
, *data
);
255 { /* NULL encryption */
256 *data
= chunk_cat("mm", *data
, mac
);
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
)
270 this->signer_in
= signer
;
271 this->crypter_in
= crypter
;
276 this->signer_out
= signer
;
277 this->crypter_out
= crypter
;
280 { /* generate IVs if none given */
281 this->rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
286 METHOD(tls_protection_t
, destroy
, void,
287 private_tls_protection_t
*this)
289 DESTROY_IF(this->rng
);
296 tls_protection_t
*tls_protection_create(tls_t
*tls
,
297 tls_compression_t
*compression
)
299 private_tls_protection_t
*this;
305 .set_cipher
= _set_cipher
,
309 .compression
= compression
,
312 return &this->public;