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
);
115 if (data
.len
< bs
|| data
.len
% bs
)
117 DBG1(DBG_IKE
, "encrypted TLS record not multiple of block size");
121 { /* < TLSv1.1 uses IV from key derivation/last block */
123 next_iv
= chunk_clone(chunk_create(data
.ptr
+ data
.len
- bs
, bs
));
126 { /* TLSv1.1 uses random IVs, prepended to record */
127 iv
= chunk_create(data
.ptr
, bs
);
128 data
= chunk_skip(data
, bs
);
131 DBG1(DBG_IKE
, "TLS record too short to decrypt");
135 this->crypter_in
->decrypt(this->crypter_in
, data
, iv
, NULL
);
138 { /* next record IV is last ciphertext block of this record */
139 memcpy(this->iv_in
.ptr
, next_iv
.ptr
, next_iv
.len
);
143 padding_length
= data
.ptr
[data
.len
- 1];
144 if (padding_length
>= data
.len
)
146 DBG1(DBG_IKE
, "invalid TLS record padding");
149 data
.len
-= padding_length
+ 1;
153 chunk_t mac
, macdata
, header
;
156 bs
= this->signer_in
->get_block_size(this->signer_in
);
159 DBG1(DBG_IKE
, "TLS record too short to verify MAC");
162 mac
= chunk_skip(data
, data
.len
- bs
);
165 header
= sigheader(this->seq_in
, type
,
166 this->tls
->get_version(this->tls
), data
.len
);
167 macdata
= chunk_cat("mc", header
, data
);
168 if (!this->signer_in
->verify_signature(this->signer_in
, macdata
, mac
))
170 DBG1(DBG_IKE
, "TLS record MAC verification failed");
177 if (type
== TLS_CHANGE_CIPHER_SPEC
)
185 return this->compression
->process(this->compression
, type
, data
);
188 METHOD(tls_protection_t
, build
, status_t
,
189 private_tls_protection_t
*this, tls_content_type_t
*type
, chunk_t
*data
)
193 status
= this->compression
->build(this->compression
, type
, data
);
194 if (*type
== TLS_CHANGE_CIPHER_SPEC
)
200 if (status
== NEED_MORE
)
202 if (this->signer_out
)
206 header
= sigheader(this->seq_out
, *type
,
207 this->tls
->get_version(this->tls
), data
->len
);
208 this->signer_out
->get_signature(this->signer_out
, header
, NULL
);
210 this->signer_out
->allocate_signature(this->signer_out
, *data
, &mac
);
211 if (this->crypter_out
)
214 u_int8_t bs
, padding_length
;
216 bs
= this->crypter_out
->get_block_size(this->crypter_out
);
217 padding_length
= bs
- ((data
->len
+ mac
.len
+ 1) % bs
);
219 padding
= chunk_alloca(padding_length
);
220 memset(padding
.ptr
, padding_length
, padding
.len
);
222 if (this->iv_out
.len
)
223 { /* < TLSv1.1 uses IV from key derivation/last block */
227 { /* TLSv1.1 uses random IVs, prepended to record */
230 DBG1(DBG_IKE
, "no RNG supported to generate TLS IV");
234 this->rng
->allocate_bytes(this->rng
, bs
, &iv
);
237 *data
= chunk_cat("mmcc", *data
, mac
, padding
,
238 chunk_from_thing(padding_length
));
240 this->crypter_out
->encrypt(this->crypter_out
, *data
, iv
, NULL
);
242 if (this->iv_out
.len
)
243 { /* next record IV is last ciphertext block of this record */
244 memcpy(this->iv_out
.ptr
, data
->ptr
- this->iv_out
.len
,
249 *data
= chunk_cat("mm", iv
, *data
);
253 { /* NULL encryption */
254 *data
= chunk_cat("mm", *data
, mac
);
262 METHOD(tls_protection_t
, set_cipher
, void,
263 private_tls_protection_t
*this, bool inbound
, signer_t
*signer
,
264 crypter_t
*crypter
, chunk_t iv
)
268 this->signer_in
= signer
;
269 this->crypter_in
= crypter
;
274 this->signer_out
= signer
;
275 this->crypter_out
= crypter
;
278 { /* generate IVs if none given */
279 this->rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
284 METHOD(tls_protection_t
, destroy
, void,
285 private_tls_protection_t
*this)
287 DESTROY_IF(this->rng
);
294 tls_protection_t
*tls_protection_create(tls_t
*tls
,
295 tls_compression_t
*compression
)
297 private_tls_protection_t
*this;
303 .set_cipher
= _set_cipher
,
307 .compression
= compression
,
310 return &this->public;