2 * Copyright (C) 2012-2013 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * Hochschule fuer Technik Rapperswil
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 #include "esp_context.h"
24 #include <utils/debug.h>
27 * Should be a multiple of 8
29 #define ESP_DEFAULT_WINDOW_SIZE 128
31 typedef struct private_esp_context_t private_esp_context_t
;
34 * Private additions to esp_context_t.
36 struct private_esp_context_t
{
44 * AEAD wrapper or method to encrypt/decrypt/authenticate ESP packets
49 * The highest sequence number that was successfully verified
50 * and authenticated, or assigned in an outbound context
55 * The bit in the window of the highest authenticated sequence number
60 * The size of the anti-replay window (in bits)
65 * The anti-replay window buffer
70 * TRUE in case of an inbound ESP context
76 * Set or unset a bit in the window.
78 static inline void set_window_bit(private_esp_context_t
*this,
79 u_int index
, bool set
)
81 u_int i
= index
/ CHAR_BIT
;
85 this->window
.ptr
[i
] |= 1 << (index
% CHAR_BIT
);
89 this->window
.ptr
[i
] &= ~(1 << (index
% CHAR_BIT
));
94 * Get a bit from the window.
96 static inline bool get_window_bit(private_esp_context_t
*this, u_int index
)
98 u_int i
= index
/ CHAR_BIT
;
100 return this->window
.ptr
[i
] & (1 << index
% CHAR_BIT
);
104 * Returns TRUE if the supplied seqno is not already marked in the window
106 static bool check_window(private_esp_context_t
*this, u_int32_t seqno
)
110 offset
= this->last_seqno
- seqno
;
111 offset
= (this->seqno_index
- offset
) % this->window_size
;
112 return !get_window_bit(this, offset
);
115 METHOD(esp_context_t
, verify_seqno
, bool,
116 private_esp_context_t
*this, u_int32_t seqno
)
123 if (seqno
> this->last_seqno
)
124 { /* |----------------------------------------|
125 * <---------^ ^ or <---------^ ^
130 else if (seqno
> 0 && this->window_size
> this->last_seqno
- seqno
)
131 { /* |----------------------------------------|
132 * <---------^ or <---------^
136 return check_window(this, seqno
);
139 { /* |----------------------------------------|
147 METHOD(esp_context_t
, set_authenticated_seqno
, void,
148 private_esp_context_t
*this, u_int32_t seqno
)
157 if (seqno
> this->last_seqno
)
158 { /* shift the window to the new highest authenticated seqno */
159 shift
= seqno
- this->last_seqno
;
160 shift
= shift
< this->window_size
? shift
: this->window_size
;
161 for (i
= 0; i
< shift
; ++i
)
163 this->seqno_index
= (this->seqno_index
+ 1) % this->window_size
;
164 set_window_bit(this, this->seqno_index
, FALSE
);
166 set_window_bit(this, this->seqno_index
, TRUE
);
167 this->last_seqno
= seqno
;
170 { /* seqno is inside the window, set the corresponding window bit */
171 i
= this->last_seqno
- seqno
;
172 set_window_bit(this, (this->seqno_index
- i
) % this->window_size
, TRUE
);
176 METHOD(esp_context_t
, get_seqno
, u_int32_t
,
177 private_esp_context_t
*this)
179 return this->last_seqno
;
182 METHOD(esp_context_t
, next_seqno
, bool,
183 private_esp_context_t
*this, u_int32_t
*seqno
)
185 if (this->inbound
|| this->last_seqno
== UINT32_MAX
)
186 { /* inbound or segno would cycle */
189 *seqno
= ++this->last_seqno
;
193 METHOD(esp_context_t
, get_aead
, aead_t
*,
194 private_esp_context_t
*this)
199 METHOD(esp_context_t
, destroy
, void,
200 private_esp_context_t
*this)
202 chunk_free(&this->window
);
203 DESTROY_IF(this->aead
);
208 * Create AEAD wrapper around traditional encryption/integrity algorithms
210 static bool create_traditional(private_esp_context_t
*this, int enc_alg
,
211 chunk_t enc_key
, int int_alg
, chunk_t int_key
)
213 crypter_t
*crypter
= NULL
;
214 signer_t
*signer
= NULL
;
219 crypter
= lib
->crypto
->create_crypter(lib
->crypto
, enc_alg
,
227 DBG1(DBG_ESP
, "failed to create ESP context: unsupported encryption "
231 if (!crypter
->set_key(crypter
, enc_key
))
233 DBG1(DBG_ESP
, "failed to create ESP context: setting encryption key "
240 case AUTH_HMAC_SHA1_96
:
241 case AUTH_HMAC_SHA2_256_128
:
242 case AUTH_HMAC_SHA2_384_192
:
243 case AUTH_HMAC_SHA2_512_256
:
244 signer
= lib
->crypto
->create_signer(lib
->crypto
, int_alg
);
251 DBG1(DBG_ESP
, "failed to create ESP context: unsupported integrity "
255 if (!signer
->set_key(signer
, int_key
))
257 DBG1(DBG_ESP
, "failed to create ESP context: setting signature key "
261 this->aead
= aead_create(crypter
, signer
);
271 * Described in header.
273 esp_context_t
*esp_context_create(int enc_alg
, chunk_t enc_key
,
274 int int_alg
, chunk_t int_key
, bool inbound
)
276 private_esp_context_t
*this;
280 .get_aead
= _get_aead
,
281 .get_seqno
= _get_seqno
,
282 .next_seqno
= _next_seqno
,
283 .verify_seqno
= _verify_seqno
,
284 .set_authenticated_seqno
= _set_authenticated_seqno
,
288 .window_size
= ESP_DEFAULT_WINDOW_SIZE
,
291 if (!create_traditional(this, enc_alg
, enc_key
, int_alg
, int_key
))
299 this->window
= chunk_alloc(this->window_size
/ CHAR_BIT
+ 1);
300 memset(this->window
.ptr
, 0, this->window
.len
);
302 return &this->public;